From 2d06436a348f59d32e1f88b1bf95bd33115648b3 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 15:37:35 -0700 Subject: [PATCH 1/9] Implement logging in ocio_source_setup.py Replaced print statements with logging for better control over output levels and formatting. Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index 1a4ef8c2a..a58988d35 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -5,8 +5,18 @@ # from rv import rvtypes, commands import os +import logging import PyOpenColorIO as OCIO +logging.basicConfig(format="%(levelname)s: %(message)s") + +package_logger = logging.getLogger("OCIOSourceSetup") + +if "RV_OCIO_SOURCE_SETUP_DEBUG" in os.environ: + package_logger.setLevel(logging.DEBUG) +else: + package_logger.setLevel(logging.INFO) + # # Default implementations of helper methods # @@ -284,7 +294,7 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): if commands.nodeType(pNode).startswith("OCIO"): commands.ocioUpdateConfig(pNode) - print(("INFO: using %s node for %s %s" % (nodeType, source, pipeSlot))) + package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) return # @@ -320,17 +330,17 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): DEFAULT_PIPE[pipeSlot] = currentPipelineNodes pipelineList = ocio_node_from_media(self.config, srcPipeline, DEFAULT_PIPE[pipeSlot], media, attrDict) except Exception as inst: - print(("ERROR: Problem occurred while loading OCIO settings for %s: %s" % (nodeType, inst))) + package_logger.error("Problem occurred while loading OCIO settings for %s: %s", nodeType, inst) return try: pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: - print(("ERROR: Unable to make use of ocio_node_from_media return: %s" % inst)) + package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) if pipeline == DEFAULT_PIPE[pipeSlot]: return - print(("INFO: using %s node for %s %s" % (nodeType, source, pipeSlot))) + package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) commands.setStringProperty(srcPipeline + ".pipeline.nodes", pipeline, True) pipeNodes = commands.nodesInGroup(srcPipeline) @@ -340,7 +350,7 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): try: applyProps(stageOCIO, pNode["context"], pNode["properties"]) except KeyError as inst: - print(("ERROR: Unable to apply properties to %s: %s" % (stageOCIO, inst))) + package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) commands.redraw() @@ -358,7 +368,7 @@ def disableSourceOCIO(self, source, nodeType): if pipeSlot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipeSlot]: return - print(("INFO: resetting %s for %s" % (pipeSlot, source))) + package_logger.info("resetting %s for %s", pipeSlot, source) commands.setStringProperty(srcPipeline + ".pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) commands.redraw() @@ -393,18 +403,18 @@ def useDisplayOCIO(self, group): DEFAULT_PIPE[groupName] = currentPipelineNodes pipelineList = ocio_node_from_media(self.config, dpipeline, DEFAULT_PIPE[groupName]) except Exception as inst: - print(("ERROR: Problem occurred while loading OCIO settings for OCIODisplay: %s" % inst)) + package_logger.error("Problem occurred while loading OCIO settings for OCIODisplay: %s", inst) return try: pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: - print(("ERROR: Unable to make use of ocio_node_from_media return: %s" % inst)) + package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) if pipeline == DEFAULT_PIPE[groupName]: return device = commands.getStringProperty(group + ".device.name")[0] - print(("INFO: using OCIODisplay for display: %s" % device)) + package_logger.info("using OCIODisplay for display: %s", device) dpipeline = groupMemberOfType(group, groupName) commands.setStringProperty(dpipeline + ".pipeline.nodes", pipeline, True) @@ -416,7 +426,7 @@ def useDisplayOCIO(self, group): try: applyProps(stageOCIO, pNode["context"], pNode["properties"]) except KeyError as inst: - print(("ERROR: Unable to apply properties to %s: %s" % (stageOCIO, inst))) + package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) self.usingOCIOForDisplay[group] = True commands.redraw() @@ -438,7 +448,7 @@ def disableDisplayOCIO(self, group): commands.setStringProperty(dpipeline + ".pipeline.nodes", DEFAULT_PIPE[groupName], True) device = commands.getStringProperty(group + ".device.name")[0] - print(("INFO: using RVDisplayColor for display: %s" % device)) + package_logger.info("using RVDisplayColor for display: %s", device) self.usingOCIOForDisplay[group] = False commands.redraw() @@ -516,7 +526,7 @@ def checkForDisplayGroup(self, event): self.usingOCIOForDisplay[node] = False commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) except Exception as inst: - print((str(inst), node)) + package_logger.error("%s %s", inst, node) def maybeUpdateViews(self, event): event.reject() @@ -543,7 +553,7 @@ def selectConfig(self, event): commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) commands.writeSettings("ocio_source_setup", "ocio_config", config) except Exception as inst: - print(inst) + package_logger.error(inst) def buildOCIOMenu(self): # @@ -725,7 +735,7 @@ def __init__(self): except AttributeError: pass - print(("INFO: Using %s for OCIO setup methods: %s" % (rv_ocio_setup.__file__, " ".join(inherited)))) + package_logger.info("Using %s for OCIO setup methods: %s", rv_ocio_setup.__file__, " ".join(inherited)) except ImportError: pass @@ -738,7 +748,7 @@ def __init__(self): self.config = OCIO.Config.CreateFromFile(config) OCIO.SetCurrentConfig(self.config) else: - print("WARNING: $OCIO environment variable unset!") + package_logger.warning("$OCIO environment variable unset!") self.init( "OCIO Source Setup", From a2a5e691173755644d5354ee6bde9483b595db44 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 15:43:33 -0700 Subject: [PATCH 2/9] Refactor string property access with f-strings Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index a58988d35..91f19e924 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -116,7 +116,7 @@ def ocio_node_from_media(config, node, default, media=None, attributes={}): def isOCIOManaged(nodeType): def F(): try: - managed = commands.getIntProperty("#" + nodeType + ".ocio.active")[0] != 0 + managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState @@ -130,7 +130,7 @@ def F(): groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - managed = commands.getIntProperty(dOCIO + ".ocio.active")[0] != 0 + managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState @@ -141,7 +141,7 @@ def F(): def ocioMenuCheck(nodeType, prop, value): def F(): try: - current = commands.getStringProperty("#" + nodeType + "." + prop)[0] + current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] managed = isOCIOManaged(nodeType)() == commands.CheckedMenuState checked = current == value and managed return commands.CheckedMenuState if checked else commands.NeutralMenuState @@ -157,8 +157,8 @@ def F(): groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - d = commands.getStringProperty(dOCIO + ".ocio_display.display")[0] - v = commands.getStringProperty(dOCIO + ".ocio_display.view")[0] + d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] + v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] if d == display and v == view: return commands.CheckedMenuState return commands.UncheckedMenuState @@ -172,7 +172,7 @@ def ocioEvent(nodeType, prop, value): "This function will apply its change on the current node of nodeType in the evaluation path" def F(event): - commands.setStringProperty("#" + nodeType + "." + prop, [value], True) + commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) commands.redraw() return F @@ -183,7 +183,7 @@ def ocioEventOnAllOfType(nodeType, prop, value): def F(event): for node in commands.nodesOfType(nodeType): - commands.setStringProperty(node + "." + prop, [value], True) + commands.setStringProperty(f"{node}.{prop}", [value], True) commands.redraw() return F @@ -197,10 +197,10 @@ def F(event): # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. - commands.setIntProperty(dOCIO + ".ocio.active", [0], True) - commands.setStringProperty(dOCIO + ".ocio_display.display", [display], True) - commands.setStringProperty(dOCIO + ".ocio_display.view", [view], True) - commands.setIntProperty(dOCIO + ".ocio.active", [1], True) + commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) + commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) commands.redraw() return F @@ -215,9 +215,9 @@ def groupMemberOfType(node, memberType): def applyProps(node, contextProps, propertiesProps): for pprop, avalue in propertiesProps.items(): - commands.setStringProperty(node + "." + pprop, [avalue], True) + commands.setStringProperty(f"{node}.{pprop}", [avalue], True) for cprop, cvalue in contextProps.items(): - prop = node + ".ocio_context." + cprop + prop = f"{node}.ocio_context.{cprop}" if not commands.propertyExists(prop): commands.newProperty(prop, commands.StringType, 1) commands.setStringProperty(prop, [cvalue], True) @@ -262,7 +262,7 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): the source. """ - medias = commands.getStringProperty("%s.media.movie" % source) + medias = commands.getStringProperty(f"{source}.media.movie") media = medias[0] try: @@ -316,7 +316,7 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): try: if pipeSlot not in DEFAULT_PIPE: - currentPipelineNodes = commands.getStringProperty(srcPipeline + ".pipeline.nodes") + currentPipelineNodes = commands.getStringProperty(f"{srcPipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that @@ -342,7 +342,7 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) - commands.setStringProperty(srcPipeline + ".pipeline.nodes", pipeline, True) + commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", pipeline, True) pipeNodes = commands.nodesInGroup(srcPipeline) pipeNodes.sort() for index, pNode in enumerate(pipelineList): @@ -362,7 +362,7 @@ def disableSourceOCIO(self, source, nodeType): pipeSlot = OCIO_ROLES[nodeType] srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) - nodesProp = srcPipeline + ".pipeline.nodes" + nodesProp = f"{srcPipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) if pipeSlot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipeSlot]: @@ -370,7 +370,7 @@ def disableSourceOCIO(self, source, nodeType): package_logger.info("resetting %s for %s", pipeSlot, source) - commands.setStringProperty(srcPipeline + ".pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) + commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) commands.redraw() def useDisplayOCIO(self, group): @@ -390,7 +390,7 @@ def useDisplayOCIO(self, group): try: dpipeline = groupMemberOfType(group, groupName) if groupName not in DEFAULT_PIPE: - currentPipelineNodes = commands.getStringProperty(dpipeline + ".pipeline.nodes") + currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that @@ -413,11 +413,11 @@ def useDisplayOCIO(self, group): if pipeline == DEFAULT_PIPE[groupName]: return - device = commands.getStringProperty(group + ".device.name")[0] + device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using OCIODisplay for display: %s", device) dpipeline = groupMemberOfType(group, groupName) - commands.setStringProperty(dpipeline + ".pipeline.nodes", pipeline, True) + commands.setStringProperty(f"{dpipeline}.pipeline.nodes", pipeline, True) pipeNodes = commands.nodesInGroup(dpipeline) pipeNodes.sort() @@ -439,15 +439,15 @@ def disableDisplayOCIO(self, group): groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) - nodesProp = dpipeline + ".pipeline.nodes" + nodesProp = f"{dpipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) if groupName not in DEFAULT_PIPE or current == DEFAULT_PIPE[groupName]: return - commands.setStringProperty(dpipeline + ".pipeline.nodes", DEFAULT_PIPE[groupName], True) + commands.setStringProperty(f"{dpipeline}.pipeline.nodes", DEFAULT_PIPE[groupName], True) - device = commands.getStringProperty(group + ".device.name")[0] + device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using RVDisplayColor for display: %s", device) self.usingOCIOForDisplay[group] = False @@ -594,7 +594,8 @@ def buildOCIOMenu(self): ) ) dList.append((d, vList)) - device = " " + commands.getStringProperty(display + ".device.name")[0] + device_name = commands.getStringProperty(f"{display}.device.name")[0] + device = f" {device_name}" daList.append((device, dList)) # @@ -730,7 +731,7 @@ def __init__(self): inherited = [] for method in METHODS: try: - exec("global %s; %s = rv_ocio_setup.%s" % (method, method, method)) + exec(f"global {method}; {method} = rv_ocio_setup.{method}") inherited.append(method) except AttributeError: pass From fe29e2dfadf081ef4c936d6461a93df685b0d7c6 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 16:04:35 -0700 Subject: [PATCH 3/9] Refactor OCIO management functions with partial Refactor OCIO management functions to use functools.partial for better compatibility and maintainability. Deprecate old public API methods while preserving functionality. Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 235 ++++++++++-------- 1 file changed, 136 insertions(+), 99 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index 91f19e924..ba27153b9 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -7,6 +7,7 @@ import os import logging import PyOpenColorIO as OCIO +from functools import partial logging.basicConfig(format="%(levelname)s: %(message)s") @@ -113,97 +114,129 @@ def ocio_node_from_media(config, node, default, media=None, attributes={}): # +def _is_ocio_managed(nodeType): + try: + managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 + return commands.CheckedMenuState if managed else commands.UncheckedMenuState + except Exception: + return commands.UncheckedMenuState + + def isOCIOManaged(nodeType): - def F(): - try: - managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 - return commands.CheckedMenuState if managed else commands.UncheckedMenuState - except Exception: - return commands.UncheckedMenuState + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_is_ocio_managed, nodeType=...)`. + """ + return partial(_is_ocio_managed, nodeType=nodeType) + - return F +def _is_ocio_display_managed(group): + try: + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 + return commands.CheckedMenuState if managed else commands.UncheckedMenuState + except Exception: + return commands.UncheckedMenuState def isOCIODisplayManaged(group): - def F(): - try: - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 - return commands.CheckedMenuState if managed else commands.UncheckedMenuState - except Exception: - return commands.UncheckedMenuState + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_is_ocio_display_managed, group=...)`. + """ + return partial(_is_ocio_display_managed, group=group) + - return F +def _ocio_menu_check(nodeType, prop, value): + try: + current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] + managed = _is_ocio_managed(nodeType) == commands.CheckedMenuState + checked = current == value and managed + return commands.CheckedMenuState if checked else commands.NeutralMenuState + except Exception: + return commands.DisabledMenuState def ocioMenuCheck(nodeType, prop, value): - def F(): - try: - current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] - managed = isOCIOManaged(nodeType)() == commands.CheckedMenuState - checked = current == value and managed - return commands.CheckedMenuState if checked else commands.NeutralMenuState - except Exception: - return commands.DisabledMenuState + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_ocio_menu_check, nodeType=..., prop=..., value=...)`. + """ + return partial(_ocio_menu_check, nodeType=nodeType, prop=prop, value=value) - return F + +def _ocio_display_menu_check(group, display, view): + try: + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] + v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] + if d == display and v == view: + return commands.CheckedMenuState + return commands.UncheckedMenuState + except Exception: + return commands.DisabledMenuState def ocioDisplayMenuCheck(group, display, view): - def F(): - try: - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] - v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] - if d == display and v == view: - return commands.CheckedMenuState - return commands.UncheckedMenuState - except Exception: - return commands.DisabledMenuState + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_ocio_display_menu_check, group=..., display=..., view=...)`. + """ + return partial(_ocio_display_menu_check, group=group, display=display, view=view) - return F + +def _ocio_event(event, nodeType, prop, value): + commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) + commands.redraw() def ocioEvent(nodeType, prop, value): - "This function will apply its change on the current node of nodeType in the evaluation path" + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_ocio_event, nodeType=..., prop=..., value=...)`. + Note: The internal `_ocio_event` accepts `event` as its first parameter to allow kwargs binding. + """ + return partial(_ocio_event, nodeType=nodeType, prop=prop, value=value) - def F(event): - commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) - commands.redraw() - return F +def _ocio_event_on_all_of_type(event, nodeType, prop, value): + for node in commands.nodesOfType(nodeType): + commands.setStringProperty(f"{node}.{prop}", [value], True) + commands.redraw() def ocioEventOnAllOfType(nodeType, prop, value): - "This function will apply its change on all nodes of nodeType" + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_ocio_event_on_all_of_type, nodeType=..., prop=..., value=...)`. + """ + return partial(_ocio_event_on_all_of_type, nodeType=nodeType, prop=prop, value=value) - def F(event): - for node in commands.nodesOfType(nodeType): - commands.setStringProperty(f"{node}.{prop}", [value], True) - commands.redraw() - return F +def _ocio_display_event(event, group, display, view): + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + # Both 'display' and 'view' must be set together. + # Disable the OCIONode during display/view propety changes. + # Prevents node from rebuilding shaders while it may be in an invalid state. + commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) + commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) + commands.redraw() def ocioDisplayEvent(group, display, view): - def F(event): - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - # Both 'display' and 'view' must be set together. - # Disable the OCIONode during display/view propety changes. - # Prevents node from rebuilding shaders while it may be in an invalid state. - commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) - commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) - commands.redraw() - - return F + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(_ocio_display_event, group=..., display=..., view=...)`. + """ + return partial(_ocio_display_event, group=group, display=display, view=view) def groupMemberOfType(node, memberType): @@ -495,28 +528,32 @@ def afterSessionRead(self, event): if not self.usingOCIOForDisplay.get(group, False): self.useDisplayOCIO(group) - def ocioActiveEvent(self, nodeType): - def F(event): - if nodeType not in ["OCIOFile", "OCIOLook"]: - if isOCIODisplayManaged(nodeType)() == commands.CheckedMenuState: - self.disableDisplayOCIO(nodeType) - else: - self.useDisplayOCIO(nodeType) - return + def _ocio_active_event(self, event, nodeType): + if nodeType not in ["OCIOFile", "OCIOLook"]: + if _is_ocio_display_managed(nodeType) == commands.CheckedMenuState: + self.disableDisplayOCIO(nodeType) + else: + self.useDisplayOCIO(nodeType) + return - evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) - if len(evalInfo) == 0: - evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) - if len(evalInfo) == 0: - return - source = evalInfo[0]["node"] + evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) + if len(evalInfo) == 0: + evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) + if len(evalInfo) == 0: + return + source = evalInfo[0]["node"] - if isOCIOManaged(nodeType)() == commands.CheckedMenuState: - self.disableSourceOCIO(source, nodeType) - else: - self.useSourceOCIO(source, nodeType, OCIO_DEFAULTS[nodeType]) + if _is_ocio_managed(nodeType) == commands.CheckedMenuState: + self.disableSourceOCIO(source, nodeType) + else: + self.useSourceOCIO(source, nodeType, OCIO_DEFAULTS[nodeType]) - return F + def ocioActiveEvent(self, nodeType): + """ + Deprecated: Public API maintained for backward compatibility. + Internal code should use `functools.partial(self._ocio_active_event, nodeType=...)`. + """ + return partial(self._ocio_active_event, nodeType=nodeType) def checkForDisplayGroup(self, event): event.reject() @@ -576,9 +613,9 @@ def buildOCIOMenu(self): dList = [ ( "Active", - self.ocioActiveEvent(display), + partial(self._ocio_active_event, nodeType=display), None, - isOCIODisplayManaged(display), + partial(_is_ocio_display_managed, group=display), ), ("_", None), ] @@ -588,9 +625,9 @@ def buildOCIOMenu(self): vList.append( ( v, - ocioDisplayEvent(display, d, v), + partial(_ocio_display_event, group=display, display=d, view=v), None, - ocioDisplayMenuCheck(display, d, v), + partial(_ocio_display_menu_check, group=display, display=d, view=v), ) ) dList.append((d, vList)) @@ -605,9 +642,9 @@ def buildOCIOMenu(self): cssList = [ ( "Active", - self.ocioActiveEvent("OCIOFile"), + partial(self._ocio_active_event, nodeType="OCIOFile"), None, - isOCIOManaged("OCIOFile"), + partial(_is_ocio_managed, nodeType="OCIOFile"), ), ("_", None), ] @@ -634,18 +671,18 @@ def addMenu(root, isSingle): return [ ( name, - ocioEvent("OCIOFile", "ocio.inColorSpace", name), + partial(_ocio_event, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), None, - ocioMenuCheck("OCIOFile", "ocio.inColorSpace", name), + partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: return [ ( name, - ocioEventOnAllOfType("OCIOFile", "ocio.inColorSpace", name), + partial(_ocio_event_on_all_of_type, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), None, - ocioMenuCheck("OCIOFile", "ocio.inColorSpace", name), + partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: @@ -665,9 +702,9 @@ def addMenu(root, isSingle): lsList = [ ( "Active", - self.ocioActiveEvent("OCIOLook"), + partial(self._ocio_active_event, nodeType="OCIOLook"), None, - isOCIOManaged("OCIOLook"), + partial(_is_ocio_managed, nodeType="OCIOLook"), ), ("_", None), ] @@ -677,17 +714,17 @@ def addMenu(root, isSingle): lsList.append( ( look.getName(), - ocioEvent("OCIOLook", "ocio_look.look", look.getName()), + partial(_ocio_event, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - ocioMenuCheck("OCIOLook", "ocio_look.look", look.getName()), + partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) laList.append( ( look.getName(), - ocioEventOnAllOfType("OCIOLook", "ocio_look.look", look.getName()), + partial(_ocio_event_on_all_of_type, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - ocioMenuCheck("OCIOLook", "ocio_look.look", look.getName()), + partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) From 801298b4f549e983f540c3a59a91ce2f5d2396c3 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 16:42:12 -0700 Subject: [PATCH 4/9] Add type hints and docstrings to OCIO source setup This was done with assistance from Google Gemini Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 332 ++++++++++++++---- 1 file changed, 272 insertions(+), 60 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index ba27153b9..fea3da753 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -8,6 +8,7 @@ import logging import PyOpenColorIO as OCIO from functools import partial +from typing import Any, Callable logging.basicConfig(format="%(levelname)s: %(message)s") @@ -23,29 +24,58 @@ # # -DEFAULT_PIPE = {} +DEFAULT_PIPE: dict[str, list[str]] = {} -DEFAULT_RV_PIPE = { +DEFAULT_RV_PIPE: dict[str, list[str]] = { "RVLinearizePipelineGroup": ["RVLinearize", "RVLensWarp"], "RVLookPipelineGroup": ["RVLookLUT"], "RVDisplayPipelineGroup": ["RVDisplayColor"], } -OCIO_ROLES = {"OCIOFile": "RVLinearizePipelineGroup", "OCIOLook": "RVLookPipelineGroup"} +OCIO_ROLES: dict[str, str] = {"OCIOFile": "RVLinearizePipelineGroup", "OCIOLook": "RVLookPipelineGroup"} -OCIO_DEFAULTS = {} +OCIO_DEFAULTS: dict[str, str] = {} -METHODS = ["ocio_config_from_media", "ocio_node_from_media"] +METHODS: list[str] = ["ocio_config_from_media", "ocio_node_from_media"] -def ocio_config_from_media(media, attributes): +def ocio_config_from_media(media: str | None, attributes: dict[str, Any] | None) -> OCIO.Config: + """ + Retrieve the current OCIO configuration. + + Args: + media: The media file path (unused in default implementation). + attributes: Additional attributes (unused in default implementation). + + Returns: + The current PyOpenColorIO configuration. + + Raises: + Exception: If the OCIO environment variable is not set. + """ if os.getenv("OCIO") is None: raise Exception return OCIO.GetCurrentConfig() -def ocio_node_from_media(config, node, default, media=None, attributes={}): +def ocio_node_from_media( + config: OCIO.Config, node: str, default: list[str], media: str | None = None, attributes: dict[str, Any] = {} +) -> list[dict[str, Any]]: + """ + Generate the OCIO node pipeline configuration based on the media and context. + + Args: + config: The current OCIO configuration. + node: The node or pipeline group name to evaluate. + default: The default pipeline node types. + media: The media file path. + attributes: Dictionary containing source attributes and default settings. + + Returns: + A list of dictionaries representing the node types, contexts, and properties + required to build the OCIO pipeline. + """ result = [{"nodeType": d, "context": {}, "properties": {}} for d in default] nodeType = commands.nodeType(node) @@ -66,7 +96,7 @@ def ocio_node_from_media(config, node, default, media=None, attributes={}): ] elif nodeType == "RVLinearizePipelineGroup": - inspace = config.parseColorSpaceFromString(media) + inspace = config.parseColorSpaceFromString(media) if media else "" if inspace == "": inspace = attributes.get("default_setting", "") if inspace != "": @@ -114,7 +144,16 @@ def ocio_node_from_media(config, node, default, media=None, attributes={}): # -def _is_ocio_managed(nodeType): +def _is_ocio_managed(nodeType: str) -> int: + """ + Internal callback logic to determine if a specific node type is currently managed by OCIO. + + Args: + nodeType: The node type to check. + + Returns: + The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). + """ try: managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState @@ -122,7 +161,7 @@ def _is_ocio_managed(nodeType): return commands.UncheckedMenuState -def isOCIOManaged(nodeType): +def isOCIOManaged(nodeType: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_is_ocio_managed, nodeType=...)`. @@ -130,18 +169,29 @@ def isOCIOManaged(nodeType): return partial(_is_ocio_managed, nodeType=nodeType) -def _is_ocio_display_managed(group): +def _is_ocio_display_managed(group: str) -> int: + """ + Internal callback logic to determine if a display group is currently managed by OCIO. + + Args: + group: The display group node name. + + Returns: + The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). + """ try: groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + if not dOCIO: + return commands.UncheckedMenuState managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState -def isOCIODisplayManaged(group): +def isOCIODisplayManaged(group: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_is_ocio_display_managed, group=...)`. @@ -149,7 +199,18 @@ def isOCIODisplayManaged(group): return partial(_is_ocio_display_managed, group=group) -def _ocio_menu_check(nodeType, prop, value): +def _ocio_menu_check(nodeType: str, prop: str, value: str) -> int: + """ + Internal callback logic to determine the menu check state for a specific OCIO property. + + Args: + nodeType: The OCIO node type. + prop: The property name to check. + value: The value to compare against the current property value. + + Returns: + The RV menu state (Checked, Neutral, or Disabled). + """ try: current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] managed = _is_ocio_managed(nodeType) == commands.CheckedMenuState @@ -159,7 +220,7 @@ def _ocio_menu_check(nodeType, prop, value): return commands.DisabledMenuState -def ocioMenuCheck(nodeType, prop, value): +def ocioMenuCheck(nodeType: str, prop: str, value: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_ocio_menu_check, nodeType=..., prop=..., value=...)`. @@ -167,11 +228,24 @@ def ocioMenuCheck(nodeType, prop, value): return partial(_ocio_menu_check, nodeType=nodeType, prop=prop, value=value) -def _ocio_display_menu_check(group, display, view): +def _ocio_display_menu_check(group: str, display: str, view: str) -> int: + """ + Internal callback logic to determine the menu check state for a display/view combination. + + Args: + group: The display group node name. + display: The OCIO display name. + view: The OCIO view name. + + Returns: + The RV menu state (Checked, Unchecked, or Disabled). + """ try: groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + if not dOCIO: + return commands.UncheckedMenuState d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] if d == display and v == view: @@ -181,7 +255,7 @@ def _ocio_display_menu_check(group, display, view): return commands.DisabledMenuState -def ocioDisplayMenuCheck(group, display, view): +def ocioDisplayMenuCheck(group: str, display: str, view: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_ocio_display_menu_check, group=..., display=..., view=...)`. @@ -189,12 +263,21 @@ def ocioDisplayMenuCheck(group, display, view): return partial(_ocio_display_menu_check, group=group, display=display, view=view) -def _ocio_event(event, nodeType, prop, value): +def _ocio_event(event: Any, nodeType: str, prop: str, value: str) -> None: + """ + Internal callback logic to set a property on the current node of nodeType in the evaluation path. + + Args: + event: The RV event object. + nodeType: The OCIO node type. + prop: The property name to set. + value: The value to assign to the property. + """ commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) commands.redraw() -def ocioEvent(nodeType, prop, value): +def ocioEvent(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_ocio_event, nodeType=..., prop=..., value=...)`. @@ -203,13 +286,22 @@ def ocioEvent(nodeType, prop, value): return partial(_ocio_event, nodeType=nodeType, prop=prop, value=value) -def _ocio_event_on_all_of_type(event, nodeType, prop, value): +def _ocio_event_on_all_of_type(event: Any, nodeType: str, prop: str, value: str) -> None: + """ + Internal callback logic to set a property on all nodes of nodeType. + + Args: + event: The RV event object. + nodeType: The OCIO node type. + prop: The property name to set. + value: The value to assign to the property. + """ for node in commands.nodesOfType(nodeType): commands.setStringProperty(f"{node}.{prop}", [value], True) commands.redraw() -def ocioEventOnAllOfType(nodeType, prop, value): +def ocioEventOnAllOfType(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_ocio_event_on_all_of_type, nodeType=..., prop=..., value=...)`. @@ -217,10 +309,21 @@ def ocioEventOnAllOfType(nodeType, prop, value): return partial(_ocio_event_on_all_of_type, nodeType=nodeType, prop=prop, value=value) -def _ocio_display_event(event, group, display, view): +def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None: + """ + Internal callback logic to change the active display and view for a display group. + + Args: + event: The RV event object. + group: The display group node name. + display: The OCIO display name. + view: The OCIO view name. + """ groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + if not dOCIO: + return # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. @@ -231,7 +334,7 @@ def _ocio_display_event(event, group, display, view): commands.redraw() -def ocioDisplayEvent(group, display, view): +def ocioDisplayEvent(group: str, display: str, view: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(_ocio_display_event, group=..., display=..., view=...)`. @@ -239,14 +342,32 @@ def ocioDisplayEvent(group, display, view): return partial(_ocio_display_event, group=group, display=display, view=view) -def groupMemberOfType(node, memberType): +def groupMemberOfType(node: str, memberType: str) -> str | None: + """ + Find the first member of a group node that matches a specific node type. + + Args: + node: The parent group node name. + memberType: The node type to search for. + + Returns: + The name of the child node if found, otherwise None. + """ for n in commands.nodesInGroup(node): if commands.nodeType(n) == memberType: return n return None -def applyProps(node, contextProps, propertiesProps): +def applyProps(node: str, contextProps: dict[str, str], propertiesProps: dict[str, str]) -> None: + """ + Apply standard and context properties to an OCIO node. + + Args: + node: The target node name. + contextProps: A dictionary of context variables and their values. + propertiesProps: A dictionary of standard properties and their values. + """ for pprop, avalue in propertiesProps.items(): commands.setStringProperty(f"{node}.{pprop}", [avalue], True) for cprop, cvalue in contextProps.items(): @@ -286,13 +407,18 @@ class OCIOSourceSetupMode(rvtypes.MinorMode): between 0 and 10). """ - def useSourceOCIO(self, source, nodeType, defaultSetting=""): + def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> None: """ This tells the source group to use OCIO instead of the RV linearize node. There is also ocio.look and ocio.preCache which can be activated in this way. For this code we're only assuming that OCIO is going to be used to linearize the source. + + Args: + source: The name of the source group node. + nodeType: The OCIO node type to activate (e.g., 'OCIOFile'). + defaultSetting: The default fallback setting for color space or look. """ medias = commands.getStringProperty(f"{source}.media.movie") @@ -321,6 +447,9 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): pipeSlot = OCIO_ROLES[nodeType] srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) + if not srcPipeline: + return + ocioNode = groupMemberOfType(srcPipeline, nodeType) if ocioNode is not None and self.readingSession: for pNode in commands.nodesInGroup(srcPipeline): @@ -370,6 +499,8 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) + return + if pipeline == DEFAULT_PIPE[pipeSlot]: return @@ -387,14 +518,21 @@ def useSourceOCIO(self, source, nodeType, defaultSetting=""): commands.redraw() - def disableSourceOCIO(self, source, nodeType): + def disableSourceOCIO(self, source: str, nodeType: str) -> None: """ This reverts the source group's linearize node back to using a native RVLinearize node. + + Args: + source: The name of the source group node. + nodeType: The OCIO node type being disabled. """ pipeSlot = OCIO_ROLES[nodeType] srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) + if not srcPipeline: + return + nodesProp = f"{srcPipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) @@ -406,7 +544,7 @@ def disableSourceOCIO(self, source, nodeType): commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) commands.redraw() - def useDisplayOCIO(self, group): + def useDisplayOCIO(self, group: str) -> None: """ This installs the OCIODisplay node in the DisplayGroup's display pipeline in place of RV's RVDisplayColor node. @@ -414,6 +552,9 @@ def useDisplayOCIO(self, group): NOTE: in RV4 all display devices are separate DisplayGroups. So each one can have a completely different view and display transform. + + Args: + group: The display group node name. """ if self.usingOCIOForDisplay.get(group, False) or self.config is None: @@ -422,6 +563,9 @@ def useDisplayOCIO(self, group): groupName = "RVDisplayPipelineGroup" try: dpipeline = groupMemberOfType(group, groupName) + if not dpipeline: + return + if groupName not in DEFAULT_PIPE: currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") @@ -443,13 +587,14 @@ def useDisplayOCIO(self, group): pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) + return + if pipeline == DEFAULT_PIPE[groupName]: return device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using OCIODisplay for display: %s", device) - dpipeline = groupMemberOfType(group, groupName) commands.setStringProperty(f"{dpipeline}.pipeline.nodes", pipeline, True) pipeNodes = commands.nodesInGroup(dpipeline) @@ -464,14 +609,20 @@ def useDisplayOCIO(self, group): self.usingOCIOForDisplay[group] = True commands.redraw() - def disableDisplayOCIO(self, group): + def disableDisplayOCIO(self, group: str) -> None: """ This reverts the DisplayGroup's display pipeline back to using RV's native RVDisplayColor node. + + Args: + group: The display group node name. """ groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) + if not dpipeline: + return + nodesProp = f"{dpipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) @@ -486,12 +637,15 @@ def disableDisplayOCIO(self, group): self.usingOCIOForDisplay[group] = False commands.redraw() - def sourceSetup(self, event): + def sourceSetup(self, event: Any) -> None: """ This function should be bound to the "source-group-complete" event. It will attempt to use OCIO to infer the incoming file space. If it succeeds, the OCIOFile node of the source group is activated and used to convert to the ROLE_SCENE_LINEAR space. + + Args: + event: The RV event object triggering the setup. """ event.reject() # don't eat this event -- allow others to get it too @@ -502,6 +656,9 @@ def sourceSetup(self, event): imageSource = groupMemberOfType(group, "RVImageSource") source = fileSource if imageSource is None else imageSource + if not source: + return + for nodeType in OCIO_ROLES.keys(): self.useSourceOCIO(source, nodeType) @@ -512,15 +669,27 @@ def sourceSetup(self, event): # if len(commands.nodesOfType("OCIOFile")) == 1: - for group in commands.nodesOfType("RVDisplayGroup"): - if not self.usingOCIOForDisplay.get(group, False): - self.useDisplayOCIO(group) + for dgroup in commands.nodesOfType("RVDisplayGroup"): + if not self.usingOCIOForDisplay.get(dgroup, False): + self.useDisplayOCIO(dgroup) + + def beforeSessionRead(self, event: Any) -> None: + """ + Flag that a session is currently being read. - def beforeSessionRead(self, event): + Args: + event: The RV event object. + """ event.reject() self.readingSession = True - def afterSessionRead(self, event): + def afterSessionRead(self, event: Any) -> None: + """ + Clear the session read flag and re-initialize OCIO display if needed. + + Args: + event: The RV event object. + """ event.reject() self.readingSession = False if len(commands.nodesOfType("OCIOFile")) > 1: @@ -528,7 +697,14 @@ def afterSessionRead(self, event): if not self.usingOCIOForDisplay.get(group, False): self.useDisplayOCIO(group) - def _ocio_active_event(self, event, nodeType): + def _ocio_active_event(self, event: Any, nodeType: str) -> None: + """ + Toggle the active state of an OCIO node or display group. + + Args: + event: The RV event object. + nodeType: The OCIO node type or display group to toggle. + """ if nodeType not in ["OCIOFile", "OCIOLook"]: if _is_ocio_display_managed(nodeType) == commands.CheckedMenuState: self.disableDisplayOCIO(nodeType) @@ -548,14 +724,20 @@ def _ocio_active_event(self, event, nodeType): else: self.useSourceOCIO(source, nodeType, OCIO_DEFAULTS[nodeType]) - def ocioActiveEvent(self, nodeType): + def ocioActiveEvent(self, nodeType: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. Internal code should use `functools.partial(self._ocio_active_event, nodeType=...)`. """ return partial(self._ocio_active_event, nodeType=nodeType) - def checkForDisplayGroup(self, event): + def checkForDisplayGroup(self, event: Any) -> None: + """ + Check for newly created or modified display groups and rebuild the menu. + + Args: + event: The RV event object. + """ event.reject() try: node = event.contents() @@ -565,12 +747,24 @@ def checkForDisplayGroup(self, event): except Exception as inst: package_logger.error("%s %s", inst, node) - def maybeUpdateViews(self, event): + def maybeUpdateViews(self, event: Any) -> None: + """ + Rebuild the OCIO menu if a display view has changed. + + Args: + event: The RV event object. + """ event.reject() if event.contents().endswith("ocio_display.display"): commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) - def selectConfig(self, event): + def selectConfig(self, event: Any) -> None: + """ + Prompt the user to manually select an OCIO configuration file. + + Args: + event: The RV event object. + """ try: config = commands.openFileDialog(True, False, False, "ocio|OCIO Config", None)[0] self.config = OCIO.Config.CreateFromFile(config) @@ -592,7 +786,13 @@ def selectConfig(self, event): except Exception as inst: package_logger.error(inst) - def buildOCIOMenu(self): + def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: + """ + Construct the RV menu items required for OCIO management. + + Returns: + A list defining the OCIO menu structure. + """ # # Try to acquire OCIO config to populate the display menu # @@ -639,7 +839,7 @@ def buildOCIOMenu(self): # Apply file space changes only to the visible source # - cssList = [ + cssList: list[Any] = [ ( "Active", partial(self._ocio_active_event, nodeType="OCIOFile"), @@ -648,24 +848,26 @@ def buildOCIOMenu(self): ), ("_", None), ] - csaList = [] + csaList: list[Any] = [] - def addPath(family, tree): + def addPath(family: list[str], tree: list[list[str]]) -> None: for f in family: for t in tree: if f in t: - return addPath(family[1:], t) + addPath(family[1:], t) + return tree.append([f]) - return addPath(family, tree) + addPath(family, tree) + return families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self.config.getColorSpaces()] - root = [] + root: list[list[str]] = [] for family in families: addPath(family, root) - def addMenu(root, isSingle): - if len(root) == 1: - name = root[0] + def addMenu(root_node: list[Any], isSingle: bool) -> list[Any]: + if len(root_node) == 1: + name = root_node[0] if isSingle: OCIO_DEFAULTS.setdefault("OCIOFile", name) return [ @@ -687,9 +889,9 @@ def addMenu(root, isSingle): ] else: menu = [] - for r in root[1:]: + for r in root_node[1:]: menu += addMenu(r, isSingle) - return [(root[0], menu)] + return [(root_node[0], menu)] for r in root: cssList += addMenu(r, True) @@ -699,7 +901,7 @@ def addMenu(root, isSingle): # Apply file look changes only to the visible source # - lsList = [ + lsList: list[Any] = [ ( "Active", partial(self._ocio_active_event, nodeType="OCIOLook"), @@ -708,7 +910,7 @@ def addMenu(root, isSingle): ), ("_", None), ] - laList = [] + laList: list[Any] = [] for look in self.config.getLooks(): OCIO_DEFAULTS.setdefault("OCIOLook", look.getName()) lsList.append( @@ -728,7 +930,7 @@ def addMenu(root, isSingle): ) ) - final = [ + final: list[Any] = [ ("Current Source", None, None, lambda: commands.DisabledMenuState), (" File Color Space", cssList), ] @@ -750,12 +952,16 @@ def addMenu(root, isSingle): return [("OCIO", final)] - def __init__(self): + def __init__(self) -> None: + """ + Initialize the minor mode, attempt to load inherited configuration, + and bind the mode events to RV. + """ rvtypes.MinorMode.__init__(self) - self.usingOCIOForDisplay = {} - self.readingSession = False - self.config = None + self.usingOCIOForDisplay: dict[str, bool] = {} + self.readingSession: bool = False + self.config: OCIO.Config | None = None # # Look for an implementation of the OCIOHelper on the PATH. @@ -815,5 +1021,11 @@ def __init__(self): # -def createMode(): +def createMode() -> OCIOSourceSetupMode: + """ + Factory function used by the RV Mode Manager to instantiate the mode. + + Returns: + An instance of OCIOSourceSetupMode. + """ return OCIOSourceSetupMode() From 7b29e54022c1d5822d74f93392f3fce2c84754a2 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 17:16:05 -0700 Subject: [PATCH 5/9] Refactor ocio_node_from_media and clean up code This is meant as an amendment to the last commit Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 34 ++++--------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index fea3da753..c71cf92b7 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -60,7 +60,7 @@ def ocio_config_from_media(media: str | None, attributes: dict[str, Any] | None) def ocio_node_from_media( - config: OCIO.Config, node: str, default: list[str], media: str | None = None, attributes: dict[str, Any] = {} + config: OCIO.Config, node: str, default: list[str], media: str | None = None, attributes: dict[str, Any] | None = None ) -> list[dict[str, Any]]: """ Generate the OCIO node pipeline configuration based on the media and context. @@ -76,6 +76,9 @@ def ocio_node_from_media( A list of dictionaries representing the node types, contexts, and properties required to build the OCIO pipeline. """ + if attributes is None: + attributes = {} + result = [{"nodeType": d, "context": {}, "properties": {}} for d in default] nodeType = commands.nodeType(node) @@ -96,7 +99,7 @@ def ocio_node_from_media( ] elif nodeType == "RVLinearizePipelineGroup": - inspace = config.parseColorSpaceFromString(media) if media else "" + inspace = config.parseColorSpaceFromString(media) if inspace == "": inspace = attributes.get("default_setting", "") if inspace != "": @@ -183,8 +186,6 @@ def _is_ocio_display_managed(group: str) -> int: groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - if not dOCIO: - return commands.UncheckedMenuState managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: @@ -244,8 +245,6 @@ def _ocio_display_menu_check(group: str, display: str, view: str) -> int: groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - if not dOCIO: - return commands.UncheckedMenuState d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] if d == display and v == view: @@ -322,8 +321,6 @@ def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - if not dOCIO: - return # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. @@ -447,9 +444,6 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> pipeSlot = OCIO_ROLES[nodeType] srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) - if not srcPipeline: - return - ocioNode = groupMemberOfType(srcPipeline, nodeType) if ocioNode is not None and self.readingSession: for pNode in commands.nodesInGroup(srcPipeline): @@ -530,9 +524,6 @@ def disableSourceOCIO(self, source: str, nodeType: str) -> None: pipeSlot = OCIO_ROLES[nodeType] srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) - if not srcPipeline: - return - nodesProp = f"{srcPipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) @@ -563,9 +554,6 @@ def useDisplayOCIO(self, group: str) -> None: groupName = "RVDisplayPipelineGroup" try: dpipeline = groupMemberOfType(group, groupName) - if not dpipeline: - return - if groupName not in DEFAULT_PIPE: currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") @@ -620,9 +608,6 @@ def disableDisplayOCIO(self, group: str) -> None: groupName = "RVDisplayPipelineGroup" dpipeline = groupMemberOfType(group, groupName) - if not dpipeline: - return - nodesProp = f"{dpipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) @@ -656,9 +641,6 @@ def sourceSetup(self, event: Any) -> None: imageSource = groupMemberOfType(group, "RVImageSource") source = fileSource if imageSource is None else imageSource - if not source: - return - for nodeType in OCIO_ROLES.keys(): self.useSourceOCIO(source, nodeType) @@ -854,11 +836,9 @@ def addPath(family: list[str], tree: list[list[str]]) -> None: for f in family: for t in tree: if f in t: - addPath(family[1:], t) - return + return addPath(family[1:], t) tree.append([f]) - addPath(family, tree) - return + return addPath(family, tree) families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self.config.getColorSpaces()] root: list[list[str]] = [] From ff9dc39e4a36a3283d66f70b76688ba23b003d67 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Mon, 20 Jul 2026 17:24:11 -0700 Subject: [PATCH 6/9] Refactor addPath and method overriding logic Refactored addPath function to remove redundant returns and improve clarity. Updated method overriding to use getattr for better attribute handling. Signed-off-by: Erwan Leroy --- .../rv-packages/ocio_source_setup/ocio_source_setup.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index c71cf92b7..393fd0f97 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -836,9 +836,11 @@ def addPath(family: list[str], tree: list[list[str]]) -> None: for f in family: for t in tree: if f in t: - return addPath(family[1:], t) + addPath(family[1:], t) + return tree.append([f]) - return addPath(family, tree) + addPath(family, tree) + return families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self.config.getColorSpaces()] root: list[list[str]] = [] @@ -954,7 +956,8 @@ def __init__(self) -> None: inherited = [] for method in METHODS: try: - exec(f"global {method}; {method} = rv_ocio_setup.{method}") + override_method = getattr(rv_ocio_setup, method) + globals()[method] = override_method inherited.append(method) except AttributeError: pass From 02ca15136a97a99054a66827ec5e7cfb16a2a802 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Tue, 21 Jul 2026 03:34:41 -0700 Subject: [PATCH 7/9] Refactor variable names for consistency Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 446 +++++++++--------- 1 file changed, 222 insertions(+), 224 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index 393fd0f97..514bd9529 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -81,9 +81,9 @@ def ocio_node_from_media( result = [{"nodeType": d, "context": {}, "properties": {}} for d in default] - nodeType = commands.nodeType(node) + node_type = commands.nodeType(node) - if nodeType == "RVDisplayPipelineGroup": + if node_type == "RVDisplayPipelineGroup": display = config.getDefaultDisplay() result = [ { @@ -98,25 +98,25 @@ def ocio_node_from_media( } ] - elif nodeType == "RVLinearizePipelineGroup": - inspace = config.parseColorSpaceFromString(media) - if inspace == "": - inspace = attributes.get("default_setting", "") - if inspace != "": + elif node_type == "RVLinearizePipelineGroup": + in_space = config.parseColorSpaceFromString(media) + if in_space == "": + in_space = attributes.get("default_setting", "") + if in_space != "": result = [ { "nodeType": "OCIOFile", "context": {}, "properties": { "ocio.function": "color", - "ocio.inColorSpace": inspace, + "ocio.inColorSpace": in_space, "ocio_color.outColorSpace": OCIO.ROLE_SCENE_LINEAR, }, }, {"nodeType": "RVLensWarp", "context": {}, "properties": {}}, ] - elif nodeType == "RVLookPipelineGroup": + elif node_type == "RVLookPipelineGroup": # If our config has a Look named "shot_specific_look" and uses the # environment/context variable "$SHOT" to locate any required files # on disk, then this is what that would likely look like: @@ -147,29 +147,29 @@ def ocio_node_from_media( # -def _is_ocio_managed(nodeType: str) -> int: +def _is_ocio_managed(node_type: str) -> int: """ Internal callback logic to determine if a specific node type is currently managed by OCIO. Args: - nodeType: The node type to check. + node_type: The node type to check. Returns: The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). """ try: - managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 + managed = commands.getIntProperty(f"#{node_type}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState -def isOCIOManaged(nodeType: str) -> Callable[[], int]: +def isOCIOManaged(node_type: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_is_ocio_managed, nodeType=...)`. + Internal code should use `functools.partial(_is_ocio_managed, node_type=...)`. """ - return partial(_is_ocio_managed, nodeType=nodeType) + return partial(_is_ocio_managed, node_type=node_type) def _is_ocio_display_managed(group: str) -> int: @@ -183,10 +183,10 @@ def _is_ocio_display_managed(group: str) -> int: The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). """ try: - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 + group_name = "RVDisplayPipelineGroup" + d_pipeline = groupMemberOfType(group, group_name) + d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") + managed = commands.getIntProperty(f"{d_ocio}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState @@ -200,12 +200,12 @@ def isOCIODisplayManaged(group: str) -> Callable[[], int]: return partial(_is_ocio_display_managed, group=group) -def _ocio_menu_check(nodeType: str, prop: str, value: str) -> int: +def _ocio_menu_check(node_type: str, prop: str, value: str) -> int: """ Internal callback logic to determine the menu check state for a specific OCIO property. Args: - nodeType: The OCIO node type. + node_type: The OCIO node type. prop: The property name to check. value: The value to compare against the current property value. @@ -213,20 +213,20 @@ def _ocio_menu_check(nodeType: str, prop: str, value: str) -> int: The RV menu state (Checked, Neutral, or Disabled). """ try: - current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] - managed = _is_ocio_managed(nodeType) == commands.CheckedMenuState + current = commands.getStringProperty(f"#{node_type}.{prop}")[0] + managed = _is_ocio_managed(node_type) == commands.CheckedMenuState checked = current == value and managed return commands.CheckedMenuState if checked else commands.NeutralMenuState except Exception: return commands.DisabledMenuState -def ocioMenuCheck(nodeType: str, prop: str, value: str) -> Callable[[], int]: +def ocioMenuCheck(node_type: str, prop: str, value: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_menu_check, nodeType=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_menu_check, node_type=..., prop=..., value=...)`. """ - return partial(_ocio_menu_check, nodeType=nodeType, prop=prop, value=value) + return partial(_ocio_menu_check, node_type=node_type, prop=prop, value=value) def _ocio_display_menu_check(group: str, display: str, view: str) -> int: @@ -242,11 +242,11 @@ def _ocio_display_menu_check(group: str, display: str, view: str) -> int: The RV menu state (Checked, Unchecked, or Disabled). """ try: - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - d = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] - v = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] + group_name = "RVDisplayPipelineGroup" + d_pipeline = groupMemberOfType(group, group_name) + d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") + d = commands.getStringProperty(f"{d_ocio}.ocio_display.display")[0] + v = commands.getStringProperty(f"{d_ocio}.ocio_display.view")[0] if d == display and v == view: return commands.CheckedMenuState return commands.UncheckedMenuState @@ -262,50 +262,50 @@ def ocioDisplayMenuCheck(group: str, display: str, view: str) -> Callable[[], in return partial(_ocio_display_menu_check, group=group, display=display, view=view) -def _ocio_event(event: Any, nodeType: str, prop: str, value: str) -> None: +def _ocio_event(event: Any, node_type: str, prop: str, value: str) -> None: """ - Internal callback logic to set a property on the current node of nodeType in the evaluation path. + Internal callback logic to set a property on the current node of node_type in the evaluation path. Args: event: The RV event object. - nodeType: The OCIO node type. + node_type: The OCIO node type. prop: The property name to set. value: The value to assign to the property. """ - commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) + commands.setStringProperty(f"#{node_type}.{prop}", [value], True) commands.redraw() -def ocioEvent(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: +def ocioEvent(node_type: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_event, nodeType=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_event, node_type=..., prop=..., value=...)`. Note: The internal `_ocio_event` accepts `event` as its first parameter to allow kwargs binding. """ - return partial(_ocio_event, nodeType=nodeType, prop=prop, value=value) + return partial(_ocio_event, node_type=node_type, prop=prop, value=value) -def _ocio_event_on_all_of_type(event: Any, nodeType: str, prop: str, value: str) -> None: +def _ocio_event_on_all_of_type(event: Any, node_type: str, prop: str, value: str) -> None: """ - Internal callback logic to set a property on all nodes of nodeType. + Internal callback logic to set a property on all nodes of node_type. Args: event: The RV event object. - nodeType: The OCIO node type. + node_type: The OCIO node type. prop: The property name to set. value: The value to assign to the property. """ - for node in commands.nodesOfType(nodeType): + for node in commands.nodesOfType(node_type): commands.setStringProperty(f"{node}.{prop}", [value], True) commands.redraw() -def ocioEventOnAllOfType(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: +def ocioEventOnAllOfType(node_type: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_event_on_all_of_type, nodeType=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_event_on_all_of_type, node_type=..., prop=..., value=...)`. """ - return partial(_ocio_event_on_all_of_type, nodeType=nodeType, prop=prop, value=value) + return partial(_ocio_event_on_all_of_type, node_type=node_type, prop=prop, value=value) def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None: @@ -318,16 +318,16 @@ def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None display: The OCIO display name. view: The OCIO view name. """ - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + group_name = "RVDisplayPipelineGroup" + d_pipeline = groupMemberOfType(group, group_name) + d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. - commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) - commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) + commands.setIntProperty(f"{d_ocio}.ocio.active", [0], True) + commands.setStringProperty(f"{d_ocio}.ocio_display.display", [display], True) + commands.setStringProperty(f"{d_ocio}.ocio_display.view", [view], True) + commands.setIntProperty(f"{d_ocio}.ocio.active", [1], True) commands.redraw() @@ -339,39 +339,39 @@ def ocioDisplayEvent(group: str, display: str, view: str) -> Callable[[Any], Non return partial(_ocio_display_event, group=group, display=display, view=view) -def groupMemberOfType(node: str, memberType: str) -> str | None: +def groupMemberOfType(node: str, member_type: str) -> str | None: """ Find the first member of a group node that matches a specific node type. Args: node: The parent group node name. - memberType: The node type to search for. + member_type: The node type to search for. Returns: The name of the child node if found, otherwise None. """ for n in commands.nodesInGroup(node): - if commands.nodeType(n) == memberType: + if commands.nodeType(n) == member_type: return n return None -def applyProps(node: str, contextProps: dict[str, str], propertiesProps: dict[str, str]) -> None: +def applyProps(node: str, context_props: dict[str, str], properties_props: dict[str, str]) -> None: """ Apply standard and context properties to an OCIO node. Args: node: The target node name. - contextProps: A dictionary of context variables and their values. - propertiesProps: A dictionary of standard properties and their values. + context_props: A dictionary of context variables and their values. + properties_props: A dictionary of standard properties and their values. """ - for pprop, avalue in propertiesProps.items(): - commands.setStringProperty(f"{node}.{pprop}", [avalue], True) - for cprop, cvalue in contextProps.items(): - prop = f"{node}.ocio_context.{cprop}" + for p_prop, a_value in properties_props.items(): + commands.setStringProperty(f"{node}.{p_prop}", [a_value], True) + for c_prop, c_value in context_props.items(): + prop = f"{node}.ocio_context.{c_prop}" if not commands.propertyExists(prop): commands.newProperty(prop, commands.StringType, 1) - commands.setStringProperty(prop, [cvalue], True) + commands.setStringProperty(prop, [c_value], True) # @@ -404,7 +404,7 @@ class OCIOSourceSetupMode(rvtypes.MinorMode): between 0 and 10). """ - def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> None: + def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") -> None: """ This tells the source group to use OCIO instead of the RV linearize node. There is also ocio.look and ocio.preCache @@ -414,25 +414,25 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> Args: source: The name of the source group node. - nodeType: The OCIO node type to activate (e.g., 'OCIOFile'). - defaultSetting: The default fallback setting for color space or look. + node_type: The OCIO node type to activate (e.g., 'OCIOFile'). + default_setting: The default fallback setting for color space or look. """ medias = commands.getStringProperty(f"{source}.media.movie") media = medias[0] try: - srcAttrs = commands.sourceAttributes(source, media) - attrDict = dict(zip([i[0] for i in srcAttrs], [j[1] for j in srcAttrs])) - attrDict["source_node"] = source - attrDict["default_setting"] = defaultSetting + src_attrs = commands.sourceAttributes(source, media) + attr_dict = dict(zip([i[0] for i in src_attrs], [j[1] for j in src_attrs])) + attr_dict["source_node"] = source + attr_dict["default_setting"] = default_setting except Exception: - attrDict = {} + attr_dict = {} - if self.config is None: + if self._config is None: try: - self.config = ocio_config_from_media(media, attrDict) - OCIO.SetCurrentConfig(self.config) + self._config = ocio_config_from_media(media, attr_dict) + OCIO.SetCurrentConfig(self._config) commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) except Exception: return @@ -442,15 +442,15 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> # then use the one we have and return # - pipeSlot = OCIO_ROLES[nodeType] - srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) - ocioNode = groupMemberOfType(srcPipeline, nodeType) - if ocioNode is not None and self.readingSession: - for pNode in commands.nodesInGroup(srcPipeline): - if commands.nodeType(pNode).startswith("OCIO"): - commands.ocioUpdateConfig(pNode) + pipe_slot = OCIO_ROLES[node_type] + src_pipeline = groupMemberOfType(commands.nodeGroup(source), pipe_slot) + ocio_node = groupMemberOfType(src_pipeline, node_type) + if ocio_node is not None and self._reading_session: + for p_node in commands.nodesInGroup(src_pipeline): + if commands.nodeType(p_node).startswith("OCIO"): + commands.ocioUpdateConfig(p_node) - package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) + package_logger.info("using %s node for %s %s", node_type, source, pipe_slot) return # @@ -471,8 +471,8 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> # try: - if pipeSlot not in DEFAULT_PIPE: - currentPipelineNodes = commands.getStringProperty(f"{srcPipeline}.pipeline.nodes") + if pipe_slot not in DEFAULT_PIPE: + current_pipeline_nodes = commands.getStringProperty(f"{src_pipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that @@ -480,59 +480,59 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> # want this pipeline to be considered the default (non OCIO). # Example: srcPipelineNodes = [ "OCIOFile" "RVLensWarp" ] # We will use the RV default instead in that special case. - if nodeType in currentPipelineNodes and pipeSlot in DEFAULT_RV_PIPE: - DEFAULT_PIPE[pipeSlot] = DEFAULT_RV_PIPE[pipeSlot] + if node_type in current_pipeline_nodes and pipe_slot in DEFAULT_RV_PIPE: + DEFAULT_PIPE[pipe_slot] = DEFAULT_RV_PIPE[pipe_slot] else: - DEFAULT_PIPE[pipeSlot] = currentPipelineNodes - pipelineList = ocio_node_from_media(self.config, srcPipeline, DEFAULT_PIPE[pipeSlot], media, attrDict) + DEFAULT_PIPE[pipe_slot] = current_pipeline_nodes + pipeline_list = ocio_node_from_media(self._config, src_pipeline, DEFAULT_PIPE[pipe_slot], media, attr_dict) except Exception as inst: - package_logger.error("Problem occurred while loading OCIO settings for %s: %s", nodeType, inst) + package_logger.error("Problem occurred while loading OCIO settings for %s: %s", node_type, inst) return try: - pipeline = [p["nodeType"] for p in pipelineList] + pipeline = [p["nodeType"] for p in pipeline_list] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) return - if pipeline == DEFAULT_PIPE[pipeSlot]: + if pipeline == DEFAULT_PIPE[pipe_slot]: return - package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) + package_logger.info("using %s node for %s %s", node_type, source, pipe_slot) - commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", pipeline, True) - pipeNodes = commands.nodesInGroup(srcPipeline) - pipeNodes.sort() - for index, pNode in enumerate(pipelineList): - stageOCIO = pipeNodes[index] + commands.setStringProperty(f"{src_pipeline}.pipeline.nodes", pipeline, True) + pipe_nodes = commands.nodesInGroup(src_pipeline) + pipe_nodes.sort() + for index, p_node in enumerate(pipeline_list): + stage_ocio = pipe_nodes[index] try: - applyProps(stageOCIO, pNode["context"], pNode["properties"]) + applyProps(stage_ocio, p_node["context"], p_node["properties"]) except KeyError as inst: - package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) + package_logger.error("Unable to apply properties to %s: %s", stage_ocio, inst) commands.redraw() - def disableSourceOCIO(self, source: str, nodeType: str) -> None: + def disableSourceOCIO(self, source: str, node_type: str) -> None: """ This reverts the source group's linearize node back to using a native RVLinearize node. Args: source: The name of the source group node. - nodeType: The OCIO node type being disabled. + node_type: The OCIO node type being disabled. """ - pipeSlot = OCIO_ROLES[nodeType] - srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) - nodesProp = f"{srcPipeline}.pipeline.nodes" - current = commands.getStringProperty(nodesProp) + pipe_slot = OCIO_ROLES[node_type] + src_pipeline = groupMemberOfType(commands.nodeGroup(source), pipe_slot) + nodes_prop = f"{src_pipeline}.pipeline.nodes" + current = commands.getStringProperty(nodes_prop) - if pipeSlot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipeSlot]: + if pipe_slot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipe_slot]: return - package_logger.info("resetting %s for %s", pipeSlot, source) + package_logger.info("resetting %s for %s", pipe_slot, source) - commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) + commands.setStringProperty(f"{src_pipeline}.pipeline.nodes", DEFAULT_PIPE[pipe_slot], True) commands.redraw() def useDisplayOCIO(self, group: str) -> None: @@ -548,53 +548,53 @@ def useDisplayOCIO(self, group: str) -> None: group: The display group node name. """ - if self.usingOCIOForDisplay.get(group, False) or self.config is None: + if self._using_ocio_for_display.get(group, False) or self._config is None: return - groupName = "RVDisplayPipelineGroup" + group_name = "RVDisplayPipelineGroup" try: - dpipeline = groupMemberOfType(group, groupName) - if groupName not in DEFAULT_PIPE: - currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") + d_pipeline = groupMemberOfType(group, group_name) + if group_name not in DEFAULT_PIPE: + current_pipeline_nodes = commands.getStringProperty(f"{d_pipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that # is already OCIO color corrected in which case we do not # want this pipeline to be considered the default (non OCIO). # We will use the RV default instead in that special case. - if "OCIODisplay" in currentPipelineNodes and groupName in DEFAULT_RV_PIPE: - DEFAULT_PIPE[groupName] = DEFAULT_RV_PIPE[groupName] + if "OCIODisplay" in current_pipeline_nodes and group_name in DEFAULT_RV_PIPE: + DEFAULT_PIPE[group_name] = DEFAULT_RV_PIPE[group_name] else: - DEFAULT_PIPE[groupName] = currentPipelineNodes - pipelineList = ocio_node_from_media(self.config, dpipeline, DEFAULT_PIPE[groupName]) + DEFAULT_PIPE[group_name] = current_pipeline_nodes + pipeline_list = ocio_node_from_media(self._config, d_pipeline, DEFAULT_PIPE[group_name]) except Exception as inst: package_logger.error("Problem occurred while loading OCIO settings for OCIODisplay: %s", inst) return try: - pipeline = [p["nodeType"] for p in pipelineList] + pipeline = [p["nodeType"] for p in pipeline_list] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) return - if pipeline == DEFAULT_PIPE[groupName]: + if pipeline == DEFAULT_PIPE[group_name]: return device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using OCIODisplay for display: %s", device) - commands.setStringProperty(f"{dpipeline}.pipeline.nodes", pipeline, True) + commands.setStringProperty(f"{d_pipeline}.pipeline.nodes", pipeline, True) - pipeNodes = commands.nodesInGroup(dpipeline) - pipeNodes.sort() - for index, pNode in enumerate(pipelineList): - stageOCIO = pipeNodes[index] + pipe_nodes = commands.nodesInGroup(d_pipeline) + pipe_nodes.sort() + for index, p_node in enumerate(pipeline_list): + stage_ocio = pipe_nodes[index] try: - applyProps(stageOCIO, pNode["context"], pNode["properties"]) + applyProps(stage_ocio, p_node["context"], p_node["properties"]) except KeyError as inst: - package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) + package_logger.error("Unable to apply properties to %s: %s", stage_ocio, inst) - self.usingOCIOForDisplay[group] = True + self._using_ocio_for_display[group] = True commands.redraw() def disableDisplayOCIO(self, group: str) -> None: @@ -606,20 +606,20 @@ def disableDisplayOCIO(self, group: str) -> None: group: The display group node name. """ - groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - nodesProp = f"{dpipeline}.pipeline.nodes" - current = commands.getStringProperty(nodesProp) + group_name = "RVDisplayPipelineGroup" + d_pipeline = groupMemberOfType(group, group_name) + nodes_prop = f"{d_pipeline}.pipeline.nodes" + current = commands.getStringProperty(nodes_prop) - if groupName not in DEFAULT_PIPE or current == DEFAULT_PIPE[groupName]: + if group_name not in DEFAULT_PIPE or current == DEFAULT_PIPE[group_name]: return - commands.setStringProperty(f"{dpipeline}.pipeline.nodes", DEFAULT_PIPE[groupName], True) + commands.setStringProperty(f"{d_pipeline}.pipeline.nodes", DEFAULT_PIPE[group_name], True) device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using RVDisplayColor for display: %s", device) - self.usingOCIOForDisplay[group] = False + self._using_ocio_for_display[group] = False commands.redraw() def sourceSetup(self, event: Any) -> None: @@ -637,12 +637,12 @@ def sourceSetup(self, event: Any) -> None: args = event.contents().split(";;") group = args[0] - fileSource = groupMemberOfType(group, "RVFileSource") - imageSource = groupMemberOfType(group, "RVImageSource") - source = fileSource if imageSource is None else imageSource + file_source = groupMemberOfType(group, "RVFileSource") + image_source = groupMemberOfType(group, "RVImageSource") + source = file_source if image_source is None else image_source - for nodeType in OCIO_ROLES.keys(): - self.useSourceOCIO(source, nodeType) + for node_type in OCIO_ROLES.keys(): + self.useSourceOCIO(source, node_type) # # If this is the first OCIO color pipeline for a source assume @@ -651,9 +651,9 @@ def sourceSetup(self, event: Any) -> None: # if len(commands.nodesOfType("OCIOFile")) == 1: - for dgroup in commands.nodesOfType("RVDisplayGroup"): - if not self.usingOCIOForDisplay.get(dgroup, False): - self.useDisplayOCIO(dgroup) + for d_group in commands.nodesOfType("RVDisplayGroup"): + if not self._using_ocio_for_display.get(d_group, False): + self.useDisplayOCIO(d_group) def beforeSessionRead(self, event: Any) -> None: """ @@ -663,7 +663,7 @@ def beforeSessionRead(self, event: Any) -> None: event: The RV event object. """ event.reject() - self.readingSession = True + self._reading_session = True def afterSessionRead(self, event: Any) -> None: """ @@ -673,45 +673,45 @@ def afterSessionRead(self, event: Any) -> None: event: The RV event object. """ event.reject() - self.readingSession = False + self._reading_session = False if len(commands.nodesOfType("OCIOFile")) > 1: for group in commands.nodesOfType("RVDisplayGroup"): - if not self.usingOCIOForDisplay.get(group, False): + if not self._using_ocio_for_display.get(group, False): self.useDisplayOCIO(group) - def _ocio_active_event(self, event: Any, nodeType: str) -> None: + def _ocio_active_event(self, event: Any, node_type: str) -> None: """ Toggle the active state of an OCIO node or display group. Args: event: The RV event object. - nodeType: The OCIO node type or display group to toggle. + node_type: The OCIO node type or display group to toggle. """ - if nodeType not in ["OCIOFile", "OCIOLook"]: - if _is_ocio_display_managed(nodeType) == commands.CheckedMenuState: - self.disableDisplayOCIO(nodeType) + if node_type not in ["OCIOFile", "OCIOLook"]: + if _is_ocio_display_managed(node_type) == commands.CheckedMenuState: + self.disableDisplayOCIO(node_type) else: - self.useDisplayOCIO(nodeType) + self.useDisplayOCIO(node_type) return - evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) - if len(evalInfo) == 0: - evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) - if len(evalInfo) == 0: + eval_info = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) + if len(eval_info) == 0: + eval_info = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) + if len(eval_info) == 0: return - source = evalInfo[0]["node"] + source = eval_info[0]["node"] - if _is_ocio_managed(nodeType) == commands.CheckedMenuState: - self.disableSourceOCIO(source, nodeType) + if _is_ocio_managed(node_type) == commands.CheckedMenuState: + self.disableSourceOCIO(source, node_type) else: - self.useSourceOCIO(source, nodeType, OCIO_DEFAULTS[nodeType]) + self.useSourceOCIO(source, node_type, OCIO_DEFAULTS[node_type]) - def ocioActiveEvent(self, nodeType: str) -> Callable[[Any], None]: + def ocioActiveEvent(self, node_type: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(self._ocio_active_event, nodeType=...)`. + Internal code should use `functools.partial(self._ocio_active_event, node_type=...)`. """ - return partial(self._ocio_active_event, nodeType=nodeType) + return partial(self._ocio_active_event, node_type=node_type) def checkForDisplayGroup(self, event: Any) -> None: """ @@ -724,7 +724,7 @@ def checkForDisplayGroup(self, event: Any) -> None: try: node = event.contents() if commands.nodeType(node) == "RVDisplayGroup": - self.usingOCIOForDisplay[node] = False + self._using_ocio_for_display[node] = False commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) except Exception as inst: package_logger.error("%s %s", inst, node) @@ -749,19 +749,19 @@ def selectConfig(self, event: Any) -> None: """ try: config = commands.openFileDialog(True, False, False, "ocio|OCIO Config", None)[0] - self.config = OCIO.Config.CreateFromFile(config) - OCIO.SetCurrentConfig(self.config) + self._config = OCIO.Config.CreateFromFile(config) + OCIO.SetCurrentConfig(self._config) for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for nodeType in OCIO_ROLES.keys(): - self.disableSourceOCIO(source, nodeType) + for node_type in OCIO_ROLES.keys(): + self.disableSourceOCIO(source, node_type) for group in commands.nodesOfType("RVDisplayGroup"): self.disableDisplayOCIO(group) DEFAULT_PIPE.clear() for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for nodeType in OCIO_ROLES.keys(): - self.useSourceOCIO(source, nodeType) + for node_type in OCIO_ROLES.keys(): + self.useSourceOCIO(source, node_type) for group in commands.nodesOfType("RVDisplayGroup"): - self.usingOCIOForDisplay[group] = False + self._using_ocio_for_display[group] = False self.useDisplayOCIO(group) commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) commands.writeSettings("ocio_source_setup", "ocio_config", config) @@ -779,10 +779,10 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: # Try to acquire OCIO config to populate the display menu # - if self.config is None: + if self._config is None: try: - self.config = ocio_config_from_media(None, None) - OCIO.SetCurrentConfig(self.config) + self._config = ocio_config_from_media(None, None) + OCIO.SetCurrentConfig(self._config) except Exception: return [("OCIO", [("Choose Config...", self.selectConfig, None, None)])] @@ -790,21 +790,21 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: # Make a unique entry for each device's display group # - daList = [] + da_list = [] for display in commands.nodesOfType("RVDisplayGroup"): - dList = [ + d_list = [ ( "Active", - partial(self._ocio_active_event, nodeType=display), + partial(self._ocio_active_event, node_type=display), None, partial(_is_ocio_display_managed, group=display), ), ("_", None), ] - for d in self.config.getDisplays(): - vList = [] - for v in self.config.getViews(d): - vList.append( + for d in self._config.getDisplays(): + v_list = [] + for v in self._config.getViews(d): + v_list.append( ( v, partial(_ocio_display_event, group=display, display=d, view=v), @@ -812,123 +812,121 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: partial(_ocio_display_menu_check, group=display, display=d, view=v), ) ) - dList.append((d, vList)) + d_list.append((d, v_list)) device_name = commands.getStringProperty(f"{display}.device.name")[0] device = f" {device_name}" - daList.append((device, dList)) + da_list.append((device, d_list)) # # Apply file space changes only to the visible source # - cssList: list[Any] = [ + css_list: list[Any] = [ ( "Active", - partial(self._ocio_active_event, nodeType="OCIOFile"), + partial(self._ocio_active_event, node_type="OCIOFile"), None, - partial(_is_ocio_managed, nodeType="OCIOFile"), + partial(_is_ocio_managed, node_type="OCIOFile"), ), ("_", None), ] - csaList: list[Any] = [] + csa_list: list[Any] = [] def addPath(family: list[str], tree: list[list[str]]) -> None: for f in family: for t in tree: if f in t: - addPath(family[1:], t) - return + return addPath(family[1:], t) tree.append([f]) - addPath(family, tree) - return + return addPath(family, tree) - families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self.config.getColorSpaces()] + families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self._config.getColorSpaces()] root: list[list[str]] = [] for family in families: addPath(family, root) - def addMenu(root_node: list[Any], isSingle: bool) -> list[Any]: + def addMenu(root_node: list[Any], is_single: bool) -> list[Any]: if len(root_node) == 1: name = root_node[0] - if isSingle: + if is_single: OCIO_DEFAULTS.setdefault("OCIOFile", name) return [ ( name, - partial(_ocio_event, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_event, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), None, - partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_menu_check, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: return [ ( name, - partial(_ocio_event_on_all_of_type, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_event_on_all_of_type, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), None, - partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_menu_check, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: menu = [] for r in root_node[1:]: - menu += addMenu(r, isSingle) + menu += addMenu(r, is_single) return [(root_node[0], menu)] for r in root: - cssList += addMenu(r, True) - csaList += addMenu(r, False) + css_list += addMenu(r, True) + csa_list += addMenu(r, False) # # Apply file look changes only to the visible source # - lsList: list[Any] = [ + ls_list: list[Any] = [ ( "Active", - partial(self._ocio_active_event, nodeType="OCIOLook"), + partial(self._ocio_active_event, node_type="OCIOLook"), None, - partial(_is_ocio_managed, nodeType="OCIOLook"), + partial(_is_ocio_managed, node_type="OCIOLook"), ), ("_", None), ] - laList: list[Any] = [] - for look in self.config.getLooks(): + la_list: list[Any] = [] + for look in self._config.getLooks(): OCIO_DEFAULTS.setdefault("OCIOLook", look.getName()) - lsList.append( + ls_list.append( ( look.getName(), - partial(_ocio_event, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_event, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_menu_check, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) - laList.append( + la_list.append( ( look.getName(), - partial(_ocio_event_on_all_of_type, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_event_on_all_of_type, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_menu_check, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) final: list[Any] = [ ("Current Source", None, None, lambda: commands.DisabledMenuState), - (" File Color Space", cssList), + (" File Color Space", css_list), ] - if len(lsList) > 2: - final += [(" Look", lsList)] + if len(ls_list) > 2: + final += [(" Look", ls_list)] final += [ ("All Sources", None, None, lambda: commands.DisabledMenuState), - (" File Color Space", csaList), + (" File Color Space", csa_list), ] - if len(laList) > 0: - final += [(" Look", laList)] + if len(la_list) > 0: + final += [(" Look", la_list)] final += [ ("_", None), ("Displays", None, None, lambda: commands.DisabledMenuState), ] - final += daList + final += da_list final += [("_", None)] final += [("Change Config...", self.selectConfig, None, None)] @@ -939,11 +937,11 @@ def __init__(self) -> None: Initialize the minor mode, attempt to load inherited configuration, and bind the mode events to RV. """ - rvtypes.MinorMode.__init__(self) + super().__init__() - self.usingOCIOForDisplay: dict[str, bool] = {} - self.readingSession: bool = False - self.config: OCIO.Config | None = None + self._using_ocio_for_display: dict[str, bool] = {} + self._reading_session: bool = False + self._config: OCIO.Config | None = None # # Look for an implementation of the OCIOHelper on the PATH. @@ -972,8 +970,8 @@ def __init__(self) -> None: if os.getenv("OCIO") is None: config = commands.readSettings("ocio_source_setup", "ocio_config", "") if config != "" and os.path.isfile(config): - self.config = OCIO.Config.CreateFromFile(config) - OCIO.SetCurrentConfig(self.config) + self._config = OCIO.Config.CreateFromFile(config) + OCIO.SetCurrentConfig(self._config) else: package_logger.warning("$OCIO environment variable unset!") From 967c62d68c10ff417b3e33ebea379e9f0ee0099f Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Tue, 21 Jul 2026 03:41:54 -0700 Subject: [PATCH 8/9] Revert some variable names Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 446 +++++++++--------- 1 file changed, 224 insertions(+), 222 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index 514bd9529..e82945bbd 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -81,9 +81,9 @@ def ocio_node_from_media( result = [{"nodeType": d, "context": {}, "properties": {}} for d in default] - node_type = commands.nodeType(node) + nodeType = commands.nodeType(node) - if node_type == "RVDisplayPipelineGroup": + if nodeType == "RVDisplayPipelineGroup": display = config.getDefaultDisplay() result = [ { @@ -98,25 +98,25 @@ def ocio_node_from_media( } ] - elif node_type == "RVLinearizePipelineGroup": - in_space = config.parseColorSpaceFromString(media) - if in_space == "": - in_space = attributes.get("default_setting", "") - if in_space != "": + elif nodeType == "RVLinearizePipelineGroup": + inspace = config.parseColorSpaceFromString(media) if media else "" + if inspace == "": + inspace = attributes.get("default_setting", "") + if inspace != "": result = [ { "nodeType": "OCIOFile", "context": {}, "properties": { "ocio.function": "color", - "ocio.inColorSpace": in_space, + "ocio.inColorSpace": inspace, "ocio_color.outColorSpace": OCIO.ROLE_SCENE_LINEAR, }, }, {"nodeType": "RVLensWarp", "context": {}, "properties": {}}, ] - elif node_type == "RVLookPipelineGroup": + elif nodeType == "RVLookPipelineGroup": # If our config has a Look named "shot_specific_look" and uses the # environment/context variable "$SHOT" to locate any required files # on disk, then this is what that would likely look like: @@ -147,29 +147,29 @@ def ocio_node_from_media( # -def _is_ocio_managed(node_type: str) -> int: +def _is_ocio_managed(nodeType: str) -> int: """ Internal callback logic to determine if a specific node type is currently managed by OCIO. Args: - node_type: The node type to check. + nodeType: The node type to check. Returns: The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). """ try: - managed = commands.getIntProperty(f"#{node_type}.ocio.active")[0] != 0 + managed = commands.getIntProperty(f"#{nodeType}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState -def isOCIOManaged(node_type: str) -> Callable[[], int]: +def isOCIOManaged(nodeType: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_is_ocio_managed, node_type=...)`. + Internal code should use `functools.partial(_is_ocio_managed, nodeType=...)`. """ - return partial(_is_ocio_managed, node_type=node_type) + return partial(_is_ocio_managed, nodeType=nodeType) def _is_ocio_display_managed(group: str) -> int: @@ -183,10 +183,10 @@ def _is_ocio_display_managed(group: str) -> int: The RV menu state (CheckedMenuState if managed, UncheckedMenuState otherwise). """ try: - group_name = "RVDisplayPipelineGroup" - d_pipeline = groupMemberOfType(group, group_name) - d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") - managed = commands.getIntProperty(f"{d_ocio}.ocio.active")[0] != 0 + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState @@ -200,12 +200,12 @@ def isOCIODisplayManaged(group: str) -> Callable[[], int]: return partial(_is_ocio_display_managed, group=group) -def _ocio_menu_check(node_type: str, prop: str, value: str) -> int: +def _ocio_menu_check(nodeType: str, prop: str, value: str) -> int: """ Internal callback logic to determine the menu check state for a specific OCIO property. Args: - node_type: The OCIO node type. + nodeType: The OCIO node type. prop: The property name to check. value: The value to compare against the current property value. @@ -213,20 +213,20 @@ def _ocio_menu_check(node_type: str, prop: str, value: str) -> int: The RV menu state (Checked, Neutral, or Disabled). """ try: - current = commands.getStringProperty(f"#{node_type}.{prop}")[0] - managed = _is_ocio_managed(node_type) == commands.CheckedMenuState + current = commands.getStringProperty(f"#{nodeType}.{prop}")[0] + managed = _is_ocio_managed(nodeType) == commands.CheckedMenuState checked = current == value and managed return commands.CheckedMenuState if checked else commands.NeutralMenuState except Exception: return commands.DisabledMenuState -def ocioMenuCheck(node_type: str, prop: str, value: str) -> Callable[[], int]: +def ocioMenuCheck(nodeType: str, prop: str, value: str) -> Callable[[], int]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_menu_check, node_type=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_menu_check, nodeType=..., prop=..., value=...)`. """ - return partial(_ocio_menu_check, node_type=node_type, prop=prop, value=value) + return partial(_ocio_menu_check, nodeType=nodeType, prop=prop, value=value) def _ocio_display_menu_check(group: str, display: str, view: str) -> int: @@ -242,12 +242,12 @@ def _ocio_display_menu_check(group: str, display: str, view: str) -> int: The RV menu state (Checked, Unchecked, or Disabled). """ try: - group_name = "RVDisplayPipelineGroup" - d_pipeline = groupMemberOfType(group, group_name) - d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") - d = commands.getStringProperty(f"{d_ocio}.ocio_display.display")[0] - v = commands.getStringProperty(f"{d_ocio}.ocio_display.view")[0] - if d == display and v == view: + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + currentDisplay = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] + currentView = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] + if currentDisplay == display and currentView == view: return commands.CheckedMenuState return commands.UncheckedMenuState except Exception: @@ -262,50 +262,50 @@ def ocioDisplayMenuCheck(group: str, display: str, view: str) -> Callable[[], in return partial(_ocio_display_menu_check, group=group, display=display, view=view) -def _ocio_event(event: Any, node_type: str, prop: str, value: str) -> None: +def _ocio_event(event: Any, nodeType: str, prop: str, value: str) -> None: """ - Internal callback logic to set a property on the current node of node_type in the evaluation path. + Internal callback logic to set a property on the current node of nodeType in the evaluation path. Args: event: The RV event object. - node_type: The OCIO node type. + nodeType: The OCIO node type. prop: The property name to set. value: The value to assign to the property. """ - commands.setStringProperty(f"#{node_type}.{prop}", [value], True) + commands.setStringProperty(f"#{nodeType}.{prop}", [value], True) commands.redraw() -def ocioEvent(node_type: str, prop: str, value: str) -> Callable[[Any], None]: +def ocioEvent(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_event, node_type=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_event, nodeType=..., prop=..., value=...)`. Note: The internal `_ocio_event` accepts `event` as its first parameter to allow kwargs binding. """ - return partial(_ocio_event, node_type=node_type, prop=prop, value=value) + return partial(_ocio_event, nodeType=nodeType, prop=prop, value=value) -def _ocio_event_on_all_of_type(event: Any, node_type: str, prop: str, value: str) -> None: +def _ocio_event_on_all_of_type(event: Any, nodeType: str, prop: str, value: str) -> None: """ - Internal callback logic to set a property on all nodes of node_type. + Internal callback logic to set a property on all nodes of nodeType. Args: event: The RV event object. - node_type: The OCIO node type. + nodeType: The OCIO node type. prop: The property name to set. value: The value to assign to the property. """ - for node in commands.nodesOfType(node_type): + for node in commands.nodesOfType(nodeType): commands.setStringProperty(f"{node}.{prop}", [value], True) commands.redraw() -def ocioEventOnAllOfType(node_type: str, prop: str, value: str) -> Callable[[Any], None]: +def ocioEventOnAllOfType(nodeType: str, prop: str, value: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(_ocio_event_on_all_of_type, node_type=..., prop=..., value=...)`. + Internal code should use `functools.partial(_ocio_event_on_all_of_type, nodeType=..., prop=..., value=...)`. """ - return partial(_ocio_event_on_all_of_type, node_type=node_type, prop=prop, value=value) + return partial(_ocio_event_on_all_of_type, nodeType=nodeType, prop=prop, value=value) def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None: @@ -318,16 +318,16 @@ def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None display: The OCIO display name. view: The OCIO view name. """ - group_name = "RVDisplayPipelineGroup" - d_pipeline = groupMemberOfType(group, group_name) - d_ocio = groupMemberOfType(d_pipeline, "OCIODisplay") + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. - commands.setIntProperty(f"{d_ocio}.ocio.active", [0], True) - commands.setStringProperty(f"{d_ocio}.ocio_display.display", [display], True) - commands.setStringProperty(f"{d_ocio}.ocio_display.view", [view], True) - commands.setIntProperty(f"{d_ocio}.ocio.active", [1], True) + commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) + commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) + commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) commands.redraw() @@ -339,39 +339,39 @@ def ocioDisplayEvent(group: str, display: str, view: str) -> Callable[[Any], Non return partial(_ocio_display_event, group=group, display=display, view=view) -def groupMemberOfType(node: str, member_type: str) -> str | None: +def groupMemberOfType(node: str, memberType: str) -> str | None: """ Find the first member of a group node that matches a specific node type. Args: node: The parent group node name. - member_type: The node type to search for. + memberType: The node type to search for. Returns: The name of the child node if found, otherwise None. """ for n in commands.nodesInGroup(node): - if commands.nodeType(n) == member_type: + if commands.nodeType(n) == memberType: return n return None -def applyProps(node: str, context_props: dict[str, str], properties_props: dict[str, str]) -> None: +def applyProps(node: str, contextProps: dict[str, str], propertiesProps: dict[str, str]) -> None: """ Apply standard and context properties to an OCIO node. Args: node: The target node name. - context_props: A dictionary of context variables and their values. - properties_props: A dictionary of standard properties and their values. + contextProps: A dictionary of context variables and their values. + propertiesProps: A dictionary of standard properties and their values. """ - for p_prop, a_value in properties_props.items(): - commands.setStringProperty(f"{node}.{p_prop}", [a_value], True) - for c_prop, c_value in context_props.items(): - prop = f"{node}.ocio_context.{c_prop}" + for pprop, avalue in propertiesProps.items(): + commands.setStringProperty(f"{node}.{pprop}", [avalue], True) + for cprop, cvalue in contextProps.items(): + prop = f"{node}.ocio_context.{cprop}" if not commands.propertyExists(prop): commands.newProperty(prop, commands.StringType, 1) - commands.setStringProperty(prop, [c_value], True) + commands.setStringProperty(prop, [cvalue], True) # @@ -404,7 +404,7 @@ class OCIOSourceSetupMode(rvtypes.MinorMode): between 0 and 10). """ - def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") -> None: + def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> None: """ This tells the source group to use OCIO instead of the RV linearize node. There is also ocio.look and ocio.preCache @@ -414,25 +414,25 @@ def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") Args: source: The name of the source group node. - node_type: The OCIO node type to activate (e.g., 'OCIOFile'). - default_setting: The default fallback setting for color space or look. + nodeType: The OCIO node type to activate (e.g., 'OCIOFile'). + defaultSetting: The default fallback setting for color space or look. """ medias = commands.getStringProperty(f"{source}.media.movie") media = medias[0] try: - src_attrs = commands.sourceAttributes(source, media) - attr_dict = dict(zip([i[0] for i in src_attrs], [j[1] for j in src_attrs])) - attr_dict["source_node"] = source - attr_dict["default_setting"] = default_setting + srcAttrs = commands.sourceAttributes(source, media) + attrDict = dict(zip([i[0] for i in srcAttrs], [j[1] for j in srcAttrs])) + attrDict["source_node"] = source + attrDict["default_setting"] = defaultSetting except Exception: - attr_dict = {} + attrDict = {} - if self._config is None: + if self.config is None: try: - self._config = ocio_config_from_media(media, attr_dict) - OCIO.SetCurrentConfig(self._config) + self.config = ocio_config_from_media(media, attrDict) + OCIO.SetCurrentConfig(self.config) commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) except Exception: return @@ -442,15 +442,15 @@ def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") # then use the one we have and return # - pipe_slot = OCIO_ROLES[node_type] - src_pipeline = groupMemberOfType(commands.nodeGroup(source), pipe_slot) - ocio_node = groupMemberOfType(src_pipeline, node_type) - if ocio_node is not None and self._reading_session: - for p_node in commands.nodesInGroup(src_pipeline): - if commands.nodeType(p_node).startswith("OCIO"): - commands.ocioUpdateConfig(p_node) + pipeSlot = OCIO_ROLES[nodeType] + srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) + ocioNode = groupMemberOfType(srcPipeline, nodeType) + if ocioNode is not None and self.readingSession: + for pNode in commands.nodesInGroup(srcPipeline): + if commands.nodeType(pNode).startswith("OCIO"): + commands.ocioUpdateConfig(pNode) - package_logger.info("using %s node for %s %s", node_type, source, pipe_slot) + package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) return # @@ -471,8 +471,8 @@ def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") # try: - if pipe_slot not in DEFAULT_PIPE: - current_pipeline_nodes = commands.getStringProperty(f"{src_pipeline}.pipeline.nodes") + if pipeSlot not in DEFAULT_PIPE: + currentPipelineNodes = commands.getStringProperty(f"{srcPipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that @@ -480,59 +480,59 @@ def useSourceOCIO(self, source: str, node_type: str, default_setting: str = "") # want this pipeline to be considered the default (non OCIO). # Example: srcPipelineNodes = [ "OCIOFile" "RVLensWarp" ] # We will use the RV default instead in that special case. - if node_type in current_pipeline_nodes and pipe_slot in DEFAULT_RV_PIPE: - DEFAULT_PIPE[pipe_slot] = DEFAULT_RV_PIPE[pipe_slot] + if nodeType in currentPipelineNodes and pipeSlot in DEFAULT_RV_PIPE: + DEFAULT_PIPE[pipeSlot] = DEFAULT_RV_PIPE[pipeSlot] else: - DEFAULT_PIPE[pipe_slot] = current_pipeline_nodes - pipeline_list = ocio_node_from_media(self._config, src_pipeline, DEFAULT_PIPE[pipe_slot], media, attr_dict) + DEFAULT_PIPE[pipeSlot] = currentPipelineNodes + pipelineList = ocio_node_from_media(self.config, srcPipeline, DEFAULT_PIPE[pipeSlot], media, attrDict) except Exception as inst: - package_logger.error("Problem occurred while loading OCIO settings for %s: %s", node_type, inst) + package_logger.error("Problem occurred while loading OCIO settings for %s: %s", nodeType, inst) return try: - pipeline = [p["nodeType"] for p in pipeline_list] + pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) return - if pipeline == DEFAULT_PIPE[pipe_slot]: + if pipeline == DEFAULT_PIPE[pipeSlot]: return - package_logger.info("using %s node for %s %s", node_type, source, pipe_slot) + package_logger.info("using %s node for %s %s", nodeType, source, pipeSlot) - commands.setStringProperty(f"{src_pipeline}.pipeline.nodes", pipeline, True) - pipe_nodes = commands.nodesInGroup(src_pipeline) - pipe_nodes.sort() - for index, p_node in enumerate(pipeline_list): - stage_ocio = pipe_nodes[index] + commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", pipeline, True) + pipeNodes = commands.nodesInGroup(srcPipeline) + pipeNodes.sort() + for index, pNode in enumerate(pipelineList): + stageOCIO = pipeNodes[index] try: - applyProps(stage_ocio, p_node["context"], p_node["properties"]) + applyProps(stageOCIO, pNode["context"], pNode["properties"]) except KeyError as inst: - package_logger.error("Unable to apply properties to %s: %s", stage_ocio, inst) + package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) commands.redraw() - def disableSourceOCIO(self, source: str, node_type: str) -> None: + def disableSourceOCIO(self, source: str, nodeType: str) -> None: """ This reverts the source group's linearize node back to using a native RVLinearize node. Args: source: The name of the source group node. - node_type: The OCIO node type being disabled. + nodeType: The OCIO node type being disabled. """ - pipe_slot = OCIO_ROLES[node_type] - src_pipeline = groupMemberOfType(commands.nodeGroup(source), pipe_slot) - nodes_prop = f"{src_pipeline}.pipeline.nodes" - current = commands.getStringProperty(nodes_prop) + pipeSlot = OCIO_ROLES[nodeType] + srcPipeline = groupMemberOfType(commands.nodeGroup(source), pipeSlot) + nodesProp = f"{srcPipeline}.pipeline.nodes" + current = commands.getStringProperty(nodesProp) - if pipe_slot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipe_slot]: + if pipeSlot not in DEFAULT_PIPE or current == DEFAULT_PIPE[pipeSlot]: return - package_logger.info("resetting %s for %s", pipe_slot, source) + package_logger.info("resetting %s for %s", pipeSlot, source) - commands.setStringProperty(f"{src_pipeline}.pipeline.nodes", DEFAULT_PIPE[pipe_slot], True) + commands.setStringProperty(f"{srcPipeline}.pipeline.nodes", DEFAULT_PIPE[pipeSlot], True) commands.redraw() def useDisplayOCIO(self, group: str) -> None: @@ -548,53 +548,53 @@ def useDisplayOCIO(self, group: str) -> None: group: The display group node name. """ - if self._using_ocio_for_display.get(group, False) or self._config is None: + if self.usingOCIOForDisplay.get(group, False) or self.config is None: return - group_name = "RVDisplayPipelineGroup" + groupName = "RVDisplayPipelineGroup" try: - d_pipeline = groupMemberOfType(group, group_name) - if group_name not in DEFAULT_PIPE: - current_pipeline_nodes = commands.getStringProperty(f"{d_pipeline}.pipeline.nodes") + dpipeline = groupMemberOfType(group, groupName) + if groupName not in DEFAULT_PIPE: + currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that # is already OCIO color corrected in which case we do not # want this pipeline to be considered the default (non OCIO). # We will use the RV default instead in that special case. - if "OCIODisplay" in current_pipeline_nodes and group_name in DEFAULT_RV_PIPE: - DEFAULT_PIPE[group_name] = DEFAULT_RV_PIPE[group_name] + if "OCIODisplay" in currentPipelineNodes and groupName in DEFAULT_RV_PIPE: + DEFAULT_PIPE[groupName] = DEFAULT_RV_PIPE[groupName] else: - DEFAULT_PIPE[group_name] = current_pipeline_nodes - pipeline_list = ocio_node_from_media(self._config, d_pipeline, DEFAULT_PIPE[group_name]) + DEFAULT_PIPE[groupName] = currentPipelineNodes + pipelineList = ocio_node_from_media(self.config, dpipeline, DEFAULT_PIPE[groupName]) except Exception as inst: package_logger.error("Problem occurred while loading OCIO settings for OCIODisplay: %s", inst) return try: - pipeline = [p["nodeType"] for p in pipeline_list] + pipeline = [p["nodeType"] for p in pipelineList] except KeyError as inst: package_logger.error("Unable to make use of ocio_node_from_media return: %s", inst) return - if pipeline == DEFAULT_PIPE[group_name]: + if pipeline == DEFAULT_PIPE[groupName]: return device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using OCIODisplay for display: %s", device) - commands.setStringProperty(f"{d_pipeline}.pipeline.nodes", pipeline, True) + commands.setStringProperty(f"{dpipeline}.pipeline.nodes", pipeline, True) - pipe_nodes = commands.nodesInGroup(d_pipeline) - pipe_nodes.sort() - for index, p_node in enumerate(pipeline_list): - stage_ocio = pipe_nodes[index] + pipeNodes = commands.nodesInGroup(dpipeline) + pipeNodes.sort() + for index, pNode in enumerate(pipelineList): + stageOCIO = pipeNodes[index] try: - applyProps(stage_ocio, p_node["context"], p_node["properties"]) + applyProps(stageOCIO, pNode["context"], pNode["properties"]) except KeyError as inst: - package_logger.error("Unable to apply properties to %s: %s", stage_ocio, inst) + package_logger.error("Unable to apply properties to %s: %s", stageOCIO, inst) - self._using_ocio_for_display[group] = True + self.usingOCIOForDisplay[group] = True commands.redraw() def disableDisplayOCIO(self, group: str) -> None: @@ -606,20 +606,20 @@ def disableDisplayOCIO(self, group: str) -> None: group: The display group node name. """ - group_name = "RVDisplayPipelineGroup" - d_pipeline = groupMemberOfType(group, group_name) - nodes_prop = f"{d_pipeline}.pipeline.nodes" - current = commands.getStringProperty(nodes_prop) + groupName = "RVDisplayPipelineGroup" + dpipeline = groupMemberOfType(group, groupName) + nodesProp = f"{dpipeline}.pipeline.nodes" + current = commands.getStringProperty(nodesProp) - if group_name not in DEFAULT_PIPE or current == DEFAULT_PIPE[group_name]: + if groupName not in DEFAULT_PIPE or current == DEFAULT_PIPE[groupName]: return - commands.setStringProperty(f"{d_pipeline}.pipeline.nodes", DEFAULT_PIPE[group_name], True) + commands.setStringProperty(f"{dpipeline}.pipeline.nodes", DEFAULT_PIPE[groupName], True) device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using RVDisplayColor for display: %s", device) - self._using_ocio_for_display[group] = False + self.usingOCIOForDisplay[group] = False commands.redraw() def sourceSetup(self, event: Any) -> None: @@ -637,12 +637,12 @@ def sourceSetup(self, event: Any) -> None: args = event.contents().split(";;") group = args[0] - file_source = groupMemberOfType(group, "RVFileSource") - image_source = groupMemberOfType(group, "RVImageSource") - source = file_source if image_source is None else image_source + fileSource = groupMemberOfType(group, "RVFileSource") + imageSource = groupMemberOfType(group, "RVImageSource") + source = fileSource if imageSource is None else imageSource - for node_type in OCIO_ROLES.keys(): - self.useSourceOCIO(source, node_type) + for nodeType in OCIO_ROLES.keys(): + self.useSourceOCIO(source, nodeType) # # If this is the first OCIO color pipeline for a source assume @@ -651,9 +651,9 @@ def sourceSetup(self, event: Any) -> None: # if len(commands.nodesOfType("OCIOFile")) == 1: - for d_group in commands.nodesOfType("RVDisplayGroup"): - if not self._using_ocio_for_display.get(d_group, False): - self.useDisplayOCIO(d_group) + for dgroup in commands.nodesOfType("RVDisplayGroup"): + if not self.usingOCIOForDisplay.get(dgroup, False): + self.useDisplayOCIO(dgroup) def beforeSessionRead(self, event: Any) -> None: """ @@ -663,7 +663,7 @@ def beforeSessionRead(self, event: Any) -> None: event: The RV event object. """ event.reject() - self._reading_session = True + self.readingSession = True def afterSessionRead(self, event: Any) -> None: """ @@ -673,45 +673,45 @@ def afterSessionRead(self, event: Any) -> None: event: The RV event object. """ event.reject() - self._reading_session = False + self.readingSession = False if len(commands.nodesOfType("OCIOFile")) > 1: for group in commands.nodesOfType("RVDisplayGroup"): - if not self._using_ocio_for_display.get(group, False): + if not self.usingOCIOForDisplay.get(group, False): self.useDisplayOCIO(group) - def _ocio_active_event(self, event: Any, node_type: str) -> None: + def _ocio_active_event(self, event: Any, nodeType: str) -> None: """ Toggle the active state of an OCIO node or display group. Args: event: The RV event object. - node_type: The OCIO node type or display group to toggle. + nodeType: The OCIO node type or display group to toggle. """ - if node_type not in ["OCIOFile", "OCIOLook"]: - if _is_ocio_display_managed(node_type) == commands.CheckedMenuState: - self.disableDisplayOCIO(node_type) + if nodeType not in ["OCIOFile", "OCIOLook"]: + if _is_ocio_display_managed(nodeType) == commands.CheckedMenuState: + self.disableDisplayOCIO(nodeType) else: - self.useDisplayOCIO(node_type) + self.useDisplayOCIO(nodeType) return - eval_info = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) - if len(eval_info) == 0: - eval_info = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) - if len(eval_info) == 0: + evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) + if len(evalInfo) == 0: + evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) + if len(evalInfo) == 0: return - source = eval_info[0]["node"] + source = evalInfo[0]["node"] - if _is_ocio_managed(node_type) == commands.CheckedMenuState: - self.disableSourceOCIO(source, node_type) + if _is_ocio_managed(nodeType) == commands.CheckedMenuState: + self.disableSourceOCIO(source, nodeType) else: - self.useSourceOCIO(source, node_type, OCIO_DEFAULTS[node_type]) + self.useSourceOCIO(source, nodeType, OCIO_DEFAULTS[nodeType]) - def ocioActiveEvent(self, node_type: str) -> Callable[[Any], None]: + def ocioActiveEvent(self, nodeType: str) -> Callable[[Any], None]: """ Deprecated: Public API maintained for backward compatibility. - Internal code should use `functools.partial(self._ocio_active_event, node_type=...)`. + Internal code should use `functools.partial(self._ocio_active_event, nodeType=...)`. """ - return partial(self._ocio_active_event, node_type=node_type) + return partial(self._ocio_active_event, nodeType=nodeType) def checkForDisplayGroup(self, event: Any) -> None: """ @@ -724,7 +724,7 @@ def checkForDisplayGroup(self, event: Any) -> None: try: node = event.contents() if commands.nodeType(node) == "RVDisplayGroup": - self._using_ocio_for_display[node] = False + self.usingOCIOForDisplay[node] = False commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) except Exception as inst: package_logger.error("%s %s", inst, node) @@ -749,19 +749,19 @@ def selectConfig(self, event: Any) -> None: """ try: config = commands.openFileDialog(True, False, False, "ocio|OCIO Config", None)[0] - self._config = OCIO.Config.CreateFromFile(config) - OCIO.SetCurrentConfig(self._config) + self.config = OCIO.Config.CreateFromFile(config) + OCIO.SetCurrentConfig(self.config) for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for node_type in OCIO_ROLES.keys(): - self.disableSourceOCIO(source, node_type) + for nodeType in OCIO_ROLES.keys(): + self.disableSourceOCIO(source, nodeType) for group in commands.nodesOfType("RVDisplayGroup"): self.disableDisplayOCIO(group) DEFAULT_PIPE.clear() for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for node_type in OCIO_ROLES.keys(): - self.useSourceOCIO(source, node_type) + for nodeType in OCIO_ROLES.keys(): + self.useSourceOCIO(source, nodeType) for group in commands.nodesOfType("RVDisplayGroup"): - self._using_ocio_for_display[group] = False + self.usingOCIOForDisplay[group] = False self.useDisplayOCIO(group) commands.defineModeMenu("OCIO Source Setup", self.buildOCIOMenu(), True) commands.writeSettings("ocio_source_setup", "ocio_config", config) @@ -779,10 +779,10 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: # Try to acquire OCIO config to populate the display menu # - if self._config is None: + if self.config is None: try: - self._config = ocio_config_from_media(None, None) - OCIO.SetCurrentConfig(self._config) + self.config = ocio_config_from_media(None, None) + OCIO.SetCurrentConfig(self.config) except Exception: return [("OCIO", [("Choose Config...", self.selectConfig, None, None)])] @@ -790,21 +790,21 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: # Make a unique entry for each device's display group # - da_list = [] + daList = [] for display in commands.nodesOfType("RVDisplayGroup"): - d_list = [ + dList = [ ( "Active", - partial(self._ocio_active_event, node_type=display), + partial(self._ocio_active_event, nodeType=display), None, partial(_is_ocio_display_managed, group=display), ), ("_", None), ] - for d in self._config.getDisplays(): - v_list = [] - for v in self._config.getViews(d): - v_list.append( + for d in self.config.getDisplays(): + vList = [] + for v in self.config.getViews(d): + vList.append( ( v, partial(_ocio_display_event, group=display, display=d, view=v), @@ -812,121 +812,123 @@ def buildOCIOMenu(self) -> list[tuple[str, list[Any]]]: partial(_ocio_display_menu_check, group=display, display=d, view=v), ) ) - d_list.append((d, v_list)) + dList.append((d, vList)) device_name = commands.getStringProperty(f"{display}.device.name")[0] device = f" {device_name}" - da_list.append((device, d_list)) + daList.append((device, dList)) # # Apply file space changes only to the visible source # - css_list: list[Any] = [ + cssList: list[Any] = [ ( "Active", - partial(self._ocio_active_event, node_type="OCIOFile"), + partial(self._ocio_active_event, nodeType="OCIOFile"), None, - partial(_is_ocio_managed, node_type="OCIOFile"), + partial(_is_ocio_managed, nodeType="OCIOFile"), ), ("_", None), ] - csa_list: list[Any] = [] + csaList: list[Any] = [] def addPath(family: list[str], tree: list[list[str]]) -> None: for f in family: for t in tree: if f in t: - return addPath(family[1:], t) + addPath(family[1:], t) + return tree.append([f]) - return addPath(family, tree) + addPath(family, tree) + return - families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self._config.getColorSpaces()] + families = [(cs.getFamily().split("/") + [cs.getName()]) for cs in self.config.getColorSpaces()] root: list[list[str]] = [] for family in families: addPath(family, root) - def addMenu(root_node: list[Any], is_single: bool) -> list[Any]: + def addMenu(root_node: list[Any], isSingle: bool) -> list[Any]: if len(root_node) == 1: name = root_node[0] - if is_single: + if isSingle: OCIO_DEFAULTS.setdefault("OCIOFile", name) return [ ( name, - partial(_ocio_event, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_event, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), None, - partial(_ocio_menu_check, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: return [ ( name, - partial(_ocio_event_on_all_of_type, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_event_on_all_of_type, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), None, - partial(_ocio_menu_check, node_type="OCIOFile", prop="ocio.inColorSpace", value=name), + partial(_ocio_menu_check, nodeType="OCIOFile", prop="ocio.inColorSpace", value=name), ) ] else: menu = [] for r in root_node[1:]: - menu += addMenu(r, is_single) + menu += addMenu(r, isSingle) return [(root_node[0], menu)] for r in root: - css_list += addMenu(r, True) - csa_list += addMenu(r, False) + cssList += addMenu(r, True) + csaList += addMenu(r, False) # # Apply file look changes only to the visible source # - ls_list: list[Any] = [ + lsList: list[Any] = [ ( "Active", - partial(self._ocio_active_event, node_type="OCIOLook"), + partial(self._ocio_active_event, nodeType="OCIOLook"), None, - partial(_is_ocio_managed, node_type="OCIOLook"), + partial(_is_ocio_managed, nodeType="OCIOLook"), ), ("_", None), ] - la_list: list[Any] = [] - for look in self._config.getLooks(): + laList: list[Any] = [] + for look in self.config.getLooks(): OCIO_DEFAULTS.setdefault("OCIOLook", look.getName()) - ls_list.append( + lsList.append( ( look.getName(), - partial(_ocio_event, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_event, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - partial(_ocio_menu_check, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) - la_list.append( + laList.append( ( look.getName(), - partial(_ocio_event_on_all_of_type, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_event_on_all_of_type, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), None, - partial(_ocio_menu_check, node_type="OCIOLook", prop="ocio_look.look", value=look.getName()), + partial(_ocio_menu_check, nodeType="OCIOLook", prop="ocio_look.look", value=look.getName()), ) ) final: list[Any] = [ ("Current Source", None, None, lambda: commands.DisabledMenuState), - (" File Color Space", css_list), + (" File Color Space", cssList), ] - if len(ls_list) > 2: - final += [(" Look", ls_list)] + if len(lsList) > 2: + final += [(" Look", lsList)] final += [ ("All Sources", None, None, lambda: commands.DisabledMenuState), - (" File Color Space", csa_list), + (" File Color Space", csaList), ] - if len(la_list) > 0: - final += [(" Look", la_list)] + if len(laList) > 0: + final += [(" Look", laList)] final += [ ("_", None), ("Displays", None, None, lambda: commands.DisabledMenuState), ] - final += da_list + final += daList final += [("_", None)] final += [("Change Config...", self.selectConfig, None, None)] @@ -939,9 +941,9 @@ def __init__(self) -> None: """ super().__init__() - self._using_ocio_for_display: dict[str, bool] = {} - self._reading_session: bool = False - self._config: OCIO.Config | None = None + self.usingOCIOForDisplay: dict[str, bool] = {} + self.readingSession: bool = False + self.config: OCIO.Config | None = None # # Look for an implementation of the OCIOHelper on the PATH. @@ -970,8 +972,8 @@ def __init__(self) -> None: if os.getenv("OCIO") is None: config = commands.readSettings("ocio_source_setup", "ocio_config", "") if config != "" and os.path.isfile(config): - self._config = OCIO.Config.CreateFromFile(config) - OCIO.SetCurrentConfig(self._config) + self.config = OCIO.Config.CreateFromFile(config) + OCIO.SetCurrentConfig(self.config) else: package_logger.warning("$OCIO environment variable unset!") From ef3145131a2b6e293941f9f8642b5864292a2da5 Mon Sep 17 00:00:00 2001 From: Erwan Leroy Date: Tue, 21 Jul 2026 03:50:06 -0700 Subject: [PATCH 9/9] Refactor OCIO source setup for improved clarity Signed-off-by: Erwan Leroy --- .../ocio_source_setup/ocio_source_setup.py | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py index e82945bbd..ef20f3b5f 100644 --- a/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py +++ b/src/plugins/rv-packages/ocio_source_setup/ocio_source_setup.py @@ -100,9 +100,9 @@ def ocio_node_from_media( elif nodeType == "RVLinearizePipelineGroup": inspace = config.parseColorSpaceFromString(media) if media else "" - if inspace == "": + if not inspace: inspace = attributes.get("default_setting", "") - if inspace != "": + if inspace: result = [ { "nodeType": "OCIOFile", @@ -130,7 +130,7 @@ def ocio_node_from_media( # "ocio_look.look" : "shot_specific_look"}}] look = attributes.get("default_setting", "") - if look != "": + if look: result = [ { "nodeType": "OCIOLook", @@ -184,9 +184,9 @@ def _is_ocio_display_managed(group: str) -> int: """ try: groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - managed = commands.getIntProperty(f"{dOCIO}.ocio.active")[0] != 0 + display_pipeline = groupMemberOfType(group, groupName) + display_ocio = groupMemberOfType(display_pipeline, "OCIODisplay") + managed = commands.getIntProperty(f"{display_ocio}.ocio.active")[0] != 0 return commands.CheckedMenuState if managed else commands.UncheckedMenuState except Exception: return commands.UncheckedMenuState @@ -243,10 +243,10 @@ def _ocio_display_menu_check(group: str, display: str, view: str) -> int: """ try: groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") - currentDisplay = commands.getStringProperty(f"{dOCIO}.ocio_display.display")[0] - currentView = commands.getStringProperty(f"{dOCIO}.ocio_display.view")[0] + display_pipeline = groupMemberOfType(group, groupName) + display_ocio = groupMemberOfType(display_pipeline, "OCIODisplay") + currentDisplay = commands.getStringProperty(f"{display_ocio}.ocio_display.display")[0] + currentView = commands.getStringProperty(f"{display_ocio}.ocio_display.view")[0] if currentDisplay == display and currentView == view: return commands.CheckedMenuState return commands.UncheckedMenuState @@ -319,15 +319,15 @@ def _ocio_display_event(event: Any, group: str, display: str, view: str) -> None view: The OCIO view name. """ groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - dOCIO = groupMemberOfType(dpipeline, "OCIODisplay") + display_pipeline = groupMemberOfType(group, groupName) + display_ocio = groupMemberOfType(display_pipeline, "OCIODisplay") # Both 'display' and 'view' must be set together. # Disable the OCIONode during display/view propety changes. # Prevents node from rebuilding shaders while it may be in an invalid state. - commands.setIntProperty(f"{dOCIO}.ocio.active", [0], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.display", [display], True) - commands.setStringProperty(f"{dOCIO}.ocio_display.view", [view], True) - commands.setIntProperty(f"{dOCIO}.ocio.active", [1], True) + commands.setIntProperty(f"{display_ocio}.ocio.active", [0], True) + commands.setStringProperty(f"{display_ocio}.ocio_display.display", [display], True) + commands.setStringProperty(f"{display_ocio}.ocio_display.view", [view], True) + commands.setIntProperty(f"{display_ocio}.ocio.active", [1], True) commands.redraw() @@ -423,7 +423,7 @@ def useSourceOCIO(self, source: str, nodeType: str, defaultSetting: str = "") -> try: srcAttrs = commands.sourceAttributes(source, media) - attrDict = dict(zip([i[0] for i in srcAttrs], [j[1] for j in srcAttrs])) + attrDict = {attr[0]: attr[1] for attr in srcAttrs} attrDict["source_node"] = source attrDict["default_setting"] = defaultSetting except Exception: @@ -553,9 +553,9 @@ def useDisplayOCIO(self, group: str) -> None: groupName = "RVDisplayPipelineGroup" try: - dpipeline = groupMemberOfType(group, groupName) + display_pipeline = groupMemberOfType(group, groupName) if groupName not in DEFAULT_PIPE: - currentPipelineNodes = commands.getStringProperty(f"{dpipeline}.pipeline.nodes") + currentPipelineNodes = commands.getStringProperty(f"{display_pipeline}.pipeline.nodes") # We need to handle the following special case here: # We might be in the process of reloading an RV session that @@ -566,7 +566,7 @@ def useDisplayOCIO(self, group: str) -> None: DEFAULT_PIPE[groupName] = DEFAULT_RV_PIPE[groupName] else: DEFAULT_PIPE[groupName] = currentPipelineNodes - pipelineList = ocio_node_from_media(self.config, dpipeline, DEFAULT_PIPE[groupName]) + pipelineList = ocio_node_from_media(self.config, display_pipeline, DEFAULT_PIPE[groupName]) except Exception as inst: package_logger.error("Problem occurred while loading OCIO settings for OCIODisplay: %s", inst) return @@ -583,9 +583,9 @@ def useDisplayOCIO(self, group: str) -> None: device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using OCIODisplay for display: %s", device) - commands.setStringProperty(f"{dpipeline}.pipeline.nodes", pipeline, True) + commands.setStringProperty(f"{display_pipeline}.pipeline.nodes", pipeline, True) - pipeNodes = commands.nodesInGroup(dpipeline) + pipeNodes = commands.nodesInGroup(display_pipeline) pipeNodes.sort() for index, pNode in enumerate(pipelineList): stageOCIO = pipeNodes[index] @@ -607,14 +607,14 @@ def disableDisplayOCIO(self, group: str) -> None: """ groupName = "RVDisplayPipelineGroup" - dpipeline = groupMemberOfType(group, groupName) - nodesProp = f"{dpipeline}.pipeline.nodes" + display_pipeline = groupMemberOfType(group, groupName) + nodesProp = f"{display_pipeline}.pipeline.nodes" current = commands.getStringProperty(nodesProp) if groupName not in DEFAULT_PIPE or current == DEFAULT_PIPE[groupName]: return - commands.setStringProperty(f"{dpipeline}.pipeline.nodes", DEFAULT_PIPE[groupName], True) + commands.setStringProperty(f"{display_pipeline}.pipeline.nodes", DEFAULT_PIPE[groupName], True) device = commands.getStringProperty(f"{group}.device.name")[0] package_logger.info("using RVDisplayColor for display: %s", device) @@ -639,9 +639,9 @@ def sourceSetup(self, event: Any) -> None: group = args[0] fileSource = groupMemberOfType(group, "RVFileSource") imageSource = groupMemberOfType(group, "RVImageSource") - source = fileSource if imageSource is None else imageSource + source = imageSource or fileSource - for nodeType in OCIO_ROLES.keys(): + for nodeType in OCIO_ROLES: self.useSourceOCIO(source, nodeType) # @@ -695,9 +695,9 @@ def _ocio_active_event(self, event: Any, nodeType: str) -> None: return evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVFileSource", None) - if len(evalInfo) == 0: + if not evalInfo: evalInfo = commands.metaEvaluateClosestByType(commands.frame(), "RVImageSource", None) - if len(evalInfo) == 0: + if not evalInfo: return source = evalInfo[0]["node"] @@ -752,13 +752,13 @@ def selectConfig(self, event: Any) -> None: self.config = OCIO.Config.CreateFromFile(config) OCIO.SetCurrentConfig(self.config) for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for nodeType in OCIO_ROLES.keys(): + for nodeType in OCIO_ROLES: self.disableSourceOCIO(source, nodeType) for group in commands.nodesOfType("RVDisplayGroup"): self.disableDisplayOCIO(group) DEFAULT_PIPE.clear() for source in commands.nodesOfType("RVFileSource") + commands.nodesOfType("RVImageSource"): - for nodeType in OCIO_ROLES.keys(): + for nodeType in OCIO_ROLES: self.useSourceOCIO(source, nodeType) for group in commands.nodesOfType("RVDisplayGroup"): self.usingOCIOForDisplay[group] = False @@ -971,7 +971,7 @@ def __init__(self) -> None: # An externally set OCIO env var takes precendence if os.getenv("OCIO") is None: config = commands.readSettings("ocio_source_setup", "ocio_config", "") - if config != "" and os.path.isfile(config): + if config and os.path.isfile(config): self.config = OCIO.Config.CreateFromFile(config) OCIO.SetCurrentConfig(self.config) else: