diff --git a/openpype/pipeline/colorspace.py b/openpype/pipeline/colorspace.py index 0b23c2b4e3..72c140195e 100644 --- a/openpype/pipeline/colorspace.py +++ b/openpype/pipeline/colorspace.py @@ -19,6 +19,7 @@ log = Logger.get_logger(__name__) class CashedData: remapping = None + python3compatible = None @contextlib.contextmanager @@ -118,16 +119,23 @@ def get_imageio_colorspace_from_filepath( if ext_match and file_match: colorspace_name = file_rule["colorspace"] + # if no file rule matched, try to get colorspace + # from filepath with OCIO v2 way + # QUESTION: should we override file rules from our settings and + # in ocio v2 only focus on file rules set in config file? + if ( + compatibility_check_config_version(config_data["path"], major=2) + and not colorspace_name + ): + colorspace_name = get_colorspace_from_filepath( + config_data["path"], path) + if not colorspace_name: log.info("No imageio file rule matched input path: '{}'".format( path )) return None - if compatibility_check_config_version(config_data["path"], major=2): - colorspace_name = get_colorspace_from_filepath( - config_data["path"], path) - # validate matching colorspace with config if validate and config_data: validate_imageio_colorspace_in_config( @@ -312,33 +320,39 @@ def get_wrapped_with_subprocess(command_group, command, **kwargs): def compatibility_check(): """Making sure PyOpenColorIO is importable""" + if CashedData.python3compatible is not None: + return CashedData.python3compatible + try: import PyOpenColorIO # noqa: F401 + CashedData.python3compatible = True except ImportError: - return False + CashedData.python3compatible = False # compatible - return True + return CashedData.python3compatible def compatibility_check_config_version(config_path, major=1, minor=None): """Making sure PyOpenColorIO config version is compatible""" - try: - import PyOpenColorIO as ocio - config = ocio.Config().CreateFromFile(str(config_path)) - config_version_major = config.getMajorVersion() - config_version_minor = config.getMinorVersion() - print(config_version_major, config_version_minor) + if not compatibility_check(): + # python environment is not compatible with PyOpenColorIO + # needs to be run in subprocess + version_data = get_wrapped_with_subprocess( + "config", "get_version", config_path=config_path + ) - # check major version - if config_version_major != major: - return False - # check minor version - if minor and config_version_minor != minor: - return False + from openpype.scripts.ocio_wrapper import _get_version_data - except ImportError: + version_data = _get_version_data(config_path) + + # check major version + if version_data["major"] != major: + return False + + # check minor version + if minor and version_data["minor"] != minor: return False # compatible diff --git a/openpype/scripts/ocio_wrapper.py b/openpype/scripts/ocio_wrapper.py index 1c86216347..4332ea5b01 100644 --- a/openpype/scripts/ocio_wrapper.py +++ b/openpype/scripts/ocio_wrapper.py @@ -184,6 +184,68 @@ def _get_views_data(config_path): return data_ +@config.command( + name="get_version", + help=( + "return major and minor version from config file " + "--config_path input arg is required" + "--out_path input arg is required" + ) +) +@click.option("--config_path", required=True, + help="path where to read ocio config file", + type=click.Path(exists=True)) +@click.option("--out_path", required=True, + help="path where to write output json file", + type=click.Path()) +def get_version(config_path, out_path): + """Get version of config. + + Python 2 wrapped console command + + Args: + config_path (str): ocio config file path string + out_path (str): temp json file path string + + Example of use: + > pyton.exe ./ocio_wrapper.py config get_version \ + --config_path= --out_path= + """ + json_path = Path(out_path) + + out_data = _get_version_data(config_path) + + with open(json_path, "w") as f_: + json.dump(out_data, f_) + + print(f"Config version data are saved to '{json_path}'") + + +def _get_version_data(config_path): + """Return major and minor version info. + + Args: + config_path (str): path string leading to config.ocio + + Raises: + IOError: Input config does not exist. + + Returns: + dict: minor and major keys with values + """ + config_path = Path(config_path) + + if not config_path.is_file(): + raise IOError("Input path should be `config.ocio` file") + + config = ocio.Config().CreateFromFile(str(config_path)) + + return { + "major": config.getMajorVersion(), + "minor": config.getMinorVersion() + } + + @colorspace.command( name="get_colorspace_from_filepath", help=( @@ -198,7 +260,7 @@ def _get_views_data(config_path): type=click.Path(exists=True)) @click.option("--filepath", required=True, help="path to file to get colorspace from", - type=click.Path(exists=True)) + type=click.Path()) @click.option("--out_path", required=True, help="path where to write output json file", type=click.Path()) diff --git a/tests/unit/openpype/pipeline/test_colorspace.py b/tests/unit/openpype/pipeline/test_colorspace.py index c22acee2d4..a6fcc68055 100644 --- a/tests/unit/openpype/pipeline/test_colorspace.py +++ b/tests/unit/openpype/pipeline/test_colorspace.py @@ -185,5 +185,70 @@ class TestPipelineColorspace(TestPipeline): assert expected_hiero == hiero_file_rules, ( f"Not matching file rules {expected_hiero}") + def test_get_imageio_colorspace_from_filepath_p3(self, project_settings): + """Test Colorspace from filepath with python 3 compatibility mode + + Also test ocio v2 file rules + """ + nuke_filepath = "renderCompMain_baking_h264.mp4" + hiero_filepath = "prerenderCompMain.mp4" + + expected_nuke = "Camera Rec.709" + expected_hiero = "Gamma 2.2 Rec.709 - Texture" + + nuke_colorspace = colorspace.get_imageio_colorspace_from_filepath( + nuke_filepath, + "nuke", + "test_project", + project_settings=project_settings + ) + assert expected_nuke == nuke_colorspace, ( + f"Not matching colorspace {expected_nuke}") + + hiero_colorspace = colorspace.get_imageio_colorspace_from_filepath( + hiero_filepath, + "hiero", + "test_project", + project_settings=project_settings + ) + assert expected_hiero == hiero_colorspace, ( + f"Not matching colorspace {expected_hiero}") + + def test_get_imageio_colorspace_from_filepath_python2mode( + self, project_settings): + """Test Colorspace from filepath with python 2 compatibility mode + + Also test ocio v2 file rules + """ + nuke_filepath = "renderCompMain_baking_h264.mp4" + hiero_filepath = "prerenderCompMain.mp4" + + expected_nuke = "Camera Rec.709" + expected_hiero = "Gamma 2.2 Rec.709 - Texture" + + # switch to python 2 compatibility mode + colorspace.CashedData.python3compatible = False + + nuke_colorspace = colorspace.get_imageio_colorspace_from_filepath( + nuke_filepath, + "nuke", + "test_project", + project_settings=project_settings + ) + assert expected_nuke == nuke_colorspace, ( + f"Not matching colorspace {expected_nuke}") + + hiero_colorspace = colorspace.get_imageio_colorspace_from_filepath( + hiero_filepath, + "hiero", + "test_project", + project_settings=project_settings + ) + assert expected_hiero == hiero_colorspace, ( + f"Not matching colorspace {expected_hiero}") + + # return to python 3 compatibility mode + colorspace.CashedData.python3compatible = None + test_case = TestPipelineColorspace()