From 574ccd856eba78d493b56b4e63d8beb24ef8fb9b Mon Sep 17 00:00:00 2001 From: Bernard Lefebvre <37628108+BernardLefebvre@users.noreply.github.com> Date: Fri, 22 Jan 2021 12:10:17 -0500 Subject: [PATCH] Adsk Contrib - More python tests and bindings fixes (#1274) * More python tests and fixes: - re-add commented tests. - add new tests for FileRules. - Fix issues outlined by tests. Signed-off-by: Bernard Lefebvre * Adjust baker test to account for small differences Signed-off-by: Bernard Lefebvre * Forgot to remove the complete string test Signed-off-by: Bernard Lefebvre * GroupTranform::write(), new enums, Lut1DTransform python tests Signed-off-by: Bernard Lefebvre * Forgot files Signed-off-by: Bernard Lefebvre Co-authored-by: doug-walker <43830961+doug-walker@users.noreply.github.com> --- .../api/python/frozen/pyopencolorio_baker.rst | 4 + .../python/frozen/pyopencolorio_config.rst | 10 +- .../pyopencolorio_fixedfunctionstyle.rst | 21 + .../frozen/pyopencolorio_grouptransform.rst | 4 +- .../frozen/pyopencolorio_lut1dhueadjust.rst | 11 +- .../frozen/pyopencolorio_rangetransform.rst | 10 +- include/OpenColorIO/OpenColorTransforms.h | 3 +- include/OpenColorIO/OpenColorTypes.h | 10 +- src/OpenColorIO/ParseUtils.cpp | 7 + .../ops/fixedfunction/FixedFunctionOpData.cpp | 9 + src/OpenColorIO/ops/lut1d/Lut1DOpData.cpp | 16 +- src/OpenColorIO/ops/lut1d/Lut1DOpData.h | 2 +- src/OpenColorIO/transforms/GroupTransform.cpp | 3 +- src/OpenColorIO/transforms/GroupTransform.h | 1 - src/OpenColorIO/transforms/Lut1DTransform.cpp | 2 +- src/OpenColorIO/transforms/Lut1DTransform.h | 2 +- src/apps/ociomakeclf/main.cpp | 3 +- src/apps/ociowrite/main.cpp | 3 +- src/bindings/python/PyBaker.cpp | 7 +- src/bindings/python/PyConfig.cpp | 15 +- src/bindings/python/PyContext.cpp | 2 +- src/bindings/python/PyFileRules.cpp | 3 + src/bindings/python/PyGroupTransform.cpp | 33 +- src/bindings/python/PyOpenColorIO.cpp | 4 +- src/bindings/python/PyRangeTransform.cpp | 4 +- src/bindings/python/PyTypes.cpp | 10 +- tests/cpu/Baker_tests.cpp | 1 - tests/cpu/fileformats/FileFormatCCC_tests.cpp | 3 +- tests/cpu/fileformats/FileFormatCC_tests.cpp | 3 +- tests/cpu/fileformats/FileFormatCDL_tests.cpp | 9 +- tests/cpu/fileformats/FileFormatCTF_tests.cpp | 7 +- .../FixedFunctionTransform_tests.cpp | 13 + tests/cpu/transforms/Lut1DTransform_tests.cpp | 10 + tests/python/BakerTest.py | 107 +++-- tests/python/CDLTransformTest.py | 4 +- tests/python/CPUProcessorTest.py | 11 +- tests/python/ConstantsTest.py | 98 ++--- tests/python/ContextTest.py | 56 +-- tests/python/FileRulesTest.py | 381 ++++++++++++++++++ tests/python/FixedFunctionTransformTest.py | 7 +- tests/python/GroupTransformTest.py | 2 +- tests/python/Lut1DTransformTest.py | 151 +++++++ tests/python/MainTest.py | 52 --- tests/python/OpenColorIOTestSuite.py | 36 +- tests/python/RangeTransformTest.py | 35 +- 45 files changed, 868 insertions(+), 317 deletions(-) create mode 100644 tests/python/FileRulesTest.py create mode 100644 tests/python/Lut1DTransformTest.py delete mode 100644 tests/python/MainTest.py diff --git a/docs/api/python/frozen/pyopencolorio_baker.rst b/docs/api/python/frozen/pyopencolorio_baker.rst index 6a08cb61..61927e4b 100644 --- a/docs/api/python/frozen/pyopencolorio_baker.rst +++ b/docs/api/python/frozen/pyopencolorio_baker.rst @@ -145,6 +145,10 @@ .. py:class:: FormatIterator :module: PyOpenColorIO.Baker + Iterator on LUT baker Formats. + + Each item is a tuple containing format name and format extension. + .. py:method:: FormatIterator.__getitem__(self: PyOpenColorIO.Baker.FormatIterator, arg0: int) -> tuple :module: PyOpenColorIO.Baker diff --git a/docs/api/python/frozen/pyopencolorio_config.rst b/docs/api/python/frozen/pyopencolorio_config.rst index 7711050a..bc0090bf 100644 --- a/docs/api/python/frozen/pyopencolorio_config.rst +++ b/docs/api/python/frozen/pyopencolorio_config.rst @@ -228,17 +228,9 @@ The fcn accepts either a color space name, role name, or alias. (Color space names take precedence over roles.) - .. py:method:: Config.getColorSpaceFromFilepath(*args, **kwargs) + .. py:method:: Config.getColorSpaceFromFilepath(self: PyOpenColorIO.Config, filePath: str) -> tuple :module: PyOpenColorIO - Overloaded function. - - 1. getColorSpaceFromFilepath(self: PyOpenColorIO.Config, filePath: str) -> str - - Get the color space of the first rule that matched filePath. - - 2. getColorSpaceFromFilepath(self: PyOpenColorIO.Config, filePath: str, ruleIndex: int) -> str - Get the color space of the first rule that matched filePath. diff --git a/docs/api/python/frozen/pyopencolorio_fixedfunctionstyle.rst b/docs/api/python/frozen/pyopencolorio_fixedfunctionstyle.rst index d1ad9edb..3c0db130 100644 --- a/docs/api/python/frozen/pyopencolorio_fixedfunctionstyle.rst +++ b/docs/api/python/frozen/pyopencolorio_fixedfunctionstyle.rst @@ -30,6 +30,12 @@ FIXED_FUNCTION_XYZ_TO_LUV : CIE XYZ to 1976 CIELUV colour space (D65 white) + FIXED_FUNCTION_ACES_GAMUTMAP_02 : ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET. + + FIXED_FUNCTION_ACES_GAMUTMAP_07 : ACES 0.7 Gamut clamping algorithm -- NOT IMPLEMENTED YET. + + FIXED_FUNCTION_ACES_GAMUTMAP_13 : ACES 1.3 Gamut mapping algorithm -- NOT IMPLEMENTED YET. + .. py:method:: name() -> str :property: @@ -38,6 +44,21 @@ :value: + .. py:attribute:: FixedFunctionStyle.FIXED_FUNCTION_ACES_GAMUTMAP_02 + :module: PyOpenColorIO + :value: + + + .. py:attribute:: FixedFunctionStyle.FIXED_FUNCTION_ACES_GAMUTMAP_07 + :module: PyOpenColorIO + :value: + + + .. py:attribute:: FixedFunctionStyle.FIXED_FUNCTION_ACES_GAMUTMAP_13 + :module: PyOpenColorIO + :value: + + .. py:attribute:: FixedFunctionStyle.FIXED_FUNCTION_ACES_GLOW_03 :module: PyOpenColorIO :value: diff --git a/docs/api/python/frozen/pyopencolorio_grouptransform.rst b/docs/api/python/frozen/pyopencolorio_grouptransform.rst index e02a3f09..fc11841b 100644 --- a/docs/api/python/frozen/pyopencolorio_grouptransform.rst +++ b/docs/api/python/frozen/pyopencolorio_grouptransform.rst @@ -73,7 +73,7 @@ Overloaded function. - 1. write(self: PyOpenColorIO.GroupTransform, config: OpenColorIO_v2_0rc1::Config, context: OpenColorIO_v2_0rc1::Context, formatName: str, fileName: str) -> None + 1. write(self: PyOpenColorIO.GroupTransform, config: PyOpenColorIO.Config, formatName: str, fileName: str) -> None Write the transforms comprising the group to the stream. @@ -89,7 +89,7 @@ formats << " (." << GroupTransform::GetFormatExtensionByIndex(i) << ")"; } - 2. write(self: PyOpenColorIO.GroupTransform, config: OpenColorIO_v2_0rc1::Config, context: OpenColorIO_v2_0rc1::Context, formatName: str) -> str + 2. write(self: PyOpenColorIO.GroupTransform, config: PyOpenColorIO.Config, formatName: str) -> str Write the transforms comprising the group to the stream. diff --git a/docs/api/python/frozen/pyopencolorio_lut1dhueadjust.rst b/docs/api/python/frozen/pyopencolorio_lut1dhueadjust.rst index f55c7ae0..7df3f5ce 100644 --- a/docs/api/python/frozen/pyopencolorio_lut1dhueadjust.rst +++ b/docs/api/python/frozen/pyopencolorio_lut1dhueadjust.rst @@ -10,9 +10,11 @@ Members: - HUE_NONE : + HUE_NONE : No adjustment. - HUE_DW3 : + HUE_DW3 : Algorithm used in ACES Output Transforms through v0.7. + + HUE_WYPN : Weighted Yellow Power Norm -- NOT IMPLEMENTED YET. .. py:method:: name() -> str :property: @@ -26,3 +28,8 @@ :module: PyOpenColorIO :value: + + .. py:attribute:: Lut1DHueAdjust.HUE_WYPN + :module: PyOpenColorIO + :value: + diff --git a/docs/api/python/frozen/pyopencolorio_rangetransform.rst b/docs/api/python/frozen/pyopencolorio_rangetransform.rst index d1f6865a..0ae5ba5f 100644 --- a/docs/api/python/frozen/pyopencolorio_rangetransform.rst +++ b/docs/api/python/frozen/pyopencolorio_rangetransform.rst @@ -152,16 +152,14 @@ Set the Range style to clamp or not input values. - .. py:method:: RangeTransform.unsetMaxOutValue(*args, **kwargs) + .. py:method:: RangeTransform.unsetMaxInValue(self: PyOpenColorIO.RangeTransform) -> None :module: PyOpenColorIO - Overloaded function. + Unset the maximum value for the input. - 1. unsetMaxOutValue(self: PyOpenColorIO.RangeTransform) -> None - Unset the maximum value for the output. - - 2. unsetMaxOutValue(self: PyOpenColorIO.RangeTransform) -> None + .. py:method:: RangeTransform.unsetMaxOutValue(self: PyOpenColorIO.RangeTransform) -> None + :module: PyOpenColorIO Unset the maximum value for the output. diff --git a/include/OpenColorIO/OpenColorTransforms.h b/include/OpenColorIO/OpenColorTransforms.h index dd48ba34..120c3c52 100644 --- a/include/OpenColorIO/OpenColorTransforms.h +++ b/include/OpenColorIO/OpenColorTransforms.h @@ -1363,7 +1363,6 @@ public: * @endcode */ virtual void write(const ConstConfigRcPtr & config, - const ConstContextRcPtr & context, const char * formatName, std::ostream & os) const = 0; @@ -1681,7 +1680,7 @@ public: * feature that was used in some versions of ACES. This adjusts the hue * of the result to approximately match the input. */ - virtual void setHueAdjust(Lut1DHueAdjust algo) noexcept = 0; + virtual void setHueAdjust(Lut1DHueAdjust algo) = 0; virtual Interpolation getInterpolation() const = 0; virtual void setInterpolation(Interpolation algo) = 0; diff --git a/include/OpenColorIO/OpenColorTypes.h b/include/OpenColorIO/OpenColorTypes.h index 4296b7d8..52cbefb5 100644 --- a/include/OpenColorIO/OpenColorTypes.h +++ b/include/OpenColorIO/OpenColorTypes.h @@ -417,8 +417,9 @@ enum BitDepth /// Used by :cpp:class`Lut1DTransform` to control optional hue restoration algorithm. enum Lut1DHueAdjust { - HUE_NONE = 0, // No adjustment. - HUE_DW3 // Algorithm used in ACES Output Transforms through v0.7. + HUE_NONE = 0, ///< No adjustment. + HUE_DW3, ///< Algorithm used in ACES Output Transforms through v0.7. + HUE_WYPN ///< Weighted Yellow Power Norm -- NOT IMPLEMENTED YET }; /// Used by \ref PackedImageDesc to indicate the channel ordering of the image to process. @@ -473,7 +474,10 @@ enum FixedFunctionStyle FIXED_FUNCTION_RGB_TO_HSV, ///< Classic RGB to HSV function FIXED_FUNCTION_XYZ_TO_xyY, ///< CIE XYZ to 1931 xy chromaticity coordinates FIXED_FUNCTION_XYZ_TO_uvY, ///< CIE XYZ to 1976 u'v' chromaticity coordinates - FIXED_FUNCTION_XYZ_TO_LUV ///< CIE XYZ to 1976 CIELUV colour space (D65 white) + FIXED_FUNCTION_XYZ_TO_LUV, ///< CIE XYZ to 1976 CIELUV colour space (D65 white) + FIXED_FUNCTION_ACES_GAMUTMAP_02, ///< ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET + FIXED_FUNCTION_ACES_GAMUTMAP_07, ///< ACES 0.7 Gamut clamping algorithm -- NOT IMPLEMENTED YET + FIXED_FUNCTION_ACES_GAMUTMAP_13 ///< ACES 1.3 Gamut mapping algorithm -- NOT IMPLEMENTED YET }; /// Enumeration of the :cpp:class:`ExposureContrastTransform` transform algorithms. diff --git a/src/OpenColorIO/ParseUtils.cpp b/src/OpenColorIO/ParseUtils.cpp index 7bdc3e26..e43654dd 100644 --- a/src/OpenColorIO/ParseUtils.cpp +++ b/src/OpenColorIO/ParseUtils.cpp @@ -350,6 +350,13 @@ const char * FixedFunctionStyleToString(FixedFunctionStyle style) case FIXED_FUNCTION_XYZ_TO_xyY: return "XYZ_TO_xyY"; case FIXED_FUNCTION_XYZ_TO_uvY: return "XYZ_TO_uvY"; case FIXED_FUNCTION_XYZ_TO_LUV: return "XYZ_TO_LUV"; + case FIXED_FUNCTION_ACES_GAMUTMAP_02: + case FIXED_FUNCTION_ACES_GAMUTMAP_07: + case FIXED_FUNCTION_ACES_GAMUTMAP_13: + throw Exception("Unimplemented fixed function types: " + "FIXED_FUNCTION_ACES_GAMUTMAP_02, " + "FIXED_FUNCTION_ACES_GAMUTMAP_07, and " + "FIXED_FUNCTION_ACES_GAMUTMAP_13."); } // Default style is meaningless. diff --git a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp index d7aa0a91..c668501b 100644 --- a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp +++ b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp @@ -244,6 +244,15 @@ FixedFunctionOpData::Style FixedFunctionOpData::ConvertStyle(FixedFunctionStyle { return FixedFunctionOpData::XYZ_TO_LUV; } + case FIXED_FUNCTION_ACES_GAMUTMAP_02: + case FIXED_FUNCTION_ACES_GAMUTMAP_07: + case FIXED_FUNCTION_ACES_GAMUTMAP_13: + { + throw Exception("Unimplemented fixed function types: " + "FIXED_FUNCTION_ACES_GAMUTMAP_02, " + "FIXED_FUNCTION_ACES_GAMUTMAP_07, and " + "FIXED_FUNCTION_ACES_GAMUTMAP_13."); + } } std::stringstream ss("Unknown FixedFunction transform style: "); diff --git a/src/OpenColorIO/ops/lut1d/Lut1DOpData.cpp b/src/OpenColorIO/ops/lut1d/Lut1DOpData.cpp index 03280e86..9524229f 100644 --- a/src/OpenColorIO/ops/lut1d/Lut1DOpData.cpp +++ b/src/OpenColorIO/ops/lut1d/Lut1DOpData.cpp @@ -313,6 +313,11 @@ bool Lut1DOpData::IsValidInterpolation(Interpolation interpolation) void Lut1DOpData::validate() const { + if (m_hueAdjust == HUE_WYPN) + { + throw Exception("1D LUT HUE_WYPN hue adjust style is not implemented."); + } + if (!IsValidInterpolation(m_interpolation)) { std::ostringstream oss; @@ -465,8 +470,13 @@ bool Lut1DOpData::operator==(const OpData & other) const return haveEqualBasics(*lop); } -void Lut1DOpData::setHueAdjust(Lut1DHueAdjust algo) noexcept +void Lut1DOpData::setHueAdjust(Lut1DHueAdjust algo) { + if (algo == HUE_WYPN) + { + throw Exception("1D LUT HUE_WYPN hue adjust style is not implemented."); + } + m_hueAdjust = algo; } @@ -526,6 +536,10 @@ const char* GetHueAdjustName(Lut1DHueAdjust algo) { return "none"; } + case HUE_WYPN: + { + throw Exception("1D LUT HUE_WYPN hue adjust style is not implemented."); + } } throw Exception("1D LUT has an invalid hue adjust style."); } diff --git a/src/OpenColorIO/ops/lut1d/Lut1DOpData.h b/src/OpenColorIO/ops/lut1d/Lut1DOpData.h index b1468d22..ea68072a 100644 --- a/src/OpenColorIO/ops/lut1d/Lut1DOpData.h +++ b/src/OpenColorIO/ops/lut1d/Lut1DOpData.h @@ -144,7 +144,7 @@ public: inline Lut1DHueAdjust getHueAdjust() const noexcept { return m_hueAdjust; } - void setHueAdjust(Lut1DHueAdjust algo) noexcept; + void setHueAdjust(Lut1DHueAdjust algo); // Get an array containing the LUT elements. // The elements are stored as a vector [r0,g0,b0, r1,g1,b1, r2,g2,b2, ...]. diff --git a/src/OpenColorIO/transforms/GroupTransform.cpp b/src/OpenColorIO/transforms/GroupTransform.cpp index 2efdce17..89ba45c2 100755 --- a/src/OpenColorIO/transforms/GroupTransform.cpp +++ b/src/OpenColorIO/transforms/GroupTransform.cpp @@ -112,7 +112,6 @@ void GroupTransformImpl::prependTransform(TransformRcPtr transform) noexcept } void GroupTransformImpl::write(const ConstConfigRcPtr & config, - const ConstContextRcPtr & context, const char * formatName, std::ostream & os) const { @@ -128,7 +127,7 @@ void GroupTransformImpl::write(const ConstConfigRcPtr & config, try { - fmt->write(config, context, *this, formatName, os); + fmt->write(config, config->getCurrentContext(), *this, formatName, os); } catch (std::exception & e) { diff --git a/src/OpenColorIO/transforms/GroupTransform.h b/src/OpenColorIO/transforms/GroupTransform.h index af1ac26a..03840408 100644 --- a/src/OpenColorIO/transforms/GroupTransform.h +++ b/src/OpenColorIO/transforms/GroupTransform.h @@ -53,7 +53,6 @@ public: void prependTransform(TransformRcPtr transform) noexcept override; void write(const ConstConfigRcPtr & config, - const ConstContextRcPtr & context, const char * formatName, std::ostream & os) const override; diff --git a/src/OpenColorIO/transforms/Lut1DTransform.cpp b/src/OpenColorIO/transforms/Lut1DTransform.cpp index e024cc2f..c24964db 100644 --- a/src/OpenColorIO/transforms/Lut1DTransform.cpp +++ b/src/OpenColorIO/transforms/Lut1DTransform.cpp @@ -139,7 +139,7 @@ void Lut1DTransformImpl::setOutputRawHalfs(bool isRawHalfs) noexcept data().setOutputRawHalfs(isRawHalfs); } -void Lut1DTransformImpl::setHueAdjust(Lut1DHueAdjust algo) noexcept +void Lut1DTransformImpl::setHueAdjust(Lut1DHueAdjust algo) { data().setHueAdjust(algo); } diff --git a/src/OpenColorIO/transforms/Lut1DTransform.h b/src/OpenColorIO/transforms/Lut1DTransform.h index 63f644f4..3b9ce5e4 100644 --- a/src/OpenColorIO/transforms/Lut1DTransform.h +++ b/src/OpenColorIO/transforms/Lut1DTransform.h @@ -50,7 +50,7 @@ public: void setOutputRawHalfs(bool isRawHalfs) noexcept override; Lut1DHueAdjust getHueAdjust() const noexcept override; - void setHueAdjust(Lut1DHueAdjust algo) noexcept override; + void setHueAdjust(Lut1DHueAdjust algo) override; Interpolation getInterpolation() const override; void setInterpolation(Interpolation algo) override; diff --git a/src/apps/ociomakeclf/main.cpp b/src/apps/ociomakeclf/main.cpp index 29e1fb25..b79c7713 100644 --- a/src/apps/ociomakeclf/main.cpp +++ b/src/apps/ociomakeclf/main.cpp @@ -55,8 +55,7 @@ void CreateOutputLutFile(const std::string & outLutFilepath, OCIO::ConstGroupTra try { const auto group = optProcessor->createGroupTransform(); - group->write(config, config->getCurrentContext(), - "Academy/ASC Common LUT Format", outfs); + group->write(config, "Academy/ASC Common LUT Format", outfs); } catch (const OCIO::Exception &) { diff --git a/src/apps/ociowrite/main.cpp b/src/apps/ociowrite/main.cpp index b86bd4c5..17987119 100644 --- a/src/apps/ociowrite/main.cpp +++ b/src/apps/ociowrite/main.cpp @@ -192,8 +192,7 @@ int main(int argc, const char **argv) if (outfs) { const auto group = processor->createGroupTransform(); - group->write(config, config->getCurrentContext(), - transformFileFormat.c_str(), outfs); + group->write(config, transformFileFormat.c_str(), outfs); outfs.close(); } else diff --git a/src/bindings/python/PyBaker.cpp b/src/bindings/python/PyBaker.cpp index 2e083d36..2de4b67e 100644 --- a/src/bindings/python/PyBaker.cpp +++ b/src/bindings/python/PyBaker.cpp @@ -33,7 +33,12 @@ void bindPyBaker(py::module & m) auto clsFormatIterator = py::class_( - clsBaker, "FormatIterator"); + clsBaker, "FormatIterator", + R"doc( +Iterator on LUT baker Formats. + +Each item is a tuple containing format name and format extension. +)doc"); clsBaker .def(py::init(&Baker::Create), diff --git a/src/bindings/python/PyConfig.cpp b/src/bindings/python/PyConfig.cpp index 8991edeb..6b2075b0 100644 --- a/src/bindings/python/PyConfig.cpp +++ b/src/bindings/python/PyConfig.cpp @@ -495,14 +495,13 @@ void bindPyConfig(py::module & m) .def("setFileRules", &Config::setFileRules, "fileRules"_a, DOC(Config, setFileRules)) .def("getColorSpaceFromFilepath", - (const char * (Config::*)(const char *) const) &Config::getColorSpaceFromFilepath, - "filePath"_a, - DOC(Config, getColorSpaceFromFilepath)) - .def("getColorSpaceFromFilepath", - (const char * (Config::*)(const char *, size_t &) const) - &Config::getColorSpaceFromFilepath, - "filePath"_a, "ruleIndex"_a, - DOC(Config, getColorSpaceFromFilepath)) + [](ConfigRcPtr & self, const std::string & filePath) + { + size_t ruleIndex = 0; + std::string csName = self->getColorSpaceFromFilepath(filePath.c_str(), ruleIndex); + return py::make_tuple(csName, ruleIndex); + }, "filePath"_a, + DOC(Config, getColorSpaceFromFilepath)) .def("filepathOnlyMatchesDefaultRule", &Config::filepathOnlyMatchesDefaultRule, "filePath"_a, DOC(Config, filepathOnlyMatchesDefaultRule)) diff --git a/src/bindings/python/PyContext.cpp b/src/bindings/python/PyContext.cpp index e9615dfb..46f0448e 100644 --- a/src/bindings/python/PyContext.cpp +++ b/src/bindings/python/PyContext.cpp @@ -108,7 +108,7 @@ void bindPyContext(py::module & m) }) .def("__len__", &Context::getNumStringVars, DOC(Context, getNumStringVars)) - .def("__getitem__", [](ContextRcPtr & self, const std::string & name) -> bool + .def("__getitem__", [](ContextRcPtr & self, const std::string & name) -> const char * { for (int i = 0; i < self->getNumStringVars(); i++) { diff --git a/src/bindings/python/PyFileRules.cpp b/src/bindings/python/PyFileRules.cpp index 4a0bd9fd..370e4cd1 100644 --- a/src/bindings/python/PyFileRules.cpp +++ b/src/bindings/python/PyFileRules.cpp @@ -70,6 +70,9 @@ void bindPyFileRules(py::module & m) .def("isDefault", &FileRules::isDefault, DOC(FileRules, isDefault)); defRepr(clsFileRules); + + m.attr("DEFAULT_RULE_NAME") = FileRules::DefaultRuleName; + m.attr("FILE_PATH_SEARCH_RULE_NAME") = FileRules::FilePathSearchRuleName; } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyGroupTransform.cpp b/src/bindings/python/PyGroupTransform.cpp index 27553527..5f020be9 100644 --- a/src/bindings/python/PyGroupTransform.cpp +++ b/src/bindings/python/PyGroupTransform.cpp @@ -25,6 +25,7 @@ using WriteFormatIterator = PyIterator; void bindPyGroupTransform(py::module & m) { GroupTransformRcPtr DEFAULT = GroupTransform::Create(); + ConfigRcPtr EMPTY_CONFIG = Config::Create(); auto clsGroupTransform = py::class_( @@ -78,28 +79,44 @@ void bindPyGroupTransform(py::module & m) .def("prependTransform", &GroupTransform::prependTransform, "transform"_a, DOC(GroupTransform, prependTransform)) .def("write", [](GroupTransformRcPtr & self, - const ConstConfigRcPtr & config, - const ConstContextRcPtr & context, + ConstConfigRcPtr & config, const std::string & formatName, const std::string & fileName) { + if (!config) + { + config = GetCurrentConfig(); + } + if (!config) + { + throw Exception("A config is required."); + } std::ofstream f(fileName.c_str()); - self->write(config, context, formatName.c_str(), f); + self->write(config, formatName.c_str(), f); f.close(); }, - "config"_a, "context"_a, "formatName"_a, "fileName"_a, + "config"_a = EMPTY_CONFIG, + "formatName"_a.none(false), "fileName"_a.none(false), DOC(GroupTransform, write)) .def("write", [](GroupTransformRcPtr & self, const ConstConfigRcPtr & config, - const ConstContextRcPtr & context, const std::string & formatName) { + ConstConfigRcPtr cfg = config; + if (!config) + { + cfg = GetCurrentConfig(); + } + if (!cfg) + { + throw Exception("A config is required."); + } std::ostringstream os; - self->write(config, context, formatName.c_str(), os); + self->write(cfg, formatName.c_str(), os); return os.str(); }, - "config"_a, "context"_a, "formatName"_a, - DOC(GroupTransform, write)); + "config"_a = EMPTY_CONFIG, "formatName"_a, + DOC(GroupTransform, write)); defRepr(clsGroupTransform); diff --git a/src/bindings/python/PyOpenColorIO.cpp b/src/bindings/python/PyOpenColorIO.cpp index 379163b7..4ac5966e 100644 --- a/src/bindings/python/PyOpenColorIO.cpp +++ b/src/bindings/python/PyOpenColorIO.cpp @@ -67,8 +67,9 @@ PYBIND11_MODULE(PyOpenColorIO, m) m.attr("__doc__") = "OpenColorIO (OCIO) is a complete color management solution geared towards motion picture production"; // Classes - bindPyTransform(m); bindPyConfig(m); + bindPyContext(m); + bindPyTransform(m); bindPyFileRules(m); bindPyColorSpace(m); bindPyColorSpaceSet(m); @@ -81,7 +82,6 @@ PYBIND11_MODULE(PyOpenColorIO, m) bindPyBaker(m); bindPyImageDesc(m); bindPyGpuShaderCreator(m); - bindPyContext(m); bindPyViewingRules(m); bindPySystemMonitors(m); bindPyGradingData(m); diff --git a/src/bindings/python/PyRangeTransform.cpp b/src/bindings/python/PyRangeTransform.cpp index 601a1477..06914b29 100644 --- a/src/bindings/python/PyRangeTransform.cpp +++ b/src/bindings/python/PyRangeTransform.cpp @@ -71,8 +71,8 @@ void bindPyRangeTransform(py::module & m) DOC(RangeTransform, setMaxInValue)) .def("hasMaxInValue", &RangeTransform::hasMaxInValue, DOC(RangeTransform, hasMaxInValue)) - .def("unsetMaxOutValue", &RangeTransform::unsetMaxOutValue, - DOC(RangeTransform, unsetMaxOutValue)) + .def("unsetMaxInValue", &RangeTransform::unsetMaxInValue, + DOC(RangeTransform, unsetMaxInValue)) .def("getMinOutValue", &RangeTransform::getMinOutValue, DOC(RangeTransform, getMinOutValue)) .def("setMinOutValue", &RangeTransform::setMinOutValue, "value"_a, diff --git a/src/bindings/python/PyTypes.cpp b/src/bindings/python/PyTypes.cpp index 56efa4b2..e79733ca 100644 --- a/src/bindings/python/PyTypes.cpp +++ b/src/bindings/python/PyTypes.cpp @@ -211,8 +211,10 @@ void bindPyTypes(py::module & m) .value("HUE_NONE", HUE_NONE, DOC(PyOpenColorIO, Lut1DHueAdjust, HUE_NONE)) - .value("HUE_DW3", HUE_DW3, + .value("HUE_DW3", HUE_DW3, DOC(PyOpenColorIO, Lut1DHueAdjust, HUE_DW3)) + .value("HUE_WYPN", HUE_WYPN, + DOC(PyOpenColorIO, Lut1DHueAdjust, HUE_WYPN)) .export_values(); py::enum_( @@ -305,6 +307,12 @@ void bindPyTypes(py::module & m) DOC(PyOpenColorIO, FixedFunctionStyle, FIXED_FUNCTION_XYZ_TO_uvY)) .value("FIXED_FUNCTION_XYZ_TO_LUV", FIXED_FUNCTION_XYZ_TO_LUV, DOC(PyOpenColorIO, FixedFunctionStyle, FIXED_FUNCTION_XYZ_TO_LUV)) + .value("FIXED_FUNCTION_ACES_GAMUTMAP_02", FIXED_FUNCTION_ACES_GAMUTMAP_02, + DOC(PyOpenColorIO, FixedFunctionStyle, FIXED_FUNCTION_ACES_GAMUTMAP_02)) + .value("FIXED_FUNCTION_ACES_GAMUTMAP_07", FIXED_FUNCTION_ACES_GAMUTMAP_07, + DOC(PyOpenColorIO, FixedFunctionStyle, FIXED_FUNCTION_ACES_GAMUTMAP_07)) + .value("FIXED_FUNCTION_ACES_GAMUTMAP_13", FIXED_FUNCTION_ACES_GAMUTMAP_13, + DOC(PyOpenColorIO, FixedFunctionStyle, FIXED_FUNCTION_ACES_GAMUTMAP_13)) .export_values(); py::enum_( diff --git a/tests/cpu/Baker_tests.cpp b/tests/cpu/Baker_tests.cpp index 3268d0aa..4eddf47b 100644 --- a/tests/cpu/Baker_tests.cpp +++ b/tests/cpu/Baker_tests.cpp @@ -57,7 +57,6 @@ void CompareFloats(const std::string& floats1, const std::string& floats2) OCIO_ADD_TEST(Baker, bake) { - // SSE aware test, similar to python test. OCIO::BakerRcPtr bake = OCIO::Baker::Create(); static const std::string myProfile = diff --git a/tests/cpu/fileformats/FileFormatCCC_tests.cpp b/tests/cpu/fileformats/FileFormatCCC_tests.cpp index 63130041..74c19e57 100644 --- a/tests/cpu/fileformats/FileFormatCCC_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCCC_tests.cpp @@ -339,8 +339,7 @@ OCIO_ADD_TEST(FileFormatCCC, write) auto cfg = OCIO::Config::CreateRaw(); std::ostringstream oss; - OCIO_CHECK_NO_THROW(group->write(cfg, cfg->getCurrentContext(), - OCIO::FILEFORMAT_COLOR_CORRECTION_COLLECTION, oss)); + OCIO_CHECK_NO_THROW(group->write(cfg, OCIO::FILEFORMAT_COLOR_CORRECTION_COLLECTION, oss)); constexpr char RESULT[] { R"( This is a color correction collection example. It includes all possible description uses. diff --git a/tests/cpu/fileformats/FileFormatCC_tests.cpp b/tests/cpu/fileformats/FileFormatCC_tests.cpp index 4864b558..4b314557 100644 --- a/tests/cpu/fileformats/FileFormatCC_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCC_tests.cpp @@ -169,8 +169,7 @@ OCIO_ADD_TEST(FileFormatCC, test_cc2_load_save) std::ostringstream outputTransform; OCIO::ConstConfigRcPtr cfg = OCIO::Config::CreateRaw(); - OCIO_CHECK_NO_THROW(group->write(cfg, cfg->getCurrentContext(), - OCIO::FILEFORMAT_COLOR_CORRECTION, outputTransform)); + OCIO_CHECK_NO_THROW(group->write(cfg, OCIO::FILEFORMAT_COLOR_CORRECTION, outputTransform)); const std::string expected{ R"( Example look diff --git a/tests/cpu/fileformats/FileFormatCDL_tests.cpp b/tests/cpu/fileformats/FileFormatCDL_tests.cpp index 6032e6a8..cdd4a840 100644 --- a/tests/cpu/fileformats/FileFormatCDL_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCDL_tests.cpp @@ -296,8 +296,7 @@ OCIO_ADD_TEST(FileFormatCDL, write) auto cfg = OCIO::Config::CreateRaw(); std::ostringstream oss; - OCIO_CHECK_NO_THROW(group->write(cfg, cfg->getCurrentContext(), - OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss)); + OCIO_CHECK_NO_THROW(group->write(cfg,OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss)); constexpr char RESULT[]{ R"( This is a color decision list example. It includes all possible description uses. @@ -392,13 +391,11 @@ OCIO_ADD_TEST(FileFormatCDL, write) // Empty group. group = OCIO::GroupTransform::Create(); - OCIO_CHECK_THROW_WHAT(group->write(cfg, cfg->getCurrentContext(), - OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss), + OCIO_CHECK_THROW_WHAT(group->write(cfg, OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss), OCIO::Exception, "there should be at least one CDL"); // Only CDL. group->appendTransform(OCIO::RangeTransform::Create()); - OCIO_CHECK_THROW_WHAT(group->write(cfg, cfg->getCurrentContext(), - OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss), + OCIO_CHECK_THROW_WHAT(group->write(cfg, OCIO::FILEFORMAT_COLOR_DECISION_LIST, oss), OCIO::Exception, "only CDL can be written"); } diff --git a/tests/cpu/fileformats/FileFormatCTF_tests.cpp b/tests/cpu/fileformats/FileFormatCTF_tests.cpp index 4e25122b..ab58d78d 100644 --- a/tests/cpu/fileformats/FileFormatCTF_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCTF_tests.cpp @@ -3682,13 +3682,13 @@ namespace void WriteGroupCTF(OCIO::ConstGroupTransformRcPtr group, std::ostringstream & outputTransform) { OCIO::ConstConfigRcPtr cfg = OCIO::Config::CreateRaw(); - group->write(cfg, cfg->getCurrentContext(), OCIO::FILEFORMAT_CTF, outputTransform); + group->write(cfg, OCIO::FILEFORMAT_CTF, outputTransform); } void WriteGroupCLF(OCIO::ConstGroupTransformRcPtr group, std::ostringstream & outputTransform) { OCIO::ConstConfigRcPtr cfg = OCIO::Config::CreateRaw(); - group->write(cfg, cfg->getCurrentContext(), OCIO::FILEFORMAT_CLF, outputTransform); + group->write(cfg, OCIO::FILEFORMAT_CLF, outputTransform); } void ValidateFixedFunctionStyleNoParam(OCIO::FixedFunctionOpData::Style style, int lineNo) @@ -5542,8 +5542,7 @@ OCIO_ADD_TEST(CTFTransform, legacy_cdl) group->appendTransform(cdl); std::ostringstream outputTransform; - OCIO_CHECK_NO_THROW(group->write(config, config->getCurrentContext(), OCIO::FILEFORMAT_CTF, - outputTransform)); + OCIO_CHECK_NO_THROW(group->write(config, OCIO::FILEFORMAT_CTF, outputTransform)); // For OCIO v1, an ASC CDL was implemented as a Matrix/Gamma/Matrix rather // than as a dedicated op as in v2 and onward. diff --git a/tests/cpu/transforms/FixedFunctionTransform_tests.cpp b/tests/cpu/transforms/FixedFunctionTransform_tests.cpp index c02cf050..314f7c98 100644 --- a/tests/cpu/transforms/FixedFunctionTransform_tests.cpp +++ b/tests/cpu/transforms/FixedFunctionTransform_tests.cpp @@ -54,4 +54,17 @@ OCIO_ADD_TEST(FixedFunctionTransform, basic) OCIO_CHECK_THROW_WHAT(func->validate(), OCIO::Exception, "The style 'RGB_TO_HSV' must have " "zero parameters but 1 found."); + + OCIO_CHECK_THROW_WHAT(func->setStyle(OCIO::FIXED_FUNCTION_ACES_GAMUTMAP_13), OCIO::Exception, + "Unimplemented fixed function types: " + "FIXED_FUNCTION_ACES_GAMUTMAP_02, " + "FIXED_FUNCTION_ACES_GAMUTMAP_07, and " + "FIXED_FUNCTION_ACES_GAMUTMAP_13."); + + OCIO_CHECK_THROW_WHAT( + OCIO::FixedFunctionTransform::Create(OCIO::FIXED_FUNCTION_ACES_GAMUTMAP_07), + OCIO::Exception, "Unimplemented fixed function types: " + "FIXED_FUNCTION_ACES_GAMUTMAP_02, " + "FIXED_FUNCTION_ACES_GAMUTMAP_07, and " + "FIXED_FUNCTION_ACES_GAMUTMAP_13."); } diff --git a/tests/cpu/transforms/Lut1DTransform_tests.cpp b/tests/cpu/transforms/Lut1DTransform_tests.cpp index f2ff7f24..0b2fc8e9 100644 --- a/tests/cpu/transforms/Lut1DTransform_tests.cpp +++ b/tests/cpu/transforms/Lut1DTransform_tests.cpp @@ -171,3 +171,13 @@ OCIO_ADD_TEST(Lut1DTransform, non_monotonic) OCIO_CHECK_EQUAL(g, 0.25f); OCIO_CHECK_EQUAL(b, 0.25f); } + +OCIO_ADD_TEST(Lut1DTransform, hue_adjust) +{ + auto lut = OCIO::Lut1DTransform::Create(); + OCIO_CHECK_EQUAL(lut->getHueAdjust(), OCIO::HUE_NONE); + OCIO_CHECK_NO_THROW(lut->setHueAdjust(OCIO::HUE_DW3)); + OCIO_CHECK_EQUAL(lut->getHueAdjust(), OCIO::HUE_DW3); + OCIO_CHECK_THROW_WHAT(lut->setHueAdjust(OCIO::HUE_WYPN), OCIO::Exception, + "1D LUT HUE_WYPN hue adjust style is not implemented."); +} diff --git a/tests/python/BakerTest.py b/tests/python/BakerTest.py index bee418e5..ef1a6698 100644 --- a/tests/python/BakerTest.py +++ b/tests/python/BakerTest.py @@ -8,10 +8,6 @@ import PyOpenColorIO as OCIO class BakerTest(unittest.TestCase): - def __init__(self, testName, sseBuild): - super(BakerTest, self).__init__(testName) - self.useSSE = sseBuild - SIMPLE_PROFILE = """ocio_profile_version: 1 strictparsing: false @@ -31,7 +27,7 @@ colorspaces: allocation: uniform to_reference: ! {value: [2.2, 2.2, 2.2, 1]}""" - EXPECTED_LUT_NONSSE = """CSPLUTV100 + EXPECTED_LUT = """CSPLUTV100 3D BEGIN METADATA @@ -57,62 +53,55 @@ END METADATA 0.042823 6.622026 6.622026 6.622026 6.622026 6.622026 -""" - - EXPECTED_LUT_SSE = """CSPLUTV100 -3D - -BEGIN METADATA -END METADATA - -4 -0.000977 0.039373 1.587398 64.000168 -0.000000 0.333333 0.666667 1.000000 -4 -0.000977 0.039373 1.587398 64.000168 -0.000000 0.333333 0.666667 1.000000 -4 -0.000977 0.039373 1.587398 64.000168 -0.000000 0.333333 0.666667 1.000000 - -2 2 2 -0.042823 0.042823 0.042823 -6.622035 0.042823 0.042823 -0.042823 6.622035 0.042823 -6.622035 6.622035 0.042823 -0.042823 0.042823 6.622035 -6.622035 0.042823 6.622035 -0.042823 6.622035 6.622035 -6.622035 6.622035 6.622035 - """ def test_interface(self): + """ + Test similar to C++ CPU test. + """ bake = OCIO.Baker() - bakee = bake.createEditableCopy() cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) - self.assertEqual(2, cfg.getNumColorSpaces()) - bakee.setConfig(cfg) - cfg2 = bakee.getConfig() - self.assertEqual(2, cfg2.getNumColorSpaces()) - bakee.setFormat("cinespace") - self.assertEqual("cinespace", bakee.getFormat()) - bakee.setInputSpace("lnh") - self.assertEqual("lnh", bakee.getInputSpace()) - bakee.setLooks("foo, +bar") - self.assertEqual("foo, +bar", bakee.getLooks()) - bakee.setLooks("") - bakee.setTargetSpace("test") - self.assertEqual("test", bakee.getTargetSpace()) - bakee.setShaperSize(4) - self.assertEqual(4, bakee.getShaperSize()) - bakee.setCubeSize(2) - self.assertEqual(2, bakee.getCubeSize()) - output = bakee.bake() - if self.useSSE == True: - self.assertEqual(self.EXPECTED_LUT_SSE, output) - else: - self.assertEqual(self.EXPECTED_LUT_NONSSE, output) - self.assertEqual(10, bakee.getNumFormats()) - self.assertEqual("cinespace", bakee.getFormatNameByIndex(4)) - self.assertEqual("3dl", bakee.getFormatExtensionByIndex(1)) + cs = cfg.getColorSpaces() + self.assertEqual(len(cs), 2) + bake.setConfig(cfg) + cfg2 = bake.getConfig() + cs2 = cfg2.getColorSpaces() + self.assertEqual(len(cs2), 2) + + bake.setFormat("cinespace") + self.assertEqual("cinespace", bake.getFormat()) + bake.setInputSpace("lnh") + self.assertEqual("lnh", bake.getInputSpace()) + bake.setLooks("foo, +bar") + self.assertEqual("foo, +bar", bake.getLooks()) + bake.setLooks("") + bake.setTargetSpace("test") + self.assertEqual("test", bake.getTargetSpace()) + bake.setShaperSize(4) + self.assertEqual(4, bake.getShaperSize()) + bake.setCubeSize(2) + self.assertEqual(2, bake.getCubeSize()) + output = bake.bake() + lines = output.splitlines() + expected_lines = self.EXPECTED_LUT.splitlines() + self.assertEqual(len(lines), len(expected_lines)) + # Text compare for the first lines. + for i in range(6): + self.assertEqual(lines[i], expected_lines[i]) + # Compare values after (results might be slightly different on some plaforms). + for i in range(6, len(lines)): + # Skip blank lines. + if lines[i] == '': + continue + # Line 16 is the cube size. + if i == 16: + self.assertEqual(lines[i], expected_lines[i]) + continue + lf = lines[i].split(' ') + elf = expected_lines[i].split(' ') + for j in range(len(lf)): + self.assertAlmostEqual(float(lf[j]), float(elf[j]), delta = 0.00001) + fmts = bake.getFormats() + self.assertEqual(len(fmts), 10) + self.assertEqual("cinespace", fmts[4][0]) + self.assertEqual("3dl", fmts[1][1]) diff --git a/tests/python/CDLTransformTest.py b/tests/python/CDLTransformTest.py index 5a91e105..dbf6c59d 100644 --- a/tests/python/CDLTransformTest.py +++ b/tests/python/CDLTransformTest.py @@ -165,10 +165,10 @@ class CDLTransformTest(unittest.TestCase): self.assertEqual(cdl.getSat(), 0.7) # Write CDL back. - config = OCIO.Config.CreateRaw() + cfg = OCIO.Config.CreateRaw() grp = OCIO.GroupTransform() grp.appendTransform(cdl) - self.assertEqual(grp.write(config, config.getCurrentContext(), 'ColorCorrection'), + self.assertEqual(grp.write(config=cfg, formatName='ColorCorrection'), """ this is a description diff --git a/tests/python/CPUProcessorTest.py b/tests/python/CPUProcessorTest.py index 00533889..071a5442 100644 --- a/tests/python/CPUProcessorTest.py +++ b/tests/python/CPUProcessorTest.py @@ -101,7 +101,7 @@ class CPUProcessorTest(unittest.TestCase): # BIT_DEPTH_F32 cls.float_rgb_1d = np.concatenate(( [-65504.0], - np.flip(-log_range, 0), + np.flipud(-log_range), [0.0], log_range, [65504.0] @@ -133,9 +133,8 @@ class CPUProcessorTest(unittest.TestCase): cls.uint16_rgb_1d = np.linspace( 0, 2**16-1, num=63, - endpoint=True, - dtype=np.uint16 - ) + endpoint=True + ).astype(np.uint16) cls.uint16_rgb_2d = cls.uint16_rgb_1d.reshape([21, 3]) cls.uint16_rgb_3d = cls.uint16_rgb_1d.reshape([7, 3, 3]) @@ -151,9 +150,7 @@ class CPUProcessorTest(unittest.TestCase): cls.uint8_rgb_1d = np.linspace( 0, 2**8-1, num=63, - endpoint=True, - dtype=np.uint8 - ) + endpoint=True).astype(np.uint8) cls.uint8_rgb_2d = cls.uint8_rgb_1d.reshape([21, 3]) cls.uint8_rgb_3d = cls.uint8_rgb_1d.reshape([7, 3, 3]) diff --git a/tests/python/ConstantsTest.py b/tests/python/ConstantsTest.py index bdb272d5..4fcaa493 100644 --- a/tests/python/ConstantsTest.py +++ b/tests/python/ConstantsTest.py @@ -6,68 +6,50 @@ import PyOpenColorIO as OCIO class ConstantsTest(unittest.TestCase): - def test_interface(self): + def test_string_constants(self): + """ + Verify string constants exposed by OCIO. + """ + # EnvironmentMode (env. variables). + self.assertEqual(OCIO.OCIO_CONFIG_ENVVAR, 'OCIO') + self.assertEqual(OCIO.OCIO_ACTIVE_DISPLAYS_ENVVAR, 'OCIO_ACTIVE_DISPLAYS') + self.assertEqual(OCIO.OCIO_ACTIVE_VIEWS_ENVVAR, 'OCIO_ACTIVE_VIEWS') + self.assertEqual(OCIO.OCIO_INACTIVE_COLORSPACES_ENVVAR, 'OCIO_INACTIVE_COLORSPACES') + self.assertEqual(OCIO.OCIO_OPTIMIZATION_FLAGS_ENVVAR, 'OCIO_OPTIMIZATION_FLAGS') + self.assertEqual(OCIO.OCIO_USER_CATEGORIES_ENVVAR, 'OCIO_USER_CATEGORIES_ENVVAR') - # LoggingLevel - self.assertEqual(OCIO.LOGGING_LEVEL_NONE, "none") - self.assertEqual(OCIO.LOGGING_LEVEL_WARNING, "warning") - self.assertEqual(OCIO.LOGGING_LEVEL_INFO, "info") - self.assertEqual(OCIO.LOGGING_LEVEL_DEBUG, "debug") - self.assertEqual(OCIO.LOGGING_LEVEL_UNKNOWN, "unknown") + # Cache (env. variables). + self.assertEqual(OCIO.OCIO_DISABLE_ALL_CACHES, 'OCIO_DISABLE_ALL_CACHES') + self.assertEqual(OCIO.OCIO_DISABLE_PROCESSOR_CACHES, 'OCIO_DISABLE_PROCESSOR_CACHES') + self.assertEqual(OCIO.OCIO_DISABLE_CACHE_FALLBACK, 'OCIO_DISABLE_CACHE_FALLBACK') - # TransformDirection - self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, "forward") - self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, "inverse") - self.assertEqual(OCIO.GetInverseTransformDirection(OCIO.TRANSFORM_DIR_FORWARD), - OCIO.TRANSFORM_DIR_INVERSE) - self.assertEqual(OCIO.GetInverseTransformDirection(OCIO.TRANSFORM_DIR_INVERSE), - OCIO.TRANSFORM_DIR_FORWARD) + # Roles. + self.assertEqual(OCIO.ROLE_DEFAULT, 'default') + self.assertEqual(OCIO.ROLE_REFERENCE, 'reference') + self.assertEqual(OCIO.ROLE_DATA, 'data') + self.assertEqual(OCIO.ROLE_COLOR_PICKING, 'color_picking') + self.assertEqual(OCIO.ROLE_SCENE_LINEAR, 'scene_linear') + self.assertEqual(OCIO.ROLE_COMPOSITING_LOG, 'compositing_log') + self.assertEqual(OCIO.ROLE_COLOR_TIMING, 'color_timing') + self.assertEqual(OCIO.ROLE_TEXTURE_PAINT, 'texture_paint') + self.assertEqual(OCIO.ROLE_MATTE_PAINT, 'matte_paint') + self.assertEqual(OCIO.ROLE_RENDERING, 'rendering') + self.assertEqual(OCIO.ROLE_INTERCHANGE_SCENE, 'aces_interchange') + self.assertEqual(OCIO.ROLE_INTERCHANGE_DISPLAY, 'cie_xyz_d65_interchange') - # ColorSpaceDirection - self.assertEqual(OCIO.COLORSPACE_DIR_TO_REFERENCE, "to_reference") - self.assertEqual(OCIO.COLORSPACE_DIR_FROM_REFERENCE, "from_reference") + # Shared View. + self.assertEqual(OCIO.OCIO_VIEW_USE_DISPLAY_NAME, '') - # BitDepth - self.assertEqual(OCIO.BIT_DEPTH_UNKNOWN, "unknown") - self.assertEqual(OCIO.BIT_DEPTH_UINT8, "8ui") - self.assertEqual(OCIO.BIT_DEPTH_UINT10, "10ui") - self.assertEqual(OCIO.BIT_DEPTH_UINT12, "12ui") - self.assertEqual(OCIO.BIT_DEPTH_UINT14, "14ui") - self.assertEqual(OCIO.BIT_DEPTH_UINT16, "16ui") - self.assertEqual(OCIO.BIT_DEPTH_UINT32, "32ui") - self.assertEqual(OCIO.BIT_DEPTH_F16, "16f") - self.assertEqual(OCIO.BIT_DEPTH_F32, "32f") + # FormatMetadata. + self.assertEqual(OCIO.METADATA_DESCRIPTION, 'Description') + self.assertEqual(OCIO.METADATA_INFO, 'Info') + self.assertEqual(OCIO.METADATA_INPUT_DESCRIPTOR, 'InputDescriptor') + self.assertEqual(OCIO.METADATA_OUTPUT_DESCRIPTOR, 'OutputDescriptor') + self.assertEqual(OCIO.METADATA_NAME, 'name') + self.assertEqual(OCIO.METADATA_ID, 'id') - # Allocation - self.assertEqual(OCIO.ALLOCATION_UNKNOWN, "unknown") - self.assertEqual(OCIO.ALLOCATION_UNIFORM, "uniform") - self.assertEqual(OCIO.ALLOCATION_LG2, "lg2") + # FileRules. + self.assertEqual(OCIO.DEFAULT_RULE_NAME, 'Default') + self.assertEqual(OCIO.FILE_PATH_SEARCH_RULE_NAME, 'ColorSpaceNamePathSearch') - # Interpolation - self.assertEqual(OCIO.INTERP_UNKNOWN, "unknown") - self.assertEqual(OCIO.INTERP_NEAREST, "nearest") - self.assertEqual(OCIO.INTERP_LINEAR, "linear") - self.assertEqual(OCIO.INTERP_TETRAHEDRAL, "tetrahedral") - self.assertEqual(OCIO.INTERP_BEST, "best") - # GpuLanguage - self.assertEqual(OCIO.GPU_LANGUAGE_UNKNOWN, "unknown") - self.assertEqual(OCIO.GPU_LANGUAGE_CG, "cg") - self.assertEqual(OCIO.GPU_LANGUAGE_GLSL_1_0, "glsl_1.0") - self.assertEqual(OCIO.GPU_LANGUAGE_GLSL_1_3, "glsl_1.3") - - # EnvironmentMode - self.assertEqual(OCIO.ENV_ENVIRONMENT_UNKNOWN, "unknown") - self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_PREDEFINED, "loadpredefined") - self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_ALL, "loadall") - - # Roles - self.assertEqual(OCIO.ROLE_DEFAULT, "default") - self.assertEqual(OCIO.ROLE_REFERENCE, "reference") - self.assertEqual(OCIO.ROLE_DATA, "data") - self.assertEqual(OCIO.ROLE_COLOR_PICKING, "color_picking") - self.assertEqual(OCIO.ROLE_SCENE_LINEAR, "scene_linear") - self.assertEqual(OCIO.ROLE_COMPOSITING_LOG, "compositing_log") - self.assertEqual(OCIO.ROLE_COLOR_TIMING, "color_timing") - self.assertEqual(OCIO.ROLE_TEXTURE_PAINT, "texture_paint") - self.assertEqual(OCIO.ROLE_MATTE_PAINT, "matte_paint") diff --git a/tests/python/ContextTest.py b/tests/python/ContextTest.py index 62673542..bb75c5ab 100644 --- a/tests/python/ContextTest.py +++ b/tests/python/ContextTest.py @@ -7,37 +7,41 @@ import PyOpenColorIO as OCIO class ContextTest(unittest.TestCase): def test_interface(self): + """ + Construct and use Context. + """ cont = OCIO.Context() - cont.setSearchPath("testing123") - cont.setWorkingDir("/dir/123") - self.assertEqual("$4c2d66a612fc25ddd509591e1dead57b", cont.getCacheID()) - self.assertEqual("testing123", cont.getSearchPath()) - self.assertEqual("/dir/123", cont.getWorkingDir()) - cont["TeSt"] = "foobar" - self.assertEqual("foobar", cont["TeSt"]) + cont.setSearchPath('testing123') + cont.setWorkingDir('/dir/123') + self.assertEqual('$4c2d66a612fc25ddd509591e1dead57b', cont.getCacheID()) + self.assertEqual('testing123', cont.getSearchPath()) + self.assertEqual('/dir/123', cont.getWorkingDir()) + cont['TeSt'] = 'foobar' + self.assertEqual('foobar', cont['TeSt']) self.assertEqual(1, len(cont)) - self.assertEqual("TeSt", cont.getStringVarNameByIndex(0)) + cont_iter = iter(cont) + self.assertEqual(len(cont_iter), 1) + self.assertEqual(cont_iter[0], 'TeSt') cont.loadEnvironment() - self.assertNotEqual(0, cont.getNumStringVars()) - cont.setStringVar("TEST1", "foobar") - self.assertEqual("/foo/foobar/bar", cont.resolveStringVar("/foo/${TEST1}/bar")) + self.assertEqual(len(cont), 1) + cont['TEST1'] = 'foobar' + self.assertEqual(len(cont), 2) + self.assertEqual('/foo/foobar/bar', cont.resolveStringVar('/foo/${TEST1}/bar')) cont.clearStringVars() - self.assertEqual(0, cont.getNumStringVars()) + self.assertEqual(len(cont), 0) self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_PREDEFINED, cont.getEnvironmentMode()) cont.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_ALL) self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_ALL, cont.getEnvironmentMode()) cont.clearSearchPaths() - self.assertEqual(0, cont.getNumSearchPaths()) - cont.addSearchPath("First/ Path") - self.assertEqual(1, cont.getNumSearchPaths()) - cont.addSearchPath("D:\\Second\\Path\\") - self.assertEqual(2, cont.getNumSearchPaths()) - self.assertEqual("First/ Path", cont.getSearchPathByIndex(0)) - self.assertEqual("D:\\Second\\Path\\", cont.getSearchPathByIndex(1)) - try: - cont.setSearchPath("testing123") - foo = cont.resolveFileLocation("test.lut") - print(foo) - except OCIO.ExceptionMissingFile as e: - #print e - pass + sp = cont.getSearchPaths() + self.assertEqual(len(sp), 0) + cont.addSearchPath('First/ Path') + self.assertEqual(len(sp), 1) + cont.addSearchPath('D:\\Second\\Path\\') + self.assertEqual(len(sp), 2) + self.assertEqual(next(sp), 'First/ Path') + self.assertEqual(next(sp), 'D:\\Second\\Path\\') + + cont.setSearchPath('testing123') + with self.assertRaises(OCIO.ExceptionMissingFile): + foo = cont.resolveFileLocation('test.lut') diff --git a/tests/python/FileRulesTest.py b/tests/python/FileRulesTest.py new file mode 100644 index 00000000..55f79de6 --- /dev/null +++ b/tests/python/FileRulesTest.py @@ -0,0 +1,381 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest, os, sys +import PyOpenColorIO as OCIO + +class FileRulesTest(unittest.TestCase): + + def test_default(self): + """ + Construct and verify default values. + """ + rules = OCIO.FileRules() + self.assertTrue(rules.isDefault()) + self.assertEqual(rules.getNumEntries(), 1) + self.assertEqual(rules.getName(0), OCIO.DEFAULT_RULE_NAME) + self.assertEqual(rules.getPattern(0), '') + self.assertEqual(rules.getExtension(0), '') + self.assertEqual(rules.getRegex(0), '') + self.assertEqual(rules.getColorSpace(0), 'default') + + def test_name(self): + """ + Test getName(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'regex') + self.assertEqual(rules.getName(0), 'test') + + with self.assertRaises(OCIO.Exception): + rules.getName(4) + + with self.assertRaises(TypeError): + rules.getName('test') + + def test_pattern(self): + """ + Test get/setPattern(). + """ + rules = OCIO.FileRules() + # Inserting a rule at position 0 is moving Default rule at position 1. + rules.insertRule(0, 'test', 'colorspace', 'pattern', 'ext') + self.assertEqual(rules.getPattern(0), 'pattern') + rules.setPattern(0, 'new pattern') + self.assertEqual(rules.getPattern(0), 'new pattern') + + # Setting regex clears pattern. + rules.setRegex(0, 'regex') + self.assertEqual(rules.getPattern(0), '') + + with self.assertRaises(OCIO.Exception): + rules.setPattern(4, 'invalid index') + + # Default rule only has a color space parameter. + with self.assertRaises(OCIO.Exception): + rules.setPattern(1, 'default does not use pattern') + + with self.assertRaises(OCIO.Exception): + rules.getPattern(4) + + # Wrong strings. + for invalid in (None, '', '[]', '[a-b'): + with self.assertRaises(OCIO.Exception): + rules.setPattern(0, invalid) + + # Wrong types. + for invalid in (OCIO.TRANSFORM_DIR_INVERSE, 1): + with self.assertRaises(TypeError): + rules.setPattern(0, invalid) + + def test_extension(self): + """ + Test get/setExtension(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'pattern', 'ext') + self.assertEqual(rules.getExtension(0), 'ext') + rules.setExtension(0, 'ocio') + self.assertEqual(rules.getExtension(0), 'ocio') + + # Setting regex clears extension. + rules.setRegex(0, 'regex') + self.assertEqual(rules.getExtension(0), '') + + with self.assertRaises(OCIO.Exception): + rules.setExtension(4, 'invalid index') + + with self.assertRaises(OCIO.Exception): + rules.setExtension(1, 'default does not use extension') + + with self.assertRaises(OCIO.Exception): + rules.getExtension(4) + + # Wrong strings. + for invalid in (None, '', '[]', 'jp[gG'): + with self.assertRaises(OCIO.Exception): + rules.setExtension(0, invalid) + + # Wrong types. + for invalid in (OCIO.TRANSFORM_DIR_INVERSE, 1): + with self.assertRaises(TypeError): + rules.setExtension(0, invalid) + + def test_regex(self): + """ + Test get/setRegex(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'regex') + self.assertEqual(rules.getRegex(0), 'regex') + rules.setRegex(0, 'newregex') + self.assertEqual(rules.getRegex(0), 'newregex') + + # Setting pattern clears regex. + rules.setPattern(0, 'pattern') + self.assertEqual(rules.getRegex(0), '') + + rules.setRegex(0, 'newregex') + + # Setting extension clears regex. + rules.setExtension(0, 'ext') + self.assertEqual(rules.getRegex(0), '') + + with self.assertRaises(OCIO.Exception): + rules.setRegex(4, 'invalid index') + + with self.assertRaises(OCIO.Exception): + rules.setRegex(1, 'default does not use regex') + + with self.assertRaises(OCIO.Exception): + rules.getRegex(4) + + # Wrong strings. + for invalid in (None, '', '(.*)(\bwhat'): + with self.assertRaises(OCIO.Exception): + rules.setRegex(0, invalid) + + # Wrong types. + for invalid in (OCIO.TRANSFORM_DIR_INVERSE, 1): + with self.assertRaises(TypeError): + rules.setRegex(0, invalid) + + def test_color_space(self): + """ + Test get/setColorSpace(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'regex') + self.assertEqual(rules.getColorSpace(0), 'colorspace') + rules.setColorSpace(0, 'other') + self.assertEqual(rules.getColorSpace(0), 'other') + + # Color space of default rule can be changed. + rules.setColorSpace(1, 'raw') + self.assertEqual(rules.getColorSpace(1), 'raw') + + with self.assertRaises(OCIO.Exception): + rules.setColorSpace(4, 'invalid index') + + with self.assertRaises(OCIO.Exception): + rules.getColorSpace(4) + + # Wrong strings. + for invalid in (None, ''): + with self.assertRaises(OCIO.Exception): + rules.setColorSpace(0, invalid) + + # Wrong types. + for invalid in (OCIO.TRANSFORM_DIR_INVERSE, 1): + with self.assertRaises(TypeError): + rules.setColorSpace(0, invalid) + + def test_custom_keys(self): + """ + Test getNumCustomKeys(), getCustomKeyName(), getCustomKeyValue() and setCustomKey(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'regex') + + self.assertEqual(rules.getNumCustomKeys(0), 0) + + rules.setCustomKey(0, 'key1', 'val1') + self.assertEqual(rules.getNumCustomKeys(0), 1) + self.assertEqual(rules.getCustomKeyName(0, 0), 'key1') + self.assertEqual(rules.getCustomKeyValue(0, 0), 'val1') + + rules.setCustomKey(0, 'key1', 'new val1') + self.assertEqual(rules.getNumCustomKeys(0), 1) + self.assertEqual(rules.getCustomKeyValue(0, 0), 'new val1') + + rules.setCustomKey(0, 'key2', 'val2') + self.assertEqual(rules.getNumCustomKeys(0), 2) + self.assertEqual(rules.getCustomKeyName(0, 1), 'key2') + self.assertEqual(rules.getCustomKeyValue(0, 1), 'val2') + + with self.assertRaises(OCIO.Exception): + self.assertEqual(rules.getCustomKeyName(0, 2), '') + with self.assertRaises(OCIO.Exception): + self.assertEqual(rules.getCustomKeyValue(0, 2), '') + + with self.assertRaises(OCIO.Exception): + self.assertEqual(rules.getCustomKeyName(4, 0), '') + with self.assertRaises(OCIO.Exception): + self.assertEqual(rules.getCustomKeyValue(4, 0), '') + + def test_insert_rule(self): + """ + Test insertRule() & removeRule(). + """ + + # Rules can be inserted with pattern & extension or with regex. + + rules = OCIO.FileRules() + rules.insertRule(0, 'test', 'colorspace', 'regex') + self.assertEqual(rules.getNumEntries(), 2) + + rules.insertRule(name='first', colorSpace='colorspace', regex='regex2', ruleIndex=0) + self.assertEqual(rules.getNumEntries(), 3) + + self.assertEqual(rules.getName(0), 'first') + self.assertEqual(rules.getName(1), 'test') + self.assertEqual(rules.getName(2), OCIO.DEFAULT_RULE_NAME) + + rules.insertRule(name='second', ruleIndex=1, colorSpace='colorspace', regex='regex') + self.assertEqual(rules.getNumEntries(), 4) + + self.assertEqual(rules.getName(0), 'first') + self.assertEqual(rules.getName(1), 'second') + self.assertEqual(rules.getName(2), 'test') + self.assertEqual(rules.getName(3), OCIO.DEFAULT_RULE_NAME) + + # Default rule is always the last rule. + with self.assertRaises(OCIO.Exception): + rules.insertRule(ruleIndex=4, name='not after default', + colorSpace='colorspace2', regex='regex') + + # Rule names have to be unique. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name='first', ruleIndex=2, colorSpace='colorspace2', regex='regex') + + # 'Default' is a reserved name. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name=OCIO.DEFAULT_RULE_NAME, ruleIndex=1, colorSpace='colorspace', + regex='regex') + + # Default rule can't be removed. + with self.assertRaises(OCIO.Exception): + rules.removeRule(3) + + rules.removeRule(0) + rules.removeRule(0) + rules.removeRule(0) + self.assertEqual(rules.getNumEntries(), 1) + self.assertEqual(rules.getName(0), OCIO.DEFAULT_RULE_NAME) + + # File path search rule needs empty parameters. + + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, ruleIndex=0, colorSpace='', + regex='') + self.assertEqual(rules.getNumEntries(), 2) + rules.removeRule(0) + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, ruleIndex=0, colorSpace='', + pattern='', extension='') + self.assertEqual(rules.getNumEntries(), 2) + rules.removeRule(0) + + # Parameters have to be empty: colorspace is not empty. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, colorSpace='not empty', regex='', + ruleIndex=0) + + # Parameters have to be empty: regex is not empty. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, colorSpace='', regex='not empty', + ruleIndex=0) + + # Parameters have to be empty: pattern is not empty. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, colorSpace='', pattern='not empty', + extension='', ruleIndex=0) + + # Parameters have to be empty: extension is not empty. + with self.assertRaises(OCIO.Exception): + rules.insertRule(name=OCIO.FILE_PATH_SEARCH_RULE_NAME, colorSpace='', pattern='', + extension='not empty', ruleIndex=0) + + # There is a special function for file path search rule. + rules.insertPathSearchRule(0) + self.assertEqual(rules.getNumEntries(), 2) + self.assertEqual(rules.getName(0), OCIO.FILE_PATH_SEARCH_RULE_NAME) + self.assertEqual(rules.getName(1), OCIO.DEFAULT_RULE_NAME) + + rules.insertRule(name='first', colorSpace='colorspace', + pattern='pattern', extension='ext', ruleIndex=0) + + rules.insertRule(name='second', colorSpace='colorspace', + pattern='pattern2', extension='jpg', ruleIndex=1) + + self.assertEqual(rules.getNumEntries(), 4) + + def test_rule_priority(self): + """ + Test increaseRulePriority() & decreaseRulePriority(). + """ + rules = OCIO.FileRules() + rules.insertRule(0, 'A', 'colorspace', 'regex') + rules.insertRule(1, 'B', 'colorspace', 'regex') + rules.insertRule(2, 'C', 'colorspace', 'regex') + self.assertEqual(rules.getName(0), 'A') + self.assertEqual(rules.getName(1), 'B') + self.assertEqual(rules.getName(2), 'C') + + rules.increaseRulePriority(1) + self.assertEqual(rules.getName(0), 'B') + self.assertEqual(rules.getName(1), 'A') + self.assertEqual(rules.getName(2), 'C') + + rules.decreaseRulePriority(1) + self.assertEqual(rules.getName(0), 'B') + self.assertEqual(rules.getName(1), 'C') + self.assertEqual(rules.getName(2), 'A') + + rules.decreaseRulePriority(0) + self.assertEqual(rules.getName(0), 'C') + self.assertEqual(rules.getName(1), 'B') + self.assertEqual(rules.getName(2), 'A') + + def test_using_rules(self): + """ + Test Config.setFileRiles() & Config.getColorSpaceFromFilepath(). + """ + cfg = OCIO.Config.CreateRaw() + cs = OCIO.ColorSpace(name = 'cs1') + cfg.addColorSpace(cs) + cs = OCIO.ColorSpace(name = 'cs2') + cfg.addColorSpace(cs) + cs = OCIO.ColorSpace(name = 'cs3') + cfg.addColorSpace(cs) + + rules = OCIO.FileRules() + rules.insertRule(0, 'A', 'cs1', '*', 'jpg') + rules.insertRule(1, 'B', 'cs2', '*', 'png') + rules.insertRule(2, 'C', 'cs3', '*', 'exr') + + cfg.setFileRules(rules) + cfg_rules = cfg.getFileRules() + self.assertEqual(cfg_rules.getNumEntries(), 4) + + csName, ruleIndex = cfg.getColorSpaceFromFilepath(filePath='test.png') + self.assertEqual(csName, 'cs2') + self.assertEqual(ruleIndex, 1) + + csName, ruleIndex = cfg.getColorSpaceFromFilepath(filePath='pic.exr') + self.assertEqual(csName, 'cs3') + self.assertEqual(ruleIndex, 2) + + csName, ruleIndex = cfg.getColorSpaceFromFilepath(filePath='pic.txt') + self.assertEqual(csName, 'default') + self.assertEqual(ruleIndex, 3) + + rules.removeRule(0) + rules.removeRule(0) + rules.removeRule(0) + + rules.insertRule(0, 'exr files', 'cs1', '*', '[eE][xX][r]') + cfg.setFileRules(rules) + + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary/Path/MyFile.exr') + self.assertEqual(ruleIndex, 0) + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary/Path/MyFile.eXr') + self.assertEqual(ruleIndex, 0) + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary/Path/MyFile.EXR') + self.assertEqual(ruleIndex, 1) # Default rule. R must be lower case. + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary/Path/MyFileexr') + self.assertEqual(ruleIndex, 1) # Default rule. + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary/Path/MyFile.jpeg') + self.assertEqual(ruleIndex, 1) # Default rule. + csName, ruleIndex = cfg.getColorSpaceFromFilepath('/An/Arbitrary.exr/Path/MyFileexr') + self.assertEqual(ruleIndex, 1) # Default rule. + csName, ruleIndex = cfg.getColorSpaceFromFilepath('') + self.assertEqual(ruleIndex, 1) # Default rule. diff --git a/tests/python/FixedFunctionTransformTest.py b/tests/python/FixedFunctionTransformTest.py index fbed5245..deb10767 100644 --- a/tests/python/FixedFunctionTransformTest.py +++ b/tests/python/FixedFunctionTransformTest.py @@ -77,8 +77,11 @@ class FixedFunctionTransformTest(unittest.TestCase): OCIO.FIXED_FUNCTION_ACES_RED_MOD_03) for style in OCIO.FixedFunctionStyle.__members__.values(): - self.fixed_func_tr.setStyle(style) - self.assertEqual(self.fixed_func_tr.getStyle(), style) + if style not in [OCIO.FIXED_FUNCTION_ACES_GAMUTMAP_02, + OCIO.FIXED_FUNCTION_ACES_GAMUTMAP_07, + OCIO.FIXED_FUNCTION_ACES_GAMUTMAP_13]: + self.fixed_func_tr.setStyle(style) + self.assertEqual(self.fixed_func_tr.getStyle(), style) def test_validate_direction(self): """ diff --git a/tests/python/GroupTransformTest.py b/tests/python/GroupTransformTest.py index c0f038b1..4912c79f 100644 --- a/tests/python/GroupTransformTest.py +++ b/tests/python/GroupTransformTest.py @@ -178,7 +178,7 @@ class GroupTransformTest(unittest.TestCase): fmd.setID('clfID') fmd.addChildElement('Description','Sample clf file.') - self.assertEqual(grp.write(config, config.getCurrentContext(), 'Academy/ASC Common LUT Format'), + self.assertEqual(grp.write(config=config, formatName='Academy/ASC Common LUT Format'), """ Sample clf file. diff --git a/tests/python/Lut1DTransformTest.py b/tests/python/Lut1DTransformTest.py new file mode 100644 index 00000000..3e272ecd --- /dev/null +++ b/tests/python/Lut1DTransformTest.py @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest + +import PyOpenColorIO as OCIO + +try: + import numpy as np +except ImportError: + logger.warning( + "NumPy could not be imported. " + "Test case will lack significant coverage!" + ) + np = None + +class Lut1DTransformTest(unittest.TestCase): + + def test_default_constructor(self): + """ + Test the default constructor. + """ + lut = OCIO.Lut1DTransform() + self.assertEqual(lut.getLength(), 2) + self.assertEqual(lut.getDirection(), OCIO.TRANSFORM_DIR_FORWARD) + self.assertEqual(lut.getHueAdjust(), OCIO.HUE_NONE) + self.assertFalse(lut.getInputHalfDomain()) + self.assertFalse(lut.getOutputRawHalfs()) + self.assertEqual(lut.getInterpolation(), OCIO.INTERP_DEFAULT) + self.assertEqual(lut.getFileOutputBitDepth(), OCIO.BIT_DEPTH_UNKNOWN) + r, g, b = lut.getValue(0) + self.assertEqual([r, g, b], [0, 0, 0]) + r, g, b = lut.getValue(1) + self.assertEqual([r, g, b], [1, 1, 1]) + + def test_direction(self): + """ + Test the setDirection() and getDirection() methods. + """ + + lut = OCIO.Lut1DTransform() + + for direction in OCIO.TransformDirection.__members__.values(): + lut.setDirection(direction) + self.assertEqual(lut.getDirection(), direction) + + # Wrong type tests. + for invalid in (None, 1, 'test'): + with self.assertRaises(TypeError): + lut.setDirection(invalid) + + def test_format_metadata(self): + """ + Test the getFormatMetadata() method. + """ + + lut = OCIO.Lut1DTransform() + format_metadata = lut.getFormatMetadata() + self.assertIsInstance(format_metadata, OCIO.FormatMetadata) + self.assertEqual(format_metadata.getElementName(), 'ROOT') + self.assertEqual(format_metadata.getName(), '') + self.assertEqual(format_metadata.getID(), '') + format_metadata.setName('name') + format_metadata.setID('id') + self.assertEqual(format_metadata.getName(), 'name') + self.assertEqual(format_metadata.getID(), 'id') + + + def test_constructor_with_keywords(self): + """ + Test Lut1DTransform constructor with keywords and validate its values. + """ + lut = OCIO.Lut1DTransform( + length=65536, + inputHalfDomain=True, + outputRawHalfs=True, + fileOutputBitDepth=OCIO.BIT_DEPTH_UINT10, + hueAdjust=OCIO.HUE_DW3, + interpolation=OCIO.INTERP_BEST, + direction=OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getLength(), 65536) + self.assertEqual(lut.getDirection(), OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getHueAdjust(), OCIO.HUE_DW3) + self.assertTrue(lut.getInputHalfDomain()) + self.assertTrue(lut.getOutputRawHalfs()) + self.assertEqual(lut.getInterpolation(), OCIO.INTERP_BEST) + self.assertEqual(lut.getFileOutputBitDepth(), OCIO.BIT_DEPTH_UINT10) + + lut = OCIO.Lut1DTransform( + length=4, + direction=OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getLength(), 4) + self.assertEqual(lut.getDirection(), OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getHueAdjust(), OCIO.HUE_NONE) + self.assertFalse(lut.getInputHalfDomain()) + self.assertFalse(lut.getOutputRawHalfs()) + self.assertEqual(lut.getInterpolation(), OCIO.INTERP_DEFAULT) + self.assertEqual(lut.getFileOutputBitDepth(), OCIO.BIT_DEPTH_UNKNOWN) + + def test_constructor_with_positional(self): + """ + Test Lut1DTransform constructor without keywords and validate its values. + """ + lut = OCIO.Lut1DTransform(65536, True, True, OCIO.BIT_DEPTH_UINT10, + OCIO.HUE_DW3, OCIO.INTERP_BEST, + OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getLength(), 65536) + self.assertEqual(lut.getDirection(), OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(lut.getHueAdjust(), OCIO.HUE_DW3) + self.assertTrue(lut.getInputHalfDomain()) + self.assertTrue(lut.getOutputRawHalfs()) + self.assertEqual(lut.getInterpolation(), OCIO.INTERP_BEST) + self.assertEqual(lut.getFileOutputBitDepth(), OCIO.BIT_DEPTH_UINT10) + + def test_array(self): + """ + Get & set Lut array values. + """ + lut = OCIO.Lut1DTransform(length=3) + r, g, b = lut.getValue(0) + self.assertEqual([r, g, b], [0, 0, 0]) + r, g, b = lut.getValue(1) + self.assertEqual([r, g, b], [0.5, 0.5, 0.5]) + r, g, b = lut.getValue(2) + self.assertEqual([r, g, b], [1, 1, 1]) + + lut.setValue(0, 0.1, 0.2, 0.3) + r, g, b = lut.getValue(0) + # Values are stored as float. + self.assertAlmostEqual(r, 0.1, delta=1e-6) + self.assertAlmostEqual(g, 0.2, delta=1e-6) + self.assertAlmostEqual(b, 0.3, delta=1e-6) + + if not np: + logger.warning("NumPy not found. Skipping part of test!") + return + + data = lut.getData() + expected = np.array([0.1, 0.2, 0.3, + 0.5, 0.5, 0.5, + 1., 1., 1.]).astype(np.float32) + self.assertEqual(data.all(), expected.all()) + data[6] = 0.9 + data[7] = 1.1 + data[8] = 1.2 + lut.setData(data) + + r, g, b = lut.getValue(2) + self.assertAlmostEqual(r, 0.9, delta=1e-6) + self.assertAlmostEqual(g, 1.1, delta=1e-6) + self.assertAlmostEqual(b, 1.2, delta=1e-6) diff --git a/tests/python/MainTest.py b/tests/python/MainTest.py deleted file mode 100644 index f10bada7..00000000 --- a/tests/python/MainTest.py +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright Contributors to the OpenColorIO Project. - -import unittest, os, sys -import PyOpenColorIO as OCIO - -class MainTest(unittest.TestCase): - - FOO ="""ocio_profile_version: 2 - -search_path: \"\" -strictparsing: false -luma: [0.2126, 0.7152, 0.0722] - -roles: - default: raw - -file_rules: - - ! {name: ColorSpaceNamePathSearch} - - ! {name: Default, colorspace: default} - -displays: - sRGB: - - ! {name: Raw, colorspace: raw} - -active_displays: [] -active_views: [] - -colorspaces: - - ! - name: raw - family: raw - equalitygroup: \"\" - bitdepth: 32f - description: | - A raw color space. Conversions to and from this space are no-ops. - isdata: true - allocation: uniform -""" - - def test_interface(self): - - OCIO.ClearAllCaches() - self.assertEqual(OCIO.LOGGING_LEVEL_INFO, OCIO.GetLoggingLevel()) - OCIO.SetLoggingLevel(OCIO.LOGGING_LEVEL_NONE) - self.assertEqual(OCIO.LOGGING_LEVEL_NONE, OCIO.GetLoggingLevel()) - foo = OCIO.GetCurrentConfig() - self.assertEqual(self.FOO, foo.serialize()) - OCIO.SetLoggingLevel(OCIO.LOGGING_LEVEL_INFO) - bar = OCIO.Config().CreateFromStream(foo.serialize()) - OCIO.SetCurrentConfig(bar) - wee = OCIO.GetCurrentConfig() diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index 13822589..7d7d3834 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -41,19 +41,23 @@ sys.path.insert(0, pyopencolorio_dir) import PyOpenColorIO as OCIO import AllocationTransformTest +import BakerTest import BuiltinTransformRegistryTest import BuiltinTransformTest import CDLTransformTest -import CPUProcessorTest import ColorSpaceHelpersTest import ColorSpaceTest import ColorSpaceTransformTest import ConfigTest +import ConstantsTest +import ContextTest +import CPUProcessorTest import DisplayViewHelpersTest import DisplayViewTransformTest import ExponentTransformTest import ExponentWithLinearTransformTest import ExposureContrastTransformTest +import FileRulesTest import FileTransformTest import FixedFunctionTransformTest import FormatMetadataTest @@ -68,19 +72,15 @@ import LogCameraTransformTest import LogTransformTest import LookTest import LookTransformTest +import Lut1DTransformTest import MatrixTransformTest import MixingHelpersTest import NamedTransformTest import OpenColorIOTest import ProcessorTest +import RangeTransformTest import TransformsTest import ViewingRulesTest -#from MainTest import * -#from ConstantsTest import * -#from ConfigTest import * -#from ContextTest import * -#from Baker import * -#from RangeTransformTest import * def suite(): """Load unittest.TestCase objects from *Test.py files within ./tests/Python @@ -94,20 +94,24 @@ def suite(): loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromModule(AllocationTransformTest)) + suite.addTest(loader.loadTestsFromModule(BakerTest)) suite.addTest(loader.loadTestsFromModule(BuiltinTransformRegistryTest)) suite.addTest(loader.loadTestsFromModule(BuiltinTransformTest)) suite.addTest(loader.loadTestsFromModule(CDLTransformTest)) - suite.addTest(loader.loadTestsFromModule(CPUProcessorTest)) suite.addTest(loader.loadTestsFromModule(ColorSpaceHelpersTest)) suite.addTest(loader.loadTestsFromModule(ColorSpaceTest)) suite.addTest(loader.loadTestsFromModule(ColorSpaceTransformTest)) suite.addTest(loader.loadTestsFromModule(ConfigTest)) + suite.addTest(loader.loadTestsFromModule(ConstantsTest)) + suite.addTest(loader.loadTestsFromModule(ContextTest)) + suite.addTest(loader.loadTestsFromModule(CPUProcessorTest)) suite.addTest(loader.loadTestsFromModule(DisplayViewHelpersTest)) suite.addTest(loader.loadTestsFromModule(DisplayViewTransformTest)) suite.addTest(loader.loadTestsFromModule(ExponentTransformTest)) suite.addTest(loader.loadTestsFromModule(ExponentWithLinearTransformTest)) suite.addTest(loader.loadTestsFromModule(ExposureContrastTransformTest)) suite.addTest(loader.loadTestsFromModule(FileTransformTest)) + suite.addTest(loader.loadTestsFromModule(FileRulesTest)) suite.addTest(loader.loadTestsFromModule(FixedFunctionTransformTest)) suite.addTest(loader.loadTestsFromModule(FormatMetadataTest)) suite.addTest(loader.loadTestsFromModule(GpuShaderDescTest)) @@ -121,27 +125,15 @@ def suite(): suite.addTest(loader.loadTestsFromModule(LogTransformTest)) suite.addTest(loader.loadTestsFromModule(LookTest)) suite.addTest(loader.loadTestsFromModule(LookTransformTest)) + suite.addTest(loader.loadTestsFromModule(Lut1DTransformTest)) suite.addTest(loader.loadTestsFromModule(MatrixTransformTest)) suite.addTest(loader.loadTestsFromModule(MixingHelpersTest)) suite.addTest(loader.loadTestsFromModule(NamedTransformTest)) suite.addTest(loader.loadTestsFromModule(OpenColorIOTest)) suite.addTest(loader.loadTestsFromModule(ProcessorTest)) + suite.addTest(loader.loadTestsFromModule(RangeTransformTest)) suite.addTest(loader.loadTestsFromModule(TransformsTest)) suite.addTest(loader.loadTestsFromModule(ViewingRulesTest)) - #suite.addTest(MainTest("test_interface")) - #suite.addTest(ConstantsTest("test_interface")) - #suite.addTest(ConfigTest("test_interface")) - #suite.addTest(ConfigTest("test_is_editable")) - #suite.addTest(ContextTest("test_interface")) - #suite.addTest(RangeTransformTest("test_interface")) - #suite.addTest(RangeTransformTest("test_equality")) - #suite.addTest(RangeTransformTest("test_validation"))\ - - # Processor - # ProcessorMetadata - #suite.addTest(BakerTest("test_interface", opencolorio_sse)) - # PackedImageDesc - # PlanarImageDesc return suite diff --git a/tests/python/RangeTransformTest.py b/tests/python/RangeTransformTest.py index b331262b..2d14b81a 100644 --- a/tests/python/RangeTransformTest.py +++ b/tests/python/RangeTransformTest.py @@ -7,20 +7,22 @@ import PyOpenColorIO as OCIO class RangeTransformTest(unittest.TestCase): - def test_interface(self): - + def test_range_transform_interface(self): + """ + Test empty contructor and accessors. + """ rt = OCIO.RangeTransform() self.assertEqual(rt.getTransformType(), OCIO.TRANSFORM_TYPE_RANGE) - self.assertEqual(rt.getStyle(), "Clamp") + self.assertEqual(rt.getStyle(), OCIO.RANGE_CLAMP) self.assertEqual(rt.hasMinInValue(), False) self.assertEqual(rt.hasMaxInValue(), False) self.assertEqual(rt.hasMinOutValue(), False) self.assertEqual(rt.hasMaxOutValue(), False) - rt.setStyle("noClamp") - self.assertEqual(rt.getStyle(), "noClamp") - rt.setStyle("Clamp") + rt.setStyle(OCIO.RANGE_NO_CLAMP) + self.assertEqual(rt.getStyle(), OCIO.RANGE_NO_CLAMP) + rt.setStyle(OCIO.RANGE_CLAMP) rt.setMinInValue(0.12301234) self.assertEqual(0.12301234, rt.getMinInValue()) @@ -72,9 +74,10 @@ class RangeTransformTest(unittest.TestCase): self.assertEqual(rt.hasMinOutValue(), False) self.assertEqual(rt.hasMaxOutValue(), False) - - def test_equality(self): - + def test_range_transform_equality(self): + """ + Test range transform equality + """ rt1 = OCIO.RangeTransform() self.assertTrue(rt1.equals(rt1)) @@ -94,8 +97,10 @@ class RangeTransformTest(unittest.TestCase): self.assertTrue(rt2.equals(rt1)) - def test_validation(self): - + def test_range_transform_validation(self): + """ + Test validate() function. + """ rt1 = OCIO.RangeTransform() with self.assertRaises(Exception): rt1.validate() @@ -106,12 +111,12 @@ class RangeTransformTest(unittest.TestCase): rt1.setMinOutValue(0.12601234) rt1.validate() - rt1.setMaxInValue(1.12601234) - rt1.setMaxOutValue(1.12601234) + rt1.setMaxInValue(1.45) + rt1.setMaxOutValue(1.78) rt1.validate() - # Test one faulty range + # Test one faulty range (max has to be greater than min) rt1.setMaxInValue(0.12601234) - with self.assertRaises(Exception): + with self.assertRaises(OCIO.Exception): rt1.validate()