From 1ddddab1dbaa3a0ad7832a6c5eb622edcd90e50b Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 4 Dec 2024 18:14:17 +0200 Subject: [PATCH 01/21] refactor `RuntimeError` to `PublishError` --- client/ayon_houdini/api/lib.py | 19 +++++++++++++------ .../plugins/publish/extract_render.py | 10 ++++++---- .../plugins/publish/extract_rop.py | 7 ++++++- .../plugins/publish/validate_frame_token.py | 6 +++--- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 762aa1395b..58ad3d550a 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -26,6 +26,7 @@ from ayon_core.pipeline.workfile.workfile_template_builder import ( TemplateProfileNotFound ) +from ayon_core.pipeline.publish import PublishError from ayon_core.tools.utils import PopupUpdateKeys, SimplePopup from ayon_core.tools.utils.host_tools import get_tool_by_name @@ -286,9 +287,11 @@ def render_rop(ropnode, frame_range=None): # The hou.Error is not inherited from a Python Exception class, # so we explicitly capture the houdini error, otherwise pyblish # will remain hanging. - import traceback - traceback.print_exc() - raise RuntimeError("Render failed: {0}".format(exc)) + raise PublishError( + message="Render failed or interrupted", + description=f"An Error occurred while rendering {ropnode.path()}", + detail=f"{exc}" + ) def imprint(node, data, update=False): @@ -655,7 +658,9 @@ def get_top_referenced_parm(parm): processed = set() # disallow infinite loop while True: if parm.path() in processed: - raise RuntimeError("Parameter references result in cycle.") + raise PublishError( + message="Parameter references result in cycle.", + ) processed.add(parm.path()) @@ -681,8 +686,10 @@ def evalParmNoFrame(node, parm, pad_character="#"): try: raw = parameter.unexpandedString() except hou.Error as exc: - print("Failed: %s" % parameter) - raise RuntimeError(exc) + raise PublishError( + message=f"Failed: {parameter}", + detail=f"{exc}" + ) def replace(match): padding = 1 diff --git a/client/ayon_houdini/plugins/publish/extract_render.py b/client/ayon_houdini/plugins/publish/extract_render.py index 5004ae53e9..2d2dd8cc42 100644 --- a/client/ayon_houdini/plugins/publish/extract_render.py +++ b/client/ayon_houdini/plugins/publish/extract_render.py @@ -3,6 +3,7 @@ import pyblish.api +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin @@ -81,7 +82,8 @@ def process(self, instance): if not os.path.exists(frame) ] if missing_frames: - # TODO: Use user friendly error reporting. - raise RuntimeError("Failed to complete render extraction. " - "Missing output files: {}".format( - missing_frames)) + missing_frames = "\n\n ● ".join(missing_frames) + raise PublishError( + message="Failed to complete render extraction.", + detail=f"Missing output files:\n\n ● {missing_frames}" + ) diff --git a/client/ayon_houdini/plugins/publish/extract_rop.py b/client/ayon_houdini/plugins/publish/extract_rop.py index 7e5c5798cd..77003472f7 100644 --- a/client/ayon_houdini/plugins/publish/extract_rop.py +++ b/client/ayon_houdini/plugins/publish/extract_rop.py @@ -2,6 +2,7 @@ import pyblish.api from ayon_core.pipeline import publish +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.lib import splitext @@ -73,7 +74,11 @@ def validate_expected_frames(self, instance: pyblish.api.Instance): if not os.path.isfile(os.path.join(staging_dir, filename)) ] if missing_filenames: - raise RuntimeError(f"Missing frames: {missing_filenames}") + missing_filenames = "\n\n ● ".join(missing_filenames) + raise PublishError( + message="Failed to complete render extraction.", + detail=f"Missing frames:\n\n ● {missing_filenames}" + ) def update_representation_data(self, instance: pyblish.api.Instance, diff --git a/client/ayon_houdini/plugins/publish/validate_frame_token.py b/client/ayon_houdini/plugins/publish/validate_frame_token.py index 46c02ba6f2..3ace9b7f90 100644 --- a/client/ayon_houdini/plugins/publish/validate_frame_token.py +++ b/client/ayon_houdini/plugins/publish/validate_frame_token.py @@ -1,7 +1,7 @@ import hou import pyblish.api - +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import lib, plugin @@ -31,8 +31,8 @@ def process(self, instance): invalid = self.get_invalid(instance) if invalid: - raise RuntimeError( - "Output settings do no match for '%s'" % instance + raise PublishError( + f"Output settings do no match for '{instance}'" ) @classmethod From ee0745b5f47997b3a4cb67e21893b85eba61b9ec Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 4 Dec 2024 19:25:42 +0200 Subject: [PATCH 02/21] refactor `assert` to `PublishError` --- client/ayon_houdini/api/lib.py | 11 ++++++++--- .../plugins/publish/collect_render_products.py | 10 ++++++---- .../plugins/publish/collect_usd_layers.py | 14 ++++++++++---- client/ayon_houdini/plugins/publish/extract_usd.py | 5 ++++- client/ayon_houdini/plugins/publish/save_scene.py | 8 +++++--- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 58ad3d550a..59a3405b98 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -676,7 +676,10 @@ def get_top_referenced_parm(parm): def evalParmNoFrame(node, parm, pad_character="#"): parameter = node.parm(parm) - assert parameter, "Parameter does not exist: %s.%s" % (node, parm) + if not parameter: + raise PublishError( + message=f"Parameter does not exist: {node}.{parm}", + ) # If the parameter has a parameter reference, then get that # parameter instead as otherwise `unexpandedString()` fails. @@ -733,8 +736,10 @@ def get_color_management_preferences(): config_path = preferences["config"] config = PyOpenColorIO.Config.CreateFromFile(config_path) display = config.getDefaultDisplay() - assert display == preferences["display"], \ - "Houdini default OCIO display must match config default display" + if display != preferences["display"]: + raise PublishError( + message="Houdini default OCIO display must match config default display" + ) view = config.getDefaultView(display) preferences["display"] = display preferences["view"] = view diff --git a/client/ayon_houdini/plugins/publish/collect_render_products.py b/client/ayon_houdini/plugins/publish/collect_render_products.py index 7223f1ffe9..ddb103845c 100644 --- a/client/ayon_houdini/plugins/publish/collect_render_products.py +++ b/client/ayon_houdini/plugins/publish/collect_render_products.py @@ -6,6 +6,7 @@ import pyblish.api +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.usd import ( get_usd_render_rop_rendersettings @@ -107,10 +108,11 @@ def replace(match): filename = os.path.join(dirname, filename_base) filename = filename.replace("\\", "/") - assert "#" in filename, ( - "Couldn't resolve render product name " - "with frame number: %s" % name - ) + if "#" not in filename: + raise PublishError( + message="Couldn't resolve render product name" + f" with frame number: {name}" + ) filenames.append(filename) diff --git a/client/ayon_houdini/plugins/publish/collect_usd_layers.py b/client/ayon_houdini/plugins/publish/collect_usd_layers.py index 1073322468..79135b4523 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_layers.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_layers.py @@ -5,6 +5,7 @@ import pyblish.api from ayon_core.pipeline.create import get_product_name +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin import ayon_houdini.api.usd as usdlib @@ -27,8 +28,8 @@ def copy_instance_data(instance_src, instance_dest, attr): in the source instance's data. Raises: - KeyError: If the key does not exist on the source instance. - AssertionError: If a parent key already exists on the destination + PublishError: If the key does not exist on the source instance. + PublishError: If a parent key already exists on the destination instance but is not of the correct type (= is not a dict) """ @@ -38,12 +39,17 @@ def copy_instance_data(instance_src, instance_dest, attr): keys = attr.split(".") for i, key in enumerate(keys): if key not in src_data: - break + raise PublishError( + message= f"key '{key}' does not exist on the source instance." + ) src_value = src_data[key] if i != len(key): dest_data = dest_data.setdefault(key, {}) - assert isinstance(dest_data, dict), "Destination must be a dict" + if not isinstance(dest_data, dict): + raise PublishError( + message="Destination must be a dict." + ) src_data = src_value else: # Last iteration - assign the value diff --git a/client/ayon_houdini/plugins/publish/extract_usd.py b/client/ayon_houdini/plugins/publish/extract_usd.py index 90fd085b21..610143ec83 100644 --- a/client/ayon_houdini/plugins/publish/extract_usd.py +++ b/client/ayon_houdini/plugins/publish/extract_usd.py @@ -5,6 +5,7 @@ from ayon_core.pipeline.entity_uri import construct_ayon_entity_uri from ayon_core.pipeline.publish.lib import get_instance_expected_output_path +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.lib import render_rop from ayon_houdini.api.usd import remap_paths @@ -47,7 +48,9 @@ def process(self, instance): with remap_paths(ropnode, mapping): render_rop(ropnode) - assert os.path.exists(output), "Output does not exist: %s" % output + if not os.path.exists(output): + PublishError( + message=f"Output does not exist: {output}") if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/client/ayon_houdini/plugins/publish/save_scene.py b/client/ayon_houdini/plugins/publish/save_scene.py index e0734da5d1..1eba2c2120 100644 --- a/client/ayon_houdini/plugins/publish/save_scene.py +++ b/client/ayon_houdini/plugins/publish/save_scene.py @@ -1,6 +1,7 @@ import pyblish.api from ayon_core.pipeline import registered_host +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin @@ -16,9 +17,10 @@ def process(self, context): # Filename must not have changed since collecting host = registered_host() current_file = host.get_current_workfile() - assert context.data['currentFile'] == current_file, ( - "Collected filename from current scene name." - ) + if context.data['currentFile'] != current_file: + raise PublishError( + message="Collected filename from current scene name." + ) if host.workfile_has_unsaved_changes(): self.log.info("Saving current file: {}".format(current_file)) From 47cd40951abb582d2e2db8bd17c5220653723bae Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 4 Dec 2024 23:48:52 +0200 Subject: [PATCH 03/21] remove redundant `message` argument --- client/ayon_houdini/api/lib.py | 14 +++++--------- .../plugins/publish/collect_render_products.py | 3 +-- .../plugins/publish/collect_usd_layers.py | 6 ++---- .../ayon_houdini/plugins/publish/extract_render.py | 2 +- client/ayon_houdini/plugins/publish/extract_rop.py | 2 +- client/ayon_houdini/plugins/publish/extract_usd.py | 3 +-- client/ayon_houdini/plugins/publish/save_scene.py | 4 +--- 7 files changed, 12 insertions(+), 22 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 59a3405b98..a299f89d68 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -288,7 +288,7 @@ def render_rop(ropnode, frame_range=None): # so we explicitly capture the houdini error, otherwise pyblish # will remain hanging. raise PublishError( - message="Render failed or interrupted", + "Render failed or interrupted", description=f"An Error occurred while rendering {ropnode.path()}", detail=f"{exc}" ) @@ -658,9 +658,7 @@ def get_top_referenced_parm(parm): processed = set() # disallow infinite loop while True: if parm.path() in processed: - raise PublishError( - message="Parameter references result in cycle.", - ) + raise PublishError("Parameter references result in cycle.") processed.add(parm.path()) @@ -677,9 +675,7 @@ def evalParmNoFrame(node, parm, pad_character="#"): parameter = node.parm(parm) if not parameter: - raise PublishError( - message=f"Parameter does not exist: {node}.{parm}", - ) + raise PublishError(f"Parameter does not exist: {node}.{parm}") # If the parameter has a parameter reference, then get that # parameter instead as otherwise `unexpandedString()` fails. @@ -690,7 +686,7 @@ def evalParmNoFrame(node, parm, pad_character="#"): raw = parameter.unexpandedString() except hou.Error as exc: raise PublishError( - message=f"Failed: {parameter}", + f"Failed: {parameter}", detail=f"{exc}" ) @@ -738,7 +734,7 @@ def get_color_management_preferences(): display = config.getDefaultDisplay() if display != preferences["display"]: raise PublishError( - message="Houdini default OCIO display must match config default display" + "Houdini default OCIO display must match config default display" ) view = config.getDefaultView(display) preferences["display"] = display diff --git a/client/ayon_houdini/plugins/publish/collect_render_products.py b/client/ayon_houdini/plugins/publish/collect_render_products.py index ddb103845c..d54b614867 100644 --- a/client/ayon_houdini/plugins/publish/collect_render_products.py +++ b/client/ayon_houdini/plugins/publish/collect_render_products.py @@ -110,8 +110,7 @@ def replace(match): if "#" not in filename: raise PublishError( - message="Couldn't resolve render product name" - f" with frame number: {name}" + f"Couldn't resolve render product name with frame number: {name}" ) filenames.append(filename) diff --git a/client/ayon_houdini/plugins/publish/collect_usd_layers.py b/client/ayon_houdini/plugins/publish/collect_usd_layers.py index 79135b4523..a0eaaad75b 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_layers.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_layers.py @@ -40,16 +40,14 @@ def copy_instance_data(instance_src, instance_dest, attr): for i, key in enumerate(keys): if key not in src_data: raise PublishError( - message= f"key '{key}' does not exist on the source instance." + f"key '{key}' does not exist on the source instance." ) src_value = src_data[key] if i != len(key): dest_data = dest_data.setdefault(key, {}) if not isinstance(dest_data, dict): - raise PublishError( - message="Destination must be a dict." - ) + raise PublishError("Destination must be a dict.") src_data = src_value else: # Last iteration - assign the value diff --git a/client/ayon_houdini/plugins/publish/extract_render.py b/client/ayon_houdini/plugins/publish/extract_render.py index 2d2dd8cc42..0ed7f9108d 100644 --- a/client/ayon_houdini/plugins/publish/extract_render.py +++ b/client/ayon_houdini/plugins/publish/extract_render.py @@ -84,6 +84,6 @@ def process(self, instance): if missing_frames: missing_frames = "\n\n ● ".join(missing_frames) raise PublishError( - message="Failed to complete render extraction.", + "Failed to complete render extraction.", detail=f"Missing output files:\n\n ● {missing_frames}" ) diff --git a/client/ayon_houdini/plugins/publish/extract_rop.py b/client/ayon_houdini/plugins/publish/extract_rop.py index 77003472f7..33b212bd2e 100644 --- a/client/ayon_houdini/plugins/publish/extract_rop.py +++ b/client/ayon_houdini/plugins/publish/extract_rop.py @@ -76,7 +76,7 @@ def validate_expected_frames(self, instance: pyblish.api.Instance): if missing_filenames: missing_filenames = "\n\n ● ".join(missing_filenames) raise PublishError( - message="Failed to complete render extraction.", + "Failed to complete render extraction.", detail=f"Missing frames:\n\n ● {missing_filenames}" ) diff --git a/client/ayon_houdini/plugins/publish/extract_usd.py b/client/ayon_houdini/plugins/publish/extract_usd.py index 610143ec83..8cb030cc76 100644 --- a/client/ayon_houdini/plugins/publish/extract_usd.py +++ b/client/ayon_houdini/plugins/publish/extract_usd.py @@ -49,8 +49,7 @@ def process(self, instance): render_rop(ropnode) if not os.path.exists(output): - PublishError( - message=f"Output does not exist: {output}") + PublishError(f"Output does not exist: {output}") if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/client/ayon_houdini/plugins/publish/save_scene.py b/client/ayon_houdini/plugins/publish/save_scene.py index 1eba2c2120..80ac3f8034 100644 --- a/client/ayon_houdini/plugins/publish/save_scene.py +++ b/client/ayon_houdini/plugins/publish/save_scene.py @@ -18,9 +18,7 @@ def process(self, context): host = registered_host() current_file = host.get_current_workfile() if context.data['currentFile'] != current_file: - raise PublishError( - message="Collected filename from current scene name." - ) + raise PublishError("Collected filename from current scene name.") if host.workfile_has_unsaved_changes(): self.log.info("Saving current file: {}".format(current_file)) From 4502143ed6891c034bc74eed355f7796d6a0ef19 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 4 Dec 2024 23:58:20 +0200 Subject: [PATCH 04/21] better error message in `SaveCurrentScene` --- client/ayon_houdini/plugins/publish/save_scene.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_houdini/plugins/publish/save_scene.py b/client/ayon_houdini/plugins/publish/save_scene.py index 80ac3f8034..5e43876bae 100644 --- a/client/ayon_houdini/plugins/publish/save_scene.py +++ b/client/ayon_houdini/plugins/publish/save_scene.py @@ -18,7 +18,10 @@ def process(self, context): host = registered_host() current_file = host.get_current_workfile() if context.data['currentFile'] != current_file: - raise PublishError("Collected filename from current scene name.") + raise PublishError( + f"Collected filename '{context.data['currentFile']}' differs" + f" from current scene name '{current_file}'." + ) if host.workfile_has_unsaved_changes(): self.log.info("Saving current file: {}".format(current_file)) From 6c891cf250c4729ea299e131f54f65e70179caf5 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 5 Dec 2024 00:23:00 +0200 Subject: [PATCH 05/21] add error description in `SaveCurrentScene` --- client/ayon_houdini/plugins/publish/save_scene.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/ayon_houdini/plugins/publish/save_scene.py b/client/ayon_houdini/plugins/publish/save_scene.py index 5e43876bae..6921c3d5c8 100644 --- a/client/ayon_houdini/plugins/publish/save_scene.py +++ b/client/ayon_houdini/plugins/publish/save_scene.py @@ -1,3 +1,4 @@ +import inspect import pyblish.api from ayon_core.pipeline import registered_host @@ -20,7 +21,8 @@ def process(self, context): if context.data['currentFile'] != current_file: raise PublishError( f"Collected filename '{context.data['currentFile']}' differs" - f" from current scene name '{current_file}'." + f" from current scene name '{current_file}'.", + description=self.get_error_description() ) if host.workfile_has_unsaved_changes(): @@ -28,3 +30,13 @@ def process(self, context): host.save_workfile(current_file) else: self.log.debug("No unsaved changes, skipping file save..") + + def get_error_description(self): + return inspect.cleandoc( + """### Scene File Name Change During Publishing + + This error occurs when you validate the scene and then save it as a new file manually, or if you open a new file and continue publishing. + + Please reset the publisher and publish without changing the scene file midway. + """ + ) From fea6de3496bc1f09d2f696f9af5cece7f82e5635 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 5 Dec 2024 00:51:01 +0200 Subject: [PATCH 06/21] refactor some errors to `PublishError` --- client/ayon_houdini/api/lib.py | 8 +++++--- client/ayon_houdini/api/usd.py | 7 +++++-- .../ayon_houdini/plugins/publish/collect_output_node.py | 6 +++--- client/ayon_houdini/plugins/publish/extract_usd.py | 6 ++++-- .../plugins/publish/increment_current_file.py | 9 +++++---- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index a299f89d68..98eb1dcbd6 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -107,7 +107,7 @@ def get_output_parameter(node): elif node_type == "vray_renderer": return node.parm("SettingsOutput_img_file_path") - raise TypeError("Node type '%s' not supported" % node_type) + raise PublishError(f"Node type '{node_type}' is not supported") def get_lops_rop_context_options( @@ -141,7 +141,8 @@ def get_lops_rop_context_options( end: float = ropnode.evalParm("f2") inc: float = ropnode.evalParm("f3") else: - raise ValueError("Unsupported trange value: %s" % trange) + raise PublishError(f"Unsupported trange value: {trange}" + f" for rop node: {ropnode.path()}") rop_context_options["ropcook"] = 1.0 rop_context_options["ropstart"] = start rop_context_options["ropend"] = end @@ -161,7 +162,8 @@ def get_lops_rop_context_options( elif option_type == "float": value: float = ropnode.evalParm(f"optionfloatvalue{i}") else: - raise ValueError(f"Unsupported option type: {option_type}") + raise PublishError(f"Unsupported option type: {option_type}" + f" on rop node: '{ropnode.path()}'") rop_context_options[name] = value return rop_context_options diff --git a/client/ayon_houdini/api/usd.py b/client/ayon_houdini/api/usd.py index ed71e3487e..af03f00666 100644 --- a/client/ayon_houdini/api/usd.py +++ b/client/ayon_houdini/api/usd.py @@ -10,6 +10,9 @@ import ayon_api from pxr import Usd, Sdf, Tf, Vt, UsdRender +from ayon_core.pipeline.publish import PublishError + + log = logging.getLogger(__name__) @@ -205,8 +208,8 @@ def get_configured_save_layers(usd_rop, strip_above_layer_break=True): lop_node = get_usd_rop_loppath(usd_rop) stage = lop_node.stage(apply_viewport_overrides=False) if not stage: - raise RuntimeError( - "No valid USD stage for ROP node: " "%s" % usd_rop.path() + raise PublishError( + f"No valid USD stage for ROP node: '{usd_rop.path()}' " ) root_layer = stage.GetRootLayer() diff --git a/client/ayon_houdini/plugins/publish/collect_output_node.py b/client/ayon_houdini/plugins/publish/collect_output_node.py index c7af43ec6a..d2fe7b7749 100644 --- a/client/ayon_houdini/plugins/publish/collect_output_node.py +++ b/client/ayon_houdini/plugins/publish/collect_output_node.py @@ -1,5 +1,5 @@ import pyblish.api -from ayon_core.pipeline.publish import KnownPublishError +from ayon_core.pipeline.publish import PublishError from ayon_houdini.api import plugin @@ -67,8 +67,8 @@ def process(self, instance): out_node = node.parm("startnode").evalAsNode() else: - raise KnownPublishError( - "ROP node type '{}' is not supported.".format(node_type) + raise PublishError( + f"ROP node type '{node_type}' is not supported." ) if not out_node: diff --git a/client/ayon_houdini/plugins/publish/extract_usd.py b/client/ayon_houdini/plugins/publish/extract_usd.py index 8cb030cc76..95f80b2df1 100644 --- a/client/ayon_houdini/plugins/publish/extract_usd.py +++ b/client/ayon_houdini/plugins/publish/extract_usd.py @@ -137,5 +137,7 @@ def get_source_paths( # Single file return [os.path.join(staging, files)] - raise TypeError(f"Unsupported type for representation files: {files} " - "(supports list or str)") + raise PublishError( + f"Unsupported type for representation files: {files}" + " (supports list or str)" + ) diff --git a/client/ayon_houdini/plugins/publish/increment_current_file.py b/client/ayon_houdini/plugins/publish/increment_current_file.py index 878500f605..7d2c9ea3cd 100644 --- a/client/ayon_houdini/plugins/publish/increment_current_file.py +++ b/client/ayon_houdini/plugins/publish/increment_current_file.py @@ -4,7 +4,7 @@ from ayon_core.pipeline import registered_host from ayon_core.pipeline.publish import ( get_errored_plugins_from_context, - KnownPublishError + PublishError ) from ayon_houdini.api import plugin @@ -37,7 +37,7 @@ def process(self, context): plugin.__name__ == "HoudiniSubmitPublishDeadline" for plugin in errored_plugins ): - raise KnownPublishError( + raise PublishError( "Skipping incrementing current file because " "submission to deadline failed." ) @@ -46,8 +46,9 @@ def process(self, context): host = registered_host() current_file = host.current_file() if context.data["currentFile"] != current_file: - raise KnownPublishError( - "Collected filename mismatches from current scene name." + raise PublishError( + f"Collected filename '{context.data['currentFile']}'" + f" mismatches from current scene name '{current_file}'." ) new_filepath = version_up(current_file) From 84be3d435dd5ed92842c27e0c5fd42a8f5946ad2 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 5 Dec 2024 15:43:30 +0200 Subject: [PATCH 07/21] Use `PublishError` to the caller functions in publish plugins for `render_rop` and `evalParmNoFarm` --- client/ayon_houdini/api/lib.py | 17 ++++++----------- .../plugins/publish/collect_arnold_rop.py | 16 +++++++++++++--- .../plugins/publish/collect_karma_rop.py | 9 ++++++++- .../plugins/publish/collect_mantra_rop.py | 16 +++++++++++++--- .../plugins/publish/collect_redshift_rop.py | 16 +++++++++++++--- .../plugins/publish/collect_usd_render.py | 14 ++++++++++++-- .../plugins/publish/collect_vray_rop.py | 14 ++++++++++++-- .../plugins/publish/extract_render.py | 9 ++++++++- .../ayon_houdini/plugins/publish/extract_rop.py | 12 +++++++++++- .../ayon_houdini/plugins/publish/extract_usd.py | 9 ++++++++- 10 files changed, 104 insertions(+), 28 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 98eb1dcbd6..816b4a4ae3 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -289,11 +289,9 @@ def render_rop(ropnode, frame_range=None): # The hou.Error is not inherited from a Python Exception class, # so we explicitly capture the houdini error, otherwise pyblish # will remain hanging. - raise PublishError( - "Render failed or interrupted", - description=f"An Error occurred while rendering {ropnode.path()}", - detail=f"{exc}" - ) + import traceback + traceback.print_exc() + raise RuntimeError("Render failed: {0}".format(exc)) def imprint(node, data, update=False): @@ -676,8 +674,7 @@ def get_top_referenced_parm(parm): def evalParmNoFrame(node, parm, pad_character="#"): parameter = node.parm(parm) - if not parameter: - raise PublishError(f"Parameter does not exist: {node}.{parm}") + assert parameter, "Parameter does not exist: %s.%s" % (node, parm) # If the parameter has a parameter reference, then get that # parameter instead as otherwise `unexpandedString()` fails. @@ -687,10 +684,8 @@ def evalParmNoFrame(node, parm, pad_character="#"): try: raw = parameter.unexpandedString() except hou.Error as exc: - raise PublishError( - f"Failed: {parameter}", - detail=f"{exc}" - ) + print("Failed: %s" % parameter) + raise RuntimeError(exc) def replace(match): padding = 1 diff --git a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py index f8a605ab02..79361da420 100644 --- a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.lib import evalParmNoFrame @@ -28,13 +29,13 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = evalParmNoFrame(rop, "ar_picture") + default_prefix = self.evalParmNoFrame(rop, "ar_picture") render_products = [] export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = evalParmNoFrame( + export_prefix = self.evalParmNoFrame( rop, "ar_ass_file", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -74,7 +75,7 @@ def process(self, instance): if rop.evalParm("ar_aov_exr_enable_layer_name{}".format(index)): label = rop.evalParm("ar_aov_exr_layer_name{}".format(index)) else: - label = evalParmNoFrame(rop, "ar_aov_label{}".format(index)) + label = self.evalParmNoFrame(rop, "ar_aov_label{}".format(index)) # NOTE: # we don't collect the actual AOV path but rather assume @@ -160,3 +161,12 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files + + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_karma_rop.py b/client/ayon_houdini/plugins/publish/collect_karma_rop.py index 5ae898adae..7fbbd24f09 100644 --- a/client/ayon_houdini/plugins/publish/collect_karma_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_karma_rop.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -28,7 +29,13 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = evalParmNoFrame(rop, "picture") + try: + default_prefix = evalParmNoFrame(rop, "picture") + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter 'picture' on Rop node: {rop.path()}", + detail=f"{exc}" + ) render_products = [] # Default beauty AOV diff --git a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py index 2f4cdff320..d6588025a4 100644 --- a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -28,13 +29,13 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = evalParmNoFrame(rop, "vm_picture") + default_prefix = self.evalParmNoFrame(rop, "vm_picture") render_products = [] export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = evalParmNoFrame( + export_prefix = self.evalParmNoFrame( rop, "soho_diskfile", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -74,7 +75,7 @@ def process(self, instance): aov_enabled = rop.evalParm(aov_boolean) has_aov_path = rop.evalParm(aov_name) if has_aov_path and aov_enabled == 1: - aov_prefix = evalParmNoFrame(rop, aov_name) + aov_prefix = self.evalParmNoFrame(rop, aov_name) aov_product = self.get_render_product_name( prefix=aov_prefix, suffix=None ) @@ -137,3 +138,12 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files + + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py index 3f79438ee2..06af1b627a 100644 --- a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -27,12 +28,12 @@ class CollectRedshiftROPRenderProducts(plugin.HoudiniInstancePlugin): def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = evalParmNoFrame(rop, "RS_outputFileNamePrefix") + default_prefix = self.evalParmNoFrame(rop, "RS_outputFileNamePrefix") beauty_suffix = rop.evalParm("RS_outputBeautyAOVSuffix") export_products = [] if instance.data["splitRender"]: - export_prefix = evalParmNoFrame( + export_prefix = self.evalParmNoFrame( rop, "RS_archive_file", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -80,7 +81,7 @@ def process(self, instance): continue aov_suffix = rop.evalParm(f"RS_aovSuffix_{i}") - aov_prefix = evalParmNoFrame(rop, f"RS_aovCustomPrefix_{i}") + aov_prefix = self.evalParmNoFrame(rop, f"RS_aovCustomPrefix_{i}") if not aov_prefix: aov_prefix = default_prefix @@ -163,3 +164,12 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files + + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_usd_render.py b/client/ayon_houdini/plugins/publish/collect_usd_render.py index 2934cce246..4abba65579 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_render.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_render.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.lib import evalParmNoFrame @@ -31,7 +32,7 @@ def process(self, instance): if instance.data["splitRender"]: # USD file output - lop_output = evalParmNoFrame( + lop_output = self.evalParmNoFrame( rop, "lopoutput", pad_character="#" ) @@ -40,7 +41,7 @@ def process(self, instance): # TODO: It is possible for a user to disable this # TODO: When enabled I think only the basename of the `lopoutput` # parm is preserved, any parent folders defined are likely ignored - folder = evalParmNoFrame( + folder = self.evalParmNoFrame( rop, "savetodirectory_directory", pad_character="#" ) @@ -68,3 +69,12 @@ def replace_to_f(match): # stub required data for Submit Publish Job publish plug-in instance.data["attachTo"] = [] + + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_vray_rop.py b/client/ayon_houdini/plugins/publish/collect_vray_rop.py index ef0349f872..c44ed4245e 100644 --- a/client/ayon_houdini/plugins/publish/collect_vray_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_vray_rop.py @@ -4,6 +4,7 @@ import hou import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -28,14 +29,14 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = evalParmNoFrame(rop, "SettingsOutput_img_file_path") + default_prefix = self.evalParmNoFrame(rop, "SettingsOutput_img_file_path") render_products = [] # TODO: add render elements if render element export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = evalParmNoFrame( + export_prefix = self.evalParmNoFrame( rop, "render_export_filepath", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -132,3 +133,12 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files + + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/extract_render.py b/client/ayon_houdini/plugins/publish/extract_render.py index 0ed7f9108d..d4a0832e07 100644 --- a/client/ayon_houdini/plugins/publish/extract_render.py +++ b/client/ayon_houdini/plugins/publish/extract_render.py @@ -62,7 +62,14 @@ def process(self, instance): # previously rendered version. This situation breaks the publishing. # because There will be missing frames as ROP nodes typically cannot render different # frame ranges for each AOV; they always use the same frame range for all AOVs. - self.render_rop(instance) + try: + self.render_rop(instance) + except Exception as e: + raise PublishError( + "Render failed or interrupted", + description=f"An Error occurred while rendering {rop_node.path()}", + detail=f"{e}" + ) # `ExpectedFiles` is a list that includes one dict. expected_files = instance.data["expectedFiles"][0] diff --git a/client/ayon_houdini/plugins/publish/extract_rop.py b/client/ayon_houdini/plugins/publish/extract_rop.py index 33b212bd2e..ee05313a60 100644 --- a/client/ayon_houdini/plugins/publish/extract_rop.py +++ b/client/ayon_houdini/plugins/publish/extract_rop.py @@ -35,7 +35,17 @@ def process(self, instance: pyblish.api.Instance): # This key might be absent because render targets are not yet implemented # for all product types that use this plugin. if creator_attribute.get("render_target", "local") == "local": - self.render_rop(instance) + try: + self.render_rop(instance) + except Exception as e: + import hou + rop_node = hou.node(instance.data["instance_node"]) + raise PublishError( + "Render failed or interrupted", + description=f"An Error occurred while rendering {rop_node.path()}", + detail=f"{e}" + ) + self.validate_expected_frames(instance) # In some cases representation name is not the the extension diff --git a/client/ayon_houdini/plugins/publish/extract_usd.py b/client/ayon_houdini/plugins/publish/extract_usd.py index 95f80b2df1..47a8f1dba3 100644 --- a/client/ayon_houdini/plugins/publish/extract_usd.py +++ b/client/ayon_houdini/plugins/publish/extract_usd.py @@ -46,7 +46,14 @@ def process(self, instance): mapping.update(instance_mapping) with remap_paths(ropnode, mapping): - render_rop(ropnode) + try: + render_rop(ropnode) + except Exception as e: + raise PublishError( + "Render failed or interrupted", + description=f"An Error occurred while rendering {ropnode.path()}", + detail=f"{e}" + ) if not os.path.exists(output): PublishError(f"Output does not exist: {output}") From ece72b3e9641864fcb785e7838042398202a1d3c Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 5 Dec 2024 15:55:02 +0200 Subject: [PATCH 08/21] Move the `PublishError` to the collector --- client/ayon_houdini/api/usd.py | 7 ++----- .../ayon_houdini/plugins/publish/collect_usd_layers.py | 10 +++++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/client/ayon_houdini/api/usd.py b/client/ayon_houdini/api/usd.py index af03f00666..ed71e3487e 100644 --- a/client/ayon_houdini/api/usd.py +++ b/client/ayon_houdini/api/usd.py @@ -10,9 +10,6 @@ import ayon_api from pxr import Usd, Sdf, Tf, Vt, UsdRender -from ayon_core.pipeline.publish import PublishError - - log = logging.getLogger(__name__) @@ -208,8 +205,8 @@ def get_configured_save_layers(usd_rop, strip_above_layer_break=True): lop_node = get_usd_rop_loppath(usd_rop) stage = lop_node.stage(apply_viewport_overrides=False) if not stage: - raise PublishError( - f"No valid USD stage for ROP node: '{usd_rop.path()}' " + raise RuntimeError( + "No valid USD stage for ROP node: " "%s" % usd_rop.path() ) root_layer = stage.GetRootLayer() diff --git a/client/ayon_houdini/plugins/publish/collect_usd_layers.py b/client/ayon_houdini/plugins/publish/collect_usd_layers.py index a0eaaad75b..d62345cc29 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_layers.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_layers.py @@ -75,7 +75,15 @@ def process(self, instance): rop_node = hou.node(instance.data["instance_node"]) save_layers = [] - for layer in usdlib.get_configured_save_layers(rop_node): + try: + layers = usdlib.get_configured_save_layers(rop_node) + except Exception as exc: + raise PublishError( + f"Failed to get USD layers on rop node '{rop_node}'", + detail=f"{exc}" + ) + + for layer in layers: info = layer.rootPrims.get("HoudiniLayerInfo") save_path = info.customData.get("HoudiniSavePath") From 65249ccabf63925f7aa369ad001f550914ff2299 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 00:07:42 +0200 Subject: [PATCH 09/21] revert `copy_instance_data` and move the `PublishError` to the `process` method --- .../plugins/publish/collect_usd_layers.py | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/client/ayon_houdini/plugins/publish/collect_usd_layers.py b/client/ayon_houdini/plugins/publish/collect_usd_layers.py index d62345cc29..60de8b7c1d 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_layers.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_layers.py @@ -28,8 +28,8 @@ def copy_instance_data(instance_src, instance_dest, attr): in the source instance's data. Raises: - PublishError: If the key does not exist on the source instance. - PublishError: If a parent key already exists on the destination + KeyError: If the key does not exist on the source instance. + AssertionError: If a parent key already exists on the destination instance but is not of the correct type (= is not a dict) """ @@ -39,15 +39,12 @@ def copy_instance_data(instance_src, instance_dest, attr): keys = attr.split(".") for i, key in enumerate(keys): if key not in src_data: - raise PublishError( - f"key '{key}' does not exist on the source instance." - ) + break src_value = src_data[key] if i != len(key): dest_data = dest_data.setdefault(key, {}) - if not isinstance(dest_data, dict): - raise PublishError("Destination must be a dict.") + assert isinstance(dest_data, dict), "Destination must be a dict" src_data = src_value else: # Last iteration - assign the value @@ -159,10 +156,16 @@ def process(self, instance): # Inherit "use handles" from the source instance # TODO: Do we want to maybe copy full `publish_attributes` instead? - copy_instance_data( - instance, layer_inst, - attr="publish_attributes.CollectRopFrameRange.use_handles" - ) + try: + copy_instance_data( + instance, layer_inst, + attr="publish_attributes.CollectRopFrameRange.use_handles" + ) + except Exception as exc: + raise PublishError( + "Failed to copy instance data.", + detail=f"{exc}" + ) # Allow this subset to be grouped into a USD Layer on creation layer_inst.data["productGroup"] = ( From bde4ab355fe5a33651227f5557a66fe81a4b2fef Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 00:13:56 +0200 Subject: [PATCH 10/21] =?UTF-8?q?replace=20`=E2=97=8F`=20with=20regular=20?= =?UTF-8?q?dash=20`-`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/ayon_houdini/plugins/publish/extract_render.py | 4 ++-- client/ayon_houdini/plugins/publish/extract_rop.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_houdini/plugins/publish/extract_render.py b/client/ayon_houdini/plugins/publish/extract_render.py index d4a0832e07..f7c2a2c139 100644 --- a/client/ayon_houdini/plugins/publish/extract_render.py +++ b/client/ayon_houdini/plugins/publish/extract_render.py @@ -89,8 +89,8 @@ def process(self, instance): if not os.path.exists(frame) ] if missing_frames: - missing_frames = "\n\n ● ".join(missing_frames) + missing_frames = "\n\n - ".join(missing_frames) raise PublishError( "Failed to complete render extraction.", - detail=f"Missing output files:\n\n ● {missing_frames}" + detail=f"Missing output files:\n\n - {missing_frames}" ) diff --git a/client/ayon_houdini/plugins/publish/extract_rop.py b/client/ayon_houdini/plugins/publish/extract_rop.py index ee05313a60..b6dcbc03e1 100644 --- a/client/ayon_houdini/plugins/publish/extract_rop.py +++ b/client/ayon_houdini/plugins/publish/extract_rop.py @@ -84,10 +84,10 @@ def validate_expected_frames(self, instance: pyblish.api.Instance): if not os.path.isfile(os.path.join(staging_dir, filename)) ] if missing_filenames: - missing_filenames = "\n\n ● ".join(missing_filenames) + missing_filenames = "\n\n - ".join(missing_filenames) raise PublishError( "Failed to complete render extraction.", - detail=f"Missing frames:\n\n ● {missing_filenames}" + detail=f"Missing frames:\n\n - {missing_filenames}" ) def update_representation_data(self, From 0363a57b699b214a901ac79deab352d856f93e7e Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 00:27:23 +0200 Subject: [PATCH 11/21] move `evalParmNoFrame` to `HoudiniInstancePlugin` --- client/ayon_houdini/api/plugin.py | 21 +++++++++++++++++-- .../plugins/publish/collect_arnold_rop.py | 11 ---------- .../plugins/publish/collect_mantra_rop.py | 11 ---------- .../plugins/publish/collect_redshift_rop.py | 11 ---------- .../plugins/publish/collect_usd_render.py | 11 ---------- .../plugins/publish/collect_vray_rop.py | 11 ---------- 6 files changed, 19 insertions(+), 57 deletions(-) diff --git a/client/ayon_houdini/api/plugin.py b/client/ayon_houdini/api/plugin.py index a621a2f56c..0291ea47d6 100644 --- a/client/ayon_houdini/api/plugin.py +++ b/client/ayon_houdini/api/plugin.py @@ -16,11 +16,19 @@ AYON_INSTANCE_ID, AVALON_INSTANCE_ID, load, - publish + publish, + PublishError ) from ayon_core.lib import BoolDef -from .lib import imprint, read, lsattr, add_self_publish_button, render_rop +from .lib import ( + imprint, + read, + lsattr, + add_self_publish_button, + render_rop, + evalParmNoFrame) + from .usd import get_ayon_entity_uri_from_representation_context @@ -334,6 +342,15 @@ class HoudiniInstancePlugin(pyblish.api.InstancePlugin): hosts = ["houdini"] settings_category = SETTINGS_CATEGORY + def evalParmNoFrame(self, rop, parm, **kwargs): + try: + return evalParmNoFrame(rop, parm, **kwargs) + except Exception as exc: + raise PublishError( + f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", + detail=f"{exc}" + ) + class HoudiniContextPlugin(pyblish.api.ContextPlugin): """Base class for Houdini context publish plugins.""" diff --git a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py index 79361da420..92a9101861 100644 --- a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py @@ -4,9 +4,7 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError from ayon_houdini.api import plugin -from ayon_houdini.api.lib import evalParmNoFrame class CollectArnoldROPRenderProducts(plugin.HoudiniInstancePlugin): @@ -161,12 +159,3 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files - - def evalParmNoFrame(self, rop, parm, **kwargs): - try: - return evalParmNoFrame(rop, parm, **kwargs) - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" - ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py index d6588025a4..88c7afc007 100644 --- a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py @@ -4,8 +4,6 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError -from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -138,12 +136,3 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files - - def evalParmNoFrame(self, rop, parm, **kwargs): - try: - return evalParmNoFrame(rop, parm, **kwargs) - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" - ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py index 06af1b627a..0c763416b8 100644 --- a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py @@ -4,8 +4,6 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError -from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -164,12 +162,3 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files - - def evalParmNoFrame(self, rop, parm, **kwargs): - try: - return evalParmNoFrame(rop, parm, **kwargs) - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" - ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_usd_render.py b/client/ayon_houdini/plugins/publish/collect_usd_render.py index 4abba65579..43ef1ae2f7 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_render.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_render.py @@ -4,9 +4,7 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError from ayon_houdini.api import plugin -from ayon_houdini.api.lib import evalParmNoFrame class CollectUsdRender(plugin.HoudiniInstancePlugin): @@ -69,12 +67,3 @@ def replace_to_f(match): # stub required data for Submit Publish Job publish plug-in instance.data["attachTo"] = [] - - def evalParmNoFrame(self, rop, parm, **kwargs): - try: - return evalParmNoFrame(rop, parm, **kwargs) - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" - ) \ No newline at end of file diff --git a/client/ayon_houdini/plugins/publish/collect_vray_rop.py b/client/ayon_houdini/plugins/publish/collect_vray_rop.py index c44ed4245e..9d08ec1937 100644 --- a/client/ayon_houdini/plugins/publish/collect_vray_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_vray_rop.py @@ -4,8 +4,6 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError -from ayon_houdini.api.lib import evalParmNoFrame from ayon_houdini.api import plugin @@ -133,12 +131,3 @@ def replace(match): os.path.join(dir, (file % i)).replace("\\", "/")) return expected_files - - def evalParmNoFrame(self, rop, parm, **kwargs): - try: - return evalParmNoFrame(rop, parm, **kwargs) - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" - ) \ No newline at end of file From bb446148794b9683088bcd0cbab7183717207809 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 10:44:52 +0200 Subject: [PATCH 12/21] Use `PublishValidationError` instead and use better log message --- .../plugins/publish/validate_frame_token.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/ayon_houdini/plugins/publish/validate_frame_token.py b/client/ayon_houdini/plugins/publish/validate_frame_token.py index 3ace9b7f90..29d334a376 100644 --- a/client/ayon_houdini/plugins/publish/validate_frame_token.py +++ b/client/ayon_houdini/plugins/publish/validate_frame_token.py @@ -1,7 +1,8 @@ import hou import pyblish.api -from ayon_core.pipeline.publish import PublishError +from ayon_core.pipeline.publish import PublishValidationError + from ayon_houdini.api import lib, plugin @@ -31,8 +32,9 @@ def process(self, instance): invalid = self.get_invalid(instance) if invalid: - raise PublishError( - f"Output settings do no match for '{instance}'" + raise PublishValidationError( + "No frame token '$F4' found in the output " + f"path of '{invalid[0].path()}'" ) @classmethod @@ -42,11 +44,11 @@ def get_invalid(cls, instance): # Check trange parm, 0 means Render Current Frame frame_range = node.evalParm("trange") if frame_range == 0: - return [] + return output_parm = lib.get_output_parameter(node) unexpanded_str = output_parm.unexpandedString() if "$F" not in unexpanded_str: cls.log.error("No frame token found in '%s'" % node.path()) - return [instance] + return [node] From 452f73e2313680635343738c70b39ddc3e10af03 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 10:45:39 +0200 Subject: [PATCH 13/21] remove redundant validator --- .../publish/validate_animation_settings.py | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 client/ayon_houdini/plugins/publish/validate_animation_settings.py diff --git a/client/ayon_houdini/plugins/publish/validate_animation_settings.py b/client/ayon_houdini/plugins/publish/validate_animation_settings.py deleted file mode 100644 index 1cc9e24dc9..0000000000 --- a/client/ayon_houdini/plugins/publish/validate_animation_settings.py +++ /dev/null @@ -1,53 +0,0 @@ -import hou - -import pyblish.api -from ayon_core.pipeline.publish import PublishValidationError - -from ayon_houdini.api import lib, plugin - - -class ValidateAnimationSettings(plugin.HoudiniInstancePlugin): - """Validate if the unexpanded string contains the frame ('$F') token - - This validator will only check the output parameter of the node if - the Valid Frame Range is not set to 'Render Current Frame' - - Rules: - If you render out a frame range it is mandatory to have the - frame token - '$F4' or similar - to ensure that each frame gets - written. If this is not the case you will override the same file - every time a frame is written out. - - Examples: - Good: 'my_vbd_cache.$F4.vdb' - Bad: 'my_vbd_cache.vdb' - - """ - - order = pyblish.api.ValidatorOrder - label = "Validate Frame Settings" - families = ["vdbcache"] - - def process(self, instance): - - invalid = self.get_invalid(instance) - if invalid: - raise PublishValidationError( - "Output settings do no match for '%s'" % instance - ) - - @classmethod - def get_invalid(cls, instance): - - node = hou.node(instance.data["instance_node"]) - # Check trange parm, 0 means Render Current Frame - frame_range = node.evalParm("trange") - if frame_range == 0: - return [] - - output_parm = lib.get_output_parameter(node) - unexpanded_str = output_parm.unexpandedString() - - if "$F" not in unexpanded_str: - cls.log.error("No frame token found in '%s'" % node.path()) - return [instance] From ce5a3145d7f66d0c0d46988413d2ae13196c8447 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 11:01:50 +0200 Subject: [PATCH 14/21] Move `publishError` to the caller publish plugin --- client/ayon_houdini/api/lib.py | 8 ++++---- .../plugins/publish/collect_usd_rop_layer_and_stage.py | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 816b4a4ae3..8b07ab0022 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -141,8 +141,8 @@ def get_lops_rop_context_options( end: float = ropnode.evalParm("f2") inc: float = ropnode.evalParm("f3") else: - raise PublishError(f"Unsupported trange value: {trange}" - f" for rop node: {ropnode.path()}") + raise ValueError(f"Unsupported trange value: {trange}" + f" for rop node: {ropnode.path()}") rop_context_options["ropcook"] = 1.0 rop_context_options["ropstart"] = start rop_context_options["ropend"] = end @@ -162,8 +162,8 @@ def get_lops_rop_context_options( elif option_type == "float": value: float = ropnode.evalParm(f"optionfloatvalue{i}") else: - raise PublishError(f"Unsupported option type: {option_type}" - f" on rop node: '{ropnode.path()}'") + raise ValueError(f"Unsupported option type: {option_type}" + f" on rop node: '{ropnode.path()}'") rop_context_options[name] = value return rop_context_options diff --git a/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py b/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py index 9f208d51f5..d619caa833 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py @@ -6,6 +6,7 @@ from pxr import Sdf, Usd import pyblish.api +from ayon_core.pipeline import PublishError from ayon_houdini.api import plugin from ayon_houdini.api.lib import ( get_lops_rop_context_options, @@ -82,7 +83,13 @@ def process(self, instance): lop_node: hou.LopNode rop: hou.RopNode = hou.node(instance.data["instance_node"]) - options = get_lops_rop_context_options(rop) + try: + options = get_lops_rop_context_options(rop) + except hou.Error as exc: + raise PublishError( + f"Failed to get context options on rop: {rop.path()}", + detail=f"{exc}" + ) # Log the context options self.log.debug( From 6de4af016bf1418b0c8ea2b54e77e4a01379563f Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 11:17:59 +0200 Subject: [PATCH 15/21] Move the `PublishError` to `HoudiniInstancePlugin` --- client/ayon_houdini/api/lib.py | 2 +- client/ayon_houdini/api/plugin.py | 13 ++++++++++++- .../plugins/publish/collect_cache_farm.py | 7 ++----- .../ayon_houdini/plugins/publish/collect_frames.py | 4 ++-- .../plugins/publish/validate_file_extension.py | 4 ++-- .../plugins/publish/validate_frame_token.py | 4 ++-- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 8b07ab0022..07b39a4d18 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -107,7 +107,7 @@ def get_output_parameter(node): elif node_type == "vray_renderer": return node.parm("SettingsOutput_img_file_path") - raise PublishError(f"Node type '{node_type}' is not supported") + raise TypeError(f"Node type '{node_type}' is not supported") def get_lops_rop_context_options( diff --git a/client/ayon_houdini/api/plugin.py b/client/ayon_houdini/api/plugin.py index 0291ea47d6..be6ef394ae 100644 --- a/client/ayon_houdini/api/plugin.py +++ b/client/ayon_houdini/api/plugin.py @@ -27,7 +27,9 @@ lsattr, add_self_publish_button, render_rop, - evalParmNoFrame) + evalParmNoFrame, + get_output_parameter +) from .usd import get_ayon_entity_uri_from_representation_context @@ -350,6 +352,15 @@ def evalParmNoFrame(self, rop, parm, **kwargs): f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", detail=f"{exc}" ) + + def get_output_parameter(self, node): + try: + return get_output_parameter(node) + except Exception as exc: + raise PublishError( + f"Node type '{node}' is not supported", + detail=f"{exc}" + ) class HoudiniContextPlugin(pyblish.api.ContextPlugin): diff --git a/client/ayon_houdini/plugins/publish/collect_cache_farm.py b/client/ayon_houdini/plugins/publish/collect_cache_farm.py index 53f13af366..0ee66222d2 100644 --- a/client/ayon_houdini/plugins/publish/collect_cache_farm.py +++ b/client/ayon_houdini/plugins/publish/collect_cache_farm.py @@ -1,10 +1,7 @@ import os import hou import pyblish.api -from ayon_houdini.api import ( - lib, - plugin -) +from ayon_houdini.api import plugin class CollectFarmCacheFamily(plugin.HoudiniInstancePlugin): @@ -44,7 +41,7 @@ def process(self, instance): # and CollectKarmaROPRenderProducts # Collect expected files ropnode = hou.node(instance.data["instance_node"]) - output_parm = lib.get_output_parameter(ropnode) + output_parm = self.get_output_parameter(ropnode) expected_filepath = output_parm.eval() files = instance.data.setdefault("files", list()) diff --git a/client/ayon_houdini/plugins/publish/collect_frames.py b/client/ayon_houdini/plugins/publish/collect_frames.py index a442e74835..e6c42d0e82 100644 --- a/client/ayon_houdini/plugins/publish/collect_frames.py +++ b/client/ayon_houdini/plugins/publish/collect_frames.py @@ -4,7 +4,7 @@ import hou # noqa import clique import pyblish.api -from ayon_houdini.api import lib, plugin +from ayon_houdini.api import plugin class CollectFrames(plugin.HoudiniInstancePlugin): @@ -27,7 +27,7 @@ def process(self, instance): # Evaluate the file name at the first frame. ropnode = hou.node(instance.data["instance_node"]) - output_parm = lib.get_output_parameter(ropnode) + output_parm = self.get_output_parameter(ropnode) output = output_parm.evalAtFrame(start_frame) file_name = os.path.basename(output) diff --git a/client/ayon_houdini/plugins/publish/validate_file_extension.py b/client/ayon_houdini/plugins/publish/validate_file_extension.py index 1b3a58f4b3..d9f1a74aa6 100644 --- a/client/ayon_houdini/plugins/publish/validate_file_extension.py +++ b/client/ayon_houdini/plugins/publish/validate_file_extension.py @@ -5,7 +5,7 @@ import pyblish.api from ayon_core.pipeline import PublishValidationError -from ayon_houdini.api import lib, plugin +from ayon_houdini.api import plugin class ValidateFileExtension(plugin.HoudiniInstancePlugin): @@ -50,7 +50,7 @@ def get_invalid(cls, instance): families = set(families) # Perform extension check - output = lib.get_output_parameter(node).eval() + output = cls.get_output_parameter(node).eval() _, output_extension = os.path.splitext(output) for family in families: diff --git a/client/ayon_houdini/plugins/publish/validate_frame_token.py b/client/ayon_houdini/plugins/publish/validate_frame_token.py index 29d334a376..39315b4780 100644 --- a/client/ayon_houdini/plugins/publish/validate_frame_token.py +++ b/client/ayon_houdini/plugins/publish/validate_frame_token.py @@ -3,7 +3,7 @@ import pyblish.api from ayon_core.pipeline.publish import PublishValidationError -from ayon_houdini.api import lib, plugin +from ayon_houdini.api import plugin class ValidateFrameToken(plugin.HoudiniInstancePlugin): @@ -46,7 +46,7 @@ def get_invalid(cls, instance): if frame_range == 0: return - output_parm = lib.get_output_parameter(node) + output_parm = cls.get_output_parameter(node) unexpanded_str = output_parm.unexpandedString() if "$F" not in unexpanded_str: From 33c2bb3f49845de39f16cec4f3f1183e70696bce Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 11:27:58 +0200 Subject: [PATCH 16/21] revert changes in `get_top_referenced_parm` --- client/ayon_houdini/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 07b39a4d18..0985d4ea1e 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -658,7 +658,7 @@ def get_top_referenced_parm(parm): processed = set() # disallow infinite loop while True: if parm.path() in processed: - raise PublishError("Parameter references result in cycle.") + raise RuntimeError("Parameter references result in cycle.") processed.add(parm.path()) From 15dbe436841754ad89a79f28df52d51ba0d656c4 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 6 Dec 2024 14:19:38 +0200 Subject: [PATCH 17/21] Implement `PublishError` when calling colorspace function. --- client/ayon_houdini/api/lib.py | 7 ++--- client/ayon_houdini/api/plugin.py | 16 +++++++++++- .../publish/collect_local_render_instances.py | 3 +-- .../publish/collect_render_colorspace.py | 26 ++++++++++++++++--- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 0985d4ea1e..762a3e1cf4 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -26,7 +26,6 @@ from ayon_core.pipeline.workfile.workfile_template_builder import ( TemplateProfileNotFound ) -from ayon_core.pipeline.publish import PublishError from ayon_core.tools.utils import PopupUpdateKeys, SimplePopup from ayon_core.tools.utils.host_tools import get_tool_by_name @@ -729,10 +728,8 @@ def get_color_management_preferences(): config_path = preferences["config"] config = PyOpenColorIO.Config.CreateFromFile(config_path) display = config.getDefaultDisplay() - if display != preferences["display"]: - raise PublishError( - "Houdini default OCIO display must match config default display" - ) + assert display == preferences["display"], \ + "Houdini default OCIO display must match config default display" view = config.getDefaultView(display) preferences["display"] = display preferences["view"] = view diff --git a/client/ayon_houdini/api/plugin.py b/client/ayon_houdini/api/plugin.py index be6ef394ae..df7c821d45 100644 --- a/client/ayon_houdini/api/plugin.py +++ b/client/ayon_houdini/api/plugin.py @@ -32,7 +32,11 @@ ) from .usd import get_ayon_entity_uri_from_representation_context - +from .colorspace import ( + get_color_management_preferences, + get_scene_linear_colorspace, + ARenderProduct +) SETTINGS_CATEGORY = "houdini" @@ -361,6 +365,16 @@ def get_output_parameter(self, node): f"Node type '{node}' is not supported", detail=f"{exc}" ) + + def get_scene_linear_colorspace(self): + try: + return get_scene_linear_colorspace() + except Exception as exc: + raise PublishError( + "Failed to get scene linear colorspace.", + detail=f"{exc}" + ) + class HoudiniContextPlugin(pyblish.api.ContextPlugin): diff --git a/client/ayon_houdini/plugins/publish/collect_local_render_instances.py b/client/ayon_houdini/plugins/publish/collect_local_render_instances.py index 3ba54d2f38..dabdb96903 100644 --- a/client/ayon_houdini/plugins/publish/collect_local_render_instances.py +++ b/client/ayon_houdini/plugins/publish/collect_local_render_instances.py @@ -12,7 +12,6 @@ ColormanagedPyblishPluginMixin ) from ayon_houdini.api import plugin -from ayon_houdini.api.colorspace import get_scene_linear_colorspace class CollectLocalRenderInstances(plugin.HoudiniInstancePlugin, @@ -87,7 +86,7 @@ def process(self, instance): # would need to be detected in a renderer-specific way and the # majority of production scenarios these would not be overridden. # TODO: Support renderer-specific explicit colorspace overrides - colorspace = get_scene_linear_colorspace() + colorspace = self.get_scene_linear_colorspace() for aov_name, aov_filepaths in expected_files.items(): dynamic_data = {} diff --git a/client/ayon_houdini/plugins/publish/collect_render_colorspace.py b/client/ayon_houdini/plugins/publish/collect_render_colorspace.py index cee60d4740..0f78b51e6f 100644 --- a/client/ayon_houdini/plugins/publish/collect_render_colorspace.py +++ b/client/ayon_houdini/plugins/publish/collect_render_colorspace.py @@ -1,4 +1,9 @@ -from ayon_houdini.api import plugin, colorspace +from ayon_core.pipeline import PublishError +from ayon_houdini.api import plugin +from ayon_houdini.api.colorspace import ( + ARenderProduct, + get_color_management_preferences +) import pyblish.api @@ -32,14 +37,27 @@ def process(self, instance): "Skipping collecting of render colorspace.") return aov_name = list(expected_files[0].keys()) - render_products_data = colorspace.ARenderProduct(aov_name) + try: + render_products_data = ARenderProduct(aov_name) + except Exception as exc: + raise PublishError( + "Failed to get render products with colorspace.", + detail=f"{exc}" + ) instance.data["renderProducts"] = render_products_data # Required data for `create_instances_for_aov` - colorspace_data = colorspace.get_color_management_preferences() + try: + colorspace_data = get_color_management_preferences() + except Exception as exc: + raise PublishError( + "Failed to get color management preferences.", + detail=f"{exc}" + ) + instance.data["colorspaceConfig"] = colorspace_data["config"] instance.data["colorspaceDisplay"] = colorspace_data["display"] instance.data["colorspaceView"] = colorspace_data["view"] # Used in `create_skeleton_instance()` - instance.data["colorspace"] = colorspace.get_scene_linear_colorspace() + instance.data["colorspace"] = self.get_scene_linear_colorspace() From a03e49bc665970ec532140908df82604537e7ae6 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 9 Dec 2024 11:32:27 +0200 Subject: [PATCH 18/21] refactor `f{exc}` to `str(exc)` --- client/ayon_houdini/api/plugin.py | 6 +++--- client/ayon_houdini/plugins/publish/collect_karma_rop.py | 2 +- .../plugins/publish/collect_render_colorspace.py | 4 ++-- client/ayon_houdini/plugins/publish/collect_usd_layers.py | 4 ++-- .../plugins/publish/collect_usd_rop_layer_and_stage.py | 2 +- client/ayon_houdini/plugins/publish/extract_render.py | 4 ++-- client/ayon_houdini/plugins/publish/extract_rop.py | 4 ++-- client/ayon_houdini/plugins/publish/extract_usd.py | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/ayon_houdini/api/plugin.py b/client/ayon_houdini/api/plugin.py index df7c821d45..05791af3e8 100644 --- a/client/ayon_houdini/api/plugin.py +++ b/client/ayon_houdini/api/plugin.py @@ -354,7 +354,7 @@ def evalParmNoFrame(self, rop, parm, **kwargs): except Exception as exc: raise PublishError( f"Failed evaluating parameter '{parm}' on Rop node: {rop.path()}", - detail=f"{exc}" + detail=str(exc) ) def get_output_parameter(self, node): @@ -363,7 +363,7 @@ def get_output_parameter(self, node): except Exception as exc: raise PublishError( f"Node type '{node}' is not supported", - detail=f"{exc}" + detail=str(exc) ) def get_scene_linear_colorspace(self): @@ -372,7 +372,7 @@ def get_scene_linear_colorspace(self): except Exception as exc: raise PublishError( "Failed to get scene linear colorspace.", - detail=f"{exc}" + detail=str(exc) ) diff --git a/client/ayon_houdini/plugins/publish/collect_karma_rop.py b/client/ayon_houdini/plugins/publish/collect_karma_rop.py index 7fbbd24f09..c67aa873ce 100644 --- a/client/ayon_houdini/plugins/publish/collect_karma_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_karma_rop.py @@ -34,7 +34,7 @@ def process(self, instance): except Exception as exc: raise PublishError( f"Failed evaluating parameter 'picture' on Rop node: {rop.path()}", - detail=f"{exc}" + detail=str(exc) ) render_products = [] diff --git a/client/ayon_houdini/plugins/publish/collect_render_colorspace.py b/client/ayon_houdini/plugins/publish/collect_render_colorspace.py index 0f78b51e6f..eba16c2e12 100644 --- a/client/ayon_houdini/plugins/publish/collect_render_colorspace.py +++ b/client/ayon_houdini/plugins/publish/collect_render_colorspace.py @@ -42,7 +42,7 @@ def process(self, instance): except Exception as exc: raise PublishError( "Failed to get render products with colorspace.", - detail=f"{exc}" + detail=str(exc) ) instance.data["renderProducts"] = render_products_data @@ -52,7 +52,7 @@ def process(self, instance): except Exception as exc: raise PublishError( "Failed to get color management preferences.", - detail=f"{exc}" + detail=str(exc) ) instance.data["colorspaceConfig"] = colorspace_data["config"] diff --git a/client/ayon_houdini/plugins/publish/collect_usd_layers.py b/client/ayon_houdini/plugins/publish/collect_usd_layers.py index 60de8b7c1d..50002451ba 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_layers.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_layers.py @@ -77,7 +77,7 @@ def process(self, instance): except Exception as exc: raise PublishError( f"Failed to get USD layers on rop node '{rop_node}'", - detail=f"{exc}" + detail=str(exc) ) for layer in layers: @@ -164,7 +164,7 @@ def process(self, instance): except Exception as exc: raise PublishError( "Failed to copy instance data.", - detail=f"{exc}" + detail=str(exc) ) # Allow this subset to be grouped into a USD Layer on creation diff --git a/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py b/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py index d619caa833..de706f5a8c 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_rop_layer_and_stage.py @@ -88,7 +88,7 @@ def process(self, instance): except hou.Error as exc: raise PublishError( f"Failed to get context options on rop: {rop.path()}", - detail=f"{exc}" + detail=str(exc) ) # Log the context options diff --git a/client/ayon_houdini/plugins/publish/extract_render.py b/client/ayon_houdini/plugins/publish/extract_render.py index f7c2a2c139..6f0f08a1ca 100644 --- a/client/ayon_houdini/plugins/publish/extract_render.py +++ b/client/ayon_houdini/plugins/publish/extract_render.py @@ -64,11 +64,11 @@ def process(self, instance): # frame ranges for each AOV; they always use the same frame range for all AOVs. try: self.render_rop(instance) - except Exception as e: + except Exception as exc: raise PublishError( "Render failed or interrupted", description=f"An Error occurred while rendering {rop_node.path()}", - detail=f"{e}" + detail=str(exc) ) # `ExpectedFiles` is a list that includes one dict. diff --git a/client/ayon_houdini/plugins/publish/extract_rop.py b/client/ayon_houdini/plugins/publish/extract_rop.py index b6dcbc03e1..2ac457e7f0 100644 --- a/client/ayon_houdini/plugins/publish/extract_rop.py +++ b/client/ayon_houdini/plugins/publish/extract_rop.py @@ -37,13 +37,13 @@ def process(self, instance: pyblish.api.Instance): if creator_attribute.get("render_target", "local") == "local": try: self.render_rop(instance) - except Exception as e: + except Exception as exc: import hou rop_node = hou.node(instance.data["instance_node"]) raise PublishError( "Render failed or interrupted", description=f"An Error occurred while rendering {rop_node.path()}", - detail=f"{e}" + detail=str(exc) ) self.validate_expected_frames(instance) diff --git a/client/ayon_houdini/plugins/publish/extract_usd.py b/client/ayon_houdini/plugins/publish/extract_usd.py index 47a8f1dba3..2e08043a73 100644 --- a/client/ayon_houdini/plugins/publish/extract_usd.py +++ b/client/ayon_houdini/plugins/publish/extract_usd.py @@ -48,11 +48,11 @@ def process(self, instance): with remap_paths(ropnode, mapping): try: render_rop(ropnode) - except Exception as e: + except Exception as exc: raise PublishError( "Render failed or interrupted", description=f"An Error occurred while rendering {ropnode.path()}", - detail=f"{e}" + detail=str(exc) ) if not os.path.exists(output): From 8bb8bf7877ccb7d7d536732e531c580839794973 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 9 Dec 2024 11:35:47 +0200 Subject: [PATCH 19/21] add missing argument --- client/ayon_houdini/plugins/publish/validate_file_extension.py | 2 +- client/ayon_houdini/plugins/publish/validate_frame_token.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_houdini/plugins/publish/validate_file_extension.py b/client/ayon_houdini/plugins/publish/validate_file_extension.py index d9f1a74aa6..f1599dcc6d 100644 --- a/client/ayon_houdini/plugins/publish/validate_file_extension.py +++ b/client/ayon_houdini/plugins/publish/validate_file_extension.py @@ -50,7 +50,7 @@ def get_invalid(cls, instance): families = set(families) # Perform extension check - output = cls.get_output_parameter(node).eval() + output = cls.get_output_parameter(cls, node).eval() _, output_extension = os.path.splitext(output) for family in families: diff --git a/client/ayon_houdini/plugins/publish/validate_frame_token.py b/client/ayon_houdini/plugins/publish/validate_frame_token.py index 39315b4780..0882a2fc83 100644 --- a/client/ayon_houdini/plugins/publish/validate_frame_token.py +++ b/client/ayon_houdini/plugins/publish/validate_frame_token.py @@ -46,7 +46,7 @@ def get_invalid(cls, instance): if frame_range == 0: return - output_parm = cls.get_output_parameter(node) + output_parm = cls.get_output_parameter(cls, node) unexpanded_str = output_parm.unexpandedString() if "$F" not in unexpanded_str: From 107012cdc66f36d1d19dc12e7f9ccae6e4ee1854 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 9 Dec 2024 11:39:47 +0200 Subject: [PATCH 20/21] refactor `HoudiniInstancePlugin.evalParmNoFrame` to `HoudiniInstancePlugin.eval_parm_no_frame` --- client/ayon_houdini/api/plugin.py | 2 +- client/ayon_houdini/plugins/publish/collect_arnold_rop.py | 6 +++--- client/ayon_houdini/plugins/publish/collect_karma_rop.py | 4 ++-- client/ayon_houdini/plugins/publish/collect_mantra_rop.py | 6 +++--- client/ayon_houdini/plugins/publish/collect_redshift_rop.py | 6 +++--- client/ayon_houdini/plugins/publish/collect_usd_render.py | 4 ++-- client/ayon_houdini/plugins/publish/collect_vray_rop.py | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/client/ayon_houdini/api/plugin.py b/client/ayon_houdini/api/plugin.py index 05791af3e8..11ed56a854 100644 --- a/client/ayon_houdini/api/plugin.py +++ b/client/ayon_houdini/api/plugin.py @@ -348,7 +348,7 @@ class HoudiniInstancePlugin(pyblish.api.InstancePlugin): hosts = ["houdini"] settings_category = SETTINGS_CATEGORY - def evalParmNoFrame(self, rop, parm, **kwargs): + def eval_parm_no_frame(self, rop, parm, **kwargs): try: return evalParmNoFrame(rop, parm, **kwargs) except Exception as exc: diff --git a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py index 92a9101861..20997dfb6a 100644 --- a/client/ayon_houdini/plugins/publish/collect_arnold_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_arnold_rop.py @@ -27,13 +27,13 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = self.evalParmNoFrame(rop, "ar_picture") + default_prefix = self.eval_parm_no_frame(rop, "ar_picture") render_products = [] export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = self.evalParmNoFrame( + export_prefix = self.eval_parm_no_frame( rop, "ar_ass_file", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -73,7 +73,7 @@ def process(self, instance): if rop.evalParm("ar_aov_exr_enable_layer_name{}".format(index)): label = rop.evalParm("ar_aov_exr_layer_name{}".format(index)) else: - label = self.evalParmNoFrame(rop, "ar_aov_label{}".format(index)) + label = self.eval_parm_no_frame(rop, "ar_aov_label{}".format(index)) # NOTE: # we don't collect the actual AOV path but rather assume diff --git a/client/ayon_houdini/plugins/publish/collect_karma_rop.py b/client/ayon_houdini/plugins/publish/collect_karma_rop.py index c67aa873ce..f84231338b 100644 --- a/client/ayon_houdini/plugins/publish/collect_karma_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_karma_rop.py @@ -5,7 +5,7 @@ import pyblish.api from ayon_core.pipeline import PublishError -from ayon_houdini.api.lib import evalParmNoFrame +from ayon_houdini.api.lib import eval_parm_no_frame from ayon_houdini.api import plugin @@ -30,7 +30,7 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) try: - default_prefix = evalParmNoFrame(rop, "picture") + default_prefix = eval_parm_no_frame(rop, "picture") except Exception as exc: raise PublishError( f"Failed evaluating parameter 'picture' on Rop node: {rop.path()}", diff --git a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py index 88c7afc007..6a86f220b1 100644 --- a/client/ayon_houdini/plugins/publish/collect_mantra_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_mantra_rop.py @@ -27,13 +27,13 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = self.evalParmNoFrame(rop, "vm_picture") + default_prefix = self.eval_parm_no_frame(rop, "vm_picture") render_products = [] export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = self.evalParmNoFrame( + export_prefix = self.eval_parm_no_frame( rop, "soho_diskfile", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -73,7 +73,7 @@ def process(self, instance): aov_enabled = rop.evalParm(aov_boolean) has_aov_path = rop.evalParm(aov_name) if has_aov_path and aov_enabled == 1: - aov_prefix = self.evalParmNoFrame(rop, aov_name) + aov_prefix = self.eval_parm_no_frame(rop, aov_name) aov_product = self.get_render_product_name( prefix=aov_prefix, suffix=None ) diff --git a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py index 0c763416b8..465bf273da 100644 --- a/client/ayon_houdini/plugins/publish/collect_redshift_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_redshift_rop.py @@ -26,12 +26,12 @@ class CollectRedshiftROPRenderProducts(plugin.HoudiniInstancePlugin): def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = self.evalParmNoFrame(rop, "RS_outputFileNamePrefix") + default_prefix = self.eval_parm_no_frame(rop, "RS_outputFileNamePrefix") beauty_suffix = rop.evalParm("RS_outputBeautyAOVSuffix") export_products = [] if instance.data["splitRender"]: - export_prefix = self.evalParmNoFrame( + export_prefix = self.eval_parm_no_frame( rop, "RS_archive_file", pad_character="0" ) beauty_export_product = self.get_render_product_name( @@ -79,7 +79,7 @@ def process(self, instance): continue aov_suffix = rop.evalParm(f"RS_aovSuffix_{i}") - aov_prefix = self.evalParmNoFrame(rop, f"RS_aovCustomPrefix_{i}") + aov_prefix = self.eval_parm_no_frame(rop, f"RS_aovCustomPrefix_{i}") if not aov_prefix: aov_prefix = default_prefix diff --git a/client/ayon_houdini/plugins/publish/collect_usd_render.py b/client/ayon_houdini/plugins/publish/collect_usd_render.py index 43ef1ae2f7..d524437627 100644 --- a/client/ayon_houdini/plugins/publish/collect_usd_render.py +++ b/client/ayon_houdini/plugins/publish/collect_usd_render.py @@ -30,7 +30,7 @@ def process(self, instance): if instance.data["splitRender"]: # USD file output - lop_output = self.evalParmNoFrame( + lop_output = self.eval_parm_no_frame( rop, "lopoutput", pad_character="#" ) @@ -39,7 +39,7 @@ def process(self, instance): # TODO: It is possible for a user to disable this # TODO: When enabled I think only the basename of the `lopoutput` # parm is preserved, any parent folders defined are likely ignored - folder = self.evalParmNoFrame( + folder = self.eval_parm_no_frame( rop, "savetodirectory_directory", pad_character="#" ) diff --git a/client/ayon_houdini/plugins/publish/collect_vray_rop.py b/client/ayon_houdini/plugins/publish/collect_vray_rop.py index 9d08ec1937..da14cb89c5 100644 --- a/client/ayon_houdini/plugins/publish/collect_vray_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_vray_rop.py @@ -27,14 +27,14 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - default_prefix = self.evalParmNoFrame(rop, "SettingsOutput_img_file_path") + default_prefix = self.eval_parm_no_frame(rop, "SettingsOutput_img_file_path") render_products = [] # TODO: add render elements if render element export_prefix = None export_products = [] if instance.data["splitRender"]: - export_prefix = self.evalParmNoFrame( + export_prefix = self.eval_parm_no_frame( rop, "render_export_filepath", pad_character="0" ) beauty_export_product = self.get_render_product_name( From d92689e719a3147c23b59843ace486d627894aeb Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 9 Dec 2024 11:44:27 +0200 Subject: [PATCH 21/21] Fix `eval_parm_no_frame` call --- .../ayon_houdini/plugins/publish/collect_karma_rop.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/client/ayon_houdini/plugins/publish/collect_karma_rop.py b/client/ayon_houdini/plugins/publish/collect_karma_rop.py index f84231338b..f9cd081f81 100644 --- a/client/ayon_houdini/plugins/publish/collect_karma_rop.py +++ b/client/ayon_houdini/plugins/publish/collect_karma_rop.py @@ -4,8 +4,6 @@ import hou import pyblish.api -from ayon_core.pipeline import PublishError -from ayon_houdini.api.lib import eval_parm_no_frame from ayon_houdini.api import plugin @@ -29,13 +27,7 @@ def process(self, instance): rop = hou.node(instance.data.get("instance_node")) - try: - default_prefix = eval_parm_no_frame(rop, "picture") - except Exception as exc: - raise PublishError( - f"Failed evaluating parameter 'picture' on Rop node: {rop.path()}", - detail=str(exc) - ) + default_prefix = self.eval_parm_no_frame(rop, "picture") render_products = [] # Default beauty AOV