From 46411c9723a80a781ec513d6a2cfd175cec44644 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 4 Aug 2022 11:10:45 +0100 Subject: [PATCH 001/133] Implemented review --- openpype/hosts/blender/api/__init__.py | 5 + openpype/hosts/blender/api/capture.py | 278 ++++++++++++++++ openpype/hosts/blender/api/lib.py | 9 + openpype/hosts/blender/api/plugin.py | 7 +- .../blender/plugins/create/create_review.py | 47 +++ .../blender/plugins/publish/collect_review.py | 64 ++++ .../plugins/publish/extract_playblast.py | 125 +++++++ .../plugins/publish/extract_thumbnail.py | 102 ++++++ .../plugins/publish/integrate_thumbnail.py | 10 + openpype/plugins/publish/extract_review.py | 1 + .../defaults/project_settings/blender.json | 137 ++++++++ .../schema_project_blender.json | 4 + .../schemas/schema_blender_publish.json | 308 ++++++++++++++++++ 13 files changed, 1095 insertions(+), 2 deletions(-) create mode 100644 openpype/hosts/blender/api/capture.py create mode 100644 openpype/hosts/blender/plugins/create/create_review.py create mode 100644 openpype/hosts/blender/plugins/publish/collect_review.py create mode 100644 openpype/hosts/blender/plugins/publish/extract_playblast.py create mode 100644 openpype/hosts/blender/plugins/publish/extract_thumbnail.py create mode 100644 openpype/hosts/blender/plugins/publish/integrate_thumbnail.py create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_blender_publish.json diff --git a/openpype/hosts/blender/api/__init__.py b/openpype/hosts/blender/api/__init__.py index e017d74d91..75a11affde 100644 --- a/openpype/hosts/blender/api/__init__.py +++ b/openpype/hosts/blender/api/__init__.py @@ -31,10 +31,13 @@ from .lib import ( lsattrs, read, maintained_selection, + maintained_time, get_selection, # unique_name, ) +from .capture import capture + __all__ = [ "install", @@ -56,9 +59,11 @@ __all__ = [ # Utility functions "maintained_selection", + "maintained_time", "lsattr", "lsattrs", "read", "get_selection", + "capture", # "unique_name", ] diff --git a/openpype/hosts/blender/api/capture.py b/openpype/hosts/blender/api/capture.py new file mode 100644 index 0000000000..7cf9e52cb6 --- /dev/null +++ b/openpype/hosts/blender/api/capture.py @@ -0,0 +1,278 @@ + +"""Blender Capture +Playblasting with independent viewport, camera and display options +""" +import contextlib +import bpy + +from .lib import maintained_time +from .plugin import deselect_all, create_blender_context + + +def capture( + camera=None, + width=None, + height=None, + filename=None, + start_frame=None, + end_frame=None, + step_frame=None, + sound=None, + isolate=None, + maintain_aspect_ratio=True, + overwrite=False, + image_settings=None, + display_options=None +): + """Playblast in an independent windows + Arguments: + camera (str, optional): Name of camera, defaults to "Camera" + width (int, optional): Width of output in pixels + height (int, optional): Height of output in pixels + filename (str, optional): Name of output file path. Defaults to current + render output path. + start_frame (int, optional): Defaults to current start frame. + end_frame (int, optional): Defaults to current end frame. + step_frame (int, optional): Defaults to 1. + sound (str, optional): Specify the sound node to be used during + playblast. When None (default) no sound will be used. + isolate (list): List of nodes to isolate upon capturing + maintain_aspect_ratio (bool, optional): Modify height in order to + maintain aspect ratio. + overwrite (bool, optional): Whether or not to overwrite if file + already exists. If disabled and file exists and error will be + raised. + image_settings (dict, optional): Supplied image settings for render, + using `ImageSettings` + display_options (dict, optional): Supplied display options for render + """ + + scene = bpy.context.scene + camera = camera or "Camera" + + # Ensure camera exists. + if camera not in scene.objects and camera != "AUTO": + raise RuntimeError("Camera does not exist: {0}".format(camera)) + + # Ensure resolution. + if width and height: + maintain_aspect_ratio = False + width = width or scene.render.resolution_x + height = height or scene.render.resolution_y + if maintain_aspect_ratio: + ratio = scene.render.resolution_x / scene.render.resolution_y + height = round(width / ratio) + + # Get frame range. + if start_frame is None: + start_frame = scene.frame_start + if end_frame is None: + end_frame = scene.frame_end + if step_frame is None: + step_frame = 1 + frame_range = (start_frame, end_frame, step_frame) + + if filename is None: + filename = scene.render.filepath + + render_options = { + "filepath": "{}.".format(filename.rstrip(".")), + "resolution_x": width, + "resolution_y": height, + "use_overwrite": overwrite, + } + + with _independent_window() as window: + + applied_view(window, camera, isolate, options=display_options) + + with contextlib.ExitStack() as stack: + stack.enter_context(maintain_camera(window, camera)) + stack.enter_context(applied_frame_range(window, *frame_range)) + stack.enter_context(applied_render_options(window, render_options)) + stack.enter_context(applied_image_settings(window, image_settings)) + stack.enter_context(maintained_time()) + + bpy.ops.render.opengl( + animation=True, + render_keyed_only=False, + sequencer=False, + write_still=False, + view_context=True + ) + + return filename + + +ImageSettings = { + "file_format": "FFMPEG", + "color_mode": "RGB", + "ffmpeg": { + "format": "QUICKTIME", + "use_autosplit": False, + "codec": "H264", + "constant_rate_factor": "MEDIUM", + "gopsize": 18, + "use_max_b_frames": False, + }, +} + + +def isolate_objects(window, objects): + """Isolate selection""" + deselect_all() + + for obj in objects: + obj.select_set(True) + + context = create_blender_context(selected=objects, window=window) + + bpy.ops.view3d.view_axis(context, type="FRONT") + bpy.ops.view3d.localview(context) + + deselect_all() + + +def _apply_options(entity, options): + for option, value in options.items(): + if isinstance(value, dict): + _apply_options(getattr(entity, option), value) + else: + setattr(entity, option, value) + + +def applied_view(window, camera, isolate=None, options=None): + """Apply view options to window.""" + area = window.screen.areas[0] + space = area.spaces[0] + + area.ui_type = "VIEW_3D" + + meshes = [obj for obj in window.scene.objects if obj.type == "MESH"] + + if camera == "AUTO": + space.region_3d.view_perspective = "ORTHO" + isolate_objects(window, isolate or meshes) + else: + isolate_objects(window, isolate or meshes) + space.camera = window.scene.objects.get(camera) + space.region_3d.view_perspective = "CAMERA" + + if isinstance(options, dict): + _apply_options(space, options) + else: + space.shading.type = "SOLID" + space.shading.color_type = "MATERIAL" + space.show_gizmo = False + space.overlay.show_overlays = False + + +@contextlib.contextmanager +def applied_frame_range(window, start, end, step): + """Context manager for setting frame range.""" + # Store current frame range + current_frame_start = window.scene.frame_start + current_frame_end = window.scene.frame_end + current_frame_step = window.scene.frame_step + # Apply frame range + window.scene.frame_start = start + window.scene.frame_end = end + window.scene.frame_step = step + try: + yield + finally: + # Restore frame range + window.scene.frame_start = current_frame_start + window.scene.frame_end = current_frame_end + window.scene.frame_step = current_frame_step + + +@contextlib.contextmanager +def applied_render_options(window, options): + """Context manager for setting render options.""" + render = window.scene.render + + # Store current settings + original = {} + for opt in options.copy(): + try: + original[opt] = getattr(render, opt) + except ValueError: + options.pop(opt) + + # Apply settings + _apply_options(render, options) + + try: + yield + finally: + # Restore previous settings + _apply_options(render, original) + + +@contextlib.contextmanager +def applied_image_settings(window, options): + """Context manager to override image settings.""" + + options = options or ImageSettings.copy() + ffmpeg = options.pop("ffmpeg", {}) + render = window.scene.render + + # Store current image settings + original = {} + for opt in options.copy(): + try: + original[opt] = getattr(render.image_settings, opt) + except ValueError: + options.pop(opt) + + # Store current ffmpeg settings + original_ffmpeg = {} + for opt in ffmpeg.copy(): + try: + original_ffmpeg[opt] = getattr(render.ffmpeg, opt) + except ValueError: + ffmpeg.pop(opt) + + # Apply image settings + for opt, value in options.items(): + setattr(render.image_settings, opt, value) + + # Apply ffmpeg settings + for opt, value in ffmpeg.items(): + setattr(render.ffmpeg, opt, value) + + try: + yield + finally: + # Restore previous settings + for opt, value in original.items(): + setattr(render.image_settings, opt, value) + for opt, value in original_ffmpeg.items(): + setattr(render.ffmpeg, opt, value) + + +@contextlib.contextmanager +def maintain_camera(window, camera): + """Context manager to override camera.""" + current_camera = window.scene.camera + if camera in window.scene.objects: + window.scene.camera = window.scene.objects.get(camera) + try: + yield + finally: + window.scene.camera = current_camera + + +@contextlib.contextmanager +def _independent_window(): + """Create capture-window context.""" + context = create_blender_context() + current_windows = set(bpy.context.window_manager.windows) + bpy.ops.wm.window_new(context) + window = list(set(bpy.context.window_manager.windows) - current_windows)[0] + context["window"] = window + try: + yield window + finally: + bpy.ops.wm.window_close(context) \ No newline at end of file diff --git a/openpype/hosts/blender/api/lib.py b/openpype/hosts/blender/api/lib.py index 20098c0fe8..ee127ab313 100644 --- a/openpype/hosts/blender/api/lib.py +++ b/openpype/hosts/blender/api/lib.py @@ -284,3 +284,12 @@ def maintained_selection(): # This could happen if the active node was deleted during the # context. log.exception("Failed to set active object.") + +@contextlib.contextmanager +def maintained_time(): + """Maintain current frame during context.""" + current_time = bpy.context.scene.frame_current + try: + yield + finally: + bpy.context.scene.frame_current = current_time diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index c59be8d7ff..1274795c6b 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -62,7 +62,8 @@ def prepare_data(data, container_name=None): def create_blender_context(active: Optional[bpy.types.Object] = None, - selected: Optional[bpy.types.Object] = None,): + selected: Optional[bpy.types.Object] = None, + window: Optional[bpy.types.Window] = None): """Create a new Blender context. If an object is passed as parameter, it is set as selected and active. """ @@ -72,7 +73,9 @@ def create_blender_context(active: Optional[bpy.types.Object] = None, override_context = bpy.context.copy() - for win in bpy.context.window_manager.windows: + windows = [window] if window else bpy.context.window_manager.windows + + for win in windows: for area in win.screen.areas: if area.type == 'VIEW_3D': for region in area.regions: diff --git a/openpype/hosts/blender/plugins/create/create_review.py b/openpype/hosts/blender/plugins/create/create_review.py new file mode 100644 index 0000000000..bf4ea6a7cd --- /dev/null +++ b/openpype/hosts/blender/plugins/create/create_review.py @@ -0,0 +1,47 @@ +"""Create review.""" + +import bpy + +from openpype.pipeline import legacy_io +from openpype.hosts.blender.api import plugin, lib, ops +from openpype.hosts.blender.api.pipeline import AVALON_INSTANCES + + +class CreateReview(plugin.Creator): + """Single baked camera""" + + name = "reviewDefault" + label = "Review" + family = "review" + icon = "video-camera" + + def process(self): + """ Run the creator on Blender main thread""" + mti = ops.MainThreadItem(self._process) + ops.execute_in_main_thread(mti) + + def _process(self): + # Get Instance Container or create it if it does not exist + instances = bpy.data.collections.get(AVALON_INSTANCES) + if not instances: + instances = bpy.data.collections.new(name=AVALON_INSTANCES) + bpy.context.scene.collection.children.link(instances) + + # Create instance object + asset = self.data["asset"] + subset = self.data["subset"] + name = plugin.asset_name(asset, subset) + asset_group = bpy.data.collections.new(name=name) + instances.children.link(asset_group) + self.data['task'] = legacy_io.Session.get('AVALON_TASK') + lib.imprint(asset_group, self.data) + + if (self.options or {}).get("useSelection"): + selected = lib.get_selection() + for obj in selected: + asset_group.objects.link(obj) + elif (self.options or {}).get("asset_group"): + obj = (self.options or {}).get("asset_group") + asset_group.objects.link(obj) + + return asset_group diff --git a/openpype/hosts/blender/plugins/publish/collect_review.py b/openpype/hosts/blender/plugins/publish/collect_review.py new file mode 100644 index 0000000000..09b5558d31 --- /dev/null +++ b/openpype/hosts/blender/plugins/publish/collect_review.py @@ -0,0 +1,64 @@ +import bpy + +import pyblish.api +from openpype.pipeline import legacy_io + + +class CollectReview(pyblish.api.InstancePlugin): + """Collect Review data + + """ + + order = pyblish.api.CollectorOrder + 0.3 + label = "Collect Review Data" + families = ["review"] + + def process(self, instance): + + self.log.debug(f"instance: {instance}") + + # get cameras + cameras = [ + obj + for obj in instance + if isinstance(obj, bpy.types.Object) and obj.type == "CAMERA" + ] + + assert len(cameras) == 1, ( + f"Not a single camera found in extraction: {cameras}" + ) + camera = cameras[0].name + self.log.debug(f"camera: {camera}") + + # get isolate objects list from meshes instance members . + isolate_objects = [ + obj + for obj in instance + if isinstance(obj, bpy.types.Object) and obj.type == "MESH" + ] + + if not instance.data.get("remove"): + + task = legacy_io.Session.get("AVALON_TASK") + + instance.data.update({ + "subset": f"{task}Review", + "review_camera": camera, + "frameStart": instance.context.data["frameStart"], + "frameEnd": instance.context.data["frameEnd"], + "fps": instance.context.data["fps"], + "isolate": isolate_objects, + }) + + self.log.debug(f"instance data: {instance.data}") + + # TODO : Collect audio + audio_tracks = [] + instance.data["audio"] = [] + for track in audio_tracks: + instance.data["audio"].append( + { + "offset": track.offset.get(), + "filename": track.filename.get(), + } + ) \ No newline at end of file diff --git a/openpype/hosts/blender/plugins/publish/extract_playblast.py b/openpype/hosts/blender/plugins/publish/extract_playblast.py new file mode 100644 index 0000000000..d07968d469 --- /dev/null +++ b/openpype/hosts/blender/plugins/publish/extract_playblast.py @@ -0,0 +1,125 @@ +import os +import clique + +import bpy + +import pyblish.api +import openpype.api +from openpype.hosts.blender.api import capture +from openpype.hosts.blender.api.lib import maintained_time + + +class ExtractPlayblast(openpype.api.Extractor): + """ + Extract viewport playblast. + + Takes review camera and creates review Quicktime video based on viewport + capture. + """ + + label = "Extract Playblast" + hosts = ["blender"] + families = ["review"] + optional = True + order = pyblish.api.ExtractorOrder + 0.01 + + + def process(self, instance): + self.log.info("Extracting capture..") + + self.log.info(instance.data) + print(instance.context.data) + + # get scene fps + fps = instance.data.get("fps") + if fps is None: + fps = bpy.context.scene.render.fps + instance.data["fps"] = fps + + self.log.info(f"fps: {fps}") + + # If start and end frames cannot be determined, + # get them from Blender timeline. + start = instance.data.get("frameStart", bpy.context.scene.frame_start) + end = instance.data.get("frameEnd", bpy.context.scene.frame_end) + + self.log.info(f"start: {start}, end: {end}") + assert end > start, "Invalid time range !" + + # get cameras + camera = instance.data("review_camera", None) + + # get isolate objects list + isolate = instance.data("isolate", None) + + # get ouput path + stagingdir = self.staging_dir(instance) + filename = instance.name + path = os.path.join(stagingdir, filename) + + self.log.info(f"Outputting images to {path}") + + project_settings = instance.context.data["project_settings"]["blender"] + presets = project_settings["publish"]["ExtractPlayblast"]["presets"] + preset = presets.get("default") + preset.update({ + "camera": camera, + "start_frame": start, + "end_frame": end, + "filename": path, + "overwrite": True, + "isolate": isolate, + }) + preset.setdefault( + "image_settings", + { + "file_format": "PNG", + "color_mode": "RGB", + "color_depth": "8", + "compression": 15, + }, + ) + + with maintained_time(): + path = capture(**preset) + + self.log.debug(f"playblast path {path}") + + collected_files = os.listdir(stagingdir) + collections, remainder = clique.assemble( + collected_files, + patterns=[f"{filename}\\.{clique.DIGITS_PATTERN}\\.png$"], + ) + + if len(collections) > 1: + raise RuntimeError( + f"More than one collection found in stagingdir: {stagingdir}" + ) + elif len(collections) == 0: + raise RuntimeError( + f"No collection found in stagingdir: {stagingdir}" + ) + + frame_collection = collections[0] + + self.log.info(f"We found collection of interest {frame_collection}") + + instance.data.setdefault("representations", []) + + tags = ["review"] + if not instance.data.get("keepImages"): + tags.append("delete") + + representation = { + "name": "png", + "ext": "png", + "files": list(frame_collection), + "stagingDir": stagingdir, + "frameStart": start, + "frameEnd": end, + "fps": fps, + "preview": True, + "tags": tags, + "camera_name": camera + } + instance.data["representations"].append(representation) \ No newline at end of file diff --git a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py new file mode 100644 index 0000000000..3fabdf61e0 --- /dev/null +++ b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py @@ -0,0 +1,102 @@ +import os +import glob + +import pyblish.api +import openpype.api +from openpype.hosts.blender.api import capture +from openpype.hosts.blender.api.lib import maintained_time + +import bpy + + +class ExtractThumbnail(openpype.api.Extractor): + """Extract viewport thumbnail. + + Takes review camera and creates a thumbnail based on viewport + capture. + + """ + + label = "Extract Thumbnail" + hosts = ["blender"] + families = ["review"] + order = pyblish.api.ExtractorOrder + 0.01 + + def process(self, instance): + self.log.info("Extracting capture..") + + stagingdir = self.staging_dir(instance) + filename = instance.name + path = os.path.join(stagingdir, filename) + + self.log.info(f"Outputting images to {path}") + + camera = instance.data.get("review_camera", "AUTO") + start = instance.data.get("frameStart", bpy.context.scene.frame_start) + family = instance.data.get("family") + isolate = instance.data("isolate", None) + + project_settings = instance.context.data["project_settings"]["blender"] + extractor_settings = project_settings["publish"]["ExtractThumbnail"] + presets = extractor_settings.get("presets") + + preset = presets.get(family, {}) + + preset.update({ + "camera": camera, + "start_frame": start, + "end_frame": start, + "filename": path, + "overwrite": True, + "isolate": isolate, + }) + preset.setdefault( + "image_settings", + { + "file_format": "JPEG", + "color_mode": "RGB", + "quality": 100, + }, + ) + + with maintained_time(): + path = capture(**preset) + + thumbnail = os.path.basename(self._fix_output_path(path)) + + self.log.info(f"thumbnail: {thumbnail}") + + instance.data.setdefault("representations", []) + + representation = { + "name": "thumbnail", + "ext": "jpg", + "files": thumbnail, + "stagingDir": stagingdir, + "thumbnail": True + } + instance.data["representations"].append(representation) + + def _fix_output_path(self, filepath): + """"Workaround to return correct filepath. + + To workaround this we just glob.glob() for any file extensions and + assume the latest modified file is the correct file and return it. + + """ + # Catch cancelled playblast + if filepath is None: + self.log.warning( + "Playblast did not result in output path. " + "Playblast is probably interrupted." + ) + return None + + if not os.path.exists(filepath): + files = glob.glob(f"{filepath}.*.jpg") + + if not files: + raise RuntimeError(f"Couldn't find playblast from: {filepath}") + filepath = max(files, key=os.path.getmtime) + + return filepath \ No newline at end of file diff --git a/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py b/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py new file mode 100644 index 0000000000..489db673de --- /dev/null +++ b/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py @@ -0,0 +1,10 @@ +import pyblish.api +from openpype.plugins.publish import integrate_thumbnail + + +class IntegrateThumbnails(integrate_thumbnail.IntegrateThumbnails): + """Integrate Thumbnails.""" + + label = "Integrate Thumbnails" + order = pyblish.api.IntegratorOrder + 0.01 + families = ["review"] diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index 533a87acb4..5068b0261e 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -41,6 +41,7 @@ class ExtractReview(pyblish.api.InstancePlugin): hosts = [ "nuke", "maya", + "blender", "shell", "hiero", "premiere", diff --git a/openpype/settings/defaults/project_settings/blender.json b/openpype/settings/defaults/project_settings/blender.json index a7262dcb5d..e3be0b50ee 100644 --- a/openpype/settings/defaults/project_settings/blender.json +++ b/openpype/settings/defaults/project_settings/blender.json @@ -2,5 +2,142 @@ "workfile_builder": { "create_first_version": false, "custom_templates": [] + }, + "publish": { + "ValidateLinkedVersion": { + "enabled": true, + "optional": true, + "active": true + }, + "ValidateLinkedData": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractBlend": { + "enabled": true, + "optional": true, + "active": true, + "pack_images": true + }, + "ExtractBlendAnimation": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractCamera": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractFBX": { + "enabled": true, + "optional": true, + "active": true, + "scale_length": 0 + }, + "ExtractAnimationFBX": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractABC": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractLayout": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractThumbnail": { + "enabled": true, + "optional": true, + "active": true, + "presets": { + "model": { + "image_settings": { + "file_format": "JPEG", + "color_mode": "RGB", + "quality": 100 + }, + "display_options": { + "shading": { + "light": "STUDIO", + "studio_light": "Default", + "type": "SOLID", + "color_type": "OBJECT", + "show_xray": false, + "show_shadows": false, + "show_cavity": true + }, + "overlay": { + "show_overlays": false + } + } + }, + "rig": { + "image_settings": { + "file_format": "JPEG", + "color_mode": "RGB", + "quality": 100 + }, + "display_options": { + "shading": { + "light": "STUDIO", + "studio_light": "Default", + "type": "SOLID", + "color_type": "OBJECT", + "show_xray": true, + "show_shadows": false, + "show_cavity": false + }, + "overlay": { + "show_overlays": true, + "show_ortho_grid": false, + "show_floor": false, + "show_axis_x": false, + "show_axis_y": false, + "show_axis_z": false, + "show_text": false, + "show_stats": false, + "show_cursor": false, + "show_annotation": false, + "show_extras": false, + "show_relationship_lines": false, + "show_outline_selected": false, + "show_motion_paths": false, + "show_object_origins": false, + "show_bones": true + } + } + } + } + }, + "ExtractPlayblast": { + "enabled": true, + "optional": true, + "active": true, + "presets": { + "default": { + "image_settings": { + "file_format": "PNG", + "color_mode": "RGB", + "color_depth": "8", + "compression": 15 + }, + "display_options": { + "shading": { + "type": "MATERIAL", + "render_pass": "COMBINED" + }, + "overlay": { + "show_overlays": false + } + } + } + } + } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json b/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json index af09329a03..4c72ebda2f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json @@ -12,6 +12,10 @@ "workfile_builder/builder_on_start", "workfile_builder/profiles" ] + }, + { + "type": "schema", + "name": "schema_blender_publish" } ] } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_blender_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_blender_publish.json new file mode 100644 index 0000000000..a634b6dabe --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_blender_publish.json @@ -0,0 +1,308 @@ +{ + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "label", + "label": "Validators" + }, + { + "type": "dict", + "collapsible": true, + "key": "ValidateLinkedVersion", + "label": "Validate Linked Version", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ValidateLinkedData", + "label": "Validate Linked Data", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Extractors" + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractBlend", + "label": "Extract Blend", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "boolean", + "key": "pack_images", + "label": "Pack Images" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractBlendAnimation", + "label": "Extract Blend Animation", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractCamera", + "label": "Extract Camera as FBX", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractFBX", + "label": "Extract FBX (model and rig)", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "number", + "key": "scale_length", + "label": "Scale length", + "decimal": 3, + "minimum": 0, + "maximum": 1000 + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractAnimationFBX", + "label": "Extract Animation FBX", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractABC", + "label": "Extract ABC (model and pointcache)", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractLayout", + "label": "Extract Layout as JSON", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractThumbnail", + "label": "ExtractThumbnail", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "raw-json", + "key": "presets", + "label": "Presets" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractPlayblast", + "label": "ExtractPlayblast", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "raw-json", + "key": "presets", + "label": "Presets" + } + ] + } + ] +} \ No newline at end of file From 13997f4b4cc55c2168c360870593ea561daf1eeb Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 4 Aug 2022 12:22:44 +0100 Subject: [PATCH 002/133] Removed thumbnail integrator --- .../blender/plugins/publish/integrate_thumbnail.py | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 openpype/hosts/blender/plugins/publish/integrate_thumbnail.py diff --git a/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py b/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py deleted file mode 100644 index 489db673de..0000000000 --- a/openpype/hosts/blender/plugins/publish/integrate_thumbnail.py +++ /dev/null @@ -1,10 +0,0 @@ -import pyblish.api -from openpype.plugins.publish import integrate_thumbnail - - -class IntegrateThumbnails(integrate_thumbnail.IntegrateThumbnails): - """Integrate Thumbnails.""" - - label = "Integrate Thumbnails" - order = pyblish.api.IntegratorOrder + 0.01 - families = ["review"] From a380069aad8ff9445666637aac638ae37f04eac4 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 9 Jan 2023 16:23:46 +0000 Subject: [PATCH 003/133] Hound fixes --- openpype/hosts/blender/api/capture.py | 2 +- openpype/hosts/blender/api/lib.py | 1 + openpype/hosts/blender/plugins/publish/collect_review.py | 2 +- openpype/hosts/blender/plugins/publish/extract_playblast.py | 3 +-- openpype/hosts/blender/plugins/publish/extract_thumbnail.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/blender/api/capture.py b/openpype/hosts/blender/api/capture.py index 7cf9e52cb6..849f8ee629 100644 --- a/openpype/hosts/blender/api/capture.py +++ b/openpype/hosts/blender/api/capture.py @@ -275,4 +275,4 @@ def _independent_window(): try: yield window finally: - bpy.ops.wm.window_close(context) \ No newline at end of file + bpy.ops.wm.window_close(context) diff --git a/openpype/hosts/blender/api/lib.py b/openpype/hosts/blender/api/lib.py index dd3cc48a98..6526f1fb87 100644 --- a/openpype/hosts/blender/api/lib.py +++ b/openpype/hosts/blender/api/lib.py @@ -285,6 +285,7 @@ def maintained_selection(): # context. log.exception("Failed to set active object.") + @contextlib.contextmanager def maintained_time(): """Maintain current frame during context.""" diff --git a/openpype/hosts/blender/plugins/publish/collect_review.py b/openpype/hosts/blender/plugins/publish/collect_review.py index 09b5558d31..d6abd9d967 100644 --- a/openpype/hosts/blender/plugins/publish/collect_review.py +++ b/openpype/hosts/blender/plugins/publish/collect_review.py @@ -61,4 +61,4 @@ class CollectReview(pyblish.api.InstancePlugin): "offset": track.offset.get(), "filename": track.filename.get(), } - ) \ No newline at end of file + ) diff --git a/openpype/hosts/blender/plugins/publish/extract_playblast.py b/openpype/hosts/blender/plugins/publish/extract_playblast.py index d07968d469..1114b633be 100644 --- a/openpype/hosts/blender/plugins/publish/extract_playblast.py +++ b/openpype/hosts/blender/plugins/publish/extract_playblast.py @@ -23,7 +23,6 @@ class ExtractPlayblast(openpype.api.Extractor): optional = True order = pyblish.api.ExtractorOrder + 0.01 - def process(self, instance): self.log.info("Extracting capture..") @@ -122,4 +121,4 @@ class ExtractPlayblast(openpype.api.Extractor): "tags": tags, "camera_name": camera } - instance.data["representations"].append(representation) \ No newline at end of file + instance.data["representations"].append(representation) diff --git a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py index 3fabdf61e0..5e9d876989 100644 --- a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py @@ -99,4 +99,4 @@ class ExtractThumbnail(openpype.api.Extractor): raise RuntimeError(f"Couldn't find playblast from: {filepath}") filepath = max(files, key=os.path.getmtime) - return filepath \ No newline at end of file + return filepath From 1575f24539b134f4e19315529338060c4d6ab00f Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Wed, 11 Jan 2023 15:51:01 +0000 Subject: [PATCH 004/133] Remove OCIO submodule --- vendor/configs/OpenColorIO-Configs | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/configs/OpenColorIO-Configs diff --git a/vendor/configs/OpenColorIO-Configs b/vendor/configs/OpenColorIO-Configs deleted file mode 160000 index 0bb079c08b..0000000000 --- a/vendor/configs/OpenColorIO-Configs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0bb079c08be410030669cbf5f19ff869b88af953 From 255fd940a1bb2c9cfab2bca9e064a036abf86ab4 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Wed, 11 Jan 2023 15:51:28 +0000 Subject: [PATCH 005/133] Fix default settings syntax error --- openpype/settings/defaults/project_settings/blender.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/blender.json b/openpype/settings/defaults/project_settings/blender.json index e0adeb96da..7eabec6106 100644 --- a/openpype/settings/defaults/project_settings/blender.json +++ b/openpype/settings/defaults/project_settings/blender.json @@ -65,7 +65,7 @@ "enabled": true, "optional": true, "active": false - } + }, "ExtractThumbnail": { "enabled": true, "optional": true, From 1da3854c82e6145e42d2e986263e4dbe7f5d950e Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 16 Jan 2023 11:04:22 +0000 Subject: [PATCH 006/133] Implemented suggestions --- .../hosts/blender/plugins/publish/extract_thumbnail.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py index 5e9d876989..ba455cf450 100644 --- a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py @@ -21,6 +21,7 @@ class ExtractThumbnail(openpype.api.Extractor): hosts = ["blender"] families = ["review"] order = pyblish.api.ExtractorOrder + 0.01 + presets = {} def process(self, instance): self.log.info("Extracting capture..") @@ -36,11 +37,7 @@ class ExtractThumbnail(openpype.api.Extractor): family = instance.data.get("family") isolate = instance.data("isolate", None) - project_settings = instance.context.data["project_settings"]["blender"] - extractor_settings = project_settings["publish"]["ExtractThumbnail"] - presets = extractor_settings.get("presets") - - preset = presets.get(family, {}) + preset = self.presets.get(family, {}) preset.update({ "camera": camera, From 9c221a36c30a05de6c9b67e17b4ca941f01a4c31 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Sun, 29 Jan 2023 15:22:52 +0300 Subject: [PATCH 007/133] use recommended Reactor env variables --- openpype/hosts/fusion/deploy/fusion_shared.prefs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index 998c6a6d66..5bfde9a5c9 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -4,8 +4,7 @@ Global = { Paths = { Map = { ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", - ["Reactor:"] = "$(REACTOR)", - + ["Reactor:"] = "$(REACTOR_INSTALL_PATHMAP)/Reactor", ["Config:"] = "UserPaths:Config;OpenPype:Config", ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", ["UserPaths:"] = "UserData:;AllData:;Fusion:;Reactor:Deploy" From bb0d128f1d4b22f6744eed58ad91f649b8642d83 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Sun, 29 Jan 2023 22:37:07 +0300 Subject: [PATCH 008/133] nightly version is not parsed --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ceab9eeff1..2fc4f6fe39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.15.1-nightly.1" # OpenPype +version = "3.15.1" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From c1f88602a09bd7b476344f2a1fbf8efb8789734d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 31 Jan 2023 03:14:43 +0300 Subject: [PATCH 009/133] split get comp and get fusion, add get comp name just in case --- openpype/hosts/fusion/api/lib.py | 22 +++++++++++++++++++--- openpype/hosts/fusion/api/workio.py | 7 ++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index a33e5cf289..851e9ec94a 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -302,10 +302,26 @@ def get_frame_path(path): return filename, padding, ext +def get_comp_name(comp=None): + """Get basename of the comp's filename""" + if comp: + comp_name = os.path.basename(comp.GetAttrs()["COMPS_FileName"]) + return comp_name + + +def get_fusion(): + """Get Fusion instance""" + app = getattr(sys.modules["BlackmagicFusion"], "scriptapp", None) + if app: + fusion = app("Fusion", "localhost") + return fusion + + def get_current_comp(): - """Hack to get current comp in this session""" - fusion = getattr(sys.modules["__main__"], "fusion", None) - return fusion.CurrentComp if fusion else None + """Get current comp in this session""" + fusion = get_fusion() + comp = fusion.CurrentComp + return comp @contextlib.contextmanager diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index 939b2ff4be..da36a83988 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -2,7 +2,7 @@ import sys import os -from .lib import get_current_comp +from .lib import get_fusion, get_current_comp def file_extensions(): @@ -20,10 +20,7 @@ def save_file(filepath): def open_file(filepath): - # Hack to get fusion, see - # openpype.hosts.fusion.api.pipeline.get_current_comp() - fusion = getattr(sys.modules["__main__"], "fusion", None) - + fusion = get_fusion() return fusion.LoadComp(filepath) From c0c859b6f1f0c34db4c0024a4b751c9715d5c6bf Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 31 Jan 2023 03:15:43 +0300 Subject: [PATCH 010/133] set a temporary profile folder, copy existing prefs there --- .../hosts/fusion/hooks/pre_fusion_setup.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index d043d54322..f6cec86e3b 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -1,4 +1,7 @@ import os +import shutil +import platform +from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR @@ -17,6 +20,25 @@ class FusionPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] + def get_profile_source(self): + fusion_prefs_path = "Blackmagic Design/Fusion/Profiles/Default/Fusion.prefs" + if platform.system() == "Windows": + prefs_source = Path(os.getenv("AppData")) / fusion_prefs_path + elif platform.system() == "Darwin": + prefs_source = Path(os.path.expanduser("~/Library/Application Support/")) / fusion_prefs_path + elif platform.system() == "Linux": + prefs_source = Path(os.path.expanduser("~/.fusion")) / fusion_prefs_path + + return str(prefs_source) + + def copy_existing_prefs(self, profile_directory: str): + dest_folder = os.path.join(profile_directory, "Default") + os.makedirs(dest_folder, exist_ok=True) + prefs_source = self.get_profile_source() + if os.path.exists(prefs_source): + shutil.copy(prefs_source, dest_folder) + self.log.info(f"successfully copied preferences:\n {prefs_source} to {dest_folder}") + def execute(self): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 @@ -50,12 +72,20 @@ class FusionPrelaunch(PreLaunchHook): # TODO: Detect Fusion version to only set for specific Fusion build self.launch_context.env["FUSION16_PYTHON36_HOME"] = py3_dir - # Add our Fusion Master Prefs which is the only way to customize + # Add custom Fusion Master Prefs and the temporary profile directory variables to customize # Fusion to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR + profile_dir_var = "FUSION16_PROFILE_DIR" # used by Fusion 16, 17 and 18 pref_var = "FUSION16_MasterPrefs" # used by Fusion 16, 17 and 18 + profile_dir = os.path.join(FUSION_HOST_DIR, "deploy", "Prefs") prefs = os.path.join(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + + # now copy the default Fusion profile to a working directory + if not os.path.exists(profile_dir): + self.copy_existing_prefs(profile_dir) + self.log.info(f"Setting {profile_dir_var}: {profile_dir}") + self.launch_context.env[profile_dir_var] = profile_dir self.log.info(f"Setting {pref_var}: {prefs}") self.launch_context.env[pref_var] = prefs From 0c23f212c08811d2fb3cafa2980f0344afee5a5b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 31 Jan 2023 03:18:20 +0300 Subject: [PATCH 011/133] remove Reactor mapping as it is copied from existing prefs --- openpype/hosts/fusion/deploy/fusion_shared.prefs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index 5bfde9a5c9..d9451ea295 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -4,10 +4,9 @@ Global = { Paths = { Map = { ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", - ["Reactor:"] = "$(REACTOR_INSTALL_PATHMAP)/Reactor", ["Config:"] = "UserPaths:Config;OpenPype:Config", ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", - ["UserPaths:"] = "UserData:;AllData:;Fusion:;Reactor:Deploy" + ["UserPaths:"] = "UserData:;GIT:;AllData:;Fusion:;Reactor:Deploy" }, }, Script = { From cfd718d943dc4b0cf22eb5bff5a10b12dfe4cf3b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 2 Feb 2023 00:07:27 +0300 Subject: [PATCH 012/133] rollback the get_fusion, properly return comp name --- openpype/hosts/fusion/api/lib.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index 851e9ec94a..ac30e1ff99 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -305,16 +305,13 @@ def get_frame_path(path): def get_comp_name(comp=None): """Get basename of the comp's filename""" if comp: - comp_name = os.path.basename(comp.GetAttrs()["COMPS_FileName"]) - return comp_name + return comp.GetAttrs()["COMPS_Name"] def get_fusion(): """Get Fusion instance""" - app = getattr(sys.modules["BlackmagicFusion"], "scriptapp", None) - if app: - fusion = app("Fusion", "localhost") - return fusion + fusion = getattr(sys.modules["__main__"], "fusion", None) + return fusion def get_current_comp(): From 735a35010fb9e667d3191a54cee5e01a24f2ab6a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 2 Feb 2023 09:55:45 +0000 Subject: [PATCH 013/133] Fix assembly job submission --- .../plugins/publish/submit_maya_deadline.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 070d4eab18..230dc52618 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -410,8 +410,10 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): assembly_job_info.Name += " - Tile Assembly Job" assembly_job_info.Frames = 1 assembly_job_info.MachineLimit = 1 - assembly_job_info.Priority = instance.data.get("tile_priority", - self.tile_priority) + assembly_job_info.Priority = instance.data.get( + "tile_priority", self.tile_priority + ) + assembly_job_info.TileJob = False assembly_plugin_info = { "CleanupTiles": 1, @@ -438,13 +440,11 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): frame_assembly_job_info.JobDependencies = tile_job_id # write assembly job config files - now = datetime.now() - config_file = os.path.join( output_dir, "{}_config_{}.txt".format( os.path.splitext(file)[0], - now.strftime("%Y_%m_%d_%H_%M_%S") + datetime.now().strftime("%Y_%m_%d_%H_%M_%S") ) ) try: @@ -455,6 +455,8 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): self.log.warning("Path is unreachable: " "`{}`".format(output_dir)) + assembly_plugin_info["ConfigFile"] = config_file + with open(config_file, "w") as cf: print("TileCount={}".format(tiles_count), file=cf) print("ImageFileName={}".format(file), file=cf) @@ -463,6 +465,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): print("ImageHeight={}".format( instance.data.get("resolutionHeight")), file=cf) + with open(config_file, "a") as cf: tiles = _format_tiles( file, 0, instance.data.get("tilesX"), @@ -474,14 +477,12 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): for k, v in sorted(tiles.items()): print("{}={}".format(k, v), file=cf) - payload = self.assemble_payload( - job_info=frame_assembly_job_info, - plugin_info=assembly_plugin_info.copy(), - # todo: aux file transfers don't work with deadline webservice - # add config file as job auxFile - # aux_files=[config_file] + assembly_payloads.append( + self.assemble_payload( + job_info=frame_assembly_job_info, + plugin_info=assembly_plugin_info.copy(), + ) ) - assembly_payloads.append(payload) # Submit assembly jobs assembly_job_ids = [] @@ -491,6 +492,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): "submitting assembly job {} of {}".format(i + 1, num_assemblies) ) + self.log.info(payload) assembly_job_id = self.submit(payload) assembly_job_ids.append(assembly_job_id) From 0223d94552dda376548e8446bcea88b33de9dd19 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 2 Feb 2023 12:50:52 +0000 Subject: [PATCH 014/133] Fix OpenPypeTileAssembler --- .../OpenPypeTileAssembler.py | 92 +------------------ 1 file changed, 5 insertions(+), 87 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py index 625a3f1a28..674938e641 100644 --- a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py +++ b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py @@ -320,12 +320,7 @@ class OpenPypeTileAssembler(DeadlinePlugin): output_file = data["ImageFileName"] output_file = RepositoryUtils.CheckPathMapping(output_file) output_file = self.process_path(output_file) - """ - _, ext = os.path.splitext(output_file) - if "exr" not in ext: - self.FailRender( - "[{}] Only EXR format is supported for now.".format(ext)) - """ + tile_info = [] for tile in range(int(data["TileCount"])): tile_info.append({ @@ -336,11 +331,6 @@ class OpenPypeTileAssembler(DeadlinePlugin): "width": int(data["Tile{}Width".format(tile)]) }) - # FFMpeg doesn't support tile coordinates at the moment. - # arguments = self.tile_completer_ffmpeg_args( - # int(data["ImageWidth"]), int(data["ImageHeight"]), - # tile_info, output_file) - arguments = self.tile_oiio_args( int(data["ImageWidth"]), int(data["ImageHeight"]), tile_info, output_file) @@ -362,20 +352,20 @@ class OpenPypeTileAssembler(DeadlinePlugin): def pre_render_tasks(self): """Load config file and do remapping.""" self.LogInfo("OpenPype Tile Assembler starting...") - scene_filename = self.GetDataFilename() + config_file = self.GetPluginInfoEntry("ConfigFile") temp_scene_directory = self.CreateTempDirectory( "thread" + str(self.GetThreadNumber())) - temp_scene_filename = Path.GetFileName(scene_filename) + temp_scene_filename = Path.GetFileName(config_file) self.config_file = Path.Combine( temp_scene_directory, temp_scene_filename) if SystemUtils.IsRunningOnWindows(): RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator( - scene_filename, self.config_file, "/", "\\") + config_file, self.config_file, "/", "\\") else: RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator( - scene_filename, self.config_file, "\\", "/") + config_file, self.config_file, "\\", "/") os.chmod(self.config_file, os.stat(self.config_file).st_mode) def post_render_tasks(self): @@ -459,75 +449,3 @@ class OpenPypeTileAssembler(DeadlinePlugin): args.append(output_path) return args - - def tile_completer_ffmpeg_args( - self, output_width, output_height, tiles_info, output_path): - """Generate ffmpeg arguments for tile assembly. - - Expected inputs are tiled images. - - Args: - output_width (int): Width of output image. - output_height (int): Height of output image. - tiles_info (list): List of tile items, each item must be - dictionary with `filepath`, `pos_x` and `pos_y` keys - representing path to file and x, y coordinates on output - image where top-left point of tile item should start. - output_path (str): Path to file where should be output stored. - - Returns: - (list): ffmpeg arguments. - - """ - previous_name = "base" - ffmpeg_args = [] - filter_complex_strs = [] - - filter_complex_strs.append("nullsrc=size={}x{}[{}]".format( - output_width, output_height, previous_name - )) - - new_tiles_info = {} - for idx, tile_info in enumerate(tiles_info): - # Add input and store input index - filepath = tile_info["filepath"] - ffmpeg_args.append("-i \"{}\"".format(filepath.replace("\\", "/"))) - - # Prepare initial filter complex arguments - index_name = "input{}".format(idx) - filter_complex_strs.append( - "[{}]setpts=PTS-STARTPTS[{}]".format(idx, index_name) - ) - tile_info["index"] = idx - new_tiles_info[index_name] = tile_info - - # Set frames to 1 - ffmpeg_args.append("-frames 1") - - # Concatenation filter complex arguments - global_index = 1 - total_index = len(new_tiles_info) - for index_name, tile_info in new_tiles_info.items(): - item_str = ( - "[{previous_name}][{index_name}]overlay={pos_x}:{pos_y}" - ).format( - previous_name=previous_name, - index_name=index_name, - pos_x=tile_info["pos_x"], - pos_y=tile_info["pos_y"] - ) - new_previous = "tmp{}".format(global_index) - if global_index != total_index: - item_str += "[{}]".format(new_previous) - filter_complex_strs.append(item_str) - previous_name = new_previous - global_index += 1 - - joined_parts = ";".join(filter_complex_strs) - filter_complex_str = "-filter_complex \"{}\"".format(joined_parts) - - ffmpeg_args.append(filter_complex_str) - ffmpeg_args.append("-y") - ffmpeg_args.append("\"{}\"".format(output_path)) - - return ffmpeg_args From ce44ceb1fdd65be4451922b1e8ca0096923dd29f Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 2 Feb 2023 12:51:09 +0000 Subject: [PATCH 015/133] Fix y tiles ordering. --- .../plugins/publish/submit_maya_deadline.py | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 230dc52618..6261a69706 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -466,13 +466,16 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): instance.data.get("resolutionHeight")), file=cf) with open(config_file, "a") as cf: + # Need to reverse the order of the y tiles, because image + # coordinates are calculated from bottom left corner. tiles = _format_tiles( file, 0, instance.data.get("tilesX"), instance.data.get("tilesY"), instance.data.get("resolutionWidth"), instance.data.get("resolutionHeight"), - payload_plugin_info["OutputFilePrefix"] + payload_plugin_info["OutputFilePrefix"], + reversed_y=True )[1] for k, v in sorted(tiles.items()): print("{}={}".format(k, v), file=cf) @@ -752,8 +755,15 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): def _format_tiles( - filename, index, tiles_x, tiles_y, - width, height, prefix): + filename, + index, + tiles_x, + tiles_y, + width, + height, + prefix, + reversed_y=False +): """Generate tile entries for Deadline tile job. Returns two dictionaries - one that can be directly used in Deadline @@ -790,6 +800,7 @@ def _format_tiles( width (int): Width resolution of final image. height (int): Height resolution of final image. prefix (str): Image prefix. + reversed_y (bool): Reverses the order of the y tiles. Returns: (dict, dict): Tuple of two dictionaries - first can be used to @@ -812,12 +823,16 @@ def _format_tiles( cfg["TilesCropped"] = "False" tile = 0 + range_y = range(1, tiles_y + 1) + reversed_y_range = list(reversed(range_y)) for tile_x in range(1, tiles_x + 1): - for tile_y in reversed(range(1, tiles_y + 1)): + for i, tile_y in enumerate(range_y): + tile_y_index = tile_y + if reversed_y: + tile_y_index = reversed_y_range[i] + tile_prefix = "_tile_{}x{}_{}x{}_".format( - tile_x, tile_y, - tiles_x, - tiles_y + tile_x, tile_y_index, tiles_x, tiles_y ) new_filename = "{}/{}{}".format( @@ -832,11 +847,14 @@ def _format_tiles( right = (tile_x * w_space) - 1 # Job info - out["JobInfo"]["OutputFilename{}Tile{}".format(index, tile)] = new_filename # noqa: E501 + key = "OutputFilename{}Tile{}".format(index, tile) + out["JobInfo"][key] = new_filename # Plugin Info - out["PluginInfo"]["RegionPrefix{}".format(str(tile))] = \ - "/{}".format(tile_prefix).join(prefix.rsplit("/", 1)) + key = "RegionPrefix{}".format(str(tile)) + out["PluginInfo"][key] = "/{}".format( + tile_prefix + ).join(prefix.rsplit("/", 1)) out["PluginInfo"]["RegionTop{}".format(tile)] = top out["PluginInfo"]["RegionBottom{}".format(tile)] = bottom out["PluginInfo"]["RegionLeft{}".format(tile)] = left From 5b961887a392f3f99a829562634701d2b8961fe4 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 2 Feb 2023 18:08:09 +0000 Subject: [PATCH 016/133] Add plugin version. --- .../plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py index 674938e641..f9c5db1800 100644 --- a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py +++ b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py @@ -16,6 +16,10 @@ from Deadline.Scripting import ( FileUtils, RepositoryUtils, SystemUtils) +version_major = 1 +version_minor = 0 +version_patch = 0 +version_string = ".".join([version_major, version_minor, version_patch]) STRING_TAGS = { "format" } @@ -264,6 +268,7 @@ class OpenPypeTileAssembler(DeadlinePlugin): def initialize_process(self): """Initialization.""" + print("Plugin version: {}".format(version_string)) self.SingleFramesOnly = True self.StdoutHandling = True self.renderer = self.GetPluginInfoEntryWithDefault( From 97ff180d039c22dce44f5f53e0ecf6177363705e Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 2 Feb 2023 18:20:05 +0000 Subject: [PATCH 017/133] Fix plugin version --- .../plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py index f9c5db1800..ef76937b5a 100644 --- a/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py +++ b/openpype/modules/deadline/repository/custom/plugins/OpenPypeTileAssembler/OpenPypeTileAssembler.py @@ -19,7 +19,7 @@ from Deadline.Scripting import ( version_major = 1 version_minor = 0 version_patch = 0 -version_string = ".".join([version_major, version_minor, version_patch]) +version_string = "{}.{}.{}".format(version_major, version_minor, version_patch) STRING_TAGS = { "format" } @@ -268,7 +268,7 @@ class OpenPypeTileAssembler(DeadlinePlugin): def initialize_process(self): """Initialization.""" - print("Plugin version: {}".format(version_string)) + self.LogInfo("Plugin version: {}".format(version_string)) self.SingleFramesOnly = True self.StdoutHandling = True self.renderer = self.GetPluginInfoEntryWithDefault( From 324eaa26b91cbcef39d416bc6cd5bbf9e848cb65 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 02:21:14 +0300 Subject: [PATCH 018/133] use temp folder to store the prefs, check if FUSION16_PROFILE_DIR exists --- .../hosts/fusion/hooks/pre_fusion_setup.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index f6cec86e3b..01b2a37b74 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -19,8 +19,14 @@ class FusionPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] + OPENPYPE_FUSION_PROFILE_DIR = "~/.openpype/hosts/fusion/prefs" def get_profile_source(self): + fusion_var_prefs_dir = os.getenv("FUSION16_PROFILE_DIR") + if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): + self.log.info(f"local Fusion prefs environment is set to {fusion_var_prefs_dir}") + return os.path.join(fusion_var_prefs_dir, "Fusion.prefs") + fusion_prefs_path = "Blackmagic Design/Fusion/Profiles/Default/Fusion.prefs" if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData")) / fusion_prefs_path @@ -32,16 +38,19 @@ class FusionPrelaunch(PreLaunchHook): return str(prefs_source) def copy_existing_prefs(self, profile_directory: str): - dest_folder = os.path.join(profile_directory, "Default") - os.makedirs(dest_folder, exist_ok=True) + dest_folder = Path(profile_directory) / "Default" + dest_folder.mkdir(exist_ok=True, parents=True) prefs_source = self.get_profile_source() - if os.path.exists(prefs_source): - shutil.copy(prefs_source, dest_folder) - self.log.info(f"successfully copied preferences:\n {prefs_source} to {dest_folder}") + if not Path(prefs_source).exists(): + self.log.warning(f"Fusion preferences file not found in {prefs_source}") + return + shutil.copy(prefs_source, dest_folder) + self.log.info(f"successfully copied preferences:\n {prefs_source} to {dest_folder}") def execute(self): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 + py3_var = "FUSION_PYTHON3_HOME" fusion_python3_home = self.launch_context.env.get(py3_var, "") @@ -79,10 +88,11 @@ class FusionPrelaunch(PreLaunchHook): profile_dir_var = "FUSION16_PROFILE_DIR" # used by Fusion 16, 17 and 18 pref_var = "FUSION16_MasterPrefs" # used by Fusion 16, 17 and 18 - profile_dir = os.path.join(FUSION_HOST_DIR, "deploy", "Prefs") + profile_dir = os.path.expanduser(self.OPENPYPE_FUSION_PROFILE_DIR) prefs = os.path.join(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") # now copy the default Fusion profile to a working directory + # only if the openpype profile folder does not exist if not os.path.exists(profile_dir): self.copy_existing_prefs(profile_dir) self.log.info(f"Setting {profile_dir_var}: {profile_dir}") From 3b0f5601338b3299de1493b00754633a55053bf5 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 02:22:02 +0300 Subject: [PATCH 019/133] remove custom pathmap --- openpype/hosts/fusion/deploy/fusion_shared.prefs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index d9451ea295..0225b2209b 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -6,7 +6,7 @@ Global = { ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", ["Config:"] = "UserPaths:Config;OpenPype:Config", ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", - ["UserPaths:"] = "UserData:;GIT:;AllData:;Fusion:;Reactor:Deploy" + ["UserPaths:"] = "UserData:;AllData:;Fusion:;Reactor:Deploy" }, }, Script = { @@ -14,4 +14,4 @@ Global = { Python3Forced = true }, }, -} \ No newline at end of file +} From 13a364377d93fe33317a6b17b861b89f187fe54b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 02:23:30 +0300 Subject: [PATCH 020/133] use get comp filename from lib --- openpype/hosts/fusion/api/lib.py | 20 +++++++++++--------- openpype/hosts/fusion/api/workio.py | 10 +++------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index ac30e1ff99..ec96d6cf18 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -302,14 +302,8 @@ def get_frame_path(path): return filename, padding, ext -def get_comp_name(comp=None): - """Get basename of the comp's filename""" - if comp: - return comp.GetAttrs()["COMPS_Name"] - - def get_fusion(): - """Get Fusion instance""" + """Get current Fusion instance""" fusion = getattr(sys.modules["__main__"], "fusion", None) return fusion @@ -317,8 +311,16 @@ def get_fusion(): def get_current_comp(): """Get current comp in this session""" fusion = get_fusion() - comp = fusion.CurrentComp - return comp + if fusion: + comp = fusion.CurrentComp + return comp + + +def get_comp_filename(): + """Get comp's Filename""" + comp = get_current_comp() + if comp: + return comp.GetAttrs()["COMPS_FileName"] @contextlib.contextmanager diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index da36a83988..048e6e090a 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -2,7 +2,7 @@ import sys import os -from .lib import get_fusion, get_current_comp +from .lib import get_fusion, get_current_comp, get_comp_filename def file_extensions(): @@ -25,12 +25,8 @@ def open_file(filepath): def current_file(): - comp = get_current_comp() - current_filepath = comp.GetAttrs()["COMPS_FileName"] - if not current_filepath: - return None - - return current_filepath + current_filepath = get_comp_filename() + return current_filepath or None def work_root(session): From 62319248a10f91488b1417fe52cd78a3fac8e24c Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 02:26:34 +0300 Subject: [PATCH 021/133] do not override Userpaths --- openpype/hosts/fusion/deploy/fusion_shared.prefs | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index 0225b2209b..8d0e45eae5 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -6,7 +6,6 @@ Global = { ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", ["Config:"] = "UserPaths:Config;OpenPype:Config", ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", - ["UserPaths:"] = "UserData:;AllData:;Fusion:;Reactor:Deploy" }, }, Script = { From be90410047508cd4826b933dd57361f3fa576c2c Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 13:12:35 +0300 Subject: [PATCH 022/133] use pathlib over os.path, check if FUSION_PROFILE is set --- .../hosts/fusion/hooks/pre_fusion_setup.py | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 01b2a37b74..eadcb481e3 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -20,32 +20,41 @@ class FusionPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] OPENPYPE_FUSION_PROFILE_DIR = "~/.openpype/hosts/fusion/prefs" + PROFILE_NUMBER = 16 - def get_profile_source(self): - fusion_var_prefs_dir = os.getenv("FUSION16_PROFILE_DIR") + def get_fusion_profile(self) -> str: + return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") + + def get_profile_source(self) -> Path: + fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") + + # if FUSION16_PROFILE_DIR variable exists, return the profile filepath if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): - self.log.info(f"local Fusion prefs environment is set to {fusion_var_prefs_dir}") - return os.path.join(fusion_var_prefs_dir, "Fusion.prefs") - - fusion_prefs_path = "Blackmagic Design/Fusion/Profiles/Default/Fusion.prefs" + fusion_profile = self.get_fusion_profile() + fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) + self.log.info(f"Local Fusion prefs environment is set to {fusion_prefs_dir}") + fusion_prefs_filepath = fusion_prefs_dir / "Fusion.prefs" + return fusion_prefs_filepath + + # otherwise get the profile from default prefs location + fusion_prefs_path = f"Blackmagic Design/Fusion/Profiles/{fusion_var_prefs_dir}/Fusion.prefs" if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData")) / fusion_prefs_path elif platform.system() == "Darwin": - prefs_source = Path(os.path.expanduser("~/Library/Application Support/")) / fusion_prefs_path + prefs_source = Path("~/Library/Application Support/", fusion_prefs_path).expanduser() elif platform.system() == "Linux": - prefs_source = Path(os.path.expanduser("~/.fusion")) / fusion_prefs_path + prefs_source = Path("~/.fusion", fusion_prefs_path).expanduser() + + return prefs_source - return str(prefs_source) - - def copy_existing_prefs(self, profile_directory: str): - dest_folder = Path(profile_directory) / "Default" + def copy_existing_prefs(self, copy_from: Path, copy_to: Path) -> None: + dest_folder = copy_to / self.get_fusion_profile() dest_folder.mkdir(exist_ok=True, parents=True) - prefs_source = self.get_profile_source() - if not Path(prefs_source).exists(): - self.log.warning(f"Fusion preferences file not found in {prefs_source}") + if not copy_from.exists(): + self.log.warning(f"Fusion preferences file not found in {copy_from}") return - shutil.copy(prefs_source, dest_folder) - self.log.info(f"successfully copied preferences:\n {prefs_source} to {dest_folder}") + shutil.copy(str(copy_from), str(dest_folder)) # compatible with Python >= 3.6 + self.log.info(f"successfully copied preferences:\n {copy_from} to {dest_folder}") def execute(self): # making sure python 3 is installed at provided path @@ -54,12 +63,12 @@ class FusionPrelaunch(PreLaunchHook): py3_var = "FUSION_PYTHON3_HOME" fusion_python3_home = self.launch_context.env.get(py3_var, "") - self.log.info(f"Looking for Python 3 in: {fusion_python3_home}") for path in fusion_python3_home.split(os.pathsep): - # Allow defining multiple paths to allow "fallback" to other + # Allow defining multiple paths, separated by os.pathsep, to allow "fallback" to other # path. But make to set only a single path as final variable. py3_dir = os.path.normpath(path) if os.path.isdir(py3_dir): + self.log.info(f"Looking for Python 3 in: {py3_dir}") break else: raise ApplicationLaunchFailed( @@ -88,14 +97,16 @@ class FusionPrelaunch(PreLaunchHook): profile_dir_var = "FUSION16_PROFILE_DIR" # used by Fusion 16, 17 and 18 pref_var = "FUSION16_MasterPrefs" # used by Fusion 16, 17 and 18 - profile_dir = os.path.expanduser(self.OPENPYPE_FUSION_PROFILE_DIR) - prefs = os.path.join(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + op_profile_dir = Path(self.OPENPYPE_FUSION_PROFILE_DIR).expanduser() + op_master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + prefs_source = self.get_profile_source() + self.log.info(f"Got Fusion prefs file: {prefs_source}") # now copy the default Fusion profile to a working directory # only if the openpype profile folder does not exist - if not os.path.exists(profile_dir): - self.copy_existing_prefs(profile_dir) - self.log.info(f"Setting {profile_dir_var}: {profile_dir}") - self.launch_context.env[profile_dir_var] = profile_dir - self.log.info(f"Setting {pref_var}: {prefs}") - self.launch_context.env[pref_var] = prefs + if not op_profile_dir.exists(): + self.copy_existing_prefs(prefs_source, op_profile_dir) + self.log.info(f"Setting {profile_dir_var}: {op_profile_dir}") + self.launch_context.env[profile_dir_var] = str(op_profile_dir) + self.log.info(f"Setting {pref_var}: {op_master_prefs}") + self.launch_context.env[pref_var] = str(op_master_prefs) From 95280aef00d3886170f593e47129bb6560502c2b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 13:44:30 +0300 Subject: [PATCH 023/133] fix get fusion profile --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index eadcb481e3..4f000a12b2 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -26,18 +26,18 @@ class FusionPrelaunch(PreLaunchHook): return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") def get_profile_source(self) -> Path: + fusion_profile = self.get_fusion_profile() fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") # if FUSION16_PROFILE_DIR variable exists, return the profile filepath if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): - fusion_profile = self.get_fusion_profile() fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) self.log.info(f"Local Fusion prefs environment is set to {fusion_prefs_dir}") fusion_prefs_filepath = fusion_prefs_dir / "Fusion.prefs" return fusion_prefs_filepath # otherwise get the profile from default prefs location - fusion_prefs_path = f"Blackmagic Design/Fusion/Profiles/{fusion_var_prefs_dir}/Fusion.prefs" + fusion_prefs_path = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}/Fusion.prefs" if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData")) / fusion_prefs_path elif platform.system() == "Darwin": From 9d8eb7383581b3dc48d378db7ef65986a24118e2 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 3 Feb 2023 12:16:47 +0000 Subject: [PATCH 024/133] Documentation --- website/docs/artist_hosts_maya.md | 16 ++++++++++++++++ website/docs/module_deadline.md | 28 ++++++++++++++++------------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index 5cd8efa153..81164eefad 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -504,6 +504,22 @@ In the scene from where you want to publish your model create *Render subset*. P model subset (Maya set node) under corresponding `LAYER_` set under *Render instance*. During publish, it will submit this render to farm and after it is rendered, it will be attached to your model subset. +### Tile Rendering +:::note Deadline +This feature is only supported when using Deadline. See [here](module_deadline#openpypetileassembler-plugin) for setup. +::: +On the render instance objectset you'll find: + +* `Tile Rendering` - for enabling tile rendering. +* `Tile X` - number of tiles in the X axis. +* `Tile Y` - number of tiles in the Y axis. + +When submittig to Deadline, you'll get: + +- for each frame a tile rendering job, to render each from Maya. +- for each frame a tile assembly job, to assemble the rendered tiles. +- job to publish the assembled frames. + ## Render Setups ### Publishing Render Setups diff --git a/website/docs/module_deadline.md b/website/docs/module_deadline.md index c96da91909..2c02530b79 100644 --- a/website/docs/module_deadline.md +++ b/website/docs/module_deadline.md @@ -28,16 +28,16 @@ For [AWS Thinkbox Deadline](https://www.awsthinkbox.com/deadline) support you ne OpenPype integration for Deadline consists of two parts: - The `OpenPype` Deadline Plug-in -- A `GlobalJobPreLoad` Deadline Script (this gets triggered for each deadline job) +- A `GlobalJobPreLoad` Deadline Script (this gets triggered for each deadline job) The `GlobalJobPreLoad` handles populating render and publish jobs with proper environment variables using settings from the `OpenPype` Deadline Plug-in. -The `OpenPype` Deadline Plug-in must be configured to point to a valid OpenPype executable location. The executable need to be installed to +The `OpenPype` Deadline Plug-in must be configured to point to a valid OpenPype executable location. The executable need to be installed to destinations accessible by DL process. Check permissions (must be executable and accessible by Deadline process) - Enable `Tools > Super User Mode` in Deadline Monitor -- Go to `Tools > Configure Plugins...`, find `OpenPype` in the list on the left side, find location of OpenPype +- Go to `Tools > Configure Plugins...`, find `OpenPype` in the list on the left side, find location of OpenPype executable. It is recommended to use the `openpype_console` executable as it provides a bit more logging. - In case of multi OS farms, provide multiple locations, each Deadline Worker goes through the list and tries to find the first accessible @@ -45,12 +45,16 @@ executable. It is recommended to use the `openpype_console` executable as it pro ![Configure plugin](assets/deadline_configure_plugin.png) +### OpenPypeTileAssembler Plugin +To setup tile rendering copy the `OpenPypeTileAssembler` plugin to the repository; +`[OpenPype]\openpype\modules\deadline\repository\custom\plugins\OpenPypeTileAssembler` > `[DeadlineRepository]\custom\plugins\OpenPypeTileAssembler` + ## Troubleshooting #### Publishing jobs fail directly in DCCs - Double check that all previously described steps were finished -- Check that `deadlinewebservice` is running on DL server +- Check that `deadlinewebservice` is running on DL server - Check that user's machine has access to deadline server on configured port #### Jobs are failing on DL side @@ -61,40 +65,40 @@ Each publishing from OpenPype consists of 2 jobs, first one is rendering, second - Jobs are failing with `OpenPype executable was not found` error - Check if OpenPype is installed on the Worker handling this job and ensure `OpenPype` Deadline Plug-in is properly [configured](#configuration) + Check if OpenPype is installed on the Worker handling this job and ensure `OpenPype` Deadline Plug-in is properly [configured](#configuration) - Publishing job is failing with `ffmpeg not installed` error - + OpenPype executable has to have access to `ffmpeg` executable, check OpenPype `Setting > General` ![FFmpeg setting](assets/ffmpeg_path.png) - Both jobs finished successfully, but there is no review on Ftrack - Make sure that you correctly set published family to be send to Ftrack. + Make sure that you correctly set published family to be send to Ftrack. ![Ftrack Family](assets/ftrack/ftrack-collect-main.png) Example: I want send to Ftrack review of rendered images from Harmony : - `Host names`: "harmony" - - `Families`: "render" + - `Families`: "render" - `Add Ftrack Family` to "Enabled" - + Make sure that you actually configured to create review for published subset in `project_settings/ftrack/publish/CollectFtrackFamily` ![Ftrack Family](assets/deadline_review.png) - Example: I want to create review for all reviewable subsets in Harmony : + Example: I want to create review for all reviewable subsets in Harmony : - Add "harmony" as a new key an ".*" as a value. - Rendering jobs are stuck in 'Queued' state or failing Make sure that your Deadline is not limiting specific jobs to be run only on specific machines. (Eg. only some machines have installed particular application.) - + Check `project_settings/deadline` - + ![Deadline group](assets/deadline_group.png) Example: I have separated machines with "Harmony" installed into "harmony" group on Deadline. I want rendering jobs published from Harmony to run only on those machines. From b5a4fb59a578309b9f94914546acf97606c271f4 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 3 Feb 2023 12:42:27 +0000 Subject: [PATCH 025/133] Change default settings to Draft Tile Assembler. --- openpype/settings/defaults/project_settings/deadline.json | 4 ++-- .../schemas/projects_schema/schema_project_deadline.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index ceb0b2e39a..c4c3d413d1 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -23,7 +23,7 @@ "enabled": true, "optional": false, "active": true, - "tile_assembler_plugin": "OpenPypeTileAssembler", + "tile_assembler_plugin": "DraftTileAssembler", "use_published": true, "import_reference": false, "asset_dependencies": true, @@ -106,4 +106,4 @@ } } } -} \ No newline at end of file +} diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index 08a505bd47..87b375bc9f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -121,7 +121,7 @@ "DraftTileAssembler": "Draft Tile Assembler" }, { - "OpenPypeTileAssembler": "Open Image IO" + "OpenPypeTileAssembler": "OpenPype Tile Assembler" } ] }, From 25b4907b35894641930bbb86d9a583fcf82d5dbe Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 3 Feb 2023 15:56:45 +0000 Subject: [PATCH 026/133] Fix for Draft Tile Assembler --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 6261a69706..972e1810be 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -484,6 +484,9 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): self.assemble_payload( job_info=frame_assembly_job_info, plugin_info=assembly_plugin_info.copy(), + # This would fail if the client machine and webserice are + # using different storage paths. + aux_files=[config_file] ) ) From 9bba80ff6196cff4c4579bcb78db9f8ef1623081 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 3 Feb 2023 20:32:38 +0300 Subject: [PATCH 027/133] add copy fusion prefs global settings --- .../system_settings/applications.json | 8 +++++- .../host_settings/schema_fusion.json | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 936407a49b..5d75b3b606 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -835,6 +835,10 @@ "linux": "/opt/Python/3.6/bin" } }, + "copy_fusion_settings": { + "copy_prefs": false, + "prefs_path": "~/.openpype/hosts/fusion/prefs" + }, "variants": { "18": { "executables": { @@ -1302,7 +1306,9 @@ "variant_label": "Current", "use_python_2": false, "executables": { - "windows": ["C:/Program Files/CelAction/CelAction2D Studio/CelAction2D.exe"], + "windows": [ + "C:/Program Files/CelAction/CelAction2D Studio/CelAction2D.exe" + ], "darwin": [], "linux": [] }, diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json index 5960da7774..360813bcb5 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json @@ -19,6 +19,31 @@ "label": "Environment", "type": "raw-json" }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "copy_fusion_settings", + "collapsible": true, + "checkbox_key": "copy_prefs", + "label": "Copy Fusion preferences", + "children": [ + { + "type": "boolean", + "key": "copy_prefs", + "label": "Enabled" + }, + { + "key": "prefs_path", + "type": "path", + "label": "Local prefs directory" + } + ] + }, + { + "type": "splitter" + }, { "type": "dict-modifiable", "key": "variants", From 3ff8aa5c958e79000bd82967de82e436947c11fd Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Mon, 13 Feb 2023 00:39:55 +0300 Subject: [PATCH 028/133] use system settings to get data, add force sync option --- .../hosts/fusion/hooks/pre_fusion_setup.py | 71 ++++++++++++------- .../system_settings/applications.json | 3 +- .../host_settings/schema_fusion.json | 7 +- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 4f000a12b2..4dc11abce9 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -4,6 +4,7 @@ import platform from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR +from openpype.settings import get_system_settings class FusionPrelaunch(PreLaunchHook): @@ -19,14 +20,18 @@ class FusionPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] - OPENPYPE_FUSION_PROFILE_DIR = "~/.openpype/hosts/fusion/prefs" PROFILE_NUMBER = 16 - def get_fusion_profile(self) -> str: + def get_fusion_profile_name(self) -> str: + """usually set to 'Default', unless FUSION16_PROFILE is set""" return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") def get_profile_source(self) -> Path: - fusion_profile = self.get_fusion_profile() + """Get the Fusion preferences (profile) location. + Check https://www.steakunderwater.com/VFXPedia/96.0.243.189/indexad6a.html?title=Per-User_Preferences_and_Paths#Setting_the_profile_directory + for reference. + """ + fusion_profile = self.get_fusion_profile_name() fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") # if FUSION16_PROFILE_DIR variable exists, return the profile filepath @@ -44,11 +49,32 @@ class FusionPrelaunch(PreLaunchHook): prefs_source = Path("~/Library/Application Support/", fusion_prefs_path).expanduser() elif platform.system() == "Linux": prefs_source = Path("~/.fusion", fusion_prefs_path).expanduser() - + self.log.info(f"Got Fusion prefs file: {prefs_source}") return prefs_source - def copy_existing_prefs(self, copy_from: Path, copy_to: Path) -> None: - dest_folder = copy_to / self.get_fusion_profile() + def get_copy_fusion_prefs_settings(self): + """Git copy prefserences options from the global application settings""" + copy_status = copy_path = None + try: + copy_status, copy_path, force_sync = get_system_settings()["applications"]["fusion"][ + "copy_fusion_settings"].values() + except ValueError: + self.log.error('Copy prefs settings not found') + finally: + return copy_status, copy_path, force_sync + + def copy_existing_prefs(self, copy_from: Path, copy_to: Path, force_sync: bool) -> None: + """On the first Fusion launch copy the Fusion profile to the working directory. + If the Openpype profile folder exists, skip copying, unless Force sync is checked. + If the prefs were not copied on the first launch, clean Fusion profile + will be created in openpype_fusion_profile_dir. + """ + if copy_to.exists() and not force_sync: + self.log.info("Local Fusion preferences folder exists, skipping profile copy") + return + self.log.info(f"Starting copying Fusion preferences") + self.log.info(f"force_sync option is set to {force_sync}") + dest_folder = copy_to / self.get_fusion_profile_name() dest_folder.mkdir(exist_ok=True, parents=True) if not copy_from.exists(): self.log.warning(f"Fusion preferences file not found in {copy_from}") @@ -88,25 +114,22 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env["FUSION16_PYTHON36_HOME"] = py3_dir + self.launch_context.env[f"FUSION{self.PROFILE_NUMBER}_PYTHON36_HOME"] = py3_dir - # Add custom Fusion Master Prefs and the temporary profile directory variables to customize - # Fusion to define where it can read custom scripts and tools from + # Add custom Fusion Master Prefs and the temporary profile directory variables + # to customize Fusion to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - profile_dir_var = "FUSION16_PROFILE_DIR" # used by Fusion 16, 17 and 18 - pref_var = "FUSION16_MasterPrefs" # used by Fusion 16, 17 and 18 - op_profile_dir = Path(self.OPENPYPE_FUSION_PROFILE_DIR).expanduser() - op_master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") - prefs_source = self.get_profile_source() - self.log.info(f"Got Fusion prefs file: {prefs_source}") - - # now copy the default Fusion profile to a working directory - # only if the openpype profile folder does not exist - if not op_profile_dir.exists(): - self.copy_existing_prefs(prefs_source, op_profile_dir) - self.log.info(f"Setting {profile_dir_var}: {op_profile_dir}") - self.launch_context.env[profile_dir_var] = str(op_profile_dir) - self.log.info(f"Setting {pref_var}: {op_master_prefs}") - self.launch_context.env[pref_var] = str(op_master_prefs) + copy_status, openpype_fusion_profile_dir, force_sync = self.get_copy_fusion_prefs_settings() + if copy_status: + prefs_source = self.get_profile_source() + openpype_fusion_profile_dir = Path(openpype_fusion_profile_dir).expanduser() + self.copy_existing_prefs(prefs_source, openpype_fusion_profile_dir, force_sync) + fusion_profile_dir_variable = f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR" + pref_var = f"FUSION{self.PROFILE_NUMBER}_MasterPrefs" + openpype_master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + self.log.info(f"Setting {fusion_profile_dir_variable}: {openpype_fusion_profile_dir}") + self.launch_context.env[fusion_profile_dir_variable] = str(openpype_fusion_profile_dir) + self.log.info(f"Setting {pref_var}: {openpype_master_prefs}") + self.launch_context.env[pref_var] = str(openpype_master_prefs) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 5d75b3b606..9fb730568e 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -837,7 +837,8 @@ }, "copy_fusion_settings": { "copy_prefs": false, - "prefs_path": "~/.openpype/hosts/fusion/prefs" + "prefs_path": "~/.openpype/hosts/fusion/prefs", + "force_sync": false }, "variants": { "18": { diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json index 360813bcb5..48355932ae 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json @@ -27,7 +27,7 @@ "key": "copy_fusion_settings", "collapsible": true, "checkbox_key": "copy_prefs", - "label": "Copy Fusion preferences", + "label": "Copy Fusion settings when launched from OpenPype", "children": [ { "type": "boolean", @@ -38,6 +38,11 @@ "key": "prefs_path", "type": "path", "label": "Local prefs directory" + }, + { + "key":"force_sync", + "type": "boolean", + "label": "Always sync preferences on launch" } ] }, From 76bdcb49ea019fe7028bce87916b14dcf4a829f1 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Mon, 13 Feb 2023 00:40:51 +0300 Subject: [PATCH 029/133] get the prefs path correctly --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 4dc11abce9..267ee71315 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -61,7 +61,7 @@ class FusionPrelaunch(PreLaunchHook): except ValueError: self.log.error('Copy prefs settings not found') finally: - return copy_status, copy_path, force_sync + return copy_status, Path(copy_path).expanduser(), force_sync def copy_existing_prefs(self, copy_from: Path, copy_to: Path, force_sync: bool) -> None: """On the first Fusion launch copy the Fusion profile to the working directory. @@ -124,12 +124,11 @@ class FusionPrelaunch(PreLaunchHook): copy_status, openpype_fusion_profile_dir, force_sync = self.get_copy_fusion_prefs_settings() if copy_status: prefs_source = self.get_profile_source() - openpype_fusion_profile_dir = Path(openpype_fusion_profile_dir).expanduser() self.copy_existing_prefs(prefs_source, openpype_fusion_profile_dir, force_sync) fusion_profile_dir_variable = f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR" - pref_var = f"FUSION{self.PROFILE_NUMBER}_MasterPrefs" + master_prefs_variable = f"FUSION{self.PROFILE_NUMBER}_MasterPrefs" openpype_master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {fusion_profile_dir_variable}: {openpype_fusion_profile_dir}") self.launch_context.env[fusion_profile_dir_variable] = str(openpype_fusion_profile_dir) - self.log.info(f"Setting {pref_var}: {openpype_master_prefs}") - self.launch_context.env[pref_var] = str(openpype_master_prefs) + self.log.info(f"Setting {master_prefs_variable}: {openpype_master_prefs}") + self.launch_context.env[master_prefs_variable] = str(openpype_master_prefs) From 632beeb1c7ae00146910a3cfa27a8ef855edbc84 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Mon, 13 Feb 2023 00:41:29 +0300 Subject: [PATCH 030/133] use english interface by default --- .../hosts/fusion/deploy/fusion_shared.prefs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index 8d0e45eae5..17ac3ad37a 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -1,16 +1,20 @@ { Locked = true, Global = { - Paths = { - Map = { - ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", - ["Config:"] = "UserPaths:Config;OpenPype:Config", - ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", - }, - }, - Script = { - PythonVersion = 3, - Python3Forced = true - }, + Paths = { + Map = { + ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", + ["Config:"] = "UserPaths:Config;OpenPype:Config", + ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts", }, + }, + Script = { + PythonVersion = 3, + Python3Forced = true + }, + UserInterface = { + Skin = "Neutral", + Language = "en_US" + }, + }, } From 807fd736fc7ce26b6e2553cfa9c1c53d7e13360f Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Mon, 13 Feb 2023 01:50:05 +0300 Subject: [PATCH 031/133] fix typo --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 267ee71315..3bb345b72f 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -28,8 +28,7 @@ class FusionPrelaunch(PreLaunchHook): def get_profile_source(self) -> Path: """Get the Fusion preferences (profile) location. - Check https://www.steakunderwater.com/VFXPedia/96.0.243.189/indexad6a.html?title=Per-User_Preferences_and_Paths#Setting_the_profile_directory - for reference. + Check https://www.steakunderwater.com/VFXPedia/96.0.243.189/indexad6a.html?title=Per-User_Preferences_and_Paths for reference. """ fusion_profile = self.get_fusion_profile_name() fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") @@ -53,7 +52,7 @@ class FusionPrelaunch(PreLaunchHook): return prefs_source def get_copy_fusion_prefs_settings(self): - """Git copy prefserences options from the global application settings""" + """Get copy prefserences options from the global application settings""" copy_status = copy_path = None try: copy_status, copy_path, force_sync = get_system_settings()["applications"]["fusion"][ From da183c2199f6eadb567c0bf4db400124a2583674 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 16 Feb 2023 16:30:16 +0000 Subject: [PATCH 032/133] Saving with default settings properly. --- openpype/settings/defaults/project_settings/deadline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index c563531b39..e55f33bb41 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -107,4 +107,4 @@ } } } -} +} \ No newline at end of file From 63eee639f7a3f01ad15d6e9b8bc5b7608e21084b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 16 Feb 2023 18:35:23 +0000 Subject: [PATCH 033/133] Fix frames issues. --- .../deadline/plugins/publish/submit_maya_deadline.py | 1 + .../publish/validate_expected_and_rendered_files.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index cb47c854a8..19e8a258f4 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -442,6 +442,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): frame_assembly_job_info.ExtraInfo[0] = file_hash frame_assembly_job_info.ExtraInfo[1] = file frame_assembly_job_info.JobDependencies = tile_job_id + frame_assembly_job_info.Frames = frame # write assembly job config files config_file = os.path.join( diff --git a/openpype/modules/deadline/plugins/publish/validate_expected_and_rendered_files.py b/openpype/modules/deadline/plugins/publish/validate_expected_and_rendered_files.py index f0a3ddd246..9311a9d64a 100644 --- a/openpype/modules/deadline/plugins/publish/validate_expected_and_rendered_files.py +++ b/openpype/modules/deadline/plugins/publish/validate_expected_and_rendered_files.py @@ -68,8 +68,15 @@ class ValidateExpectedFiles(pyblish.api.InstancePlugin): # files to be in the folder that we might not want to use. missing = expected_files - existing_files if missing: - raise RuntimeError("Missing expected files: {}".format( - sorted(missing))) + raise RuntimeError( + "Missing expected files: {}\n" + "Expected files: {}\n" + "Existing files: {}".format( + sorted(missing), + sorted(expected_files), + sorted(existing_files) + ) + ) def _get_frame_list(self, original_job_id): """Returns list of frame ranges from all render job. From 718f4e748d86177617e12915eae7c53fdc3a5eec Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov <11698866+movalex@users.noreply.github.com> Date: Fri, 17 Feb 2023 00:46:40 +0300 Subject: [PATCH 034/133] Update openpype/hosts/fusion/hooks/pre_fusion_setup.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/fusion/hooks/pre_fusion_setup.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 3bb345b72f..9ae57d2a17 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -53,14 +53,21 @@ class FusionPrelaunch(PreLaunchHook): def get_copy_fusion_prefs_settings(self): """Get copy prefserences options from the global application settings""" - copy_status = copy_path = None - try: - copy_status, copy_path, force_sync = get_system_settings()["applications"]["fusion"][ - "copy_fusion_settings"].values() - except ValueError: - self.log.error('Copy prefs settings not found') - finally: - return copy_status, Path(copy_path).expanduser(), force_sync + copy_fusion_settings = ( + self.data + ["system_settings"] + ["applications"] + ["fusion"] + .get("copy_fusion_settings", {}) + ) + if not copy_fusion_settings: + self.log.error("Copy prefs settings not found") + copy_status = copy_fusion_settings.get("copy_status", False) + force_sync = copy_fusion_settings.get("force_sync", False) + copy_path = copy_fusion_settings.get("copy_path") or None + if copy_path: + copy_path = Path(copy_path).expanduser() + return copy_status, copy_path, force_sync def copy_existing_prefs(self, copy_from: Path, copy_to: Path, force_sync: bool) -> None: """On the first Fusion launch copy the Fusion profile to the working directory. From dacc90f9ad8ddab10ad60f814950db818e3327f3 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Feb 2023 13:31:52 +0300 Subject: [PATCH 035/133] remove redundant get gomp name function --- openpype/hosts/fusion/api/lib.py | 7 ------- openpype/hosts/fusion/api/workio.py | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index ec96d6cf18..f175d3a1d3 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -316,13 +316,6 @@ def get_current_comp(): return comp -def get_comp_filename(): - """Get comp's Filename""" - comp = get_current_comp() - if comp: - return comp.GetAttrs()["COMPS_FileName"] - - @contextlib.contextmanager def comp_lock_and_undo_chunk(comp, undo_queue_name="Script CMD"): """Lock comp and open an undo chunk during the context""" diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index 048e6e090a..8012d600da 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -25,7 +25,8 @@ def open_file(filepath): def current_file(): - current_filepath = get_comp_filename() + comp = get_current_comp() + current_filepath = comp.GetAttrs()["COMPS_FileName"] return current_filepath or None From d77c0e252be994a242d7004b675a8247abfc8326 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Feb 2023 13:49:32 +0300 Subject: [PATCH 036/133] move fusion prefs settings to project_settings --- .../hosts/fusion/hooks/pre_fusion_setup.py | 23 +++++++------- .../defaults/project_settings/fusion.json | 5 ++++ .../system_settings/applications.json | 5 ---- .../schema_project_fusion.json | 24 +++++++++++++++ .../host_settings/schema_fusion.json | 30 ------------------- 5 files changed, 39 insertions(+), 48 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 9ae57d2a17..ad2ec7eb2d 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -4,7 +4,6 @@ import platform from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR -from openpype.settings import get_system_settings class FusionPrelaunch(PreLaunchHook): @@ -39,11 +38,10 @@ class FusionPrelaunch(PreLaunchHook): self.log.info(f"Local Fusion prefs environment is set to {fusion_prefs_dir}") fusion_prefs_filepath = fusion_prefs_dir / "Fusion.prefs" return fusion_prefs_filepath - # otherwise get the profile from default prefs location fusion_prefs_path = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}/Fusion.prefs" if platform.system() == "Windows": - prefs_source = Path(os.getenv("AppData")) / fusion_prefs_path + prefs_source = Path(os.getenv("AppData"), fusion_prefs_path) elif platform.system() == "Darwin": prefs_source = Path("~/Library/Application Support/", fusion_prefs_path).expanduser() elif platform.system() == "Linux": @@ -55,8 +53,7 @@ class FusionPrelaunch(PreLaunchHook): """Get copy prefserences options from the global application settings""" copy_fusion_settings = ( self.data - ["system_settings"] - ["applications"] + ["project_settings"] ["fusion"] .get("copy_fusion_settings", {}) ) @@ -73,7 +70,7 @@ class FusionPrelaunch(PreLaunchHook): """On the first Fusion launch copy the Fusion profile to the working directory. If the Openpype profile folder exists, skip copying, unless Force sync is checked. If the prefs were not copied on the first launch, clean Fusion profile - will be created in openpype_fusion_profile_dir. + will be created in fusion_profile_dir. """ if copy_to.exists() and not force_sync: self.log.info("Local Fusion preferences folder exists, skipping profile copy") @@ -127,14 +124,14 @@ class FusionPrelaunch(PreLaunchHook): self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - copy_status, openpype_fusion_profile_dir, force_sync = self.get_copy_fusion_prefs_settings() + copy_status, fusion_profile_dir, force_sync = self.get_copy_fusion_prefs_settings() if copy_status: prefs_source = self.get_profile_source() - self.copy_existing_prefs(prefs_source, openpype_fusion_profile_dir, force_sync) + self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) fusion_profile_dir_variable = f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR" master_prefs_variable = f"FUSION{self.PROFILE_NUMBER}_MasterPrefs" - openpype_master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") - self.log.info(f"Setting {fusion_profile_dir_variable}: {openpype_fusion_profile_dir}") - self.launch_context.env[fusion_profile_dir_variable] = str(openpype_fusion_profile_dir) - self.log.info(f"Setting {master_prefs_variable}: {openpype_master_prefs}") - self.launch_context.env[master_prefs_variable] = str(openpype_master_prefs) + master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") + self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) + self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") + self.launch_context.env[master_prefs_variable] = str(master_prefs) diff --git a/openpype/settings/defaults/project_settings/fusion.json b/openpype/settings/defaults/project_settings/fusion.json index 720178e17a..74863ece43 100644 --- a/openpype/settings/defaults/project_settings/fusion.json +++ b/openpype/settings/defaults/project_settings/fusion.json @@ -16,5 +16,10 @@ "linux": [] } } + }, + "copy_fusion_settings": { + "copy_status": false, + "copy_path": "~/.openpype/hosts/fusion/prefs", + "force_sync": false } } \ No newline at end of file diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 9fb730568e..d498bccda9 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -835,11 +835,6 @@ "linux": "/opt/Python/3.6/bin" } }, - "copy_fusion_settings": { - "copy_prefs": false, - "prefs_path": "~/.openpype/hosts/fusion/prefs", - "force_sync": false - }, "variants": { "18": { "executables": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json index 8c62d75815..540f840aad 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json @@ -45,6 +45,30 @@ ] } ] + }, + { + "type": "dict", + "key": "copy_fusion_settings", + "collapsible": true, + "checkbox_key": "copy_status", + "label": "Copy Fusion settings on launch", + "children": [ + { + "type": "boolean", + "key": "copy_status", + "label": "Enabled" + }, + { + "key": "copy_path", + "type": "path", + "label": "Local prefs directory" + }, + { + "key":"force_sync", + "type": "boolean", + "label": "Force sync preferences" + } + ] } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json index 48355932ae..5960da7774 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_fusion.json @@ -19,36 +19,6 @@ "label": "Environment", "type": "raw-json" }, - { - "type": "splitter" - }, - { - "type": "dict", - "key": "copy_fusion_settings", - "collapsible": true, - "checkbox_key": "copy_prefs", - "label": "Copy Fusion settings when launched from OpenPype", - "children": [ - { - "type": "boolean", - "key": "copy_prefs", - "label": "Enabled" - }, - { - "key": "prefs_path", - "type": "path", - "label": "Local prefs directory" - }, - { - "key":"force_sync", - "type": "boolean", - "label": "Always sync preferences on launch" - } - ] - }, - { - "type": "splitter" - }, { "type": "dict-modifiable", "key": "variants", From 87ab9e35983241b255347d7f98daafadac09def6 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Feb 2023 13:50:08 +0300 Subject: [PATCH 037/133] rename get_fusion module --- openpype/hosts/fusion/api/lib.py | 4 ++-- openpype/hosts/fusion/api/workio.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index f175d3a1d3..709d3cbdc6 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -302,7 +302,7 @@ def get_frame_path(path): return filename, padding, ext -def get_fusion(): +def get_fusion_module(): """Get current Fusion instance""" fusion = getattr(sys.modules["__main__"], "fusion", None) return fusion @@ -310,7 +310,7 @@ def get_fusion(): def get_current_comp(): """Get current comp in this session""" - fusion = get_fusion() + fusion = get_fusion_module() if fusion: comp = fusion.CurrentComp return comp diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index 8012d600da..f51c4fa9c1 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -2,7 +2,7 @@ import sys import os -from .lib import get_fusion, get_current_comp, get_comp_filename +from .lib import get_fusion_module, get_current_comp, get_comp_filename def file_extensions(): @@ -20,7 +20,7 @@ def save_file(filepath): def open_file(filepath): - fusion = get_fusion() + fusion = get_fusion_module() return fusion.LoadComp(filepath) From 39ee896d7ebb4ab22d7d747bd2693e79bb7d9512 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov <11698866+movalex@users.noreply.github.com> Date: Sat, 18 Feb 2023 07:47:42 +0300 Subject: [PATCH 038/133] Update openpype/hosts/fusion/api/lib.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/fusion/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index 709d3cbdc6..4830c3b3df 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -311,7 +311,7 @@ def get_fusion_module(): def get_current_comp(): """Get current comp in this session""" fusion = get_fusion_module() - if fusion: + if fusion is not None: comp = fusion.CurrentComp return comp From ea1f10b9db63f21161cb97c6ac984d07d361e7ed Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 20 Feb 2023 12:52:08 +0000 Subject: [PATCH 039/133] Removed references to openpype.api --- openpype/hosts/blender/plugins/publish/extract_playblast.py | 5 ++--- openpype/hosts/blender/plugins/publish/extract_thumbnail.py | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/blender/plugins/publish/extract_playblast.py b/openpype/hosts/blender/plugins/publish/extract_playblast.py index 1114b633be..8dc2f66c22 100644 --- a/openpype/hosts/blender/plugins/publish/extract_playblast.py +++ b/openpype/hosts/blender/plugins/publish/extract_playblast.py @@ -4,12 +4,12 @@ import clique import bpy import pyblish.api -import openpype.api +from openpype.pipeline import publish from openpype.hosts.blender.api import capture from openpype.hosts.blender.api.lib import maintained_time -class ExtractPlayblast(openpype.api.Extractor): +class ExtractPlayblast(publish.Extractor): """ Extract viewport playblast. @@ -27,7 +27,6 @@ class ExtractPlayblast(openpype.api.Extractor): self.log.info("Extracting capture..") self.log.info(instance.data) - print(instance.context.data) # get scene fps fps = instance.data.get("fps") diff --git a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py index ba455cf450..65c3627375 100644 --- a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py @@ -2,14 +2,14 @@ import os import glob import pyblish.api -import openpype.api +from openpype.pipeline import publish from openpype.hosts.blender.api import capture from openpype.hosts.blender.api.lib import maintained_time import bpy -class ExtractThumbnail(openpype.api.Extractor): +class ExtractThumbnail(publish.Extractor): """Extract viewport thumbnail. Takes review camera and creates a thumbnail based on viewport From 7fe1473dde672e83dc62236d697cc70bd0feebc9 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 21 Feb 2023 00:13:53 +0300 Subject: [PATCH 040/133] disable root toggle, rename settings --- .../defaults/project_settings/fusion.json | 2 +- .../projects_schema/schema_project_fusion.json | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/openpype/settings/defaults/project_settings/fusion.json b/openpype/settings/defaults/project_settings/fusion.json index 74863ece43..97c1c52579 100644 --- a/openpype/settings/defaults/project_settings/fusion.json +++ b/openpype/settings/defaults/project_settings/fusion.json @@ -18,8 +18,8 @@ } }, "copy_fusion_settings": { + "copy_path": "~/.openpype/hosts/fusion/profiles", "copy_status": false, - "copy_path": "~/.openpype/hosts/fusion/prefs", "force_sync": false } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json index 540f840aad..464cf2c06d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json @@ -50,23 +50,22 @@ "type": "dict", "key": "copy_fusion_settings", "collapsible": true, - "checkbox_key": "copy_status", - "label": "Copy Fusion settings on launch", + "label": "Local Fusion profile settings", "children": [ - { - "type": "boolean", - "key": "copy_status", - "label": "Enabled" - }, { "key": "copy_path", "type": "path", - "label": "Local prefs directory" + "label": "Local Fusion profile directory" + }, + { + "type": "boolean", + "key": "copy_status", + "label": "Copy profile on first launch" }, { "key":"force_sync", "type": "boolean", - "label": "Force sync preferences" + "label": "Resync profile on each launch" } ] } From 7466f576ba9d8c1ca37b272320ae47c251018ca5 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 21 Feb 2023 00:14:17 +0300 Subject: [PATCH 041/133] remove redundant import --- openpype/hosts/fusion/api/workio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index f51c4fa9c1..fbb5a588f4 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -2,7 +2,7 @@ import sys import os -from .lib import get_fusion_module, get_current_comp, get_comp_filename +from .lib import get_fusion_module, get_current_comp def file_extensions(): From 1235894970870e0317a3c275c4acbea52504c762 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 21 Feb 2023 02:41:32 +0300 Subject: [PATCH 042/133] copy all fusion pref files, update docs --- .../hosts/fusion/hooks/pre_fusion_setup.py | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index ad2ec7eb2d..949f86d981 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -17,35 +17,40 @@ class FusionPrelaunch(PreLaunchHook): as set in openpype/hosts/fusion/deploy/fusion_shared.prefs to enable the OpenPype menu and force Python 3 over Python 2. + PROFILE_NUMBER is used because from the Fusion v16 the profile folder + is project-specific, but then it was abandoned by devs, + and despite it is already Fusion version 18, still FUSION16_PROFILE_DIR is used. + The variable is added in case the version number will be updated or deleted + so we could easily change the version or disable it. """ app_groups = ["fusion"] PROFILE_NUMBER = 16 + def get_fusion_profile_name(self) -> str: """usually set to 'Default', unless FUSION16_PROFILE is set""" return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") def get_profile_source(self) -> Path: """Get the Fusion preferences (profile) location. - Check https://www.steakunderwater.com/VFXPedia/96.0.243.189/indexad6a.html?title=Per-User_Preferences_and_Paths for reference. + Check Per-User_Preferences_and_Paths on VFXpedia for reference. """ fusion_profile = self.get_fusion_profile_name() fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") - # if FUSION16_PROFILE_DIR variable exists, return the profile filepath + # if FUSION16_PROFILE_DIR variable exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) self.log.info(f"Local Fusion prefs environment is set to {fusion_prefs_dir}") - fusion_prefs_filepath = fusion_prefs_dir / "Fusion.prefs" - return fusion_prefs_filepath - # otherwise get the profile from default prefs location - fusion_prefs_path = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}/Fusion.prefs" + return fusion_prefs_dir + # otherwise get the profile folder from default location + fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" if platform.system() == "Windows": - prefs_source = Path(os.getenv("AppData"), fusion_prefs_path) + prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) elif platform.system() == "Darwin": - prefs_source = Path("~/Library/Application Support/", fusion_prefs_path).expanduser() + prefs_source = Path("~/Library/Application Support/", fusion_prefs_dir).expanduser() elif platform.system() == "Linux": - prefs_source = Path("~/.fusion", fusion_prefs_path).expanduser() + prefs_source = Path("~/.fusion", fusion_prefs_dir).expanduser() self.log.info(f"Got Fusion prefs file: {prefs_source}") return prefs_source @@ -67,10 +72,11 @@ class FusionPrelaunch(PreLaunchHook): return copy_status, copy_path, force_sync def copy_existing_prefs(self, copy_from: Path, copy_to: Path, force_sync: bool) -> None: - """On the first Fusion launch copy the Fusion profile to the working directory. - If the Openpype profile folder exists, skip copying, unless Force sync is checked. - If the prefs were not copied on the first launch, clean Fusion profile - will be created in fusion_profile_dir. + """On the first Fusion launch copy the contents of Fusion profile directory + to the working predefined location. If the Openpype profile folder exists, + skip copying, unless re-sync is checked. + If the prefs were not copied on the first launch, + clean Fusion profile will be created in fusion_profile_dir. """ if copy_to.exists() and not force_sync: self.log.info("Local Fusion preferences folder exists, skipping profile copy") @@ -82,7 +88,10 @@ class FusionPrelaunch(PreLaunchHook): if not copy_from.exists(): self.log.warning(f"Fusion preferences file not found in {copy_from}") return - shutil.copy(str(copy_from), str(dest_folder)) # compatible with Python >= 3.6 + for file in copy_from.iterdir(): + if file.suffix in (".prefs", ".def", ".blocklist", "fu"): + # convert Path to str to be compatible with Python 3.6 and above + shutil.copy(str(file), str(dest_folder)) self.log.info(f"successfully copied preferences:\n {copy_from} to {dest_folder}") def execute(self): @@ -93,8 +102,9 @@ class FusionPrelaunch(PreLaunchHook): fusion_python3_home = self.launch_context.env.get(py3_var, "") for path in fusion_python3_home.split(os.pathsep): - # Allow defining multiple paths, separated by os.pathsep, to allow "fallback" to other - # path. But make to set only a single path as final variable. + # Allow defining multiple paths, separated by os.pathsep, + # to allow "fallback" to other path. + # But make to set only a single path as final variable. py3_dir = os.path.normpath(path) if os.path.isdir(py3_dir): self.log.info(f"Looking for Python 3 in: {py3_dir}") @@ -119,8 +129,9 @@ class FusionPrelaunch(PreLaunchHook): # TODO: Detect Fusion version to only set for specific Fusion build self.launch_context.env[f"FUSION{self.PROFILE_NUMBER}_PYTHON36_HOME"] = py3_dir - # Add custom Fusion Master Prefs and the temporary profile directory variables - # to customize Fusion to define where it can read custom scripts and tools from + # Add custom Fusion Master Prefs and the temporary + # profile directory variables to customize Fusion + # to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR From 2d6cc7788199c26e338ab6e960aef1fc25caca9b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 21 Feb 2023 02:42:36 +0300 Subject: [PATCH 043/133] fle formatting --- .../hosts/fusion/hooks/pre_fusion_setup.py | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 949f86d981..3f521bb60d 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -17,16 +17,16 @@ class FusionPrelaunch(PreLaunchHook): as set in openpype/hosts/fusion/deploy/fusion_shared.prefs to enable the OpenPype menu and force Python 3 over Python 2. - PROFILE_NUMBER is used because from the Fusion v16 the profile folder + PROFILE_NUMBER is used because from the Fusion v16 the profile folder is project-specific, but then it was abandoned by devs, and despite it is already Fusion version 18, still FUSION16_PROFILE_DIR is used. The variable is added in case the version number will be updated or deleted so we could easily change the version or disable it. """ + app_groups = ["fusion"] PROFILE_NUMBER = 16 - def get_fusion_profile_name(self) -> str: """usually set to 'Default', unless FUSION16_PROFILE is set""" return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") @@ -41,14 +41,18 @@ class FusionPrelaunch(PreLaunchHook): # if FUSION16_PROFILE_DIR variable exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) - self.log.info(f"Local Fusion prefs environment is set to {fusion_prefs_dir}") + self.log.info( + f"Local Fusion prefs environment is set to {fusion_prefs_dir}" + ) return fusion_prefs_dir # otherwise get the profile folder from default location fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) elif platform.system() == "Darwin": - prefs_source = Path("~/Library/Application Support/", fusion_prefs_dir).expanduser() + prefs_source = Path( + "~/Library/Application Support/", fusion_prefs_dir + ).expanduser() elif platform.system() == "Linux": prefs_source = Path("~/.fusion", fusion_prefs_dir).expanduser() self.log.info(f"Got Fusion prefs file: {prefs_source}") @@ -56,11 +60,8 @@ class FusionPrelaunch(PreLaunchHook): def get_copy_fusion_prefs_settings(self): """Get copy prefserences options from the global application settings""" - copy_fusion_settings = ( - self.data - ["project_settings"] - ["fusion"] - .get("copy_fusion_settings", {}) + copy_fusion_settings = self.data["project_settings"]["fusion"].get( + "copy_fusion_settings", {} ) if not copy_fusion_settings: self.log.error("Copy prefs settings not found") @@ -71,7 +72,9 @@ class FusionPrelaunch(PreLaunchHook): copy_path = Path(copy_path).expanduser() return copy_status, copy_path, force_sync - def copy_existing_prefs(self, copy_from: Path, copy_to: Path, force_sync: bool) -> None: + def copy_existing_prefs( + self, copy_from: Path, copy_to: Path, force_sync: bool + ) -> None: """On the first Fusion launch copy the contents of Fusion profile directory to the working predefined location. If the Openpype profile folder exists, skip copying, unless re-sync is checked. @@ -79,21 +82,25 @@ class FusionPrelaunch(PreLaunchHook): clean Fusion profile will be created in fusion_profile_dir. """ if copy_to.exists() and not force_sync: - self.log.info("Local Fusion preferences folder exists, skipping profile copy") + self.log.info( + "Local Fusion preferences folder exists, skipping profile copy" + ) return self.log.info(f"Starting copying Fusion preferences") self.log.info(f"force_sync option is set to {force_sync}") dest_folder = copy_to / self.get_fusion_profile_name() - dest_folder.mkdir(exist_ok=True, parents=True) + dest_folder.mkdir(exist_ok=True, parents=True) if not copy_from.exists(): self.log.warning(f"Fusion preferences file not found in {copy_from}") return for file in copy_from.iterdir(): if file.suffix in (".prefs", ".def", ".blocklist", "fu"): # convert Path to str to be compatible with Python 3.6 and above - shutil.copy(str(file), str(dest_folder)) - self.log.info(f"successfully copied preferences:\n {copy_from} to {dest_folder}") - + shutil.copy(str(file), str(dest_folder)) + self.log.info( + f"successfully copied preferences:\n {copy_from} to {dest_folder}" + ) + def execute(self): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 @@ -102,7 +109,7 @@ class FusionPrelaunch(PreLaunchHook): fusion_python3_home = self.launch_context.env.get(py3_var, "") for path in fusion_python3_home.split(os.pathsep): - # Allow defining multiple paths, separated by os.pathsep, + # Allow defining multiple paths, separated by os.pathsep, # to allow "fallback" to other path. # But make to set only a single path as final variable. py3_dir = os.path.normpath(path) @@ -135,7 +142,11 @@ class FusionPrelaunch(PreLaunchHook): self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - copy_status, fusion_profile_dir, force_sync = self.get_copy_fusion_prefs_settings() + ( + copy_status, + fusion_profile_dir, + force_sync, + ) = self.get_copy_fusion_prefs_settings() if copy_status: prefs_source = self.get_profile_source() self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) From 04c40b6c727fa7320360eb97dfddf5bf065095f0 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 2 Mar 2023 19:10:18 +0300 Subject: [PATCH 044/133] check if local profile folder exists, cleanup a bit --- .../hosts/fusion/hooks/pre_fusion_setup.py | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index f7b5e684cb..19d59d3806 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -17,26 +17,26 @@ class FusionPrelaunch(PreLaunchHook): as set in openpype/hosts/fusion/deploy/fusion_shared.prefs to enable the OpenPype menu and force Python 3 over Python 2. - PROFILE_NUMBER is used because from the Fusion v16 the profile folder + VERSION variable is used because from the Fusion v16 the profile folder is project-specific, but then it was abandoned by devs, - and despite it is already Fusion version 18, still FUSION16_PROFILE_DIR is used. - The variable is added in case the version number will be updated or deleted - so we could easily change the version or disable it. + and despite it is already Fusion version 18, still FUSION16_PROFILE_DIR + is used. The variable is added in case the version number will be + updated or deleted so we could easily change the version or disable it. """ app_groups = ["fusion"] - PROFILE_NUMBER = 16 + VERSION = 16 def get_fusion_profile_name(self) -> str: """usually set to 'Default', unless FUSION16_PROFILE is set""" - return os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE", "Default") + return os.getenv(f"FUSION{self.VERSION}_PROFILE", "Default") def get_profile_source(self) -> Path: """Get the Fusion preferences (profile) location. Check Per-User_Preferences_and_Paths on VFXpedia for reference. """ fusion_profile = self.get_fusion_profile_name() - fusion_var_prefs_dir = os.getenv(f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR") + fusion_var_prefs_dir = os.getenv(f"FUSION{self.VERSION}_PROFILE_DIR") # if FUSION16_PROFILE_DIR variable exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): @@ -46,7 +46,7 @@ class FusionPrelaunch(PreLaunchHook): ) return fusion_prefs_dir # otherwise get the profile folder from default location - fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" + fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" #noqa if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) elif platform.system() == "Darwin": @@ -59,7 +59,7 @@ class FusionPrelaunch(PreLaunchHook): return prefs_source def get_copy_fusion_prefs_settings(self): - """Get copy prefserences options from the global application settings""" + """Get copy preferences options from the global application settings""" copy_fusion_settings = self.data["project_settings"]["fusion"].get( "copy_fusion_settings", {} ) @@ -75,9 +75,9 @@ class FusionPrelaunch(PreLaunchHook): def copy_existing_prefs( self, copy_from: Path, copy_to: Path, force_sync: bool ) -> None: - """On the first Fusion launch copy the contents of Fusion profile directory - to the working predefined location. If the Openpype profile folder exists, - skip copying, unless re-sync is checked. + """On the first Fusion launch copy the contents of Fusion profile + directory to the working predefined location. If the Openpype profile + folder exists, skip copying, unless re-sync is checked. If the prefs were not copied on the first launch, clean Fusion profile will be created in fusion_profile_dir. """ @@ -89,13 +89,17 @@ class FusionPrelaunch(PreLaunchHook): self.log.info(f"Starting copying Fusion preferences") self.log.info(f"force_sync option is set to {force_sync}") dest_folder = copy_to / self.get_fusion_profile_name() - dest_folder.mkdir(exist_ok=True, parents=True) + try: + dest_folder.mkdir(exist_ok=True, parents=True) + except Exception: + self.log.warn(f"Could not create folder at {dest_folder}") + return if not copy_from.exists(): - self.log.warning(f"Fusion preferences file not found in {copy_from}") + self.log.warning(f"Fusion preferences not found in {copy_from}") return for file in copy_from.iterdir(): - if file.suffix in (".prefs", ".def", ".blocklist", "fu"): - # convert Path to str to be compatible with Python 3.6 and above + if file.suffix in (".prefs", ".def", ".blocklist", ".fu"): + # convert Path to str to be compatible with Python 3.6+ shutil.copy(str(file), str(dest_folder)) self.log.info( f"successfully copied preferences:\n {copy_from} to {dest_folder}" @@ -134,26 +138,26 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env[f"FUSION{self.PROFILE_NUMBER}_PYTHON36_HOME"] = py3_dir + self.launch_context.env[f"FUSION{self.VERSION}_PYTHON36_HOME"] = py3_dir #noqa # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion # to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - ( copy_status, fusion_profile_dir, force_sync, ) = self.get_copy_fusion_prefs_settings() - if copy_status: + if copy_status and fusion_profile_dir is not None: prefs_source = self.get_profile_source() - self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) - fusion_profile_dir_variable = f"FUSION{self.PROFILE_NUMBER}_PROFILE_DIR" - master_prefs_variable = f"FUSION{self.PROFILE_NUMBER}_MasterPrefs" + self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) #noqa + else: + fusion_profile_dir_variable = f"FUSION{self.VERSION}_PROFILE_DIR" + self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") #noqa + self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) #noqa + master_prefs_variable = f"FUSION{self.VERSION}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") - self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") - self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") self.launch_context.env[master_prefs_variable] = str(master_prefs) From 997351bfe2ded1e44d76f5d7bf6fecf5771c7105 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 2 Mar 2023 19:16:44 +0300 Subject: [PATCH 045/133] tame the hound --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 19d59d3806..129aadf1a5 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -46,7 +46,7 @@ class FusionPrelaunch(PreLaunchHook): ) return fusion_prefs_dir # otherwise get the profile folder from default location - fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" #noqa + fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" # noqa if platform.system() == "Windows": prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) elif platform.system() == "Darwin": @@ -138,7 +138,7 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env[f"FUSION{self.VERSION}_PYTHON36_HOME"] = py3_dir #noqa + self.launch_context.env[f"FUSION{self.VERSION}_PYTHON36_HOME"] = py3_dir # noqa # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion @@ -152,11 +152,11 @@ class FusionPrelaunch(PreLaunchHook): ) = self.get_copy_fusion_prefs_settings() if copy_status and fusion_profile_dir is not None: prefs_source = self.get_profile_source() - self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) #noqa + self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) # noqa else: fusion_profile_dir_variable = f"FUSION{self.VERSION}_PROFILE_DIR" - self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") #noqa - self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) #noqa + self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa + self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa master_prefs_variable = f"FUSION{self.VERSION}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") From 7c9c2864c51a58d7dcb4768d5483fcf35615c3e9 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Sat, 4 Mar 2023 15:41:49 +0300 Subject: [PATCH 046/133] add up to 3 decimals to fps allows input 23.976 to the FPS settings both in Project Manager and the Project Anatomy. --- .../schemas/schema_anatomy_attributes.json | 2 +- .../project_manager/project_manager/delegates.py | 5 ++++- .../tools/project_manager/project_manager/view.py | 14 ++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_attributes.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_attributes.json index 3667c9d5d8..a728024376 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_attributes.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_attributes.json @@ -10,7 +10,7 @@ "type": "number", "key": "fps", "label": "Frame Rate", - "decimal": 2, + "decimal": 3, "minimum": 0 }, { diff --git a/openpype/tools/project_manager/project_manager/delegates.py b/openpype/tools/project_manager/project_manager/delegates.py index 79e9554b0f..023dd668ec 100644 --- a/openpype/tools/project_manager/project_manager/delegates.py +++ b/openpype/tools/project_manager/project_manager/delegates.py @@ -83,15 +83,18 @@ class NumberDelegate(QtWidgets.QStyledItemDelegate): decimals(int): How many decimal points can be used. Float will be used as value if is higher than 0. """ - def __init__(self, minimum, maximum, decimals, *args, **kwargs): + def __init__(self, minimum, maximum, decimals, step, *args, **kwargs): super(NumberDelegate, self).__init__(*args, **kwargs) self.minimum = minimum self.maximum = maximum self.decimals = decimals + self.step = step def createEditor(self, parent, option, index): if self.decimals > 0: editor = DoubleSpinBoxScrollFixed(parent) + editor.setSingleStep(self.step) + editor.setDecimals(self.decimals) else: editor = SpinBoxScrollFixed(parent) diff --git a/openpype/tools/project_manager/project_manager/view.py b/openpype/tools/project_manager/project_manager/view.py index fa08943ea5..0dd04aa7b9 100644 --- a/openpype/tools/project_manager/project_manager/view.py +++ b/openpype/tools/project_manager/project_manager/view.py @@ -26,10 +26,11 @@ class NameDef: class NumberDef: - def __init__(self, minimum=None, maximum=None, decimals=None): + def __init__(self, minimum=None, maximum=None, decimals=None, step=None): self.minimum = 0 if minimum is None else minimum self.maximum = 999999999 if maximum is None else maximum self.decimals = 0 if decimals is None else decimals + self.step = 1 if decimals is None else step class TypeDef: @@ -73,14 +74,14 @@ class HierarchyView(QtWidgets.QTreeView): "type": TypeDef(), "frameStart": NumberDef(1), "frameEnd": NumberDef(1), - "fps": NumberDef(1, decimals=2), + "fps": NumberDef(1, decimals=3, step=0.01), "resolutionWidth": NumberDef(0), "resolutionHeight": NumberDef(0), "handleStart": NumberDef(0), "handleEnd": NumberDef(0), "clipIn": NumberDef(1), "clipOut": NumberDef(1), - "pixelAspect": NumberDef(0, decimals=2), + "pixelAspect": NumberDef(0, decimals=2, step=0.1), "tools_env": ToolsDef() } @@ -96,6 +97,10 @@ class HierarchyView(QtWidgets.QTreeView): "stretch": QtWidgets.QHeaderView.Interactive, "width": 140 }, + "fps": { + "stretch": QtWidgets.QHeaderView.Interactive, + "width": 65 + }, "tools_env": { "stretch": QtWidgets.QHeaderView.Interactive, "width": 200 @@ -148,7 +153,8 @@ class HierarchyView(QtWidgets.QTreeView): delegate = NumberDelegate( item_type.minimum, item_type.maximum, - item_type.decimals + item_type.decimals, + item_type.step ) elif isinstance(item_type, TypeDef): From 384d928d854d086fea75a4ae418e1d81357879d1 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Sat, 4 Mar 2023 22:19:58 +0300 Subject: [PATCH 047/133] set fps and pixel aspect precision steps default values --- openpype/tools/project_manager/project_manager/view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/project_manager/project_manager/view.py b/openpype/tools/project_manager/project_manager/view.py index 0dd04aa7b9..b35491c5b2 100644 --- a/openpype/tools/project_manager/project_manager/view.py +++ b/openpype/tools/project_manager/project_manager/view.py @@ -74,14 +74,14 @@ class HierarchyView(QtWidgets.QTreeView): "type": TypeDef(), "frameStart": NumberDef(1), "frameEnd": NumberDef(1), - "fps": NumberDef(1, decimals=3, step=0.01), + "fps": NumberDef(1, decimals=3, step=1), "resolutionWidth": NumberDef(0), "resolutionHeight": NumberDef(0), "handleStart": NumberDef(0), "handleEnd": NumberDef(0), "clipIn": NumberDef(1), "clipOut": NumberDef(1), - "pixelAspect": NumberDef(0, decimals=2, step=0.1), + "pixelAspect": NumberDef(0, decimals=2, step=0.01), "tools_env": ToolsDef() } From 962984d29614a7ba7d86f391ba61013a871947f9 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Wed, 8 Mar 2023 02:04:54 +0300 Subject: [PATCH 048/133] add separate fusion profile hook --- openpype/hosts/fusion/__init__.py | 2 + openpype/hosts/fusion/addon.py | 9 ++ .../fusion/hooks/pre_fusion_profile_hook.py | 109 ++++++++++++++++++ .../hosts/fusion/hooks/pre_fusion_setup.py | 105 +---------------- 4 files changed, 125 insertions(+), 100 deletions(-) create mode 100644 openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py diff --git a/openpype/hosts/fusion/__init__.py b/openpype/hosts/fusion/__init__.py index ddae01890b..baaaa9d6fc 100644 --- a/openpype/hosts/fusion/__init__.py +++ b/openpype/hosts/fusion/__init__.py @@ -1,10 +1,12 @@ from .addon import ( FusionAddon, FUSION_HOST_DIR, + FUSION_PROFILE_VERSION ) __all__ = ( "FusionAddon", "FUSION_HOST_DIR", + "FUSION_PROFILE_VERSION" ) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index d1bd1566b7..777c38629a 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -3,6 +3,15 @@ from openpype.modules import OpenPypeModule, IHostAddon FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) +FUSION_PROFILE_VERSION = 16 + +# FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. +# Since Fusion v16, the profile folder became project-specific, +# but then it was abandoned by BlackmagicDesign devs, and now, despite it is +# already Fusion version 18, still FUSION16_PROFILE_DIR is used. +# The variable is added in case the version number will be +# updated or deleted so we could easily change the version or disable it. + class FusionAddon(OpenPypeModule, IHostAddon): name = "fusion" diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py new file mode 100644 index 0000000000..4af67c1c0d --- /dev/null +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -0,0 +1,109 @@ +import os +import shutil +import platform +from pathlib import Path +from openpype.lib import PreLaunchHook, ApplicationLaunchFailed +from openpype.hosts.fusion import FUSION_PROFILE_VERSION as VERSION + + +class FusionCopyPrefsPrelaunch(PreLaunchHook): + """Prepares local Fusion profile directory, copies existing Fusion profile + """ + + app_groups = ["fusion"] + + def get_fusion_profile_name(self) -> str: + """usually set to 'Default', unless FUSION16_PROFILE is set""" + return os.getenv(f"FUSION{VERSION}_PROFILE", "Default") + + def get_profile_source(self) -> Path: + """Get the Fusion preferences (profile) location. + Check Per-User_Preferences_and_Paths on VFXpedia for reference. + """ + fusion_profile = self.get_fusion_profile_name() + fusion_var_prefs_dir = os.getenv(f"FUSION{VERSION}_PROFILE_DIR") + + # if FUSION16_PROFILE_DIR variable exists + if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): + fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) + self.log.info( + f"Local Fusion prefs environment is set to {fusion_prefs_dir}" + ) + return fusion_prefs_dir + # otherwise get the profile folder from default location + fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" # noqa + if platform.system() == "Windows": + prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) + elif platform.system() == "Darwin": + prefs_source = Path( + "~/Library/Application Support/", fusion_prefs_dir + ).expanduser() + elif platform.system() == "Linux": + prefs_source = Path("~/.fusion", fusion_prefs_dir).expanduser() + self.log.info(f"Got Fusion prefs file: {prefs_source}") + return prefs_source + + def get_copy_fusion_prefs_settings(self): + """Get copy preferences options from the global application settings""" + copy_fusion_settings = self.data["project_settings"]["fusion"].get( + "copy_fusion_settings", {} + ) + if not copy_fusion_settings: + self.log.error("Copy prefs settings not found") + copy_status = copy_fusion_settings.get("copy_status", False) + force_sync = copy_fusion_settings.get("force_sync", False) + copy_path = copy_fusion_settings.get("copy_path") or None + if copy_path: + copy_path = Path(copy_path).expanduser() + return copy_status, copy_path, force_sync + + def copy_existing_prefs( + self, copy_from: Path, copy_to: Path, force_sync: bool + ) -> None: + """On the first Fusion launch copy the contents of Fusion profile + directory to the working predefined location. If the Openpype profile + folder exists, skip copying, unless re-sync is checked. + If the prefs were not copied on the first launch, + clean Fusion profile will be created in fusion_profile_dir. + """ + if copy_to.exists() and not force_sync: + self.log.info( + "Local Fusion preferences folder exists, skipping profile copy" + ) + return + self.log.info(f"Starting copying Fusion preferences") + self.log.info(f"force_sync option is set to {force_sync}") + dest_folder = copy_to / self.get_fusion_profile_name() + try: + dest_folder.mkdir(exist_ok=True, parents=True) + except Exception: + self.log.warn(f"Could not create folder at {dest_folder}") + return + if not copy_from.exists(): + self.log.warning(f"Fusion preferences not found in {copy_from}") + return + for file in copy_from.iterdir(): + if file.suffix in (".prefs", ".def", ".blocklist", ".fu"): + # convert Path to str to be compatible with Python 3.6+ + shutil.copy(str(file), str(dest_folder)) + self.log.info( + f"successfully copied preferences:\n {copy_from} to {dest_folder}" + ) + + def execute(self): + ( + copy_status, + fusion_profile_dir, + force_sync, + ) = self.get_copy_fusion_prefs_settings() + + # do a copy of Fusion profile if copy_status toggle is enabled + if copy_status and fusion_profile_dir is not None: + prefs_source = self.get_profile_source() + self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) # noqa + + # Add temporary profile directory variables to customize Fusion + # to define where it can read custom scripts and tools from + fusion_profile_dir_variable = f"FUSION{VERSION}_PROFILE_DIR" + self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa + self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa \ No newline at end of file diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 129aadf1a5..bce221d357 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -4,6 +4,7 @@ import platform from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR +from openpype.hosts.fusion import FUSION_PROFILE_VERSION as VERSION class FusionPrelaunch(PreLaunchHook): @@ -16,94 +17,9 @@ class FusionPrelaunch(PreLaunchHook): This also sets FUSION16_MasterPrefs to apply the fusion master prefs as set in openpype/hosts/fusion/deploy/fusion_shared.prefs to enable the OpenPype menu and force Python 3 over Python 2. - - VERSION variable is used because from the Fusion v16 the profile folder - is project-specific, but then it was abandoned by devs, - and despite it is already Fusion version 18, still FUSION16_PROFILE_DIR - is used. The variable is added in case the version number will be - updated or deleted so we could easily change the version or disable it. """ app_groups = ["fusion"] - VERSION = 16 - - def get_fusion_profile_name(self) -> str: - """usually set to 'Default', unless FUSION16_PROFILE is set""" - return os.getenv(f"FUSION{self.VERSION}_PROFILE", "Default") - - def get_profile_source(self) -> Path: - """Get the Fusion preferences (profile) location. - Check Per-User_Preferences_and_Paths on VFXpedia for reference. - """ - fusion_profile = self.get_fusion_profile_name() - fusion_var_prefs_dir = os.getenv(f"FUSION{self.VERSION}_PROFILE_DIR") - - # if FUSION16_PROFILE_DIR variable exists - if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): - fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) - self.log.info( - f"Local Fusion prefs environment is set to {fusion_prefs_dir}" - ) - return fusion_prefs_dir - # otherwise get the profile folder from default location - fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" # noqa - if platform.system() == "Windows": - prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) - elif platform.system() == "Darwin": - prefs_source = Path( - "~/Library/Application Support/", fusion_prefs_dir - ).expanduser() - elif platform.system() == "Linux": - prefs_source = Path("~/.fusion", fusion_prefs_dir).expanduser() - self.log.info(f"Got Fusion prefs file: {prefs_source}") - return prefs_source - - def get_copy_fusion_prefs_settings(self): - """Get copy preferences options from the global application settings""" - copy_fusion_settings = self.data["project_settings"]["fusion"].get( - "copy_fusion_settings", {} - ) - if not copy_fusion_settings: - self.log.error("Copy prefs settings not found") - copy_status = copy_fusion_settings.get("copy_status", False) - force_sync = copy_fusion_settings.get("force_sync", False) - copy_path = copy_fusion_settings.get("copy_path") or None - if copy_path: - copy_path = Path(copy_path).expanduser() - return copy_status, copy_path, force_sync - - def copy_existing_prefs( - self, copy_from: Path, copy_to: Path, force_sync: bool - ) -> None: - """On the first Fusion launch copy the contents of Fusion profile - directory to the working predefined location. If the Openpype profile - folder exists, skip copying, unless re-sync is checked. - If the prefs were not copied on the first launch, - clean Fusion profile will be created in fusion_profile_dir. - """ - if copy_to.exists() and not force_sync: - self.log.info( - "Local Fusion preferences folder exists, skipping profile copy" - ) - return - self.log.info(f"Starting copying Fusion preferences") - self.log.info(f"force_sync option is set to {force_sync}") - dest_folder = copy_to / self.get_fusion_profile_name() - try: - dest_folder.mkdir(exist_ok=True, parents=True) - except Exception: - self.log.warn(f"Could not create folder at {dest_folder}") - return - if not copy_from.exists(): - self.log.warning(f"Fusion preferences not found in {copy_from}") - return - for file in copy_from.iterdir(): - if file.suffix in (".prefs", ".def", ".blocklist", ".fu"): - # convert Path to str to be compatible with Python 3.6+ - shutil.copy(str(file), str(dest_folder)) - self.log.info( - f"successfully copied preferences:\n {copy_from} to {dest_folder}" - ) def execute(self): # making sure python 3 is installed at provided path @@ -138,26 +54,15 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env[f"FUSION{self.VERSION}_PYTHON36_HOME"] = py3_dir # noqa + self.launch_context.env[f"FUSION{VERSION}_PYTHON36_HOME"] = py3_dir # noqa # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion # to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - ( - copy_status, - fusion_profile_dir, - force_sync, - ) = self.get_copy_fusion_prefs_settings() - if copy_status and fusion_profile_dir is not None: - prefs_source = self.get_profile_source() - self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) # noqa - else: - fusion_profile_dir_variable = f"FUSION{self.VERSION}_PROFILE_DIR" - self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa - self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa - master_prefs_variable = f"FUSION{self.VERSION}_MasterPrefs" + + master_prefs_variable = f"FUSION{VERSION}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") - self.launch_context.env[master_prefs_variable] = str(master_prefs) + self.launch_context.env[master_prefs_variable] = str(master_prefs) \ No newline at end of file From e1950a175fbb1a58a1ffeea9ad7620e1a2d05d02 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Wed, 8 Mar 2023 02:11:57 +0300 Subject: [PATCH 049/133] hound comments --- openpype/hosts/fusion/addon.py | 2 +- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 4 ++-- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 777c38629a..6621f88056 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -5,7 +5,7 @@ FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) FUSION_PROFILE_VERSION = 16 -# FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. +# FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. # Since Fusion v16, the profile folder became project-specific, # but then it was abandoned by BlackmagicDesign devs, and now, despite it is # already Fusion version 18, still FUSION16_PROFILE_DIR is used. diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 4af67c1c0d..b91c699cc3 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -2,7 +2,7 @@ import os import shutil import platform from pathlib import Path -from openpype.lib import PreLaunchHook, ApplicationLaunchFailed +from openpype.lib import PreLaunchHook from openpype.hosts.fusion import FUSION_PROFILE_VERSION as VERSION @@ -11,7 +11,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] - + def get_fusion_profile_name(self) -> str: """usually set to 'Default', unless FUSION16_PROFILE is set""" return os.getenv(f"FUSION{VERSION}_PROFILE", "Default") diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index bce221d357..e62c2d7ab7 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -1,6 +1,4 @@ import os -import shutil -import platform from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR From 39e694374626544f7dce258c86c5ac2809a0cf19 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Wed, 8 Mar 2023 02:35:00 +0300 Subject: [PATCH 050/133] hound comments --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 3 ++- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index b91c699cc3..e3a00a3e66 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -106,4 +106,5 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # to define where it can read custom scripts and tools from fusion_profile_dir_variable = f"FUSION{VERSION}_PROFILE_DIR" self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa - self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa \ No newline at end of file + self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa + \ No newline at end of file diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index e62c2d7ab7..ccad28401d 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -63,4 +63,5 @@ class FusionPrelaunch(PreLaunchHook): master_prefs_variable = f"FUSION{VERSION}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") - self.launch_context.env[master_prefs_variable] = str(master_prefs) \ No newline at end of file + self.launch_context.env[master_prefs_variable] = str(master_prefs) + \ No newline at end of file From a5e0e057db3aa1de71da3d24f75c6833c5219aa0 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Wed, 8 Mar 2023 02:37:59 +0300 Subject: [PATCH 051/133] good boy --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 1 - openpype/hosts/fusion/hooks/pre_fusion_setup.py | 1 - 2 files changed, 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index e3a00a3e66..7172809252 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -107,4 +107,3 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): fusion_profile_dir_variable = f"FUSION{VERSION}_PROFILE_DIR" self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa - \ No newline at end of file diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index ccad28401d..c39b9cd150 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -64,4 +64,3 @@ class FusionPrelaunch(PreLaunchHook): master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") self.launch_context.env[master_prefs_variable] = str(master_prefs) - \ No newline at end of file From b7ac37701bfc24c69bde5e5fd7a853766d4cc87d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 9 Mar 2023 23:57:12 +0300 Subject: [PATCH 052/133] WIP get fusion host version (the wrong way) --- openpype/hosts/fusion/__init__.py | 4 +- openpype/hosts/fusion/addon.py | 33 +++++-- .../fusion/hooks/pre_fusion_profile_hook.py | 91 +++++++++++-------- .../hosts/fusion/hooks/pre_fusion_setup.py | 9 +- 4 files changed, 87 insertions(+), 50 deletions(-) diff --git a/openpype/hosts/fusion/__init__.py b/openpype/hosts/fusion/__init__.py index baaaa9d6fc..f0e7843fff 100644 --- a/openpype/hosts/fusion/__init__.py +++ b/openpype/hosts/fusion/__init__.py @@ -1,12 +1,12 @@ from .addon import ( + get_fusion_profile_number, FusionAddon, FUSION_HOST_DIR, - FUSION_PROFILE_VERSION ) __all__ = ( + "get_fusion_profile_number", "FusionAddon", "FUSION_HOST_DIR", - "FUSION_PROFILE_VERSION" ) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 6621f88056..4b0ce59aaf 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -1,16 +1,35 @@ import os +import re from openpype.modules import OpenPypeModule, IHostAddon +from openpype.lib import Logger FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -FUSION_PROFILE_VERSION = 16 -# FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. -# Since Fusion v16, the profile folder became project-specific, -# but then it was abandoned by BlackmagicDesign devs, and now, despite it is -# already Fusion version 18, still FUSION16_PROFILE_DIR is used. -# The variable is added in case the version number will be -# updated or deleted so we could easily change the version or disable it. +def get_fusion_profile_number(module: str, app_data: str) -> int: + """ + FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. + Since Fusion v16, the profile folder variable became version-specific, + but then it was abandoned by BlackmagicDesign devs, and now, despite it is + already Fusion version 18, still FUSION16_PROFILE_DIR is used. + The variable is added in case the version number will be + updated or deleted so we could easily change the version or disable it. + """ + + log = Logger.get_logger(__name__) + + if not app_data: + return + fusion16_profile_versions = ("16", "17", "18") + try: + app_version = re.search(r"fusion/(\d+)", app_data).group(1) + log.info(f"{module} found Fusion profile version: {app_version}") + if app_version in fusion16_profile_versions: + return 16 + elif app_version == "9": + return 9 + except AttributeError: + log.info("Fusion version was not found in the app data") class FusionAddon(OpenPypeModule, IHostAddon): diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 7172809252..356292c85b 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -2,8 +2,9 @@ import os import shutil import platform from pathlib import Path +from pprint import pprint from openpype.lib import PreLaunchHook -from openpype.hosts.fusion import FUSION_PROFILE_VERSION as VERSION +from openpype.hosts.fusion import get_fusion_profile_number class FusionCopyPrefsPrelaunch(PreLaunchHook): @@ -11,40 +12,49 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] + order = 2 + + def get_fusion_profile_name(self, app_version) -> str: + # Returns 'Default', unless FUSION16_PROFILE is set + return os.getenv(f"FUSION{app_version}_PROFILE", "Default") - def get_fusion_profile_name(self) -> str: - """usually set to 'Default', unless FUSION16_PROFILE is set""" - return os.getenv(f"FUSION{VERSION}_PROFILE", "Default") + def check_profile_variable(self, app_version) -> Path: + # Get FUSION_PROFILE_DIR variable + fusion_profile = self.get_fusion_profile_name(app_version) + fusion_var_prefs_dir = os.getenv(f"FUSION{app_version}_PROFILE_DIR") - def get_profile_source(self) -> Path: - """Get the Fusion preferences (profile) location. - Check Per-User_Preferences_and_Paths on VFXpedia for reference. - """ - fusion_profile = self.get_fusion_profile_name() - fusion_var_prefs_dir = os.getenv(f"FUSION{VERSION}_PROFILE_DIR") - - # if FUSION16_PROFILE_DIR variable exists + # Check if FUSION_PROFILE_DIR exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): - fusion_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) + fu_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) self.log.info( - f"Local Fusion prefs environment is set to {fusion_prefs_dir}" + f"{fusion_var_prefs_dir} is set to {fu_prefs_dir}" ) - return fusion_prefs_dir - # otherwise get the profile folder from default location - fusion_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" # noqa + return fu_prefs_dir + + def get_profile_source(self, app_version) -> Path: + """Get Fusion preferences profile location. + See Per-User_Preferences_and_Paths on VFXpedia for reference. + """ + fusion_profile = self.get_fusion_profile_name(app_version) + profile_source = self.check_profile_variable(app_version) + if profile_source: + return profile_source + # otherwise get default location of the profile folder + fu_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" if platform.system() == "Windows": - prefs_source = Path(os.getenv("AppData"), fusion_prefs_dir) + profile_source = Path(os.getenv("AppData"), fu_prefs_dir) elif platform.system() == "Darwin": - prefs_source = Path( - "~/Library/Application Support/", fusion_prefs_dir + profile_source = Path( + "~/Library/Application Support/", fu_prefs_dir ).expanduser() elif platform.system() == "Linux": - prefs_source = Path("~/.fusion", fusion_prefs_dir).expanduser() - self.log.info(f"Got Fusion prefs file: {prefs_source}") - return prefs_source + profile_source = Path("~/.fusion", fu_prefs_dir).expanduser() + self.log.info(f"Got Fusion prefs file: {profile_source}") + return profile_source def get_copy_fusion_prefs_settings(self): - """Get copy preferences options from the global application settings""" + # Get copy preferences options from the global application settings + copy_fusion_settings = self.data["project_settings"]["fusion"].get( "copy_fusion_settings", {} ) @@ -57,14 +67,14 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): copy_path = Path(copy_path).expanduser() return copy_status, copy_path, force_sync - def copy_existing_prefs( + def copy_fusion_profile( self, copy_from: Path, copy_to: Path, force_sync: bool ) -> None: """On the first Fusion launch copy the contents of Fusion profile directory to the working predefined location. If the Openpype profile folder exists, skip copying, unless re-sync is checked. If the prefs were not copied on the first launch, - clean Fusion profile will be created in fusion_profile_dir. + clean Fusion profile will be created in fu_profile_dir. """ if copy_to.exists() and not force_sync: self.log.info( @@ -73,11 +83,10 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): return self.log.info(f"Starting copying Fusion preferences") self.log.info(f"force_sync option is set to {force_sync}") - dest_folder = copy_to / self.get_fusion_profile_name() try: - dest_folder.mkdir(exist_ok=True, parents=True) + copy_to.mkdir(exist_ok=True, parents=True) except Exception: - self.log.warn(f"Could not create folder at {dest_folder}") + self.log.warn(f"Could not create folder at {copy_to}") return if not copy_from.exists(): self.log.warning(f"Fusion preferences not found in {copy_from}") @@ -85,25 +94,31 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): for file in copy_from.iterdir(): if file.suffix in (".prefs", ".def", ".blocklist", ".fu"): # convert Path to str to be compatible with Python 3.6+ - shutil.copy(str(file), str(dest_folder)) + shutil.copy(str(file), str(copy_to)) self.log.info( - f"successfully copied preferences:\n {copy_from} to {dest_folder}" + f"successfully copied preferences:\n {copy_from} to {copy_to}" ) def execute(self): ( copy_status, - fusion_profile_dir, + fu_profile_dir, force_sync, ) = self.get_copy_fusion_prefs_settings() + # Get launched application context and return correct app version + app_data = self.launch_context.env.get("AVALON_APP_NAME", "fusion/18") + app_version = get_fusion_profile_number(__name__, app_data) + fu_profile = self.get_fusion_profile_name(app_version) + # do a copy of Fusion profile if copy_status toggle is enabled - if copy_status and fusion_profile_dir is not None: - prefs_source = self.get_profile_source() - self.copy_existing_prefs(prefs_source, fusion_profile_dir, force_sync) # noqa + if copy_status and fu_profile_dir is not None: + profile_source = self.get_profile_source(app_version) + dest_folder = Path(fu_profile_dir, fu_profile) + self.copy_fusion_profile(profile_source, dest_folder, force_sync) # Add temporary profile directory variables to customize Fusion # to define where it can read custom scripts and tools from - fusion_profile_dir_variable = f"FUSION{VERSION}_PROFILE_DIR" - self.log.info(f"Setting {fusion_profile_dir_variable}: {fusion_profile_dir}") # noqa - self.launch_context.env[fusion_profile_dir_variable] = str(fusion_profile_dir) # noqa + fu_profile_dir_variable = f"FUSION{app_version}_PROFILE_DIR" + self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}") + self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index c39b9cd150..7139252d2f 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -2,7 +2,7 @@ import os from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR -from openpype.hosts.fusion import FUSION_PROFILE_VERSION as VERSION +from openpype.hosts.fusion import get_fusion_profile_number class FusionPrelaunch(PreLaunchHook): @@ -18,10 +18,13 @@ class FusionPrelaunch(PreLaunchHook): """ app_groups = ["fusion"] + order = 1 def execute(self): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 + app_data = self.launch_context.env.get("AVALON_APP_NAME", "fusion/18") + app_version = get_fusion_profile_number(__name__, app_data) py3_var = "FUSION_PYTHON3_HOME" fusion_python3_home = self.launch_context.env.get(py3_var, "") @@ -52,7 +55,7 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env[f"FUSION{VERSION}_PYTHON36_HOME"] = py3_dir # noqa + self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion @@ -60,7 +63,7 @@ class FusionPrelaunch(PreLaunchHook): self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - master_prefs_variable = f"FUSION{VERSION}_MasterPrefs" + master_prefs_variable = f"FUSION{app_version}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") self.launch_context.env[master_prefs_variable] = str(master_prefs) From d01114595645868da87baf337f8a8e84dabc682b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 10 Mar 2023 00:02:26 +0300 Subject: [PATCH 053/133] hound --- .../hosts/fusion/hooks/pre_fusion_profile_hook.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 356292c85b..4369935b49 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -2,7 +2,6 @@ import os import shutil import platform from pathlib import Path -from pprint import pprint from openpype.lib import PreLaunchHook from openpype.hosts.fusion import get_fusion_profile_number @@ -13,7 +12,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): app_groups = ["fusion"] order = 2 - + def get_fusion_profile_name(self, app_version) -> str: # Returns 'Default', unless FUSION16_PROFILE is set return os.getenv(f"FUSION{app_version}_PROFILE", "Default") @@ -39,8 +38,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): profile_source = self.check_profile_variable(app_version) if profile_source: return profile_source - # otherwise get default location of the profile folder - fu_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" + # otherwise get default location of the profile folder + fu_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}" if platform.system() == "Windows": profile_source = Path(os.getenv("AppData"), fu_prefs_dir) elif platform.system() == "Darwin": @@ -110,12 +109,12 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): app_data = self.launch_context.env.get("AVALON_APP_NAME", "fusion/18") app_version = get_fusion_profile_number(__name__, app_data) fu_profile = self.get_fusion_profile_name(app_version) - + # do a copy of Fusion profile if copy_status toggle is enabled if copy_status and fu_profile_dir is not None: profile_source = self.get_profile_source(app_version) dest_folder = Path(fu_profile_dir, fu_profile) - self.copy_fusion_profile(profile_source, dest_folder, force_sync) + self.copy_fusion_profile(profile_source, dest_folder, force_sync) # Add temporary profile directory variables to customize Fusion # to define where it can read custom scripts and tools from From a04f44dcf9e97ef3fd7d8a028c8334d15ffd850d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 10 Mar 2023 00:26:05 +0300 Subject: [PATCH 054/133] use FUSION_PYTHON36_HOME for Fusion 9 --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 7139252d2f..4c73a0eee3 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -55,15 +55,13 @@ class FusionPrelaunch(PreLaunchHook): # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version # TODO: Detect Fusion version to only set for specific Fusion build - self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir + if app_version == 9: + self.launch_context.env[f"FUSION_PYTHON36_HOME"] = py3_dir + elif app_version == 16: + self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion # to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR - - master_prefs_variable = f"FUSION{app_version}_MasterPrefs" - master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") - self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") - self.launch_context.env[master_prefs_variable] = str(master_prefs) From d586231aa11ec76fbde4c9357369d2ed0ffa40c5 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 10 Mar 2023 00:28:41 +0300 Subject: [PATCH 055/133] move masterprefs setup to the correct hook --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 4369935b49..543e90cc75 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -3,7 +3,7 @@ import shutil import platform from pathlib import Path from openpype.lib import PreLaunchHook -from openpype.hosts.fusion import get_fusion_profile_number +from openpype.hosts.fusion import FUSION_HOST_DIR, get_fusion_profile_number class FusionCopyPrefsPrelaunch(PreLaunchHook): @@ -121,3 +121,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): fu_profile_dir_variable = f"FUSION{app_version}_PROFILE_DIR" self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}") self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir) + + master_prefs_variable = f"FUSION{app_version}_MasterPrefs" + master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") + self.launch_context.env[master_prefs_variable] = str(master_prefs) From 71e8af5a22007678257412ab2052b2034727729d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 10 Mar 2023 00:29:49 +0300 Subject: [PATCH 056/133] noqa line --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 4c73a0eee3..e30d241096 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -58,7 +58,7 @@ class FusionPrelaunch(PreLaunchHook): if app_version == 9: self.launch_context.env[f"FUSION_PYTHON36_HOME"] = py3_dir elif app_version == 16: - self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir + self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir # noqa # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion From 8a00c8ae33a910c40eee4bfcacad352119d3975d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 10 Mar 2023 00:31:47 +0300 Subject: [PATCH 057/133] remove unused import --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index e30d241096..38627b40c1 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -1,5 +1,4 @@ import os -from pathlib import Path from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import FUSION_HOST_DIR from openpype.hosts.fusion import get_fusion_profile_number From c3becbffe0c5476fbac0a401bb710b9246e493e4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sat, 11 Mar 2023 19:42:14 +0100 Subject: [PATCH 058/133] Fix #4429: Do not reset fps or playback timeline on applying or creating render settings --- openpype/hosts/maya/api/lib.py | 41 ++++++++++++------- openpype/hosts/maya/api/lib_rendersettings.py | 2 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 954576f02e..61106c58cf 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2099,29 +2099,40 @@ def get_frame_range(): } -def reset_frame_range(): - """Set frame range to current asset""" +def reset_frame_range(playback=True, render=True, fps=True): + """Set frame range to current asset - fps = convert_to_maya_fps( - float(legacy_io.Session.get("AVALON_FPS", 25)) - ) - set_scene_fps(fps) + Args: + playback (bool, Optional): Whether to set the maya timeline playback + frame range. Defaults to True. + render (bool, Optional): Whether to set the maya render frame range. + Defaults to True. + fps (bool, Optional): Whether to set scene FPS. Defaults to True. + """ + + if fps: + fps = convert_to_maya_fps( + float(legacy_io.Session.get("AVALON_FPS", 25)) + ) + set_scene_fps(fps) frame_range = get_frame_range() frame_start = frame_range["frameStart"] - int(frame_range["handleStart"]) frame_end = frame_range["frameEnd"] + int(frame_range["handleEnd"]) - cmds.playbackOptions(minTime=frame_start) - cmds.playbackOptions(maxTime=frame_end) - cmds.playbackOptions(animationStartTime=frame_start) - cmds.playbackOptions(animationEndTime=frame_end) - cmds.playbackOptions(minTime=frame_start) - cmds.playbackOptions(maxTime=frame_end) - cmds.currentTime(frame_start) + if playback: + cmds.playbackOptions(minTime=frame_start) + cmds.playbackOptions(maxTime=frame_end) + cmds.playbackOptions(animationStartTime=frame_start) + cmds.playbackOptions(animationEndTime=frame_end) + cmds.playbackOptions(minTime=frame_start) + cmds.playbackOptions(maxTime=frame_end) + cmds.currentTime(frame_start) - cmds.setAttr("defaultRenderGlobals.startFrame", frame_start) - cmds.setAttr("defaultRenderGlobals.endFrame", frame_end) + if render: + cmds.setAttr("defaultRenderGlobals.startFrame", frame_start) + cmds.setAttr("defaultRenderGlobals.endFrame", frame_end) def reset_scene_resolution(): diff --git a/openpype/hosts/maya/api/lib_rendersettings.py b/openpype/hosts/maya/api/lib_rendersettings.py index 7d44d4eaa6..eaa728a2f6 100644 --- a/openpype/hosts/maya/api/lib_rendersettings.py +++ b/openpype/hosts/maya/api/lib_rendersettings.py @@ -158,7 +158,7 @@ class RenderSettings(object): cmds.setAttr( "defaultArnoldDriver.mergeAOVs", multi_exr) self._additional_attribs_setter(additional_options) - reset_frame_range() + reset_frame_range(playback=False, fps=False, render=True) def _set_redshift_settings(self, width, height): """Sets settings for Redshift.""" From e2902e86232d738433a9de45f84eb3d3b0b296e1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sat, 11 Mar 2023 20:49:26 +0100 Subject: [PATCH 059/133] Fix #4109: Unify menu labels for "Set Frame Range" and "Set Resolution" --- openpype/hosts/blender/api/ops.py | 4 ++-- openpype/hosts/houdini/startup/MainMenuCommon.xml | 2 +- openpype/hosts/maya/api/menu.py | 4 ++-- openpype/hosts/resolve/api/menu.py | 8 ++++---- website/docs/artist_hosts_maya.md | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/blender/api/ops.py b/openpype/hosts/blender/api/ops.py index 481c199db2..b1fa13acb9 100644 --- a/openpype/hosts/blender/api/ops.py +++ b/openpype/hosts/blender/api/ops.py @@ -382,8 +382,8 @@ class TOPBAR_MT_avalon(bpy.types.Menu): layout.operator(LaunchLibrary.bl_idname, text="Library...") layout.separator() layout.operator(LaunchWorkFiles.bl_idname, text="Work Files...") - # TODO (jasper): maybe add 'Reload Pipeline', 'Reset Frame Range' and - # 'Reset Resolution'? + # TODO (jasper): maybe add 'Reload Pipeline', 'Set Frame Range' and + # 'Set Resolution'? def draw_avalon_menu(self, context): diff --git a/openpype/hosts/houdini/startup/MainMenuCommon.xml b/openpype/hosts/houdini/startup/MainMenuCommon.xml index c08114b71b..e12000b855 100644 --- a/openpype/hosts/houdini/startup/MainMenuCommon.xml +++ b/openpype/hosts/houdini/startup/MainMenuCommon.xml @@ -67,7 +67,7 @@ host_tools.show_workfiles(parent) - + / ``` -Doing **OpenPype → Reset Resolution** will set correct resolution on camera. +Doing **OpenPype → Set Resolution** will set correct resolution on camera. Scene is now ready for submission and should publish without errors. From 7efb019ebc799905e4fc126883aaf9ffb86936ec Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sat, 11 Mar 2023 20:50:30 +0100 Subject: [PATCH 060/133] Match id with label --- openpype/hosts/houdini/startup/MainMenuCommon.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/houdini/startup/MainMenuCommon.xml b/openpype/hosts/houdini/startup/MainMenuCommon.xml index e12000b855..47595ebd8c 100644 --- a/openpype/hosts/houdini/startup/MainMenuCommon.xml +++ b/openpype/hosts/houdini/startup/MainMenuCommon.xml @@ -66,7 +66,7 @@ host_tools.show_workfiles(parent) ]]> - + Date: Mon, 13 Mar 2023 23:00:03 +0100 Subject: [PATCH 061/133] Update tests and documentation for `ExtractorColormanaged` refactor to `ColormanagedPyblishPluginMixin` --- .../unit/openpype/pipeline/publish/test_publish_plugins.py | 6 +++--- website/docs/dev_colorspace.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/openpype/pipeline/publish/test_publish_plugins.py b/tests/unit/openpype/pipeline/publish/test_publish_plugins.py index 5c2d7b367f..88e0095e34 100644 --- a/tests/unit/openpype/pipeline/publish/test_publish_plugins.py +++ b/tests/unit/openpype/pipeline/publish/test_publish_plugins.py @@ -135,7 +135,7 @@ class TestPipelinePublishPlugins(TestPipeline): } # load plugin function for testing - plugin = publish_plugins.ExtractorColormanaged() + plugin = publish_plugins.ColormanagedPyblishPluginMixin() plugin.log = log config_data, file_rules = plugin.get_colorspace_settings(context) @@ -175,14 +175,14 @@ class TestPipelinePublishPlugins(TestPipeline): } # load plugin function for testing - plugin = publish_plugins.ExtractorColormanaged() + plugin = publish_plugins.ColormanagedPyblishPluginMixin() plugin.log = log plugin.set_representation_colorspace( representation_nuke, context, colorspace_settings=(config_data_nuke, file_rules_nuke) ) # load plugin function for testing - plugin = publish_plugins.ExtractorColormanaged() + plugin = publish_plugins.ColormanagedPyblishPluginMixin() plugin.log = log plugin.set_representation_colorspace( representation_hiero, context, diff --git a/website/docs/dev_colorspace.md b/website/docs/dev_colorspace.md index fe9a0ec1e3..14f19f10db 100644 --- a/website/docs/dev_colorspace.md +++ b/website/docs/dev_colorspace.md @@ -63,7 +63,7 @@ It's up to the Loaders to read these values and apply the correct expected color - set the `OCIO` environment variable before launching the host via a prelaunch hook - or (if the host allows) to set the workfile OCIO config path using the host's API -3. Each Extractor exporting pixel data (e.g. image or video) has to use parent class `openpype.pipeline.publish.publish_plugins.ExtractorColormanaged` and use `self.set_representation_colorspace` on the representations to be integrated. +3. Each Extractor exporting pixel data (e.g. image or video) has to inherit from the mixin class `openpype.pipeline.publish.publish_plugins.ColormanagedPyblishPluginMixin` and use `self.set_representation_colorspace` on the representations to be integrated. The **set_representation_colorspace** method adds `colorspaceData` to the representation. If the `colorspace` passed is not `None` then it is added directly to the representation with resolved config path otherwise a color space is assumed using the configured file rules. If no file rule matches the `colorspaceData` is **not** added to the representation. From 5b3cc605d8be1dafdc1114372ae7e9b7e80e3ff4 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Tue, 14 Mar 2023 04:18:48 +0300 Subject: [PATCH 062/133] add some comments --- openpype/hosts/fusion/addon.py | 12 ++++++------ .../hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 4b0ce59aaf..e3464f4be4 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -14,6 +14,10 @@ def get_fusion_profile_number(module: str, app_data: str) -> int: already Fusion version 18, still FUSION16_PROFILE_DIR is used. The variable is added in case the version number will be updated or deleted so we could easily change the version or disable it. + + app_data derives from `launch_context.env.get("AVALON_APP_NAME")`. + For the time being we will encourage user to set a version number + set in the system settings key for the Blackmagic Fusion. """ log = Logger.get_logger(__name__) @@ -42,15 +46,11 @@ class FusionAddon(OpenPypeModule, IHostAddon): def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] - return [ - os.path.join(FUSION_HOST_DIR, "hooks") - ] + return [os.path.join(FUSION_HOST_DIR, "hooks")] def add_implementation_envs(self, env, _app): # Set default values if are not already set via settings - defaults = { - "OPENPYPE_LOG_NO_COLORS": "Yes" - } + defaults = {"OPENPYPE_LOG_NO_COLORS": "Yes"} for key, value in defaults.items(): if not env.get(key): env[key] = value diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 543e90cc75..dc6a4bf85d 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -122,6 +122,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}") self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir) + # setup masterprefs file to partially alter existing or newly generated + # Fusion profile, to add OpenPype menu, scripts and and config files. master_prefs_variable = f"FUSION{app_version}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") From 1914a0dd0212473beba1ee7e4715c3d7441be057 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 14 Mar 2023 10:07:00 +0100 Subject: [PATCH 063/133] Remove unused imports --- openpype/hosts/maya/plugins/publish/extract_look.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index efeddcfbe4..bfa26d158f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -1,12 +1,10 @@ # -*- coding: utf-8 -*- """Maya look extractor.""" import os -import sys import json import tempfile import platform import contextlib -import subprocess from collections import OrderedDict from maya import cmds # noqa From e250d8935f45490ee991b9ac11bc8ec758f3c32d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 14 Mar 2023 10:14:09 +0100 Subject: [PATCH 064/133] Don't require to `arnold` plug-in to be available, don't force load it if we don't need it. --- openpype/hosts/maya/plugins/publish/extract_look.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index bfa26d158f..1893155291 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -21,6 +21,15 @@ COPY = 1 HARDLINK = 2 +def _has_arnold(): + """Return whether the arnold package is available and can be imported.""" + try: + import arnold + return True + except (ImportError, ModuleNotFoundError): + return False + + def escape_space(path): """Ensure path is enclosed by quotes to allow paths with spaces""" return '"{}"'.format(path) if " " in path else path @@ -546,7 +555,7 @@ class ExtractLook(publish.Extractor): color_space = cmds.getAttr(color_space_attr) except ValueError: # node doesn't have color space attribute - if cmds.loadPlugin("mtoa", quiet=True): + if _has_arnold(): img_info = image_info(filepath) color_space = guess_colorspace(img_info) else: @@ -558,7 +567,7 @@ class ExtractLook(publish.Extractor): render_colorspace]) else: - if cmds.loadPlugin("mtoa", quiet=True): + if _has_arnold(): img_info = image_info(filepath) color_space = guess_colorspace(img_info) if color_space == "sRGB": From f0a76b5cc56b9b6577f768f1390d06468a6cec4e Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 14 Mar 2023 11:01:45 +0100 Subject: [PATCH 065/133] Shush hound --- openpype/hosts/maya/plugins/publish/extract_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index 1893155291..bc506b7feb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -24,7 +24,7 @@ HARDLINK = 2 def _has_arnold(): """Return whether the arnold package is available and can be imported.""" try: - import arnold + import arnold # noqa: F401 return True except (ImportError, ModuleNotFoundError): return False From f1b39494be1027d757b359336dda4a7869c8764c Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 14 Mar 2023 14:50:15 +0000 Subject: [PATCH 066/133] Update openpype/modules/deadline/plugins/publish/submit_maya_deadline.py Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com> --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index f7fc608f30..53ecb9063b 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -860,7 +860,7 @@ def _format_tiles( right = (tile_x * w_space) - 1 # Job info - key = "OutputFilename{}Tile{}".format(index, tile) + key = "OutputFilename{}".format(index) out["JobInfo"][key] = new_filename # Plugin Info From 0cb3585d91e63352dff24a861c0a19fc3a96425b Mon Sep 17 00:00:00 2001 From: mre7a <68907585+mre7a@users.noreply.github.com> Date: Wed, 15 Mar 2023 12:55:50 +0100 Subject: [PATCH 067/133] Resolve missing OPENPYPE_MONGO in deadline global job preload (#4484) * replace SpawnProcess with subprocess * clean up * replace spawn process with run process --------- Co-authored-by: Seyedmohammadreza Hashemizadeh --- .../repository/custom/plugins/GlobalJobPreLoad.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index 20a58c9131..15226bb773 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -362,11 +362,11 @@ def inject_openpype_environment(deadlinePlugin): args_str = subprocess.list2cmdline(args) print(">>> Executing: {} {}".format(exe, args_str)) - process = ProcessUtils.SpawnProcess( - exe, args_str, os.path.dirname(exe) + process_exitcode = deadlinePlugin.RunProcess( + exe, args_str, os.path.dirname(exe), -1 ) - ProcessUtils.WaitForExit(process, -1) - if process.ExitCode != 0: + + if process_exitcode != 0: raise RuntimeError( "Failed to run OpenPype process to extract environments." ) From fe9c807b1fb0a9ddb56d1581c9f916c360b8c863 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 15 Mar 2023 17:13:10 +0000 Subject: [PATCH 068/133] Fix playblast panel collection --- openpype/hosts/maya/plugins/publish/collect_review.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 65ff7cf0fe..548b1c996a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -24,7 +24,9 @@ class CollectReview(pyblish.api.InstancePlugin): task = legacy_io.Session["AVALON_TASK"] # Get panel. - instance.data["panel"] = cmds.playblast(activeEditor=True) + instance.data["panel"] = cmds.playblast( + activeEditor=True + ).split("|")[-1] # get cameras members = instance.data['setMembers'] From 00a901120b3a5c0ed258af9bf03084c1c7e994de Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 02:58:54 +0300 Subject: [PATCH 069/133] check for suported fusion version --- openpype/hosts/fusion/addon.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index e3464f4be4..cb4dc76481 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -4,6 +4,8 @@ from openpype.modules import OpenPypeModule, IHostAddon from openpype.lib import Logger FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) +FUSION16_PROFILE_VERSIONS = (16, 17, 18) +FUSION9_PROFILE_VERSION = 9 def get_fusion_profile_number(module: str, app_data: str) -> int: @@ -15,8 +17,10 @@ def get_fusion_profile_number(module: str, app_data: str) -> int: The variable is added in case the version number will be updated or deleted so we could easily change the version or disable it. - app_data derives from `launch_context.env.get("AVALON_APP_NAME")`. - For the time being we will encourage user to set a version number + Currently valid Fusion versions are stored in FUSION16_PROFILE_VERSIONS + + app_data derives from `launch_context.env.get("AVALON_APP_NAME")`. + For the time being we will encourage user to set a version number set in the system settings key for the Blackmagic Fusion. """ @@ -24,16 +28,18 @@ def get_fusion_profile_number(module: str, app_data: str) -> int: if not app_data: return - fusion16_profile_versions = ("16", "17", "18") + try: app_version = re.search(r"fusion/(\d+)", app_data).group(1) - log.info(f"{module} found Fusion profile version: {app_version}") - if app_version in fusion16_profile_versions: + log.debug(f"{module} found Fusion profile version: {app_version}") + if app_version in map(str, FUSION16_PROFILE_VERSIONS): return 16 - elif app_version == "9": + elif app_version == str(FUSION9_PROFILE_VERSION): return 9 + else: + log.info(f"Found unsupported Fusion version: {app_version}") except AttributeError: - log.info("Fusion version was not found in the app data") + log.info("Fusion version was not found in the AVALON_APP_NAME data") class FusionAddon(OpenPypeModule, IHostAddon): From ef5c081b5fb77c7709bf780f552d0cc72f16a369 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 02:59:18 +0300 Subject: [PATCH 070/133] add execution order --- openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py index 6bf0f55081..47645b7e3f 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py @@ -7,6 +7,7 @@ from openpype.pipeline.template_data import get_template_data_with_names class FusionPreLaunchOCIO(PreLaunchHook): """Set OCIO environment variable for Fusion""" app_groups = ["fusion"] + order = 3 def execute(self): """Hook entry method.""" From b305aac21dd14f8d58656b8be197926ca4505316 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 03:01:35 +0300 Subject: [PATCH 071/133] fix docs --- .../hosts/fusion/hooks/pre_fusion_profile_hook.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index dc6a4bf85d..08ba9c4157 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -25,9 +25,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # Check if FUSION_PROFILE_DIR exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): fu_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile) - self.log.info( - f"{fusion_var_prefs_dir} is set to {fu_prefs_dir}" - ) + self.log.info(f"{fusion_var_prefs_dir} is set to {fu_prefs_dir}") return fu_prefs_dir def get_profile_source(self, app_version) -> Path: @@ -106,7 +104,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): ) = self.get_copy_fusion_prefs_settings() # Get launched application context and return correct app version - app_data = self.launch_context.env.get("AVALON_APP_NAME", "fusion/18") + app_data = self.launch_context.env.get("AVALON_APP_NAME") app_version = get_fusion_profile_number(__name__, app_data) fu_profile = self.get_fusion_profile_name(app_version) @@ -122,8 +120,9 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}") self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir) - # setup masterprefs file to partially alter existing or newly generated - # Fusion profile, to add OpenPype menu, scripts and and config files. + # Add custom Fusion Master Prefs and the temporary + # profile directory variables to customize Fusion + # to define where it can read custom scripts and tools from master_prefs_variable = f"FUSION{app_version}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") From f3e20c0af9c4a68858150a52720fb1be1cb1675b Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 03:03:39 +0300 Subject: [PATCH 072/133] force check Fusion number version in app settings --- .../hosts/fusion/hooks/pre_fusion_setup.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 38627b40c1..b9f568bad2 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -1,7 +1,9 @@ import os from openpype.lib import PreLaunchHook, ApplicationLaunchFailed -from openpype.hosts.fusion import FUSION_HOST_DIR -from openpype.hosts.fusion import get_fusion_profile_number +from openpype.hosts.fusion import ( + FUSION_HOST_DIR, + get_fusion_profile_number, +) class FusionPrelaunch(PreLaunchHook): @@ -22,8 +24,14 @@ class FusionPrelaunch(PreLaunchHook): def execute(self): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 - app_data = self.launch_context.env.get("AVALON_APP_NAME", "fusion/18") + app_data = self.launch_context.env.get("AVALON_APP_NAME") app_version = get_fusion_profile_number(__name__, app_data) + if not app_version: + raise ApplicationLaunchFailed( + "Fusion version information not found in System settings.\n" + "The key field in the 'applications/fusion/variants' " + "should consist a number, corresponding to the Fusion version" + ) py3_var = "FUSION_PYTHON3_HOME" fusion_python3_home = self.launch_context.env.get(py3_var, "") @@ -57,10 +65,9 @@ class FusionPrelaunch(PreLaunchHook): if app_version == 9: self.launch_context.env[f"FUSION_PYTHON36_HOME"] = py3_dir elif app_version == 16: - self.launch_context.env[f"FUSION{app_version}_PYTHON36_HOME"] = py3_dir # noqa + self.launch_context.env[ + f"FUSION{app_version}_PYTHON36_HOME" + ] = py3_dir - # Add custom Fusion Master Prefs and the temporary - # profile directory variables to customize Fusion - # to define where it can read custom scripts and tools from self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR From a63e297186f2fbbda5b115db9f8027d037d86d3f Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 03:08:20 +0300 Subject: [PATCH 073/133] remove unused import --- openpype/hosts/fusion/api/workio.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py index fbb5a588f4..fa4b62c123 100644 --- a/openpype/hosts/fusion/api/workio.py +++ b/openpype/hosts/fusion/api/workio.py @@ -1,5 +1,4 @@ """Host API required Work Files tool""" -import sys import os from .lib import get_fusion_module, get_current_comp From d0656e92a54e43468ab6bec24e0031a685cc9145 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov <11698866+movalex@users.noreply.github.com> Date: Thu, 16 Mar 2023 12:47:19 +0300 Subject: [PATCH 074/133] Update openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py Co-authored-by: Roy Nieterau --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 08ba9c4157..c69ac10b67 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -46,7 +46,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): ).expanduser() elif platform.system() == "Linux": profile_source = Path("~/.fusion", fu_prefs_dir).expanduser() - self.log.info(f"Got Fusion prefs file: {profile_source}") + self.log.info(f"Locating source Fusion prefs directory: {profile_source}") return profile_source def get_copy_fusion_prefs_settings(self): From d0f74f134865a95c1fa1d8e6e5135f842f424509 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov <11698866+movalex@users.noreply.github.com> Date: Thu, 16 Mar 2023 12:48:04 +0300 Subject: [PATCH 075/133] Update openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py Co-authored-by: Roy Nieterau --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index c69ac10b67..ba8997fd74 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -75,7 +75,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): """ if copy_to.exists() and not force_sync: self.log.info( - "Local Fusion preferences folder exists, skipping profile copy" + "Destination Fusion preferences folder exists, skipping profile copy" ) return self.log.info(f"Starting copying Fusion preferences") From f96670d9dfa482174584b85f93f386aff472e841 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 16 Mar 2023 11:20:00 +0100 Subject: [PATCH 076/133] use right validation for ffmpeg executable --- openpype/lib/vendor_bin_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/vendor_bin_utils.py b/openpype/lib/vendor_bin_utils.py index b6797dbba0..00dd1955fe 100644 --- a/openpype/lib/vendor_bin_utils.py +++ b/openpype/lib/vendor_bin_utils.py @@ -375,7 +375,7 @@ def get_ffmpeg_tool_path(tool="ffmpeg"): # Look to PATH for the tool if not tool_executable_path: from_path = find_executable(tool) - if from_path and _oiio_executable_validation(from_path): + if from_path and _ffmpeg_executable_validation(from_path): tool_executable_path = from_path CachedToolPaths.cache_executable_path(tool, tool_executable_path) From 1c97ec027fcfb2991c3a38a2cde309cb13543f0d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 16 Mar 2023 23:10:39 +0800 Subject: [PATCH 077/133] adding 3dsmax into apps_group at add_last_workfile_arg --- openpype/hooks/pre_add_last_workfile_arg.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 1c8746c559..2558daef30 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -14,6 +14,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): # Execute after workfile template copy order = 10 app_groups = [ + "3dsmax", "maya", "nuke", "nukex", From 3396784820145e0656b6905b4f5e99697e9f9994 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 21:32:48 +0300 Subject: [PATCH 078/133] use dictionary to store fusion versions and variables --- openpype/hosts/fusion/__init__.py | 6 ++-- openpype/hosts/fusion/addon.py | 50 +++++++++++++++++-------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/fusion/__init__.py b/openpype/hosts/fusion/__init__.py index f0e7843fff..1da11ba9d1 100644 --- a/openpype/hosts/fusion/__init__.py +++ b/openpype/hosts/fusion/__init__.py @@ -1,12 +1,14 @@ from .addon import ( - get_fusion_profile_number, + get_fusion_version, FusionAddon, FUSION_HOST_DIR, + FUSION_VERSIONS_DICT, ) __all__ = ( - "get_fusion_profile_number", + "get_fusion_version", "FusionAddon", "FUSION_HOST_DIR", + "FUSION_VERSIONS_DICT", ) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index cb4dc76481..2ea16e0d6b 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -4,24 +4,29 @@ from openpype.modules import OpenPypeModule, IHostAddon from openpype.lib import Logger FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -FUSION16_PROFILE_VERSIONS = (16, 17, 18) -FUSION9_PROFILE_VERSION = 9 + +# FUSION_VERSIONS_DICT is used by the pre-launch hooks +# The keys correspond to all currently supported Fusion versions +# Values is the list of corresponding python_home variables and a profile +# number, which is used to specify pufion profile derectory variable. +FUSION_VERSIONS_DICT = { + 9: ["FUSION_PYTHON36_HOME", 9], + 16: ["FUSION16_PYTHON36_HOME", 16], + 17: ["FUSION16_PYTHON36_HOME", 16], + 18: ["FUSION_PYTHON3_HOME", 16], +} -def get_fusion_profile_number(module: str, app_data: str) -> int: +def get_fusion_version(app_data): """ - FUSION_PROFILE_VERSION variable is used by the pre-launch hooks. - Since Fusion v16, the profile folder variable became version-specific, - but then it was abandoned by BlackmagicDesign devs, and now, despite it is - already Fusion version 18, still FUSION16_PROFILE_DIR is used. - The variable is added in case the version number will be - updated or deleted so we could easily change the version or disable it. + The function is triggered by the prelaunch hooks to get the fusion version. - Currently valid Fusion versions are stored in FUSION16_PROFILE_VERSIONS + `app_data` is obtained by prelaunch hooks from the + `launch_context.env.get("AVALON_APP_NAME")`. - app_data derives from `launch_context.env.get("AVALON_APP_NAME")`. - For the time being we will encourage user to set a version number - set in the system settings key for the Blackmagic Fusion. + To get a correct Fusion version, a version number should be present + in the `applications/fusion/variants` key + int the Blackmagic Fusion Application Settings. """ log = Logger.get_logger(__name__) @@ -29,17 +34,16 @@ def get_fusion_profile_number(module: str, app_data: str) -> int: if not app_data: return - try: - app_version = re.search(r"fusion/(\d+)", app_data).group(1) - log.debug(f"{module} found Fusion profile version: {app_version}") - if app_version in map(str, FUSION16_PROFILE_VERSIONS): - return 16 - elif app_version == str(FUSION9_PROFILE_VERSION): - return 9 + app_version_candidates = re.findall("\d+", app_data) + for app_version in app_version_candidates: + if int(app_version) in FUSION_VERSIONS_DICT: + return int(app_version) else: - log.info(f"Found unsupported Fusion version: {app_version}") - except AttributeError: - log.info("Fusion version was not found in the AVALON_APP_NAME data") + log.info( + "Unsupported Fusion version: {app_version}".format( + app_version=app_version + ) + ) class FusionAddon(OpenPypeModule, IHostAddon): From e61ec028e24f5e0dfcceb3de1902c03f66c8edd7 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 21:33:11 +0300 Subject: [PATCH 079/133] delete unused module --- openpype/hosts/fusion/api/workio.py | 38 ----------------------------- 1 file changed, 38 deletions(-) delete mode 100644 openpype/hosts/fusion/api/workio.py diff --git a/openpype/hosts/fusion/api/workio.py b/openpype/hosts/fusion/api/workio.py deleted file mode 100644 index fa4b62c123..0000000000 --- a/openpype/hosts/fusion/api/workio.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Host API required Work Files tool""" -import os - -from .lib import get_fusion_module, get_current_comp - - -def file_extensions(): - return [".comp"] - - -def has_unsaved_changes(): - comp = get_current_comp() - return comp.GetAttrs()["COMPB_Modified"] - - -def save_file(filepath): - comp = get_current_comp() - comp.Save(filepath) - - -def open_file(filepath): - fusion = get_fusion_module() - return fusion.LoadComp(filepath) - - -def current_file(): - comp = get_current_comp() - current_filepath = comp.GetAttrs()["COMPS_FileName"] - return current_filepath or None - - -def work_root(session): - work_dir = session["AVALON_WORKDIR"] - scene_dir = session.get("AVALON_SCENEDIR") - if scene_dir: - return os.path.join(work_dir, scene_dir) - else: - return work_dir From 502198d00b4420d766a4a87c6f71c63d7e35ebf8 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 21:53:12 +0300 Subject: [PATCH 080/133] update fusion hooks to get correct version and variables --- .../fusion/hooks/pre_fusion_profile_hook.py | 61 +++++++++++++------ .../hosts/fusion/hooks/pre_fusion_setup.py | 38 +++++------- 2 files changed, 56 insertions(+), 43 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index ba8997fd74..b6ddacb571 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -3,24 +3,38 @@ import shutil import platform from pathlib import Path from openpype.lib import PreLaunchHook -from openpype.hosts.fusion import FUSION_HOST_DIR, get_fusion_profile_number +from openpype.hosts.fusion import ( + FUSION_HOST_DIR, + FUSION_VERSIONS_DICT, + get_fusion_version, +) class FusionCopyPrefsPrelaunch(PreLaunchHook): - """Prepares local Fusion profile directory, copies existing Fusion profile + """ + Prepares local Fusion profile directory, copies existing Fusion profile. + This also sets FUSION MasterPrefs variable, which is used + to apply Master.prefs file to override some Fusion profile settings to: + - enable the OpenPype menu + - force Python 3 over Python 2 + - force English interface + - force grey color scheme (because it is better that the purple one!) + Master.prefs is defined in openpype/hosts/fusion/deploy/fusion_shared.prefs """ app_groups = ["fusion"] order = 2 - def get_fusion_profile_name(self, app_version) -> str: + def get_fusion_profile_name(self, profile_version) -> str: # Returns 'Default', unless FUSION16_PROFILE is set - return os.getenv(f"FUSION{app_version}_PROFILE", "Default") + return os.getenv(f"FUSION{profile_version}_PROFILE", "Default") - def check_profile_variable(self, app_version) -> Path: + def get_fusion_profile_dir(self, profile_version) -> Path: # Get FUSION_PROFILE_DIR variable - fusion_profile = self.get_fusion_profile_name(app_version) - fusion_var_prefs_dir = os.getenv(f"FUSION{app_version}_PROFILE_DIR") + fusion_profile = self.get_fusion_profile_name(profile_version) + fusion_var_prefs_dir = os.getenv( + f"FUSION{profile_version}_PROFILE_DIR" + ) # Check if FUSION_PROFILE_DIR exists if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir(): @@ -28,12 +42,12 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): self.log.info(f"{fusion_var_prefs_dir} is set to {fu_prefs_dir}") return fu_prefs_dir - def get_profile_source(self, app_version) -> Path: + def get_profile_source(self, profile_version) -> Path: """Get Fusion preferences profile location. See Per-User_Preferences_and_Paths on VFXpedia for reference. """ - fusion_profile = self.get_fusion_profile_name(app_version) - profile_source = self.check_profile_variable(app_version) + fusion_profile = self.get_fusion_profile_name(profile_version) + profile_source = self.get_fusion_profile_dir(profile_version) if profile_source: return profile_source # otherwise get default location of the profile folder @@ -46,7 +60,9 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): ).expanduser() elif platform.system() == "Linux": profile_source = Path("~/.fusion", fu_prefs_dir).expanduser() - self.log.info(f"Locating source Fusion prefs directory: {profile_source}") + self.log.info( + f"Locating source Fusion prefs directory: {profile_source}" + ) return profile_source def get_copy_fusion_prefs_settings(self): @@ -82,14 +98,20 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): self.log.info(f"force_sync option is set to {force_sync}") try: copy_to.mkdir(exist_ok=True, parents=True) - except Exception: - self.log.warn(f"Could not create folder at {copy_to}") + except PermissionError: + self.log.warn(f"Creating the folder not permitted at {copy_to}") return if not copy_from.exists(): self.log.warning(f"Fusion preferences not found in {copy_from}") return for file in copy_from.iterdir(): - if file.suffix in (".prefs", ".def", ".blocklist", ".fu"): + if file.suffix in ( + ".prefs", + ".def", + ".blocklist", + ".fu", + ".toolbars", + ): # convert Path to str to be compatible with Python 3.6+ shutil.copy(str(file), str(copy_to)) self.log.info( @@ -105,25 +127,26 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # Get launched application context and return correct app version app_data = self.launch_context.env.get("AVALON_APP_NAME") - app_version = get_fusion_profile_number(__name__, app_data) - fu_profile = self.get_fusion_profile_name(app_version) + app_version = get_fusion_version(app_data) + _, profile_version = FUSION_VERSIONS_DICT[app_version] + fu_profile = self.get_fusion_profile_name(profile_version) # do a copy of Fusion profile if copy_status toggle is enabled if copy_status and fu_profile_dir is not None: - profile_source = self.get_profile_source(app_version) + profile_source = self.get_profile_source(profile_version) dest_folder = Path(fu_profile_dir, fu_profile) self.copy_fusion_profile(profile_source, dest_folder, force_sync) # Add temporary profile directory variables to customize Fusion # to define where it can read custom scripts and tools from - fu_profile_dir_variable = f"FUSION{app_version}_PROFILE_DIR" + fu_profile_dir_variable = f"FUSION{profile_version}_PROFILE_DIR" self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}") self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir) # Add custom Fusion Master Prefs and the temporary # profile directory variables to customize Fusion # to define where it can read custom scripts and tools from - master_prefs_variable = f"FUSION{app_version}_MasterPrefs" + master_prefs_variable = f"FUSION{profile_version}_MasterPrefs" master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") self.launch_context.env[master_prefs_variable] = str(master_prefs) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index b9f568bad2..a014268c8f 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -2,20 +2,19 @@ import os from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import ( FUSION_HOST_DIR, - get_fusion_profile_number, + FUSION_VERSIONS_DICT, + get_fusion_version, ) class FusionPrelaunch(PreLaunchHook): - """Prepares OpenPype Fusion environment - - Requires FUSION_PYTHON3_HOME to be defined in the environment for Fusion - to point at a valid Python 3 build for Fusion. That is Python 3.3-3.10 - for Fusion 18 and Fusion 3.6 for Fusion 16 and 17. - - This also sets FUSION16_MasterPrefs to apply the fusion master prefs - as set in openpype/hosts/fusion/deploy/fusion_shared.prefs to enable - the OpenPype menu and force Python 3 over Python 2. + """ + Prepares OpenPype Fusion environment. + Requires correct Python home variable to be defined in the environment + settings for Fusion to point at a valid Python 3 build for Fusion. + Python3 versions that are supported by Fusion: + Fusion 9, 16, 17 : Python 3.6 + Fusion 18 : Python 3.6 - 3.10 """ app_groups = ["fusion"] @@ -25,15 +24,14 @@ class FusionPrelaunch(PreLaunchHook): # making sure python 3 is installed at provided path # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17 app_data = self.launch_context.env.get("AVALON_APP_NAME") - app_version = get_fusion_profile_number(__name__, app_data) + app_version = get_fusion_version(app_data) if not app_version: raise ApplicationLaunchFailed( "Fusion version information not found in System settings.\n" "The key field in the 'applications/fusion/variants' " "should consist a number, corresponding to the Fusion version" ) - - py3_var = "FUSION_PYTHON3_HOME" + py3_var, _ = FUSION_VERSIONS_DICT[app_version] fusion_python3_home = self.launch_context.env.get(py3_var, "") for path in fusion_python3_home.split(os.pathsep): @@ -42,7 +40,6 @@ class FusionPrelaunch(PreLaunchHook): # But make to set only a single path as final variable. py3_dir = os.path.normpath(path) if os.path.isdir(py3_dir): - self.log.info(f"Looking for Python 3 in: {py3_dir}") break else: raise ApplicationLaunchFailed( @@ -57,17 +54,10 @@ class FusionPrelaunch(PreLaunchHook): self.launch_context.env[py3_var] = py3_dir # Fusion 18+ requires FUSION_PYTHON3_HOME to also be on PATH - self.launch_context.env["PATH"] += ";" + py3_dir + if app_version > 17: + self.launch_context.env["PATH"] += ";" + py3_dir - # Fusion 16 and 17 use FUSION16_PYTHON36_HOME instead of - # FUSION_PYTHON3_HOME and will only work with a Python 3.6 version - # TODO: Detect Fusion version to only set for specific Fusion build - if app_version == 9: - self.launch_context.env[f"FUSION_PYTHON36_HOME"] = py3_dir - elif app_version == 16: - self.launch_context.env[ - f"FUSION{app_version}_PYTHON36_HOME" - ] = py3_dir + self.launch_context.env[py3_var] = py3_dir self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}") self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR From 4d252b698af788f22fd18607289991fc6cac9d48 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 21:54:45 +0300 Subject: [PATCH 081/133] fix regex escape sequence --- openpype/hosts/fusion/addon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 2ea16e0d6b..0eb7e09003 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -34,7 +34,7 @@ def get_fusion_version(app_data): if not app_data: return - app_version_candidates = re.findall("\d+", app_data) + app_version_candidates = re.findall(r"\d+", app_data) for app_version in app_version_candidates: if int(app_version) in FUSION_VERSIONS_DICT: return int(app_version) From 5ebdbcf2d284ec7c02f58454e81c998f64b423e2 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 21:55:58 +0300 Subject: [PATCH 082/133] remove whitespaces --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index a014268c8f..a337a4245e 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -10,11 +10,11 @@ from openpype.hosts.fusion import ( class FusionPrelaunch(PreLaunchHook): """ Prepares OpenPype Fusion environment. - Requires correct Python home variable to be defined in the environment + Requires correct Python home variable to be defined in the environment settings for Fusion to point at a valid Python 3 build for Fusion. Python3 versions that are supported by Fusion: Fusion 9, 16, 17 : Python 3.6 - Fusion 18 : Python 3.6 - 3.10 + Fusion 18 : Python 3.6 - 3.10 """ app_groups = ["fusion"] From dacd50061b602d73ede815cb46e1c656fe41dc9d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 22:19:46 +0300 Subject: [PATCH 083/133] fix line length --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index b6ddacb571..6e7d2558fd 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -91,7 +91,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): """ if copy_to.exists() and not force_sync: self.log.info( - "Destination Fusion preferences folder exists, skipping profile copy" + "Destination Fusion preferences folder already exists" ) return self.log.info(f"Starting copying Fusion preferences") From 30d38ab3d1da328551a52c9ae47391af4b49ada6 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 22:21:02 +0300 Subject: [PATCH 084/133] fix typo, early check if no fusion version found --- openpype/hosts/fusion/addon.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 0eb7e09003..7314267124 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -26,7 +26,7 @@ def get_fusion_version(app_data): To get a correct Fusion version, a version number should be present in the `applications/fusion/variants` key - int the Blackmagic Fusion Application Settings. + of the Blackmagic Fusion Application Settings. """ log = Logger.get_logger(__name__) @@ -35,6 +35,8 @@ def get_fusion_version(app_data): return app_version_candidates = re.findall(r"\d+", app_data) + if not app_version_candidates: + return for app_version in app_version_candidates: if int(app_version) in FUSION_VERSIONS_DICT: return int(app_version) From 97af187f8077d987851b121b02e50dc8a351caa6 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Thu, 16 Mar 2023 22:46:20 +0300 Subject: [PATCH 085/133] catch typos, update comment --- openpype/hosts/fusion/addon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 7314267124..e7c7a03fa2 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -7,8 +7,8 @@ FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) # FUSION_VERSIONS_DICT is used by the pre-launch hooks # The keys correspond to all currently supported Fusion versions -# Values is the list of corresponding python_home variables and a profile -# number, which is used to specify pufion profile derectory variable. +# Each value is a list of corresponding Python home variables and a profile +# number, which is used by the profile hook to set Fusion profile variables. FUSION_VERSIONS_DICT = { 9: ["FUSION_PYTHON36_HOME", 9], 16: ["FUSION16_PYTHON36_HOME", 16], From 3c3722d4082417bb3a2605cf2af4ee9a0448f299 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Mar 2023 00:30:25 +0300 Subject: [PATCH 086/133] use os.pathsep to build the PATH variable --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index a337a4245e..64c498dd01 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -54,8 +54,8 @@ class FusionPrelaunch(PreLaunchHook): self.launch_context.env[py3_var] = py3_dir # Fusion 18+ requires FUSION_PYTHON3_HOME to also be on PATH - if app_version > 17: - self.launch_context.env["PATH"] += ";" + py3_dir + if app_version >= 18: + self.launch_context.env["PATH"] += os.pathsep + py3_dir self.launch_context.env[py3_var] = py3_dir From fcb723068336eca63635b231cdbd6e7760182981 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Mar 2023 00:57:47 +0300 Subject: [PATCH 087/133] use immutable values --- openpype/hosts/fusion/addon.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index e7c7a03fa2..345e348c3b 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -10,10 +10,10 @@ FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) # Each value is a list of corresponding Python home variables and a profile # number, which is used by the profile hook to set Fusion profile variables. FUSION_VERSIONS_DICT = { - 9: ["FUSION_PYTHON36_HOME", 9], - 16: ["FUSION16_PYTHON36_HOME", 16], - 17: ["FUSION16_PYTHON36_HOME", 16], - 18: ["FUSION_PYTHON3_HOME", 16], + 9: ("FUSION_PYTHON36_HOME", 9), + 16: ("FUSION16_PYTHON36_HOME", 16), + 17: ("FUSION16_PYTHON36_HOME", 16), + 18: ("FUSION_PYTHON3_HOME", 16), } From d299824e219a41dc2043925916d20c90ab633d32 Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Mar 2023 01:02:51 +0300 Subject: [PATCH 088/133] ok, do not force grey interface in masterprefs (purple is still bad!) --- openpype/hosts/fusion/deploy/fusion_shared.prefs | 1 - openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 1 - 2 files changed, 2 deletions(-) diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/fusion_shared.prefs index 17ac3ad37a..b379ea7c66 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/fusion_shared.prefs @@ -13,7 +13,6 @@ Global = { Python3Forced = true }, UserInterface = { - Skin = "Neutral", Language = "en_US" }, }, diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 6e7d2558fd..15c9424990 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -18,7 +18,6 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): - enable the OpenPype menu - force Python 3 over Python 2 - force English interface - - force grey color scheme (because it is better that the purple one!) Master.prefs is defined in openpype/hosts/fusion/deploy/fusion_shared.prefs """ From 3b62d0f4a7dfba155d588cfa3c40e6fe5075a61a Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Mar 2023 01:03:22 +0300 Subject: [PATCH 089/133] clarify the error message --- openpype/hosts/fusion/hooks/pre_fusion_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_setup.py b/openpype/hosts/fusion/hooks/pre_fusion_setup.py index 64c498dd01..f27cd1674b 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_setup.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_setup.py @@ -28,8 +28,8 @@ class FusionPrelaunch(PreLaunchHook): if not app_version: raise ApplicationLaunchFailed( "Fusion version information not found in System settings.\n" - "The key field in the 'applications/fusion/variants' " - "should consist a number, corresponding to the Fusion version" + "The key field in the 'applications/fusion/variants' should " + "consist a number, corresponding to major Fusion version." ) py3_var, _ = FUSION_VERSIONS_DICT[app_version] fusion_python3_home = self.launch_context.env.get(py3_var, "") From bec46399857dd13cf482dc28688a1ffec9a15dac Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov Date: Fri, 17 Mar 2023 01:14:39 +0300 Subject: [PATCH 090/133] revert change --- openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py index 47645b7e3f..6bf0f55081 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_ocio_hook.py @@ -7,7 +7,6 @@ from openpype.pipeline.template_data import get_template_data_with_names class FusionPreLaunchOCIO(PreLaunchHook): """Set OCIO environment variable for Fusion""" app_groups = ["fusion"] - order = 3 def execute(self): """Hook entry method.""" From 289efe25f8ec1d238ee1f95433b7aea355d42fd0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 17 Mar 2023 10:35:53 +0100 Subject: [PATCH 091/133] Ftrack: Ftrack additional families filtering (#4633) * make sure all families are used for additional filtering * rely on instance and context data instead of legacy_io * formatting changes * fix variable values after change of condition * use 'families' variable for adding 'ftrack' family * Removed duplicated log * change variable name --- .../plugins/publish/collect_ftrack_family.py | 91 +++++++++---------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/collect_ftrack_family.py b/openpype/modules/ftrack/plugins/publish/collect_ftrack_family.py index 576a7d36c4..97815f490f 100644 --- a/openpype/modules/ftrack/plugins/publish/collect_ftrack_family.py +++ b/openpype/modules/ftrack/plugins/publish/collect_ftrack_family.py @@ -7,23 +7,22 @@ Provides: """ import pyblish.api -from openpype.pipeline import legacy_io from openpype.lib import filter_profiles class CollectFtrackFamily(pyblish.api.InstancePlugin): + """Adds explicitly 'ftrack' to families to upload instance to FTrack. + + Uses selection by combination of hosts/families/tasks names via + profiles resolution. + + Triggered everywhere, checks instance against configured. + + Checks advanced filtering which works on 'families' not on main + 'family', as some variants dynamically resolves addition of ftrack + based on 'families' (editorial drives it by presence of 'review') """ - Adds explicitly 'ftrack' to families to upload instance to FTrack. - Uses selection by combination of hosts/families/tasks names via - profiles resolution. - - Triggered everywhere, checks instance against configured. - - Checks advanced filtering which works on 'families' not on main - 'family', as some variants dynamically resolves addition of ftrack - based on 'families' (editorial drives it by presence of 'review') - """ label = "Collect Ftrack Family" order = pyblish.api.CollectorOrder + 0.4990 @@ -34,68 +33,64 @@ class CollectFtrackFamily(pyblish.api.InstancePlugin): self.log.warning("No profiles present for adding Ftrack family") return - add_ftrack_family = False - task_name = instance.data.get("task", - legacy_io.Session["AVALON_TASK"]) - host_name = legacy_io.Session["AVALON_APP"] + host_name = instance.context.data["hostName"] family = instance.data["family"] + task_name = instance.data.get("task") filtering_criteria = { "hosts": host_name, "families": family, "tasks": task_name } - profile = filter_profiles(self.profiles, filtering_criteria, - logger=self.log) + profile = filter_profiles( + self.profiles, + filtering_criteria, + logger=self.log + ) + + add_ftrack_family = False + families = instance.data.setdefault("families", []) if profile: - families = instance.data.get("families") add_ftrack_family = profile["add_ftrack_family"] - additional_filters = profile.get("advanced_filtering") if additional_filters: - self.log.info("'{}' families used for additional filtering". - format(families)) + families_set = set(families) | {family} + self.log.info( + "'{}' families used for additional filtering".format( + families_set)) add_ftrack_family = self._get_add_ftrack_f_from_addit_filters( additional_filters, - families, + families_set, add_ftrack_family ) - if add_ftrack_family: - self.log.debug("Adding ftrack family for '{}'". - format(instance.data.get("family"))) + result_str = "Not adding" + if add_ftrack_family: + result_str = "Adding" + if "ftrack" not in families: + families.append("ftrack") - if families: - if "ftrack" not in families: - instance.data["families"].append("ftrack") - else: - instance.data["families"] = ["ftrack"] - - result_str = "Adding" - if not add_ftrack_family: - result_str = "Not adding" self.log.info("{} 'ftrack' family for instance with '{}'".format( result_str, family )) - def _get_add_ftrack_f_from_addit_filters(self, - additional_filters, - families, - add_ftrack_family): - """ - Compares additional filters - working on instance's families. + def _get_add_ftrack_f_from_addit_filters( + self, additional_filters, families, add_ftrack_family + ): + """Compares additional filters - working on instance's families. - Triggered for more detailed filtering when main family matches, - but content of 'families' actually matter. - (For example 'review' in 'families' should result in adding to - Ftrack) + Triggered for more detailed filtering when main family matches, + but content of 'families' actually matter. + (For example 'review' in 'families' should result in adding to + Ftrack) - Args: - additional_filters (dict) - from Setting - families (list) - subfamilies - add_ftrack_family (bool) - add ftrack to families if True + Args: + additional_filters (dict) - from Setting + families (set[str]) - subfamilies + add_ftrack_family (bool) - add ftrack to families if True """ + override_filter = None override_filter_value = -1 for additional_filter in additional_filters: From 249bda0c8020ac5f8b00575de58cc17690cf697d Mon Sep 17 00:00:00 2001 From: Alexey Bogomolov <11698866+movalex@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:41:32 +0300 Subject: [PATCH 092/133] Clockify: refresh and fix the integration (#4607) * WIP clockify fix * WIP disable wp validation, make sync work * fix launcher start timer action * fix finish time entry * fix start and stop timers, cleanup, add TODO * show task name and type in description, add TODO * change rate limiter constants * black formatting * remove task type from data * cleanup debug prints * fix hound comments * remove unused import * move ids to property, fix user validation * remove f-strings, rollback description parsing * attempt to fix ftrack actions * check if sync action got some projects * get api data on process * remove unused variable * remove ratelimiter dependency * add response validation * a bit cleanup * Update openpype/modules/clockify/clockify_module.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Update openpype/modules/clockify/clockify_api.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Update openpype/modules/clockify/clockify_api.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Update openpype/modules/clockify/clockify_api.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Update openpype/modules/clockify/ftrack/server/action_clockify_sync_server.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * replace dunders with underscores * remove excessive variables * update set_user_id * continue check_running if no timer found * bring back come py2 compatibility * cleanup * get values directly from clockapi * hound * get task type to fill the tag field correctly * add logger, catch some json errors * remove check running timer, add project_id verification module * add current task_id check * remove package entries * make method private, fix typo * get task_type for the idle-restarted timer * remove trailing whitespace * show correct idle countdown values * finx indentation * Update openpype/modules/clockify/clockify_api.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Update openpype/modules/clockify/clockify_module.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * revert lock file * remove unused constants and redundant code * import clockify_api inside the method * do not query asset docs double time, add comments * add permissions check fail Exception * rename clockapi to clockify_api * formatting * removed unused variables --------- Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Co-authored-by: Jakub Trllo --- openpype/modules/clockify/clockify_api.py | 363 ++++++++---------- openpype/modules/clockify/clockify_module.py | 173 ++++----- openpype/modules/clockify/constants.py | 2 +- .../server/action_clockify_sync_server.py | 25 +- .../ftrack/user/action_clockify_sync_local.py | 26 +- .../launcher_actions/ClockifyStart.py | 48 ++- .../clockify/launcher_actions/ClockifySync.py | 55 ++- openpype/modules/clockify/widgets.py | 16 +- .../modules/timers_manager/timers_manager.py | 4 +- 9 files changed, 361 insertions(+), 351 deletions(-) diff --git a/openpype/modules/clockify/clockify_api.py b/openpype/modules/clockify/clockify_api.py index 6af911fffc..80979c83ab 100644 --- a/openpype/modules/clockify/clockify_api.py +++ b/openpype/modules/clockify/clockify_api.py @@ -6,34 +6,22 @@ import datetime import requests from .constants import ( CLOCKIFY_ENDPOINT, - ADMIN_PERMISSION_NAMES + ADMIN_PERMISSION_NAMES, ) from openpype.lib.local_settings import OpenPypeSecureRegistry - - -def time_check(obj): - if obj.request_counter < 10: - obj.request_counter += 1 - return - - wait_time = 1 - (time.time() - obj.request_time) - if wait_time > 0: - time.sleep(wait_time) - - obj.request_time = time.time() - obj.request_counter = 0 +from openpype.lib import Logger class ClockifyAPI: + log = Logger.get_logger(__name__) + def __init__(self, api_key=None, master_parent=None): self.workspace_name = None - self.workspace_id = None self.master_parent = master_parent self.api_key = api_key - self.request_counter = 0 - self.request_time = time.time() - + self._workspace_id = None + self._user_id = None self._secure_registry = None @property @@ -44,11 +32,19 @@ class ClockifyAPI: @property def headers(self): - return {"X-Api-Key": self.api_key} + return {"x-api-key": self.api_key} + + @property + def workspace_id(self): + return self._workspace_id + + @property + def user_id(self): + return self._user_id def verify_api(self): for key, value in self.headers.items(): - if value is None or value.strip() == '': + if value is None or value.strip() == "": return False return True @@ -59,65 +55,55 @@ class ClockifyAPI: if api_key is not None and self.validate_api_key(api_key) is True: self.api_key = api_key self.set_workspace() + self.set_user_id() if self.master_parent: self.master_parent.signed_in() return True return False def validate_api_key(self, api_key): - test_headers = {'X-Api-Key': api_key} - action_url = 'workspaces/' - time_check(self) + test_headers = {"x-api-key": api_key} + action_url = "user" response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=test_headers + CLOCKIFY_ENDPOINT + action_url, headers=test_headers ) if response.status_code != 200: return False return True - def validate_workspace_perm(self, workspace_id=None): - user_id = self.get_user_id() + def validate_workspace_permissions(self, workspace_id=None, user_id=None): if user_id is None: + self.log.info("No user_id found during validation") return False if workspace_id is None: workspace_id = self.workspace_id - action_url = "/workspaces/{}/users/{}/permissions".format( - workspace_id, user_id - ) - time_check(self) + action_url = f"workspaces/{workspace_id}/users?includeRoles=1" response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) - user_permissions = response.json() - for perm in user_permissions: - if perm['name'] in ADMIN_PERMISSION_NAMES: + data = response.json() + for user in data: + if user.get("id") == user_id: + roles_data = user.get("roles") + for entities in roles_data: + if entities.get("role") in ADMIN_PERMISSION_NAMES: return True return False def get_user_id(self): - action_url = 'v1/user/' - time_check(self) + action_url = "user" response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) - # this regex is neccessary: UNICODE strings are crashing - # during json serialization - id_regex = '\"{1}id\"{1}\:{1}\"{1}\w+\"{1}' - result = re.findall(id_regex, str(response.content)) - if len(result) != 1: - # replace with log and better message? - print('User ID was not found (this is a BUG!!!)') - return None - return json.loads('{'+result[0]+'}')['id'] + result = response.json() + user_id = result.get("id", None) + + return user_id def set_workspace(self, name=None): if name is None: - name = os.environ.get('CLOCKIFY_WORKSPACE', None) + name = os.environ.get("CLOCKIFY_WORKSPACE", None) self.workspace_name = name - self.workspace_id = None if self.workspace_name is None: return try: @@ -125,7 +111,7 @@ class ClockifyAPI: except Exception: result = False if result is not False: - self.workspace_id = result + self._workspace_id = result if self.master_parent is not None: self.master_parent.start_timer_check() return True @@ -139,6 +125,14 @@ class ClockifyAPI: return all_workspaces[name] return False + def set_user_id(self): + try: + user_id = self.get_user_id() + except Exception: + user_id = None + if user_id is not None: + self._user_id = user_id + def get_api_key(self): return self.secure_registry.get_item("api_key", None) @@ -146,11 +140,9 @@ class ClockifyAPI: self.secure_registry.set_item("api_key", api_key) def get_workspaces(self): - action_url = 'workspaces/' - time_check(self) + action_url = "workspaces/" response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) return { workspace["name"]: workspace["id"] for workspace in response.json() @@ -159,27 +151,22 @@ class ClockifyAPI: def get_projects(self, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/projects/'.format(workspace_id) - time_check(self) + action_url = f"workspaces/{workspace_id}/projects" response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) - - return { - project["name"]: project["id"] for project in response.json() - } + if response.status_code != 403: + result = response.json() + return {project["name"]: project["id"] for project in result} def get_project_by_id(self, project_id, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/projects/{}/'.format( + action_url = "workspaces/{}/projects/{}".format( workspace_id, project_id ) - time_check(self) response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) return response.json() @@ -187,32 +174,24 @@ class ClockifyAPI: def get_tags(self, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/tags/'.format(workspace_id) - time_check(self) + action_url = "workspaces/{}/tags".format(workspace_id) response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) - return { - tag["name"]: tag["id"] for tag in response.json() - } + return {tag["name"]: tag["id"] for tag in response.json()} def get_tasks(self, project_id, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/projects/{}/tasks/'.format( + action_url = "workspaces/{}/projects/{}/tasks".format( workspace_id, project_id ) - time_check(self) response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) - return { - task["name"]: task["id"] for task in response.json() - } + return {task["name"]: task["id"] for task in response.json()} def get_workspace_id(self, workspace_name): all_workspaces = self.get_workspaces() @@ -236,48 +215,64 @@ class ClockifyAPI: return None return all_tasks[tag_name] - def get_task_id( - self, task_name, project_id, workspace_id=None - ): + def get_task_id(self, task_name, project_id, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - all_tasks = self.get_tasks( - project_id, workspace_id - ) + all_tasks = self.get_tasks(project_id, workspace_id) if task_name not in all_tasks: return None return all_tasks[task_name] def get_current_time(self): - return str(datetime.datetime.utcnow().isoformat())+'Z' + return str(datetime.datetime.utcnow().isoformat()) + "Z" def start_time_entry( - self, description, project_id, task_id=None, tag_ids=[], - workspace_id=None, billable=True + self, + description, + project_id, + task_id=None, + tag_ids=None, + workspace_id=None, + user_id=None, + billable=True, ): # Workspace if workspace_id is None: workspace_id = self.workspace_id + # User ID + if user_id is None: + user_id = self._user_id + + # get running timer to check if we need to start it + current_timer = self.get_in_progress() # Check if is currently run another times and has same values - current = self.get_in_progress(workspace_id) - if current is not None: + # DO not restart the timer, if it is already running for curent task + if current_timer: + current_timer_hierarchy = current_timer.get("description") + current_project_id = current_timer.get("projectId") + current_task_id = current_timer.get("taskId") if ( - current.get("description", None) == description and - current.get("projectId", None) == project_id and - current.get("taskId", None) == task_id + description == current_timer_hierarchy + and project_id == current_project_id + and task_id == current_task_id ): + self.log.info( + "Timer for the current project is already running" + ) self.bool_timer_run = True return self.bool_timer_run - self.finish_time_entry(workspace_id) + self.finish_time_entry() # Convert billable to strings if billable: - billable = 'true' + billable = "true" else: - billable = 'false' + billable = "false" # Rest API Action - action_url = 'workspaces/{}/timeEntries/'.format(workspace_id) + action_url = "workspaces/{}/user/{}/time-entries".format( + workspace_id, user_id + ) start = self.get_current_time() body = { "start": start, @@ -285,169 +280,135 @@ class ClockifyAPI: "description": description, "projectId": project_id, "taskId": task_id, - "tagIds": tag_ids + "tagIds": tag_ids, } - time_check(self) response = requests.post( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) - - success = False if response.status_code < 300: - success = True - return success + return True + return False - def get_in_progress(self, workspace_id=None): - if workspace_id is None: - workspace_id = self.workspace_id - action_url = 'workspaces/{}/timeEntries/inProgress'.format( - workspace_id - ) - time_check(self) - response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers - ) + def _get_current_timer_values(self, response): + if response is None: + return try: output = response.json() except json.decoder.JSONDecodeError: - output = None - return output + return None + if output and isinstance(output, list): + return output[0] + return None - def finish_time_entry(self, workspace_id=None): + def get_in_progress(self, user_id=None, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - current = self.get_in_progress(workspace_id) - if current is None: - return + if user_id is None: + user_id = self.user_id - current_id = current["id"] - action_url = 'workspaces/{}/timeEntries/{}'.format( - workspace_id, current_id + action_url = ( + f"workspaces/{workspace_id}/user/" + f"{user_id}/time-entries?in-progress=1" ) - body = { - "start": current["timeInterval"]["start"], - "billable": current["billable"], - "description": current["description"], - "projectId": current["projectId"], - "taskId": current["taskId"], - "tagIds": current["tagIds"], - "end": self.get_current_time() - } - time_check(self) - response = requests.put( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + response = requests.get( + CLOCKIFY_ENDPOINT + action_url, headers=self.headers + ) + return self._get_current_timer_values(response) + + def finish_time_entry(self, workspace_id=None, user_id=None): + if workspace_id is None: + workspace_id = self.workspace_id + if user_id is None: + user_id = self.user_id + current_timer = self.get_in_progress() + if not current_timer: + return + action_url = "workspaces/{}/user/{}/time-entries".format( + workspace_id, user_id + ) + body = {"end": self.get_current_time()} + response = requests.patch( + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) return response.json() - def get_time_entries( - self, workspace_id=None, quantity=10 - ): + def get_time_entries(self, workspace_id=None, user_id=None, quantity=10): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/timeEntries/'.format(workspace_id) - time_check(self) + if user_id is None: + user_id = self.user_id + action_url = "workspaces/{}/user/{}/time-entries".format( + workspace_id, user_id + ) response = requests.get( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) return response.json()[:quantity] - def remove_time_entry(self, tid, workspace_id=None): + def remove_time_entry(self, tid, workspace_id=None, user_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/timeEntries/{}'.format( - workspace_id, tid + action_url = "workspaces/{}/user/{}/time-entries/{}".format( + workspace_id, user_id, tid ) - time_check(self) response = requests.delete( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers + CLOCKIFY_ENDPOINT + action_url, headers=self.headers ) return response.json() def add_project(self, name, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/projects/'.format(workspace_id) + action_url = "workspaces/{}/projects".format(workspace_id) body = { "name": name, "clientId": "", "isPublic": "false", - "estimate": { - "estimate": 0, - "type": "AUTO" - }, + "estimate": {"estimate": 0, "type": "AUTO"}, "color": "#f44336", - "billable": "true" + "billable": "true", } - time_check(self) response = requests.post( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) return response.json() def add_workspace(self, name): - action_url = 'workspaces/' + action_url = "workspaces/" body = {"name": name} - time_check(self) response = requests.post( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) return response.json() - def add_task( - self, name, project_id, workspace_id=None - ): + def add_task(self, name, project_id, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/projects/{}/tasks/'.format( + action_url = "workspaces/{}/projects/{}/tasks".format( workspace_id, project_id ) - body = { - "name": name, - "projectId": project_id - } - time_check(self) + body = {"name": name, "projectId": project_id} response = requests.post( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) return response.json() def add_tag(self, name, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = 'workspaces/{}/tags'.format(workspace_id) - body = { - "name": name - } - time_check(self) + action_url = "workspaces/{}/tags".format(workspace_id) + body = {"name": name} response = requests.post( - CLOCKIFY_ENDPOINT + action_url, - headers=self.headers, - json=body + CLOCKIFY_ENDPOINT + action_url, headers=self.headers, json=body ) return response.json() - def delete_project( - self, project_id, workspace_id=None - ): + def delete_project(self, project_id, workspace_id=None): if workspace_id is None: workspace_id = self.workspace_id - action_url = '/workspaces/{}/projects/{}'.format( + action_url = "/workspaces/{}/projects/{}".format( workspace_id, project_id ) - time_check(self) response = requests.delete( CLOCKIFY_ENDPOINT + action_url, headers=self.headers, @@ -455,12 +416,12 @@ class ClockifyAPI: return response.json() def convert_input( - self, entity_id, entity_name, mode='Workspace', project_id=None + self, entity_id, entity_name, mode="Workspace", project_id=None ): if entity_id is None: error = False error_msg = 'Missing information "{}"' - if mode.lower() == 'workspace': + if mode.lower() == "workspace": if entity_id is None and entity_name is None: if self.workspace_id is not None: entity_id = self.workspace_id @@ -471,14 +432,14 @@ class ClockifyAPI: else: if entity_id is None and entity_name is None: error = True - elif mode.lower() == 'project': + elif mode.lower() == "project": entity_id = self.get_project_id(entity_name) - elif mode.lower() == 'task': + elif mode.lower() == "task": entity_id = self.get_task_id( task_name=entity_name, project_id=project_id ) else: - raise TypeError('Unknown type') + raise TypeError("Unknown type") # Raise error if error: raise ValueError(error_msg.format(mode)) diff --git a/openpype/modules/clockify/clockify_module.py b/openpype/modules/clockify/clockify_module.py index 300d5576e2..200a268ad7 100644 --- a/openpype/modules/clockify/clockify_module.py +++ b/openpype/modules/clockify/clockify_module.py @@ -2,24 +2,13 @@ import os import threading import time -from openpype.modules import ( - OpenPypeModule, - ITrayModule, - IPluginPaths -) +from openpype.modules import OpenPypeModule, ITrayModule, IPluginPaths +from openpype.client import get_asset_by_name -from .clockify_api import ClockifyAPI -from .constants import ( - CLOCKIFY_FTRACK_USER_PATH, - CLOCKIFY_FTRACK_SERVER_PATH -) +from .constants import CLOCKIFY_FTRACK_USER_PATH, CLOCKIFY_FTRACK_SERVER_PATH -class ClockifyModule( - OpenPypeModule, - ITrayModule, - IPluginPaths -): +class ClockifyModule(OpenPypeModule, ITrayModule, IPluginPaths): name = "clockify" def initialize(self, modules_settings): @@ -33,18 +22,23 @@ class ClockifyModule( self.timer_manager = None self.MessageWidgetClass = None self.message_widget = None - - self.clockapi = ClockifyAPI(master_parent=self) + self._clockify_api = None # TimersManager attributes # - set `timers_manager_connector` only in `tray_init` self.timers_manager_connector = None self._timers_manager_module = None + @property + def clockify_api(self): + if self._clockify_api is None: + from .clockify_api import ClockifyAPI + + self._clockify_api = ClockifyAPI(master_parent=self) + return self._clockify_api + def get_global_environments(self): - return { - "CLOCKIFY_WORKSPACE": self.workspace_name - } + return {"CLOCKIFY_WORKSPACE": self.workspace_name} def tray_init(self): from .widgets import ClockifySettings, MessageWidget @@ -52,7 +46,7 @@ class ClockifyModule( self.MessageWidgetClass = MessageWidget self.message_widget = None - self.widget_settings = ClockifySettings(self.clockapi) + self.widget_settings = ClockifySettings(self.clockify_api) self.widget_settings_required = None self.thread_timer_check = None @@ -61,7 +55,7 @@ class ClockifyModule( self.bool_api_key_set = False self.bool_workspace_set = False self.bool_timer_run = False - self.bool_api_key_set = self.clockapi.set_api() + self.bool_api_key_set = self.clockify_api.set_api() # Define itself as TimersManager connector self.timers_manager_connector = self @@ -71,12 +65,11 @@ class ClockifyModule( self.show_settings() return - self.bool_workspace_set = self.clockapi.workspace_id is not None + self.bool_workspace_set = self.clockify_api.workspace_id is not None if self.bool_workspace_set is False: return self.start_timer_check() - self.set_menu_visibility() def tray_exit(self, *_a, **_kw): @@ -85,23 +78,19 @@ class ClockifyModule( def get_plugin_paths(self): """Implementaton of IPluginPaths to get plugin paths.""" actions_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "launcher_actions" + os.path.dirname(os.path.abspath(__file__)), "launcher_actions" ) - return { - "actions": [actions_path] - } + return {"actions": [actions_path]} def get_ftrack_event_handler_paths(self): """Function for Ftrack module to add ftrack event handler paths.""" return { "user": [CLOCKIFY_FTRACK_USER_PATH], - "server": [CLOCKIFY_FTRACK_SERVER_PATH] + "server": [CLOCKIFY_FTRACK_SERVER_PATH], } def clockify_timer_stopped(self): self.bool_timer_run = False - # Call `ITimersManager` method self.timer_stopped() def start_timer_check(self): @@ -122,45 +111,44 @@ class ClockifyModule( def check_running(self): while self.bool_thread_check_running is True: bool_timer_run = False - if self.clockapi.get_in_progress() is not None: + if self.clockify_api.get_in_progress() is not None: bool_timer_run = True if self.bool_timer_run != bool_timer_run: if self.bool_timer_run is True: self.clockify_timer_stopped() elif self.bool_timer_run is False: - actual_timer = self.clockapi.get_in_progress() - if not actual_timer: + current_timer = self.clockify_api.get_in_progress() + if current_timer is None: + continue + current_proj_id = current_timer.get("projectId") + if not current_proj_id: continue - actual_proj_id = actual_timer["projectId"] - if not actual_proj_id: - continue - - project = self.clockapi.get_project_by_id(actual_proj_id) + project = self.clockify_api.get_project_by_id( + current_proj_id + ) if project and project.get("code") == 501: continue - project_name = project["name"] + project_name = project.get("name") - actual_timer_hierarchy = actual_timer["description"] - hierarchy_items = actual_timer_hierarchy.split("/") + current_timer_hierarchy = current_timer.get("description") + if not current_timer_hierarchy: + continue + hierarchy_items = current_timer_hierarchy.split("/") # Each pype timer must have at least 2 items! if len(hierarchy_items) < 2: continue + task_name = hierarchy_items[-1] hierarchy = hierarchy_items[:-1] - task_type = None - if len(actual_timer.get("tags", [])) > 0: - task_type = actual_timer["tags"][0].get("name") data = { "task_name": task_name, "hierarchy": hierarchy, "project_name": project_name, - "task_type": task_type } - # Call `ITimersManager` method self.timer_started(data) self.bool_timer_run = bool_timer_run @@ -184,6 +172,7 @@ class ClockifyModule( def tray_menu(self, parent_menu): # Menu for Tray App from qtpy import QtWidgets + menu = QtWidgets.QMenu("Clockify", parent_menu) menu.setProperty("submenu", "on") @@ -204,7 +193,9 @@ class ClockifyModule( parent_menu.addMenu(menu) def show_settings(self): - self.widget_settings.input_api_key.setText(self.clockapi.get_api_key()) + self.widget_settings.input_api_key.setText( + self.clockify_api.get_api_key() + ) self.widget_settings.show() def set_menu_visibility(self): @@ -218,72 +209,82 @@ class ClockifyModule( def timer_started(self, data): """Tell TimersManager that timer started.""" if self._timers_manager_module is not None: - self._timers_manager_module.timer_started(self._module.id, data) + self._timers_manager_module.timer_started(self.id, data) def timer_stopped(self): """Tell TimersManager that timer stopped.""" if self._timers_manager_module is not None: - self._timers_manager_module.timer_stopped(self._module.id) + self._timers_manager_module.timer_stopped(self.id) def stop_timer(self): """Called from TimersManager to stop timer.""" - self.clockapi.finish_time_entry() + self.clockify_api.finish_time_entry() - def start_timer(self, input_data): - """Called from TimersManager to start timer.""" - # If not api key is not entered then skip - if not self.clockapi.get_api_key(): - return - - actual_timer = self.clockapi.get_in_progress() - actual_timer_hierarchy = None - actual_project_id = None - if actual_timer is not None: - actual_timer_hierarchy = actual_timer.get("description") - actual_project_id = actual_timer.get("projectId") - - # Concatenate hierarchy and task to get description - desc_items = [val for val in input_data.get("hierarchy", [])] - desc_items.append(input_data["task_name"]) - description = "/".join(desc_items) - - # Check project existence - project_name = input_data["project_name"] - project_id = self.clockapi.get_project_id(project_name) + def _verify_project_exists(self, project_name): + project_id = self.clockify_api.get_project_id(project_name) if not project_id: - self.log.warning(( - "Project \"{}\" was not found in Clockify. Timer won't start." - ).format(project_name)) + self.log.warning( + 'Project "{}" was not found in Clockify. Timer won\'t start.' + ).format(project_name) if not self.MessageWidgetClass: return msg = ( - "Project \"{}\" is not" - " in Clockify Workspace \"{}\"." + 'Project "{}" is not' + ' in Clockify Workspace "{}".' "

Please inform your Project Manager." - ).format(project_name, str(self.clockapi.workspace_name)) + ).format(project_name, str(self.clockify_api.workspace_name)) self.message_widget = self.MessageWidgetClass( msg, "Clockify - Info Message" ) self.message_widget.closed.connect(self.on_message_widget_close) self.message_widget.show() + return False + return project_id + def start_timer(self, input_data): + """Called from TimersManager to start timer.""" + # If not api key is not entered then skip + if not self.clockify_api.get_api_key(): return - if ( - actual_timer is not None and - description == actual_timer_hierarchy and - project_id == actual_project_id - ): + task_name = input_data.get("task_name") + + # Concatenate hierarchy and task to get description + description_items = list(input_data.get("hierarchy", [])) + description_items.append(task_name) + description = "/".join(description_items) + + # Check project existence + project_name = input_data.get("project_name") + project_id = self._verify_project_exists(project_name) + if not project_id: return + # Setup timer tags tag_ids = [] - task_tag_id = self.clockapi.get_tag_id(input_data["task_type"]) + tag_name = input_data.get("task_type") + if not tag_name: + # no task_type found in the input data + # if the timer is restarted by idle time (bug?) + asset_name = input_data["hierarchy"][-1] + asset_doc = get_asset_by_name(project_name, asset_name) + task_info = asset_doc["data"]["tasks"][task_name] + tag_name = task_info.get("type", "") + if not tag_name: + self.log.info("No tag information found for the timer") + + task_tag_id = self.clockify_api.get_tag_id(tag_name) if task_tag_id is not None: tag_ids.append(task_tag_id) - self.clockapi.start_time_entry( - description, project_id, tag_ids=tag_ids + # Start timer + self.clockify_api.start_time_entry( + description, + project_id, + tag_ids=tag_ids, + workspace_id=self.clockify_api.workspace_id, + user_id=self.clockify_api.user_id, ) diff --git a/openpype/modules/clockify/constants.py b/openpype/modules/clockify/constants.py index 66f6cb899a..4574f91be1 100644 --- a/openpype/modules/clockify/constants.py +++ b/openpype/modules/clockify/constants.py @@ -9,4 +9,4 @@ CLOCKIFY_FTRACK_USER_PATH = os.path.join( ) ADMIN_PERMISSION_NAMES = ["WORKSPACE_OWN", "WORKSPACE_ADMIN"] -CLOCKIFY_ENDPOINT = "https://api.clockify.me/api/" +CLOCKIFY_ENDPOINT = "https://api.clockify.me/api/v1/" diff --git a/openpype/modules/clockify/ftrack/server/action_clockify_sync_server.py b/openpype/modules/clockify/ftrack/server/action_clockify_sync_server.py index c6b55947da..985cf49b97 100644 --- a/openpype/modules/clockify/ftrack/server/action_clockify_sync_server.py +++ b/openpype/modules/clockify/ftrack/server/action_clockify_sync_server.py @@ -4,7 +4,7 @@ from openpype_modules.ftrack.lib import ServerAction from openpype_modules.clockify.clockify_api import ClockifyAPI -class SyncClocifyServer(ServerAction): +class SyncClockifyServer(ServerAction): '''Synchronise project names and task types.''' identifier = "clockify.sync.server" @@ -14,12 +14,12 @@ class SyncClocifyServer(ServerAction): role_list = ["Pypeclub", "Administrator", "project Manager"] def __init__(self, *args, **kwargs): - super(SyncClocifyServer, self).__init__(*args, **kwargs) + super(SyncClockifyServer, self).__init__(*args, **kwargs) workspace_name = os.environ.get("CLOCKIFY_WORKSPACE") api_key = os.environ.get("CLOCKIFY_API_KEY") - self.clockapi = ClockifyAPI(api_key) - self.clockapi.set_workspace(workspace_name) + self.clockify_api = ClockifyAPI(api_key) + self.clockify_api.set_workspace(workspace_name) if api_key is None: modified_key = "None" else: @@ -48,13 +48,16 @@ class SyncClocifyServer(ServerAction): return True def launch(self, session, entities, event): - if self.clockapi.workspace_id is None: + self.clockify_api.set_api() + if self.clockify_api.workspace_id is None: return { "success": False, "message": "Clockify Workspace or API key are not set!" } - if self.clockapi.validate_workspace_perm() is False: + if not self.clockify_api.validate_workspace_permissions( + self.clockify_api.workspace_id, self.clockify_api.user_id + ): return { "success": False, "message": "Missing permissions for this action!" @@ -88,9 +91,9 @@ class SyncClocifyServer(ServerAction): task_type["name"] for task_type in task_types ] try: - clockify_projects = self.clockapi.get_projects() + clockify_projects = self.clockify_api.get_projects() if project_name not in clockify_projects: - response = self.clockapi.add_project(project_name) + response = self.clockify_api.add_project(project_name) if "id" not in response: self.log.warning( "Project \"{}\" can't be created. Response: {}".format( @@ -105,7 +108,7 @@ class SyncClocifyServer(ServerAction): ).format(project_name) } - clockify_workspace_tags = self.clockapi.get_tags() + clockify_workspace_tags = self.clockify_api.get_tags() for task_type_name in task_type_names: if task_type_name in clockify_workspace_tags: self.log.debug( @@ -113,7 +116,7 @@ class SyncClocifyServer(ServerAction): ) continue - response = self.clockapi.add_tag(task_type_name) + response = self.clockify_api.add_tag(task_type_name) if "id" not in response: self.log.warning( "Task \"{}\" can't be created. Response: {}".format( @@ -138,4 +141,4 @@ class SyncClocifyServer(ServerAction): def register(session, **kw): - SyncClocifyServer(session).register() + SyncClockifyServer(session).register() diff --git a/openpype/modules/clockify/ftrack/user/action_clockify_sync_local.py b/openpype/modules/clockify/ftrack/user/action_clockify_sync_local.py index a430791906..0e8cf6bd37 100644 --- a/openpype/modules/clockify/ftrack/user/action_clockify_sync_local.py +++ b/openpype/modules/clockify/ftrack/user/action_clockify_sync_local.py @@ -3,7 +3,7 @@ from openpype_modules.ftrack.lib import BaseAction, statics_icon from openpype_modules.clockify.clockify_api import ClockifyAPI -class SyncClocifyLocal(BaseAction): +class SyncClockifyLocal(BaseAction): '''Synchronise project names and task types.''' #: Action identifier. @@ -18,9 +18,9 @@ class SyncClocifyLocal(BaseAction): icon = statics_icon("app_icons", "clockify-white.png") def __init__(self, *args, **kwargs): - super(SyncClocifyLocal, self).__init__(*args, **kwargs) + super(SyncClockifyLocal, self).__init__(*args, **kwargs) #: CLockifyApi - self.clockapi = ClockifyAPI() + self.clockify_api = ClockifyAPI() def discover(self, session, entities, event): if ( @@ -31,14 +31,18 @@ class SyncClocifyLocal(BaseAction): return False def launch(self, session, entities, event): - self.clockapi.set_api() - if self.clockapi.workspace_id is None: + self.clockify_api.set_api() + if self.clockify_api.workspace_id is None: return { "success": False, "message": "Clockify Workspace or API key are not set!" } - if self.clockapi.validate_workspace_perm() is False: + if ( + self.clockify_api.validate_workspace_permissions( + self.clockify_api.workspace_id, self.clockify_api.user_id) + is False + ): return { "success": False, "message": "Missing permissions for this action!" @@ -74,9 +78,9 @@ class SyncClocifyLocal(BaseAction): task_type["name"] for task_type in task_types ] try: - clockify_projects = self.clockapi.get_projects() + clockify_projects = self.clockify_api.get_projects() if project_name not in clockify_projects: - response = self.clockapi.add_project(project_name) + response = self.clockify_api.add_project(project_name) if "id" not in response: self.log.warning( "Project \"{}\" can't be created. Response: {}".format( @@ -91,7 +95,7 @@ class SyncClocifyLocal(BaseAction): ).format(project_name) } - clockify_workspace_tags = self.clockapi.get_tags() + clockify_workspace_tags = self.clockify_api.get_tags() for task_type_name in task_type_names: if task_type_name in clockify_workspace_tags: self.log.debug( @@ -99,7 +103,7 @@ class SyncClocifyLocal(BaseAction): ) continue - response = self.clockapi.add_tag(task_type_name) + response = self.clockify_api.add_tag(task_type_name) if "id" not in response: self.log.warning( "Task \"{}\" can't be created. Response: {}".format( @@ -121,4 +125,4 @@ class SyncClocifyLocal(BaseAction): def register(session, **kw): - SyncClocifyLocal(session).register() + SyncClockifyLocal(session).register() diff --git a/openpype/modules/clockify/launcher_actions/ClockifyStart.py b/openpype/modules/clockify/launcher_actions/ClockifyStart.py index 7663aecc31..4a653c1b8d 100644 --- a/openpype/modules/clockify/launcher_actions/ClockifyStart.py +++ b/openpype/modules/clockify/launcher_actions/ClockifyStart.py @@ -6,9 +6,9 @@ from openpype_modules.clockify.clockify_api import ClockifyAPI class ClockifyStart(LauncherAction): name = "clockify_start_timer" label = "Clockify - Start Timer" - icon = "clockify_icon" + icon = "app_icons/clockify.png" order = 500 - clockapi = ClockifyAPI() + clockify_api = ClockifyAPI() def is_compatible(self, session): """Return whether the action is compatible with the session""" @@ -17,23 +17,39 @@ class ClockifyStart(LauncherAction): return False def process(self, session, **kwargs): + self.clockify_api.set_api() + user_id = self.clockify_api.user_id + workspace_id = self.clockify_api.workspace_id project_name = session["AVALON_PROJECT"] asset_name = session["AVALON_ASSET"] task_name = session["AVALON_TASK"] - description = asset_name - asset_doc = get_asset_by_name( - project_name, asset_name, fields=["data.parents"] - ) - if asset_doc is not None: - desc_items = asset_doc.get("data", {}).get("parents", []) - desc_items.append(asset_name) - desc_items.append(task_name) - description = "/".join(desc_items) - project_id = self.clockapi.get_project_id(project_name) - tag_ids = [] - tag_ids.append(self.clockapi.get_tag_id(task_name)) - self.clockapi.start_time_entry( - description, project_id, tag_ids=tag_ids + # fetch asset docs + asset_doc = get_asset_by_name(project_name, asset_name) + + # get task type to fill the timer tag + task_info = asset_doc["data"]["tasks"][task_name] + task_type = task_info["type"] + + # check if the task has hierarchy and fill the + parents_data = asset_doc["data"] + if parents_data is not None: + description_items = parents_data.get("parents", []) + description_items.append(asset_name) + description_items.append(task_name) + description = "/".join(description_items) + + project_id = self.clockify_api.get_project_id( + project_name, workspace_id + ) + tag_ids = [] + tag_name = task_type + tag_ids.append(self.clockify_api.get_tag_id(tag_name, workspace_id)) + self.clockify_api.start_time_entry( + description, + project_id, + tag_ids=tag_ids, + workspace_id=workspace_id, + user_id=user_id, ) diff --git a/openpype/modules/clockify/launcher_actions/ClockifySync.py b/openpype/modules/clockify/launcher_actions/ClockifySync.py index c346a1b4f6..cbd2519a04 100644 --- a/openpype/modules/clockify/launcher_actions/ClockifySync.py +++ b/openpype/modules/clockify/launcher_actions/ClockifySync.py @@ -3,20 +3,39 @@ from openpype_modules.clockify.clockify_api import ClockifyAPI from openpype.pipeline import LauncherAction -class ClockifySync(LauncherAction): +class ClockifyPermissionsCheckFailed(Exception): + """Timer start failed due to user permissions check. + Message should be self explanatory as traceback won't be shown. + """ + pass + + +class ClockifySync(LauncherAction): name = "sync_to_clockify" label = "Sync to Clockify" - icon = "clockify_white_icon" + icon = "app_icons/clockify-white.png" order = 500 - clockapi = ClockifyAPI() - have_permissions = clockapi.validate_workspace_perm() + clockify_api = ClockifyAPI() def is_compatible(self, session): - """Return whether the action is compatible with the session""" - return self.have_permissions + """Check if there's some projects to sync""" + try: + next(get_projects()) + return True + except StopIteration: + return False def process(self, session, **kwargs): + self.clockify_api.set_api() + workspace_id = self.clockify_api.workspace_id + user_id = self.clockify_api.user_id + if not self.clockify_api.validate_workspace_permissions( + workspace_id, user_id + ): + raise ClockifyPermissionsCheckFailed( + "Current CLockify user is missing permissions for this action!" + ) project_name = session.get("AVALON_PROJECT") or "" projects_to_sync = [] @@ -30,24 +49,28 @@ class ClockifySync(LauncherAction): task_types = project["config"]["tasks"].keys() projects_info[project["name"]] = task_types - clockify_projects = self.clockapi.get_projects() + clockify_projects = self.clockify_api.get_projects(workspace_id) for project_name, task_types in projects_info.items(): if project_name in clockify_projects: continue - response = self.clockapi.add_project(project_name) + response = self.clockify_api.add_project( + project_name, workspace_id + ) if "id" not in response: - self.log.error("Project {} can't be created".format( - project_name - )) + self.log.error( + "Project {} can't be created".format(project_name) + ) continue - clockify_workspace_tags = self.clockapi.get_tags() + clockify_workspace_tags = self.clockify_api.get_tags(workspace_id) for task_type in task_types: if task_type not in clockify_workspace_tags: - response = self.clockapi.add_tag(task_type) + response = self.clockify_api.add_tag( + task_type, workspace_id + ) if "id" not in response: - self.log.error('Task {} can\'t be created'.format( - task_type - )) + self.log.error( + "Task {} can't be created".format(task_type) + ) continue diff --git a/openpype/modules/clockify/widgets.py b/openpype/modules/clockify/widgets.py index 122b6212c0..8c28f38b6e 100644 --- a/openpype/modules/clockify/widgets.py +++ b/openpype/modules/clockify/widgets.py @@ -77,15 +77,15 @@ class MessageWidget(QtWidgets.QWidget): class ClockifySettings(QtWidgets.QWidget): - SIZE_W = 300 + SIZE_W = 500 SIZE_H = 130 loginSignal = QtCore.Signal(object, object, object) - def __init__(self, clockapi, optional=True): + def __init__(self, clockify_api, optional=True): super(ClockifySettings, self).__init__() - self.clockapi = clockapi + self.clockify_api = clockify_api self.optional = optional self.validated = False @@ -162,17 +162,17 @@ class ClockifySettings(QtWidgets.QWidget): def click_ok(self): api_key = self.input_api_key.text().strip() if self.optional is True and api_key == '': - self.clockapi.save_api_key(None) - self.clockapi.set_api(api_key) + self.clockify_api.save_api_key(None) + self.clockify_api.set_api(api_key) self.validated = False self._close_widget() return - validation = self.clockapi.validate_api_key(api_key) + validation = self.clockify_api.validate_api_key(api_key) if validation: - self.clockapi.save_api_key(api_key) - self.clockapi.set_api(api_key) + self.clockify_api.save_api_key(api_key) + self.clockify_api.set_api(api_key) self.validated = True self._close_widget() else: diff --git a/openpype/modules/timers_manager/timers_manager.py b/openpype/modules/timers_manager/timers_manager.py index 0ba68285a4..43286f7da4 100644 --- a/openpype/modules/timers_manager/timers_manager.py +++ b/openpype/modules/timers_manager/timers_manager.py @@ -141,7 +141,9 @@ class TimersManager( signal_handler = SignalHandler(self) idle_manager = IdleManager() widget_user_idle = WidgetUserIdle(self) - widget_user_idle.set_countdown_start(self.time_show_message) + widget_user_idle.set_countdown_start( + self.time_stop_timer - self.time_show_message + ) idle_manager.signal_reset_timer.connect( widget_user_idle.reset_countdown From 00b83e58792db4e33d5d218ce942a8667d724265 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:21:27 +0100 Subject: [PATCH 093/133] Refactor `app_data` -> `app_name` --- openpype/hosts/fusion/addon.py | 8 ++++---- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/fusion/addon.py b/openpype/hosts/fusion/addon.py index 345e348c3b..45683cfbde 100644 --- a/openpype/hosts/fusion/addon.py +++ b/openpype/hosts/fusion/addon.py @@ -17,11 +17,11 @@ FUSION_VERSIONS_DICT = { } -def get_fusion_version(app_data): +def get_fusion_version(app_name): """ The function is triggered by the prelaunch hooks to get the fusion version. - `app_data` is obtained by prelaunch hooks from the + `app_name` is obtained by prelaunch hooks from the `launch_context.env.get("AVALON_APP_NAME")`. To get a correct Fusion version, a version number should be present @@ -31,10 +31,10 @@ def get_fusion_version(app_data): log = Logger.get_logger(__name__) - if not app_data: + if not app_name: return - app_version_candidates = re.findall(r"\d+", app_data) + app_version_candidates = re.findall(r"\d+", app_name) if not app_version_candidates: return for app_version in app_version_candidates: diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 15c9424990..cf168194c3 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -125,8 +125,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): ) = self.get_copy_fusion_prefs_settings() # Get launched application context and return correct app version - app_data = self.launch_context.env.get("AVALON_APP_NAME") - app_version = get_fusion_version(app_data) + app_name = self.launch_context.env.get("AVALON_APP_NAME") + app_version = get_fusion_version(app_name) _, profile_version = FUSION_VERSIONS_DICT[app_version] fu_profile = self.get_fusion_profile_name(profile_version) From 35157c81de68b6bcb049ce610b31809856273624 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:30:04 +0100 Subject: [PATCH 094/133] Report if Fusion version not detected --- .../hosts/fusion/hooks/pre_fusion_profile_hook.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index cf168194c3..3a4d827428 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -2,7 +2,7 @@ import os import shutil import platform from pathlib import Path -from openpype.lib import PreLaunchHook +from openpype.lib import PreLaunchHook, ApplicationLaunchFailed from openpype.hosts.fusion import ( FUSION_HOST_DIR, FUSION_VERSIONS_DICT, @@ -127,6 +127,15 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # Get launched application context and return correct app version app_name = self.launch_context.env.get("AVALON_APP_NAME") app_version = get_fusion_version(app_name) + if app_version is None or True: + version_names = ", ".join(str(x) for x in FUSION_VERSIONS_DICT) + raise ApplicationLaunchFailed( + "Unable to detect valid Fusion version number from app " + f"name: {app_name}.\nMake sure to include at least a digit " + "to indicate the Fusion version like '18'.\n" + f"Detectable Fusion versions are: {version_names}" + ) + _, profile_version = FUSION_VERSIONS_DICT[app_version] fu_profile = self.get_fusion_profile_name(profile_version) From 3160a0ede09c859f1a40651af3bf805d1dca2fc7 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:30:21 +0100 Subject: [PATCH 095/133] Remove the debugging logic :) --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 3a4d827428..ee80a9c90a 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -127,7 +127,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # Get launched application context and return correct app version app_name = self.launch_context.env.get("AVALON_APP_NAME") app_version = get_fusion_version(app_name) - if app_version is None or True: + if app_version is None: version_names = ", ".join(str(x) for x in FUSION_VERSIONS_DICT) raise ApplicationLaunchFailed( "Unable to detect valid Fusion version number from app " From f6be90d7a415636e2e848ee4c0f3766dbf87eda6 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:33:16 +0100 Subject: [PATCH 096/133] Debug log instead of info log --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index ee80a9c90a..4e5ff4159b 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -93,8 +93,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): "Destination Fusion preferences folder already exists" ) return - self.log.info(f"Starting copying Fusion preferences") - self.log.info(f"force_sync option is set to {force_sync}") + self.log.info("Starting copying Fusion preferences") + self.log.debug(f"force_sync option is set to {force_sync}") try: copy_to.mkdir(exist_ok=True, parents=True) except PermissionError: From c71651e29e7c51e13513095c5f43180645375404 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:37:51 +0100 Subject: [PATCH 097/133] Match other method calls to `warning` --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 4e5ff4159b..b0a4e19f44 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -98,7 +98,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): try: copy_to.mkdir(exist_ok=True, parents=True) except PermissionError: - self.log.warn(f"Creating the folder not permitted at {copy_to}") + self.log.warning(f"Creating the folder not permitted at {copy_to}") return if not copy_from.exists(): self.log.warning(f"Fusion preferences not found in {copy_from}") From 6a06f80db0e600fdc28d85a8ccac839a38c64ead Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:39:39 +0100 Subject: [PATCH 098/133] Cosmetics + do not add new line because its confusing in command line logs --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index b0a4e19f44..339cf35a7d 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -114,7 +114,7 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # convert Path to str to be compatible with Python 3.6+ shutil.copy(str(file), str(copy_to)) self.log.info( - f"successfully copied preferences:\n {copy_from} to {copy_to}" + f"Successfully copied preferences: {copy_from} to {copy_to}" ) def execute(self): From ae44c0de29af77db9d3e9a342acc5b341cab4954 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 17 Mar 2023 16:42:23 +0100 Subject: [PATCH 099/133] Report the existing folder in the log --- openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 339cf35a7d..fd726ccda1 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -90,7 +90,8 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): """ if copy_to.exists() and not force_sync: self.log.info( - "Destination Fusion preferences folder already exists" + "Destination Fusion preferences folder already exists: " + f"{copy_to} " ) return self.log.info("Starting copying Fusion preferences") From a13f80ef972a4aec8c2a972d9566fa1c4afdef60 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 17 Mar 2023 17:14:22 +0100 Subject: [PATCH 100/133] Maya: Yeti Validate Rig Input - OP-3454 (#4554) * Collect input_SET children in instance. * Fix docs. * Only validate yeti if there are nodes in the scene. * Revert code * Remove connection logic from loader * Connection inventory action * Hound * Revert "Collect input_SET children in instance." This reverts commit 052e65ca1befb19049ee9f02f472d20cf78d8dc1. * Update docs * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau * Update website/docs/artist_hosts_maya_yeti.md Co-authored-by: Roy Nieterau * BigRoy feedback * Hound * Fix typo * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau * Update openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py Co-authored-by: Roy Nieterau * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau * Dont use AVALON_PROJECT * Hound * Update openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py Co-authored-by: Roy Nieterau --------- Co-authored-by: Roy Nieterau --- .../plugins/inventory/connect_yeti_rig.py | 178 ++++++++++++++++++ .../hosts/maya/plugins/load/load_yeti_rig.py | 94 +++------ .../validate_yeti_renderscript_callbacks.py | 12 ++ website/docs/artist_hosts_maya_yeti.md | 79 ++++---- website/docs/assets/maya-yeti_hair_setup.png | Bin 0 -> 138812 bytes .../assets/maya-yeti_load_connections.png | Bin 0 -> 125692 bytes .../docs/assets/maya-yeti_publish_setup.png | Bin 0 -> 133890 bytes website/docs/assets/maya-yeti_rig.jpg | Bin 59405 -> 0 bytes website/docs/assets/maya-yeti_rig_setup.png | Bin 0 -> 111360 bytes website/docs/assets/maya-yeti_simple_rig.png | Bin 0 -> 96188 bytes 10 files changed, 258 insertions(+), 105 deletions(-) create mode 100644 openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py create mode 100644 website/docs/assets/maya-yeti_hair_setup.png create mode 100644 website/docs/assets/maya-yeti_load_connections.png create mode 100644 website/docs/assets/maya-yeti_publish_setup.png delete mode 100644 website/docs/assets/maya-yeti_rig.jpg create mode 100644 website/docs/assets/maya-yeti_rig_setup.png create mode 100644 website/docs/assets/maya-yeti_simple_rig.png diff --git a/openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py b/openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py new file mode 100644 index 0000000000..924a1a4627 --- /dev/null +++ b/openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py @@ -0,0 +1,178 @@ +import os +import json +from collections import defaultdict + +from maya import cmds + +from openpype.pipeline import ( + InventoryAction, get_representation_context, get_representation_path +) +from openpype.hosts.maya.api.lib import get_container_members, get_id + + +class ConnectYetiRig(InventoryAction): + """Connect Yeti Rig with an animation or pointcache.""" + + label = "Connect Yeti Rig" + icon = "link" + color = "white" + + def process(self, containers): + # Validate selection is more than 1. + message = ( + "Only 1 container selected. 2+ containers needed for this action." + ) + if len(containers) == 1: + self.display_warning(message) + return + + # Categorize containers by family. + containers_by_family = defaultdict(list) + for container in containers: + family = get_representation_context( + container["representation"] + )["subset"]["data"]["family"] + containers_by_family[family].append(container) + + # Validate to only 1 source container. + source_containers = containers_by_family.get("animation", []) + source_containers += containers_by_family.get("pointcache", []) + source_container_namespaces = [ + x["namespace"] for x in source_containers + ] + message = ( + "{} animation containers selected:\n\n{}\n\nOnly select 1 of type " + "\"animation\" or \"pointcache\".".format( + len(source_containers), source_container_namespaces + ) + ) + if len(source_containers) != 1: + self.display_warning(message) + return + + source_container = source_containers[0] + source_ids = self.nodes_by_id(source_container) + + # Target containers. + target_ids = {} + inputs = [] + + yeti_rig_containers = containers_by_family.get("yetiRig") + if not yeti_rig_containers: + self.display_warning( + "Select at least one yetiRig container" + ) + return + + for container in yeti_rig_containers: + target_ids.update(self.nodes_by_id(container)) + + maya_file = get_representation_path( + get_representation_context( + container["representation"] + )["representation"] + ) + _, ext = os.path.splitext(maya_file) + settings_file = maya_file.replace(ext, ".rigsettings") + if not os.path.exists(settings_file): + continue + + with open(settings_file) as f: + inputs.extend(json.load(f)["inputs"]) + + # Compare loaded connections to scene. + for input in inputs: + source_node = source_ids.get(input["sourceID"]) + target_node = target_ids.get(input["destinationID"]) + + if not source_node or not target_node: + self.log.debug( + "Could not find nodes for input:\n" + + json.dumps(input, indent=4, sort_keys=True) + ) + continue + source_attr, target_attr = input["connections"] + + if not cmds.attributeQuery( + source_attr, node=source_node, exists=True + ): + self.log.debug( + "Could not find attribute {} on node {} for " + "input:\n{}".format( + source_attr, + source_node, + json.dumps(input, indent=4, sort_keys=True) + ) + ) + continue + + if not cmds.attributeQuery( + target_attr, node=target_node, exists=True + ): + self.log.debug( + "Could not find attribute {} on node {} for " + "input:\n{}".format( + target_attr, + target_node, + json.dumps(input, indent=4, sort_keys=True) + ) + ) + continue + + source_plug = "{}.{}".format( + source_node, source_attr + ) + target_plug = "{}.{}".format( + target_node, target_attr + ) + if cmds.isConnected( + source_plug, target_plug, ignoreUnitConversion=True + ): + self.log.debug( + "Connection already exists: {} -> {}".format( + source_plug, target_plug + ) + ) + continue + + cmds.connectAttr(source_plug, target_plug, force=True) + self.log.debug( + "Connected attributes: {} -> {}".format( + source_plug, target_plug + ) + ) + + def nodes_by_id(self, container): + ids = {} + for member in get_container_members(container): + id = get_id(member) + if not id: + continue + ids[id] = member + + return ids + + def display_warning(self, message, show_cancel=False): + """Show feedback to user. + + Returns: + bool + """ + + from qtpy import QtWidgets + + accept = QtWidgets.QMessageBox.Ok + if show_cancel: + buttons = accept | QtWidgets.QMessageBox.Cancel + else: + buttons = accept + + state = QtWidgets.QMessageBox.warning( + None, + "", + message, + buttons=buttons, + defaultButton=accept + ) + + return state == accept diff --git a/openpype/hosts/maya/plugins/load/load_yeti_rig.py b/openpype/hosts/maya/plugins/load/load_yeti_rig.py index 651607de8a..6a13d2e145 100644 --- a/openpype/hosts/maya/plugins/load/load_yeti_rig.py +++ b/openpype/hosts/maya/plugins/load/load_yeti_rig.py @@ -1,17 +1,12 @@ -import os -from collections import defaultdict +import maya.cmds as cmds -from openpype.settings import get_project_settings +from openpype.settings import get_current_project_settings import openpype.hosts.maya.api.plugin from openpype.hosts.maya.api import lib class YetiRigLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): - """ - This loader will load Yeti rig. You can select something in scene and if it - has same ID as mesh published with rig, their shapes will be linked - together. - """ + """This loader will load Yeti rig.""" families = ["yetiRig"] representations = ["ma"] @@ -22,72 +17,31 @@ class YetiRigLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): color = "orange" def process_reference( - self, context, name=None, namespace=None, options=None): + self, context, name=None, namespace=None, options=None + ): - import maya.cmds as cmds - - # get roots of selected hierarchies - selected_roots = [] - for sel in cmds.ls(sl=True, long=True): - selected_roots.append(sel.split("|")[1]) - - # get all objects under those roots - selected_hierarchy = [] - for root in selected_roots: - selected_hierarchy.append(cmds.listRelatives( - root, - allDescendents=True) or []) - - # flatten the list and filter only shapes - shapes_flat = [] - for root in selected_hierarchy: - shapes = cmds.ls(root, long=True, type="mesh") or [] - for shape in shapes: - shapes_flat.append(shape) - - # create dictionary of cbId and shape nodes - scene_lookup = defaultdict(list) - for node in shapes_flat: - cb_id = lib.get_id(node) - scene_lookup[cb_id] = node - - # load rig + group_name = "{}:{}".format(namespace, name) with lib.maintained_selection(): - file_url = self.prepare_root_value(self.fname, - context["project"]["name"]) - nodes = cmds.file(file_url, - namespace=namespace, - reference=True, - returnNewNodes=True, - groupReference=True, - groupName="{}:{}".format(namespace, name)) + file_url = self.prepare_root_value( + self.fname, context["project"]["name"] + ) + nodes = cmds.file( + file_url, + namespace=namespace, + reference=True, + returnNewNodes=True, + groupReference=True, + groupName=group_name + ) - # for every shape node we've just loaded find matching shape by its - # cbId in selection. If found outMesh of scene shape will connect to - # inMesh of loaded shape. - for destination_node in nodes: - source_node = scene_lookup[lib.get_id(destination_node)] - if source_node: - self.log.info("found: {}".format(source_node)) - self.log.info( - "creating connection to {}".format(destination_node)) - - cmds.connectAttr("{}.outMesh".format(source_node), - "{}.inMesh".format(destination_node), - force=True) - - groupName = "{}:{}".format(namespace, name) - - settings = get_project_settings(os.environ['AVALON_PROJECT']) - colors = settings['maya']['load']['colors'] - - c = colors.get('yetiRig') + settings = get_current_project_settings() + colors = settings["maya"]["load"]["colors"] + c = colors.get("yetiRig") if c is not None: - cmds.setAttr(groupName + ".useOutlinerColor", 1) - cmds.setAttr(groupName + ".outlinerColor", - (float(c[0])/255), - (float(c[1])/255), - (float(c[2])/255) + cmds.setAttr(group_name + ".useOutlinerColor", 1) + cmds.setAttr( + group_name + ".outlinerColor", + (float(c[0]) / 255), (float(c[1]) / 255), (float(c[2]) / 255) ) self[:] = nodes diff --git a/openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py b/openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py index a864a18cee..06250f5779 100644 --- a/openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py +++ b/openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py @@ -48,6 +48,18 @@ class ValidateYetiRenderScriptCallbacks(pyblish.api.InstancePlugin): yeti_loaded = cmds.pluginInfo("pgYetiMaya", query=True, loaded=True) + if not yeti_loaded and not cmds.ls(type="pgYetiMaya"): + # The yeti plug-in is available and loaded so at + # this point we don't really care whether the scene + # has any yeti callback set or not since if the callback + # is there it wouldn't error and if it weren't then + # nothing happens because there are no yeti nodes. + cls.log.info( + "Yeti is loaded but no yeti nodes were found. " + "Callback validation skipped.." + ) + return False + renderer = instance.data["renderer"] if renderer == "redshift": cls.log.info("Redshift ignores any pre and post render callbacks") diff --git a/website/docs/artist_hosts_maya_yeti.md b/website/docs/artist_hosts_maya_yeti.md index f5a6a4d2c9..aa783cc8b6 100644 --- a/website/docs/artist_hosts_maya_yeti.md +++ b/website/docs/artist_hosts_maya_yeti.md @@ -9,7 +9,9 @@ sidebar_label: Yeti OpenPype can work with [Yeti](https://peregrinelabs.com/yeti/) in two data modes. It can handle Yeti caches and Yeti rigs. -### Creating and publishing Yeti caches +## Yeti Caches + +### Creating and publishing Let start by creating simple Yeti setup, just one object and Yeti node. Open new empty scene in Maya and create sphere. Then select sphere and go **Yeti → Create Yeti Node on Mesh** @@ -44,7 +46,15 @@ You can now publish Yeti cache as any other types. **OpenPype → Publish**. It create sequence of `.fur` files and `.fursettings` metadata file with Yeti node setting. -### Loading Yeti caches +:::note Collect Yeti Cache failure +If you encounter **Collect Yeti Cache** failure during collecting phase, and the error is like +```fix +No object matches name: pgYetiMaya1Shape.cbId +``` +then it is probably caused by scene not being saved before publishing. +::: + +### Loading You can load Yeti cache by **OpenPype → Load ...**. Select your cache, right+click on it and select **Load Yeti cache**. This will create Yeti node in scene and set its @@ -52,26 +62,39 @@ cache path to point to your published cache files. Note that this Yeti node will be named with same name as the one you've used to publish cache. Also notice that when you open graph on this Yeti node, all nodes are as they were in publishing node. -### Creating and publishing Yeti Rig +## Yeti Rigs -Yeti Rigs are working in similar way as caches, but are more complex and they deal with -other data used by Yeti, like geometry and textures. +### Creating and publishing -Let's start by [loading](artist_hosts_maya.md#loading-model) into new scene some model. -I've loaded my Buddha model. +Yeti Rigs are designed to connect to published models or animation rig. The workflow gives the Yeti Rig full control on that geometry to do additional things on top of whatever input comes in, e.g. deleting faces, pushing faces in/out, subdividing, etc. -Create select model mesh, create Yeti node - **Yeti → Create Yeti Node on Mesh** and -setup similar Yeti graph as in cache example above. +Let's start with a [model](artist_hosts_maya.md#loading-model) or [rig](artist_hosts_maya.md#loading-rigs) loaded into the scene. Here we are using a simple rig. -Then select this Yeti node (mine is called with default name `pgYetiMaya1`) and -create *Yeti Rig instance* - **OpenPype → Create...** and select **Yeti Cache**. +![Maya - Yeti Simple Rig](assets/maya-yeti_simple_rig.png) + +We'll need to prepare the scene a bit. We want some Yeti hair on the ball geometry, so duplicating the geometry, adding the Yeti hair and grouping it together. + +![Maya - Yeti Hair Setup](assets/maya-yeti_hair_setup.png) + +:::note yeti nodes and types +You can use any number of Yeti nodes and types, but they have to have unique names. +::: + +Now we need to connect the Yeti Rig with the animation rig. Yeti Rigs work by publishing the attribute connections from its input nodes and reconnect them later in the pipeline. This means we can only use attribute connections to from outside of the Yeti Rig hierarchy. Internal to the Yeti Rig hierarchy, we can use any complexity of node connections. We'll connnect the Yeti Rig geometry to the animation rig, with the transform and mesh attributes. + +![Maya - Yeti Rig Setup](assets/maya-yeti_rig_setup.png) + +Now we are ready for publishing. Select the Yeti Rig group (`rig_GRP`) and +create *Yeti Rig instance* - **OpenPype → Create...** and select **Yeti Rig**. Leave `Use selection` checked. -Last step is to add our model geometry to rig instance, so middle+drag its -geometry to `input_SET` under `yetiRigDefault` set representing rig instance. +Last step is to add our geometry to the rig instance, so middle+drag its +geometry to `input_SET` under the `yetiRigMain` set representing rig instance. Note that its name can differ and is based on your subset name. -![Maya - Yeti Rig Setup](assets/maya-yeti_rig.jpg) +![Maya - Yeti Publish Setup](assets/maya-yeti_publish_setup.png) + +You can have any number of nodes in the Yeti Rig, but only nodes with incoming attribute connections from outside of the Yeti Rig hierarchy is needed in the `input_SET`. Save your scene and ready for publishing our new simple Yeti Rig! @@ -81,28 +104,14 @@ the beginning of your timeline. It will also collect all textures used in Yeti node, copy them to publish folder `resource` directory and set *Image search path* of published node to this location. -:::note Collect Yeti Cache failure -If you encounter **Collect Yeti Cache** failure during collecting phase, and the error is like -```fix -No object matches name: pgYetiMaya1Shape.cbId -``` -then it is probably caused by scene not being saved before publishing. -::: +### Loading -### Loading Yeti Rig - -You can load published Yeti Rigs as any other thing in OpenPype - **OpenPype → Load ...**, +You can load published Yeti Rigs in OpenPype with **OpenPype → Load ...**, select you Yeti rig and right+click on it. In context menu you should see -**Load Yeti Cache** and **Load Yeti Rig** items (among others). First one will -load that one frame cache. The other one will load whole rig. +**Load Yeti Rig** item (among others). -Notice that although we put only geometry into `input_SET`, whole hierarchy was -pulled inside also. This allows you to store complex scene element along Yeti -node. +To connect the Yeti Rig with published animation, we'll load in the animation and use the Inventory to establish the connections. -:::tip auto-connecting rig mesh to existing one -If you select some objects before loading rig it will try to find shapes -under selected hierarchies and match them with shapes loaded with rig (published -under `input_SET`). This mechanism uses *cbId* attribute on those shapes. -If match is found shapes are connected using their `outMesh` and `outMesh`. Thus you can easily connect existing animation to loaded rig. -::: +![Maya - Yeti Publish Setup](assets/maya-yeti_load_connections.png) + +The Yeti Rig should now be following the animation. :tada: diff --git a/website/docs/assets/maya-yeti_hair_setup.png b/website/docs/assets/maya-yeti_hair_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd7f5f97a259bb653d7bdbe171d9a12cf8ac7be GIT binary patch literal 138812 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 MZWh2!_Zu@zC-RKjZe8Y@R=?oKtf2P(R@GSfdH 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

6UB=BTN2JGQDhT}p%k(-!~F@xZG> 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≦Kv8 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-yeti_rig.jpg b/website/docs/assets/maya-yeti_rig.jpg deleted file mode 100644 index 07b13db409d0ad6bf1f887896e6f3d0fd5e7e10b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59405 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%0D1;wn^$71V{3R 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 EFKbZ!`Tzg` diff --git a/website/docs/assets/maya-yeti_rig_setup.png b/website/docs/assets/maya-yeti_rig_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..876ecba0a2b0e4496f590a650de56532c3b104f0 GIT binary patch literal 111360 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
^s@U(eB2|H$bp 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-yeti_simple_rig.png b/website/docs/assets/maya-yeti_simple_rig.png new file mode 100644 index 0000000000000000000000000000000000000000..31a60ac40b3f712e7ecd1bcdac4fc80017977594 GIT binary patch literal 96188 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

`}O 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 literal 0 HcmV?d00001 From 3159bcb878a4002459d2dbcd52f63216453475e0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 17 Mar 2023 17:39:54 +0100 Subject: [PATCH 101/133] Use right plugic class for 'CollectInstanceCommentDef' --- openpype/plugins/publish/collect_comment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/collect_comment.py b/openpype/plugins/publish/collect_comment.py index 5be04731ac..9f41e37f22 100644 --- a/openpype/plugins/publish/collect_comment.py +++ b/openpype/plugins/publish/collect_comment.py @@ -29,7 +29,7 @@ from openpype.pipeline.publish import OpenPypePyblishPluginMixin class CollectInstanceCommentDef( - pyblish.api.ContextPlugin, + pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin ): label = "Comment per instance" From f050a024aa5c97cb61c2f780349e89dbce5c0f82 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 16 Mar 2023 16:52:06 +0100 Subject: [PATCH 102/133] add an include parent hierarchy option in animation creator plugin of maya --- openpype/hosts/maya/plugins/create/create_animation.py | 4 +++- openpype/settings/defaults/project_settings/maya.json | 1 + .../schemas/projects_schema/schemas/schema_maya_create.json | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_animation.py b/openpype/hosts/maya/plugins/create/create_animation.py index a4b6e86598..2ea1b22bcb 100644 --- a/openpype/hosts/maya/plugins/create/create_animation.py +++ b/openpype/hosts/maya/plugins/create/create_animation.py @@ -13,6 +13,7 @@ class CreateAnimation(plugin.Creator): icon = "male" write_color_sets = False write_face_sets = False + include_parent_hierarchy = False include_user_defined_attributes = False def __init__(self, *args, **kwargs): @@ -37,7 +38,8 @@ class CreateAnimation(plugin.Creator): self.data["visibleOnly"] = False # Include the groups above the out_SET content - self.data["includeParentHierarchy"] = False # Include parent groups + # Include parent groups + self.data["includeParentHierarchy"] = self.include_parent_hierarchy # Default to exporting world-space self.data["worldSpace"] = True diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 63ba4542f3..2aa95fd1be 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -147,6 +147,7 @@ "enabled": true, "write_color_sets": false, "write_face_sets": false, + "include_parent_hierarchy": false, "include_user_defined_attributes": false, "defaults": [ "Main" diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json index 1598f90643..d6e6c97b8c 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json @@ -132,6 +132,11 @@ "key": "write_face_sets", "label": "Write Face Sets" }, + { + "type": "boolean", + "key": "include_parent_hierarchy", + "label": "Include Parent Hierarchy" + }, { "type": "boolean", "key": "include_user_defined_attributes", From 3eb8833596bf5b0780ebf4eca381e937e62c29b1 Mon Sep 17 00:00:00 2001 From: Thomas Fricard <51854004+friquette@users.noreply.github.com> Date: Fri, 17 Mar 2023 09:06:45 +0100 Subject: [PATCH 103/133] Update openpype/hosts/maya/plugins/create/create_animation.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/create/create_animation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_animation.py b/openpype/hosts/maya/plugins/create/create_animation.py index 2ea1b22bcb..f992ff2c1a 100644 --- a/openpype/hosts/maya/plugins/create/create_animation.py +++ b/openpype/hosts/maya/plugins/create/create_animation.py @@ -38,7 +38,6 @@ class CreateAnimation(plugin.Creator): self.data["visibleOnly"] = False # Include the groups above the out_SET content - # Include parent groups self.data["includeParentHierarchy"] = self.include_parent_hierarchy # Default to exporting world-space From ecdc8966d05b9cd5256b664dd635b7004ccfb860 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 13 Jan 2023 12:36:20 +0100 Subject: [PATCH 104/133] Implement Maya image file node loader --- .../hosts/maya/plugins/load/load_image.py | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 openpype/hosts/maya/plugins/load/load_image.py diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py new file mode 100644 index 0000000000..cdd895ff4b --- /dev/null +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -0,0 +1,176 @@ +from openpype.pipeline import ( + load, + get_representation_path +) +from openpype.lib import EnumDef +from openpype.hosts.maya.api.pipeline import containerise +from openpype.hosts.maya.api.lib import ( + unique_namespace, + namespaced +) + +from maya import cmds + + +def create_texture(): + """Create place2dTexture with file node with uv connections + + Mimics Maya "file [Texture]" creation. + """ + + place = cmds.shadingNode("place2dTexture", asUtility=True, name="place2d") + file = cmds.shadingNode("file", asTexture=True, name="file") + + connections = ["coverage", "translateFrame", "rotateFrame", "rotateUV", + "mirrorU", "mirrorV", "stagger", "wrapV", "wrapU", + "repeatUV", "offset", "noiseUV", "vertexUvThree", + "vertexUvTwo", "vertexUvOne", "vertexCameraOne"] + for attr in connections: + src = "{}.{}".format(place, attr) + dest = "{}.{}".format(file, attr) + cmds.connectAttr(src, dest) + + cmds.connectAttr(place + '.outUV', file + '.uvCoord') + cmds.connectAttr(place + '.outUvFilterSize', file + '.uvFilterSize') + + return file, place + + +def create_projection(): + """Create texture with place3dTexture and projection + + Mimics Maya "file [Projection]" creation. + """ + + file, place = create_texture() + projection = cmds.shadingNode("projection", asTexture=True, + name="projection") + place3d = cmds.shadingNode("place3dTexture", asUtility=True, + name="place3d") + + cmds.connectAttr(place3d + '.worldInverseMatrix[0]', + projection + ".placementMatrix") + cmds.connectAttr(file + '.outColor', projection + ".image") + + return file, place, projection, place3d + + +def create_stencil(): + """Create texture with extra place2dTexture offset and stencil + + Mimics Maya "file [Stencil]" creation. + """ + + file, place = create_texture() + + place_stencil = cmds.shadingNode("place2dTexture", asUtility=True, + name="place2d_stencil") + stencil = cmds.shadingNode("stencil", asTexture=True, name="stencil") + + for src_attr, dest_attr in [ + ("outUV", "uvCoord"), + ("outUvFilterSize", "uvFilterSize") + ]: + src_plug = "{}.{}".format(place_stencil, src_attr) + cmds.connectAttr(src_plug, "{}.{}".format(place, dest_attr)) + cmds.connectAttr(src_plug, "{}.{}".format(stencil, dest_attr)) + + return file, place, stencil, place_stencil + + +class FileNodeLoader(load.LoaderPlugin): + """File node loader.""" + # TODO: Implement color space manamagent OCIO (set correct color space) + + families = ["image", "plate", "render"] + label = "Load file node" + representations = ["exr", "tif", "png", "jpg"] + icon = "image" + color = "orange" + order = 2 + + options = [ + EnumDef( + "mode", + items={ + "texture": "Texture", + "projection": "Projection", + "stencil": "Stencil" + }, + default="texture", + label="Texture Mode" + ) + ] + + def load(self, context, name, namespace, data): + + path = self.fname + asset = context['asset']['name'] + namespace = namespace or unique_namespace( + asset + "_", + prefix="_" if asset[0].isdigit() else "", + suffix="_", + ) + + with namespaced(namespace, new=True) as namespace: + # Create the nodes within the namespace + nodes = { + "texture": create_texture, + "projection": create_projection, + "stencil": create_stencil + }[data.get("mode", "texture")]() + + # Set the file node attributes + file_node = cmds.ls(nodes, type="file")[0] + cmds.setAttr(file_node + ".fileTextureName", path, type="string") + + # Set UV tiling mode if UDIM tiles + # TODO: Detect UDIM tiles and set accordingly (also on update) + cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles + + # Enable sequence if publish has `startFrame` and `endFrame` and + # `startFrame != endFrame` + # TODO: Detect sequences (also on update) + # cmds.setAttr(file_node + ".useFrameExtension", True) + + # For ease of access for the user select all the nodes and select + # the file node last so that UI shows its attributes by default + cmds.select(list(nodes) + [file_node], replace=True) + + return containerise( + name=name, + namespace=namespace, + nodes=nodes, + context=context, + loader=self.__class__.__name__ + ) + + def update(self, container, representation): + + path = get_representation_path(representation) + members = cmds.sets(container['objectName'], query=True) + + file_node = cmds.ls(members, type="file")[0] + cmds.setAttr(file_node + ".fileTextureName", path, type="string") + + # Update representation + cmds.setAttr( + container["objectName"] + ".representation", + str(representation["_id"]), + type="string" + ) + + def switch(self, container, representation): + self.update(container, representation) + + def remove(self, container): + members = cmds.sets(container['objectName'], query=True) + cmds.lockNode(members, lock=False) + cmds.delete([container['objectName']] + members) + + # Clean up the namespace + try: + cmds.namespace(removeNamespace=container['namespace'], + deleteNamespaceContent=True) + except RuntimeError: + pass From c6b583e85f96acd48d2951b38e89666007075e95 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 11:36:51 +0100 Subject: [PATCH 105/133] Detect udim and frame sequences --- .../hosts/maya/plugins/load/load_image.py | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index cdd895ff4b..117d1a7d0f 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -112,6 +112,10 @@ class FileNodeLoader(load.LoaderPlugin): suffix="_", ) + repre_context = context["representation"]["context"] + has_frames = repre_context.get("frame") is not None + has_udim = repre_context.get("udim") is not None + with namespaced(namespace, new=True) as namespace: # Create the nodes within the namespace nodes = { @@ -125,13 +129,15 @@ class FileNodeLoader(load.LoaderPlugin): cmds.setAttr(file_node + ".fileTextureName", path, type="string") # Set UV tiling mode if UDIM tiles - # TODO: Detect UDIM tiles and set accordingly (also on update) - cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles + if has_udim: + cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles # Enable sequence if publish has `startFrame` and `endFrame` and # `startFrame != endFrame` - # TODO: Detect sequences (also on update) - # cmds.setAttr(file_node + ".useFrameExtension", True) + if has_frames: + is_sequence = self._is_sequence(context) + if is_sequence: + cmds.setAttr(file_node + ".useFrameExtension", True) # For ease of access for the user select all the nodes and select # the file node last so that UI shows its attributes by default @@ -174,3 +180,28 @@ class FileNodeLoader(load.LoaderPlugin): deleteNamespaceContent=True) except RuntimeError: pass + + def _is_sequence(self, context): + """Check whether frameStart and frameEnd are not the same.""" + version = context.get("version", {}) + representation = context.get("representation", {}) + + print(version) + print(representation) + + for doc in [representation, version]: + # Frame range can be set on version or representation. When set on + # representation it overrides data on subset + data = doc.get("data", {}) + start = data.get("frameStartHandle", data.get("frameStart", None)) + end = data.get("frameEndHandle", data.get("frameEnd", None)) + + if start is None or end is None: + continue + + if start != end: + return True + else: + return False + + return False From a48e638798da6eadd87904cf6652424b33759d56 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 12:33:54 +0100 Subject: [PATCH 106/133] Explicitly set the frame and udim token based on template. --- .../hosts/maya/plugins/load/load_image.py | 67 ++++++++++++++++--- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index 117d1a7d0f..b7b0b5d4c8 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -1,6 +1,7 @@ +import copy from openpype.pipeline import ( load, - get_representation_path + get_representation_context ) from openpype.lib import EnumDef from openpype.hosts.maya.api.pipeline import containerise @@ -8,6 +9,8 @@ from openpype.hosts.maya.api.lib import ( unique_namespace, namespaced ) +from openpype.pipeline.load.utils import get_representation_path_from_context + from maya import cmds @@ -104,7 +107,7 @@ class FileNodeLoader(load.LoaderPlugin): def load(self, context, name, namespace, data): - path = self.fname + path = self._format_path(context) asset = context['asset']['name'] namespace = namespace or unique_namespace( asset + "_", @@ -123,10 +126,7 @@ class FileNodeLoader(load.LoaderPlugin): "projection": create_projection, "stencil": create_stencil }[data.get("mode", "texture")]() - - # Set the file node attributes file_node = cmds.ls(nodes, type="file")[0] - cmds.setAttr(file_node + ".fileTextureName", path, type="string") # Set UV tiling mode if UDIM tiles if has_udim: @@ -137,8 +137,17 @@ class FileNodeLoader(load.LoaderPlugin): if has_frames: is_sequence = self._is_sequence(context) if is_sequence: + # When enabling useFrameExtension maya automatically + # connects an expression to .frameExtension to set + # the current frame. However, this expression is generated + # with some delay and thus it'll show a warning if frame 0 + # doesn't exist because we're explicitly setting the + # token. cmds.setAttr(file_node + ".useFrameExtension", True) + # Set the file node path attribute + cmds.setAttr(file_node + ".fileTextureName", path, type="string") + # For ease of access for the user select all the nodes and select # the file node last so that UI shows its attributes by default cmds.select(list(nodes) + [file_node], replace=True) @@ -153,7 +162,8 @@ class FileNodeLoader(load.LoaderPlugin): def update(self, container, representation): - path = get_representation_path(representation) + context = get_representation_context(representation) + path = self._format_path(context) members = cmds.sets(container['objectName'], query=True) file_node = cmds.ls(members, type="file")[0] @@ -186,9 +196,6 @@ class FileNodeLoader(load.LoaderPlugin): version = context.get("version", {}) representation = context.get("representation", {}) - print(version) - print(representation) - for doc in [representation, version]: # Frame range can be set on version or representation. When set on # representation it overrides data on subset @@ -205,3 +212,45 @@ class FileNodeLoader(load.LoaderPlugin): return False return False + + def _format_path(self, context): + """Format the path with correct tokens for frames and udim tiles.""" + + context = copy.deepcopy(context) + representation = context["representation"] + template = representation.get("data", {}).get("template") + if not template: + # No template to find token locations for + return get_representation_path_from_context(context) + + def _placeholder(key): + # Substitute with a long placeholder value so that potential + # custom formatting with padding doesn't find its way into + # our formatting, so that wouldn't be padded as 0 + return "___{}___".format(key) + + # We want to format UDIM and Frame numbers with the specific tokens + # so we in-place change the representation context so it's formatted + # with the tokens as we'd want them. So we explicitly change those + # tokens around with what we'd need. + tokens = { + "frame": "", + "udim": "" + } + has_tokens = False + repre_context = representation["context"] + for key, token in tokens.items(): + if key in repre_context: + repre_context[key] = _placeholder(key) + has_tokens = True + + # Replace with our custom template that has the tokens set + representation["data"]["template"] = template + path = get_representation_path_from_context(context) + + if has_tokens: + for key, token in tokens.items(): + if key in repre_context: + path = path.replace(_placeholder(key), token) + + return path From 1c5b82168853236b532828a0c4daf8187f0f00a8 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 12:34:58 +0100 Subject: [PATCH 107/133] Cosmetics --- openpype/hosts/maya/plugins/load/load_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index b7b0b5d4c8..c08724dca0 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -239,7 +239,7 @@ class FileNodeLoader(load.LoaderPlugin): } has_tokens = False repre_context = representation["context"] - for key, token in tokens.items(): + for key, _token in tokens.items(): if key in repre_context: repre_context[key] = _placeholder(key) has_tokens = True From 4ac950aa604b5107d68f314df94472148148f2f5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 15:26:55 +0100 Subject: [PATCH 108/133] Set color space from publish using representation color space data or falling back to imageio settings file rules in OP settings --- .../hosts/maya/plugins/load/load_image.py | 142 ++++++++++++++---- 1 file changed, 110 insertions(+), 32 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index c08724dca0..0e535f1692 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -1,16 +1,24 @@ +import os import copy + +from openpype.lib import EnumDef from openpype.pipeline import ( load, get_representation_context ) -from openpype.lib import EnumDef +from openpype.pipeline.load.utils import get_representation_path_from_context +from openpype.pipeline.colorspace import ( + get_imageio_colorspace_from_filepath, + get_imageio_config, + get_imageio_file_rules +) +from openpype.settings import get_project_settings + from openpype.hosts.maya.api.pipeline import containerise from openpype.hosts.maya.api.lib import ( unique_namespace, namespaced ) -from openpype.pipeline.load.utils import get_representation_path_from_context - from maya import cmds @@ -83,7 +91,6 @@ def create_stencil(): class FileNodeLoader(load.LoaderPlugin): """File node loader.""" - # TODO: Implement color space manamagent OCIO (set correct color space) families = ["image", "plate", "render"] label = "Load file node" @@ -107,7 +114,6 @@ class FileNodeLoader(load.LoaderPlugin): def load(self, context, name, namespace, data): - path = self._format_path(context) asset = context['asset']['name'] namespace = namespace or unique_namespace( asset + "_", @@ -115,10 +121,6 @@ class FileNodeLoader(load.LoaderPlugin): suffix="_", ) - repre_context = context["representation"]["context"] - has_frames = repre_context.get("frame") is not None - has_udim = repre_context.get("udim") is not None - with namespaced(namespace, new=True) as namespace: # Create the nodes within the namespace nodes = { @@ -126,31 +128,14 @@ class FileNodeLoader(load.LoaderPlugin): "projection": create_projection, "stencil": create_stencil }[data.get("mode", "texture")]() - file_node = cmds.ls(nodes, type="file")[0] - # Set UV tiling mode if UDIM tiles - if has_udim: - cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles + file_node = cmds.ls(nodes, type="file")[0] - # Enable sequence if publish has `startFrame` and `endFrame` and - # `startFrame != endFrame` - if has_frames: - is_sequence = self._is_sequence(context) - if is_sequence: - # When enabling useFrameExtension maya automatically - # connects an expression to .frameExtension to set - # the current frame. However, this expression is generated - # with some delay and thus it'll show a warning if frame 0 - # doesn't exist because we're explicitly setting the - # token. - cmds.setAttr(file_node + ".useFrameExtension", True) + self._apply_representation_context(context, file_node) - # Set the file node path attribute - cmds.setAttr(file_node + ".fileTextureName", path, type="string") - - # For ease of access for the user select all the nodes and select - # the file node last so that UI shows its attributes by default - cmds.select(list(nodes) + [file_node], replace=True) + # For ease of access for the user select all the nodes and select + # the file node last so that UI shows its attributes by default + cmds.select(list(nodes) + [file_node], replace=True) return containerise( name=name, @@ -167,7 +152,7 @@ class FileNodeLoader(load.LoaderPlugin): members = cmds.sets(container['objectName'], query=True) file_node = cmds.ls(members, type="file")[0] - cmds.setAttr(file_node + ".fileTextureName", path, type="string") + self._apply_representation_context(context, file_node) # Update representation cmds.setAttr( @@ -191,6 +176,51 @@ class FileNodeLoader(load.LoaderPlugin): except RuntimeError: pass + def _apply_representation_context(self, context, file_node): + """Update the file node to match the context. + + This sets the file node's attributes for: + - file path + - udim tiling mode (if it is an udim tile) + - use frame extension (if it is a sequence) + - colorspace + + """ + + repre_context = context["representation"]["context"] + has_frames = repre_context.get("frame") is not None + has_udim = repre_context.get("udim") is not None + + # Set UV tiling mode if UDIM tiles + if has_udim: + cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles + else: + cmds.setAttr(file_node + ".uvTilingMode", 0) # off + + # Enable sequence if publish has `startFrame` and `endFrame` and + # `startFrame != endFrame` + if has_frames and self._is_sequence(context): + # When enabling useFrameExtension maya automatically + # connects an expression to .frameExtension to set + # the current frame. However, this expression is generated + # with some delay and thus it'll show a warning if frame 0 + # doesn't exist because we're explicitly setting the + # token. + cmds.setAttr(file_node + ".useFrameExtension", True) + else: + cmds.setAttr(file_node + ".useFrameExtension", False) + + # Set the file node path attribute + path = self._format_path(context) + cmds.setAttr(file_node + ".fileTextureName", path, type="string") + + # Set colorspace + colorspace = self._get_colorspace(context) + if colorspace: + cmds.setAttr(file_node + ".colorSpace", colorspace, type="string") + else: + self.log.debug("Unknown colorspace - setting colorspace skipped.") + def _is_sequence(self, context): """Check whether frameStart and frameEnd are not the same.""" version = context.get("version", {}) @@ -213,6 +243,54 @@ class FileNodeLoader(load.LoaderPlugin): return False + def _get_colorspace(self, context): + """Return colorspace of the file to load. + + Retrieves the explicit colorspace from the publish. If no colorspace + data is stored with published content then project imageio settings + are used to make an assumption of the colorspace based on the file + rules. If no file rules match then None is returned. + + Returns: + str or None: The colorspace of the file or None if not detected. + + """ + + # We can't apply color spaces if management is not enabled + if not cmds.colorManagementPrefs(query=True, cmEnabled=True): + return + + representation = context["representation"] + colorspace_data = representation.get("data", {}).get("colorspaceData") + if colorspace_data: + return colorspace_data["colorspace"] + + # Assume colorspace from filepath based on project settings + project_name = context["project"]["name"] + host_name = os.environ.get("AVALON_APP") + project_settings = get_project_settings(project_name) + + config_data = get_imageio_config( + project_name, host_name, + project_settings=project_settings + ) + file_rules = get_imageio_file_rules( + project_name, host_name, + project_settings=project_settings + ) + + path = get_representation_path_from_context(context) + colorspace = get_imageio_colorspace_from_filepath( + path=path, + host_name=host_name, + project_name=project_name, + config_data=config_data, + file_rules=file_rules, + project_settings=project_settings + ) + + return colorspace + def _format_path(self, context): """Format the path with correct tokens for frames and udim tiles.""" From 5a7e90daa8df073b4af735799d6b53ba2e911921 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 15:27:42 +0100 Subject: [PATCH 109/133] Cleanup --- openpype/hosts/maya/plugins/load/load_image.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index 0e535f1692..e975fb8b61 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -147,11 +147,10 @@ class FileNodeLoader(load.LoaderPlugin): def update(self, container, representation): - context = get_representation_context(representation) - path = self._format_path(context) members = cmds.sets(container['objectName'], query=True) - file_node = cmds.ls(members, type="file")[0] + + context = get_representation_context(representation) self._apply_representation_context(context, file_node) # Update representation From 91b99cafd42b69a00dc714f1a71089de60467771 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 15:48:43 +0100 Subject: [PATCH 110/133] Correctly set the UDIM token using capitals + cleanup comment --- openpype/hosts/maya/plugins/load/load_image.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index e975fb8b61..3cf2394525 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -306,13 +306,12 @@ class FileNodeLoader(load.LoaderPlugin): # our formatting, so that wouldn't be padded as 0 return "___{}___".format(key) - # We want to format UDIM and Frame numbers with the specific tokens - # so we in-place change the representation context so it's formatted - # with the tokens as we'd want them. So we explicitly change those - # tokens around with what we'd need. + # We format UDIM and Frame numbers with their specific tokens. To do so + # we in-place change the representation context data to format the path + # with our own data tokens = { "frame": "", - "udim": "" + "udim": "" } has_tokens = False repre_context = representation["context"] From b47722b35823d557e64377e74130185b5cb143a7 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 6 Mar 2023 15:52:47 +0100 Subject: [PATCH 111/133] Fix comment --- openpype/hosts/maya/plugins/load/load_image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index 3cf2394525..b464c268fc 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -226,8 +226,8 @@ class FileNodeLoader(load.LoaderPlugin): representation = context.get("representation", {}) for doc in [representation, version]: - # Frame range can be set on version or representation. When set on - # representation it overrides data on subset + # Frame range can be set on version or representation. + # When set on representation it overrides version data. data = doc.get("data", {}) start = data.get("frameStartHandle", data.get("frameStart", None)) end = data.get("frameEndHandle", data.get("frameEnd", None)) From 812fa065cfa5068eba12e83c5bf428e9dfd68255 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 15 Mar 2023 16:08:07 +0000 Subject: [PATCH 112/133] Multiple Values - support multiple values for render attributes. - support repairing the render attributes. --- .../publish/validate_rendersettings.py | 80 ++++++++++++------- .../schemas/schema_maya_publish.json | 12 ++- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 94e2633593..3b2bd1a84a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -242,10 +242,6 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): cls.DEFAULT_PADDING, "0" * cls.DEFAULT_PADDING)) # load validation definitions from settings - validation_settings = ( - instance.context.data["project_settings"]["maya"]["publish"]["ValidateRenderSettings"].get( # noqa: E501 - "{}_render_attributes".format(renderer)) or [] - ) settings_lights_flag = instance.context.data["project_settings"].get( "maya", {}).get( "RenderSettings", {}).get( @@ -253,15 +249,54 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): instance_lights_flag = instance.data.get("renderSetupIncludeLights") if settings_lights_flag != instance_lights_flag: - cls.log.warning('Instance flag for "Render Setup Include Lights" is set to {0} and Settings flag is set to {1}'.format(instance_lights_flag, settings_lights_flag)) # noqa + cls.log.warning( + "Instance flag for \"Render Setup Include Lights\" is set to " + "{} and Settings flag is set to {}".format( + instance_lights_flag, settings_lights_flag + ) + ) # go through definitions and test if such node.attribute exists. # if so, compare its value from the one required. - for attr, value in OrderedDict(validation_settings).items(): - cls.log.debug("{}: {}".format(attr, value)) + for attribute, data in cls.get_nodes(instance, renderer).items(): + for node in data["nodes"]: + try: + render_value = cmds.getAttr( + "{}.{}".format(node, attribute) + ) + except RuntimeError: + invalid = True + cls.log.error( + "Cannot get value of {}.{}".format(node, attribute) + ) + else: + if str(render_value) not in data["values"]: + invalid = True + cls.log.error( + "Invalid value {} set on {}.{}. Expecting " + "{}".format( + render_value, node, attribute, data["values"] + ) + ) + + return invalid + + @classmethod + def get_nodes(cls, instance, renderer): + maya_settings = instance.context.data["project_settings"]["maya"] + validation_settings = ( + maya_settings["publish"]["ValidateRenderSettings"].get( + "{}_render_attributes".format(renderer) + ) or [] + ) + result = {} + for attr, values in OrderedDict(validation_settings).items(): + cls.log.debug("{}: {}".format(attr, values)) if "." not in attr: - cls.log.warning("Skipping invalid attribute defined in " - "validation settings: '{}'".format(attr)) + cls.log.warning( + "Skipping invalid attribute defined in validation " + "settings: \"{}\"".format(attr) + ) continue node_type, attribute_name = attr.split(".", 1) @@ -271,28 +306,13 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): if not nodes: cls.log.warning( - "No nodes of type '{}' found.".format(node_type)) + "No nodes of type \"{}\" found.".format(node_type) + ) continue - for node in nodes: - try: - render_value = cmds.getAttr( - "{}.{}".format(node, attribute_name)) - except RuntimeError: - invalid = True - cls.log.error( - "Cannot get value of {}.{}".format( - node, attribute_name)) - else: - if str(value) != str(render_value): - invalid = True - cls.log.error( - ("Invalid value {} set on {}.{}. " - "Expecting {}").format( - render_value, node, attribute_name, value) - ) + result[attribute_name] = {"nodes": nodes, "values": values} - return invalid + return result @classmethod def repair(cls, instance): @@ -305,6 +325,10 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): "{aov_separator}", instance.data.get("aovSeparator", "_") ) + for attribute, data in cls.get_nodes(instance, renderer).items(): + for node in data["nodes"]: + lib.set_attribute(attribute, data["values"][0], node) + with lib.renderlayer(layer_node): default = lib.RENDER_ATTRS['default'] render_attrs = lib.RENDER_ATTRS.get(renderer, default) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 3484f42f6b..5a66f8a513 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -369,7 +369,8 @@ "label": "Arnold Render Attributes", "use_label_wrap": true, "object_type": { - "type": "text" + "type": "list", + "object_type": "text" } }, { @@ -379,7 +380,8 @@ "label": "Vray Render Attributes", "use_label_wrap": true, "object_type": { - "type": "text" + "type": "list", + "object_type": "text" } }, { @@ -389,7 +391,8 @@ "label": "Redshift Render Attributes", "use_label_wrap": true, "object_type": { - "type": "text" + "type": "list", + "object_type": "text" } }, { @@ -399,7 +402,8 @@ "label": "Renderman Render Attributes", "use_label_wrap": true, "object_type": { - "type": "text" + "type": "list", + "object_type": "text" } } ] From 51fa89bef31b6b8f5ed7927bbadd31a64195977e Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 15 Mar 2023 16:08:14 +0000 Subject: [PATCH 113/133] Docs cosmetics. --- website/docs/admin_hosts_maya.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index ae0cf76f53..685213c206 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -6,13 +6,13 @@ sidebar_label: Maya ## Publish Plugins -### Render Settings Validator +### Render Settings Validator `ValidateRenderSettings` Render Settings Validator is here to make sure artists will submit renders -we correct settings. Some of these settings are needed by OpenPype but some -can be defined by TD using [OpenPype Settings UI](admin_settings.md). +with the correct settings. Some of these settings are needed by OpenPype but some +can be defined by the admin using [OpenPype Settings UI](admin_settings.md). OpenPype enforced settings include: @@ -51,7 +51,7 @@ just one instance of this node type but if that is not so, validator will go thr instances and check the value there. Node type for **VRay** settings is `VRaySettingsNode`, for **Renderman** it is `rmanGlobals`, for **Redshift** it is `RedshiftOptions`. -### Model Name Validator +### Model Name Validator `ValidateRenderSettings` @@ -95,7 +95,7 @@ You can set various aspects of scene submission to farm with per-project setting - **Optional** will mark sumission plugin optional - **Active** will enable/disable plugin - - **Tile Assembler Plugin** will set what should be used to assemble tiles on Deadline. Either **Open Image IO** will be used + - **Tile Assembler Plugin** will set what should be used to assemble tiles on Deadline. Either **Open Image IO** will be used or Deadlines **Draft Tile Assembler**. - **Use Published scene** enable to render from published scene instead of scene in work area. Rendering from published files is much safer. - **Use Asset dependencies** will mark job pending on farm until asset dependencies are fulfilled - for example Deadline will wait for scene file to be synced to cloud, etc. @@ -169,5 +169,3 @@ Fill in the necessary fields (the optional fields are regex filters) - Build your workfile ![maya build template](assets/maya-build_workfile_from_template.png) - - From 8bd4598e0907a07635b0a9aff3b0eabffa29685c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 15 Mar 2023 16:26:48 +0000 Subject: [PATCH 114/133] Update docs --- website/docs/admin_hosts_maya.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 685213c206..82109f0e0c 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -36,10 +36,9 @@ For **Renderman**: For **Arnold**: - there shouldn't be `` token when merge AOVs option is turned on - Additional check can be added via Settings - **Project Settings > Maya > Publish plugin > ValidateRenderSettings**. You can add as many options as you want for every supported renderer. In first field put node type and attribute -and in the second required value. +and in the second required value. You can create multiple values for an attribute, but when repairing it'll be the first value in the list that get selected. ![Settings example](assets/maya-admin_render_settings_validator.png) From b8633c42793ccd0c9417ad29b639c9b322591d3c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 16 Mar 2023 16:59:56 +0000 Subject: [PATCH 115/133] Ensure attributes values from settings are correct. --- .../publish/validate_rendersettings.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 3b2bd1a84a..53f340cd2c 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -13,6 +13,22 @@ from openpype.pipeline.publish import ( from openpype.hosts.maya.api import lib +def convert_to_int_or_float(string_value): + # Order of types are important here since float can convert string + # representation of integer. + types = [int, float] + for t in types: + try: + result = t(string_value) + except ValueError: + continue + else: + return result + + # Neither integer or float. + return string_value + + def get_redshift_image_format_labels(): """Return nice labels for Redshift image formats.""" var = "$g_redshiftImageFormatLabels" @@ -259,6 +275,15 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): # go through definitions and test if such node.attribute exists. # if so, compare its value from the one required. for attribute, data in cls.get_nodes(instance, renderer).items(): + # Validate the settings has values. + if not data["values"]: + cls.log.error( + "Settings for {}.{} is missing values.".format( + node, attribute + ) + ) + continue + for node in data["nodes"]: try: render_value = cmds.getAttr( @@ -270,7 +295,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): "Cannot get value of {}.{}".format(node, attribute) ) else: - if str(render_value) not in data["values"]: + if render_value not in data["values"]: invalid = True cls.log.error( "Invalid value {} set on {}.{}. Expecting " @@ -299,6 +324,8 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): ) continue + values = [convert_to_int_or_float(v) for v in values] + node_type, attribute_name = attr.split(".", 1) # first get node of that type @@ -326,6 +353,8 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): ) for attribute, data in cls.get_nodes(instance, renderer).items(): + if not data["values"]: + continue for node in data["nodes"]: lib.set_attribute(attribute, data["values"][0], node) From 917a1f4d0a20852614f32818ef13caff425c2cad Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 17 Mar 2023 10:26:56 +0000 Subject: [PATCH 116/133] Update docs image --- .../maya-admin_render_settings_validator.png | Bin 11220 -> 11855 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/website/docs/assets/maya-admin_render_settings_validator.png b/website/docs/assets/maya-admin_render_settings_validator.png index 8687b538b124c6857534d9033a46c70deb875fde..8ee11f16f6fb275901e1b11243d5a39d38d7b02c 100644 GIT binary patch literal 11855 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 literal 11220 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 Date: Fri, 17 Mar 2023 15:58:59 +0000 Subject: [PATCH 117/133] Info on attribute collection --- website/docs/admin_hosts_maya.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 82109f0e0c..23cacb4193 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -50,6 +50,10 @@ just one instance of this node type but if that is not so, validator will go thr instances and check the value there. Node type for **VRay** settings is `VRaySettingsNode`, for **Renderman** it is `rmanGlobals`, for **Redshift** it is `RedshiftOptions`. +:::info getting attribute values +If you do not know what an attributes value is supposed to be, for example for dropdown menu (enum), try changing the attribute and look in the script editor where it should log what the attribute was set to. +::: + ### Model Name Validator `ValidateRenderSettings` From 739b2db0f099286acf7f0f194403652fd23f18b1 Mon Sep 17 00:00:00 2001 From: moonyuet Date: Tue, 14 Mar 2023 09:48:24 +0100 Subject: [PATCH 118/133] MaxScene Family introduction --- .../max/plugins/create/create_maxScene.py | 26 ++++++++++ .../hosts/max/plugins/load/load_max_scene.py | 3 +- .../plugins/publish/extract_max_scene_raw.py | 3 +- openpype/plugins/publish/integrate.py | 1 + openpype/plugins/publish/integrate_legacy.py | 1 + tools/build.ps1 | 49 +++++++++---------- 6 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 openpype/hosts/max/plugins/create/create_maxScene.py diff --git a/openpype/hosts/max/plugins/create/create_maxScene.py b/openpype/hosts/max/plugins/create/create_maxScene.py new file mode 100644 index 0000000000..52da615be4 --- /dev/null +++ b/openpype/hosts/max/plugins/create/create_maxScene.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +"""Creator plugin for creating raw max scene.""" +from openpype.hosts.max.api import plugin +from openpype.pipeline import CreatedInstance + + +class CreateMaxScene(plugin.MaxCreator): + identifier = "io.openpype.creators.max.maxScene" + label = "Max Scene(Raw)" + family = "maxScene" + icon = "gear" + + def create(self, subset_name, instance_data, pre_create_data): + from pymxs import runtime as rt + sel_obj = list(rt.selection) + instance = super(CreateMaxScene, self).create( + subset_name, + instance_data, + pre_create_data) # type: CreatedInstance + container = rt.getNodeByName(instance.data.get("instance_node")) + # TODO: Disable "Add to Containers?" Panel + # parent the selected cameras into the container + for obj in sel_obj: + obj.parent = container + # for additional work on the node: + # instance_node = rt.getNodeByName(instance.get("instance_node")) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index b863b9363f..fa8b6b2894 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -9,7 +9,8 @@ from openpype.hosts.max.api import lib class MaxSceneLoader(load.LoaderPlugin): """Max Scene Loader""" - families = ["camera"] + families = ["camera", + "maxScene"] representations = ["max"] order = -8 icon = "code-fork" diff --git a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py index cacc84c591..4e567ab76e 100644 --- a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py +++ b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py @@ -19,7 +19,8 @@ class ExtractMaxSceneRaw(publish.Extractor, order = pyblish.api.ExtractorOrder - 0.2 label = "Extract Max Scene (Raw)" - hosts = ["max"] + hosts = ["max", + "maxScene"] families = ["camera"] optional = True diff --git a/openpype/plugins/publish/integrate.py b/openpype/plugins/publish/integrate.py index b117006871..69b7734c70 100644 --- a/openpype/plugins/publish/integrate.py +++ b/openpype/plugins/publish/integrate.py @@ -84,6 +84,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): "camera", "animation", "model", + "maxScene", "mayaAscii", "mayaScene", "setdress", diff --git a/openpype/plugins/publish/integrate_legacy.py b/openpype/plugins/publish/integrate_legacy.py index b93abab1d8..66c2c9be51 100644 --- a/openpype/plugins/publish/integrate_legacy.py +++ b/openpype/plugins/publish/integrate_legacy.py @@ -80,6 +80,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "camera", "animation", "model", + "maxScene", "mayaAscii", "mayaScene", "setdress", diff --git a/tools/build.ps1 b/tools/build.ps1 index 195b2dc75e..f60cb2d0c4 100644 --- a/tools/build.ps1 +++ b/tools/build.ps1 @@ -22,10 +22,10 @@ https://openpype.io/docs #> -$arguments=$ARGS -$disable_submodule_update="" -if($arguments -eq "--no-submodule-update") { - $disable_submodule_update=$true +$arguments = $ARGS +$disable_submodule_update = "" +if ($arguments -eq "--no-submodule-update") { + $disable_submodule_update = $true } $current_dir = Get-Location @@ -45,13 +45,11 @@ function Start-Progress { # $origpos.Y -= 1 - while (($job.State -eq "Running") -and ($job.State -ne "NotStarted")) - { + while (($job.State -eq "Running") -and ($job.State -ne "NotStarted")) { $host.UI.RawUI.CursorPosition = $origpos Write-Host $scroll[$idx] -NoNewline $idx++ - if ($idx -ge $scroll.Length) - { + if ($idx -ge $scroll.Length) { $idx = 0 } Start-Sleep -Milliseconds 100 @@ -59,7 +57,7 @@ function Start-Progress { # It's over - clear the activity indicator. $host.UI.RawUI.CursorPosition = $origpos Write-Host ' ' - <# + <# .SYNOPSIS Display spinner for running job .PARAMETER code @@ -69,17 +67,17 @@ function Start-Progress { function Exit-WithCode($exitcode) { - # Only exit this host process if it's a child of another PowerShell parent process... - $parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId - $parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name - if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) } + # Only exit this host process if it's a child of another PowerShell parent process... + $parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId + $parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name + if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) } - exit $exitcode + exit $exitcode } function Show-PSWarning() { if ($PSVersionTable.PSVersion.Major -lt 7) { - Write-Color -Text "!!! ", "You are using old version of PowerShell - ", "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" -Color Red, Yellow, White + Write-Color -Text "!!! ", "You are using old version of PowerShell - ", "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" -Color Red, Yellow, White Write-Color -Text " Please update to at least 7.0 - ", "https://github.com/PowerShell/PowerShell/releases" -Color Yellow, White Exit-WithCode 1 } @@ -87,7 +85,7 @@ function Show-PSWarning() { function Install-Poetry() { Write-Color -Text ">>> ", "Installing Poetry ... " -Color Green, Gray - $env:POETRY_HOME="$openpype_root\.poetry" + $env:POETRY_HOME = "$openpype_root\.poetry" (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python - } @@ -126,8 +124,8 @@ $version_file = Get-Content -Path "$($openpype_root)\openpype\version.py" $result = [regex]::Matches($version_file, '__version__ = "(?\d+\.\d+.\d+.*)"') $openpype_version = $result[0].Groups['version'].Value if (-not $openpype_version) { - Write-Color -Text "!!! ", "Cannot determine OpenPype version." -Color Yellow, Gray - Exit-WithCode 1 + Write-Color -Text "!!! ", "Cannot determine OpenPype version." -Color Yellow, Gray + Exit-WithCode 1 } # Create build directory if not exist @@ -147,7 +145,8 @@ catch { if (-not $disable_submodule_update) { Write-Color -Text ">>> ", "Making sure submodules are up-to-date ..." -Color Green, Gray & git submodule update --init --recursive -} else { +} +else { Write-Color -Text "*** ", "Not updating submodules ..." -Color Green, Gray } @@ -158,7 +157,8 @@ if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) { Write-Color -Text "NOT FOUND" -Color Yellow Write-Color -Text "*** ", "We need to install Poetry create virtual env first ..." -Color Yellow, Gray & "$openpype_root\tools\create_env.ps1" -} else { +} +else { Write-Color -Text "OK" -Color Green } @@ -173,8 +173,7 @@ $startTime = [int][double]::Parse((Get-Date -UFormat %s)) $out = & "$($env:POETRY_HOME)\bin\poetry" run python setup.py build 2>&1 Set-Content -Path "$($openpype_root)\build\build.log" -Value $out -if ($LASTEXITCODE -ne 0) -{ +if ($LASTEXITCODE -ne 0) { Write-Color -Text "------------------------------------------" -Color Red Get-Content "$($openpype_root)\build\build.log" Write-Color -Text "------------------------------------------" -Color Yellow @@ -189,8 +188,8 @@ Write-Color -Text ">>> ", "Restoring current directory" -Color Green, Gray Set-Location -Path $current_dir $endTime = [int][double]::Parse((Get-Date -UFormat %s)) -try -{ +try { New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done in $( $endTime - $startTime ) secs. You will find OpenPype and build log in build directory." -} catch {} +} +catch {} Write-Color -Text "*** ", "All done in ", $($endTime - $startTime), " secs. You will find OpenPype and build log in ", "'.\build'", " directory." -Color Green, Gray, White, Gray, White, Gray From 6a93cb199033dbd144f30c73571828b3657f88fb Mon Sep 17 00:00:00 2001 From: moonyuet Date: Tue, 14 Mar 2023 09:52:14 +0100 Subject: [PATCH 119/133] rename creator --- openpype/hosts/max/plugins/create/create_maxScene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/create/create_maxScene.py b/openpype/hosts/max/plugins/create/create_maxScene.py index 52da615be4..7900336f32 100644 --- a/openpype/hosts/max/plugins/create/create_maxScene.py +++ b/openpype/hosts/max/plugins/create/create_maxScene.py @@ -6,7 +6,7 @@ from openpype.pipeline import CreatedInstance class CreateMaxScene(plugin.MaxCreator): identifier = "io.openpype.creators.max.maxScene" - label = "Max Scene(Raw)" + label = "Max Scene" family = "maxScene" icon = "gear" From 5895b4f376714dce66f5d8a40552cda71b92368c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 15 Mar 2023 21:42:15 +0800 Subject: [PATCH 120/133] putting maxScene into correct families --- .../plugins/publish/extract_max_scene_raw.py | 6 +-- tools/build.ps1 | 49 ++++++++++--------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py index 4e567ab76e..969f87be48 100644 --- a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py +++ b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py @@ -19,9 +19,9 @@ class ExtractMaxSceneRaw(publish.Extractor, order = pyblish.api.ExtractorOrder - 0.2 label = "Extract Max Scene (Raw)" - hosts = ["max", - "maxScene"] - families = ["camera"] + hosts = ["max"] + families = ["camera", + "maxScene"] optional = True def process(self, instance): diff --git a/tools/build.ps1 b/tools/build.ps1 index f60cb2d0c4..195b2dc75e 100644 --- a/tools/build.ps1 +++ b/tools/build.ps1 @@ -22,10 +22,10 @@ https://openpype.io/docs #> -$arguments = $ARGS -$disable_submodule_update = "" -if ($arguments -eq "--no-submodule-update") { - $disable_submodule_update = $true +$arguments=$ARGS +$disable_submodule_update="" +if($arguments -eq "--no-submodule-update") { + $disable_submodule_update=$true } $current_dir = Get-Location @@ -45,11 +45,13 @@ function Start-Progress { # $origpos.Y -= 1 - while (($job.State -eq "Running") -and ($job.State -ne "NotStarted")) { + while (($job.State -eq "Running") -and ($job.State -ne "NotStarted")) + { $host.UI.RawUI.CursorPosition = $origpos Write-Host $scroll[$idx] -NoNewline $idx++ - if ($idx -ge $scroll.Length) { + if ($idx -ge $scroll.Length) + { $idx = 0 } Start-Sleep -Milliseconds 100 @@ -57,7 +59,7 @@ function Start-Progress { # It's over - clear the activity indicator. $host.UI.RawUI.CursorPosition = $origpos Write-Host ' ' - <# + <# .SYNOPSIS Display spinner for running job .PARAMETER code @@ -67,17 +69,17 @@ function Start-Progress { function Exit-WithCode($exitcode) { - # Only exit this host process if it's a child of another PowerShell parent process... - $parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId - $parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name - if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) } + # Only exit this host process if it's a child of another PowerShell parent process... + $parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId + $parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name + if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) } - exit $exitcode + exit $exitcode } function Show-PSWarning() { if ($PSVersionTable.PSVersion.Major -lt 7) { - Write-Color -Text "!!! ", "You are using old version of PowerShell - ", "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" -Color Red, Yellow, White + Write-Color -Text "!!! ", "You are using old version of PowerShell - ", "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" -Color Red, Yellow, White Write-Color -Text " Please update to at least 7.0 - ", "https://github.com/PowerShell/PowerShell/releases" -Color Yellow, White Exit-WithCode 1 } @@ -85,7 +87,7 @@ function Show-PSWarning() { function Install-Poetry() { Write-Color -Text ">>> ", "Installing Poetry ... " -Color Green, Gray - $env:POETRY_HOME = "$openpype_root\.poetry" + $env:POETRY_HOME="$openpype_root\.poetry" (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python - } @@ -124,8 +126,8 @@ $version_file = Get-Content -Path "$($openpype_root)\openpype\version.py" $result = [regex]::Matches($version_file, '__version__ = "(?\d+\.\d+.\d+.*)"') $openpype_version = $result[0].Groups['version'].Value if (-not $openpype_version) { - Write-Color -Text "!!! ", "Cannot determine OpenPype version." -Color Yellow, Gray - Exit-WithCode 1 + Write-Color -Text "!!! ", "Cannot determine OpenPype version." -Color Yellow, Gray + Exit-WithCode 1 } # Create build directory if not exist @@ -145,8 +147,7 @@ catch { if (-not $disable_submodule_update) { Write-Color -Text ">>> ", "Making sure submodules are up-to-date ..." -Color Green, Gray & git submodule update --init --recursive -} -else { +} else { Write-Color -Text "*** ", "Not updating submodules ..." -Color Green, Gray } @@ -157,8 +158,7 @@ if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) { Write-Color -Text "NOT FOUND" -Color Yellow Write-Color -Text "*** ", "We need to install Poetry create virtual env first ..." -Color Yellow, Gray & "$openpype_root\tools\create_env.ps1" -} -else { +} else { Write-Color -Text "OK" -Color Green } @@ -173,7 +173,8 @@ $startTime = [int][double]::Parse((Get-Date -UFormat %s)) $out = & "$($env:POETRY_HOME)\bin\poetry" run python setup.py build 2>&1 Set-Content -Path "$($openpype_root)\build\build.log" -Value $out -if ($LASTEXITCODE -ne 0) { +if ($LASTEXITCODE -ne 0) +{ Write-Color -Text "------------------------------------------" -Color Red Get-Content "$($openpype_root)\build\build.log" Write-Color -Text "------------------------------------------" -Color Yellow @@ -188,8 +189,8 @@ Write-Color -Text ">>> ", "Restoring current directory" -Color Green, Gray Set-Location -Path $current_dir $endTime = [int][double]::Parse((Get-Date -UFormat %s)) -try { +try +{ New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done in $( $endTime - $startTime ) secs. You will find OpenPype and build log in build directory." -} -catch {} +} catch {} Write-Color -Text "*** ", "All done in ", $($endTime - $startTime), " secs. You will find OpenPype and build log in ", "'.\build'", " directory." -Color Green, Gray, White, Gray, White, Gray From b2be8462c4ce95b17084e96f949377612681b8a1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 15 Mar 2023 23:32:54 +0800 Subject: [PATCH 121/133] updating the loader so that the version will work in scene inventory --- .../hosts/max/plugins/load/load_max_scene.py | 3 +- .../publish/validate_no_max_content.py | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 openpype/hosts/max/plugins/publish/validate_no_max_content.py diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index fa8b6b2894..460f4822a6 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -47,8 +47,7 @@ class MaxSceneLoader(load.LoaderPlugin): path = get_representation_path(representation) node = rt.getNodeByName(container["instance_node"]) - - max_objects = self.get_container_children(node) + max_objects = node.Children for max_object in max_objects: max_object.source = path diff --git a/openpype/hosts/max/plugins/publish/validate_no_max_content.py b/openpype/hosts/max/plugins/publish/validate_no_max_content.py new file mode 100644 index 0000000000..0cf3b53044 --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_no_max_content.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +import pyblish.api +from openpype.pipeline import PublishValidationError +from pymxs import runtime as rt + + +class ValidateMaxContents(pyblish.api.InstancePlugin): + """Validates Max contents. + + Check if MaxScene container includes any contents underneath. + """ + + order = pyblish.api.ValidatorOrder + families = ["maxScene"] + hosts = ["max"] + label = "Max Scene Contents" + + def process(self, instance): + invalid = self.get_invalid(instance) + if invalid: + raise PublishValidationError("No content found in the container") + + def get_invalid(self, instance): + invalid = [] + container = rt.getNodeByName(instance.data["instance_node"]) + if not container.Children: + invalid.append(container) + + return invalid From e35f7e0bb5d805b80f46aa9fdb1e40a18667fa2a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 16 Mar 2023 00:06:29 +0800 Subject: [PATCH 122/133] update the validator which errors out with the empty container --- .../plugins/publish/validate_no_max_content.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_no_max_content.py b/openpype/hosts/max/plugins/publish/validate_no_max_content.py index 0cf3b53044..c20a1968ed 100644 --- a/openpype/hosts/max/plugins/publish/validate_no_max_content.py +++ b/openpype/hosts/max/plugins/publish/validate_no_max_content.py @@ -11,19 +11,13 @@ class ValidateMaxContents(pyblish.api.InstancePlugin): """ order = pyblish.api.ValidatorOrder - families = ["maxScene"] + families = ["camera", + "maxScene", + "maxrender"] hosts = ["max"] label = "Max Scene Contents" def process(self, instance): - invalid = self.get_invalid(instance) - if invalid: - raise PublishValidationError("No content found in the container") - - def get_invalid(self, instance): - invalid = [] container = rt.getNodeByName(instance.data["instance_node"]) - if not container.Children: - invalid.append(container) - - return invalid + if not list(container.Children): + raise PublishValidationError("No content found in the container") From 99ed91d0adb162a61005ce689d485d6f25619808 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 16 Mar 2023 14:03:25 +0800 Subject: [PATCH 123/133] fix the bug of submitting the frames for published job --- openpype/hosts/max/api/lib_renderproducts.py | 48 ++++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index a74a6a7426..350eb97661 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -8,6 +8,7 @@ from openpype.hosts.max.api.lib import ( get_current_renderer, get_default_render_folder ) +from openpype.pipeline.context_tools import get_current_project_asset from openpype.settings import get_project_settings from openpype.pipeline import legacy_io @@ -34,14 +35,20 @@ class RenderProducts(object): filename, container) + context = get_current_project_asset() + startFrame = context["data"].get("frameStart") + endFrame = context["data"].get("frameEnd") + 1 + img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa - full_render_list = [] - beauty = self.beauty_render_product(output_file, img_fmt) - full_render_list.append(beauty) + full_render_list = self.beauty_render_product(output_file, + startFrame, + endFrame, + img_fmt) renderer_class = get_current_renderer() renderer = str(renderer_class).split(":")[0] + if renderer == "VUE_File_Renderer": return full_render_list @@ -54,6 +61,8 @@ class RenderProducts(object): "Quicksilver_Hardware_Renderer", ]: render_elem_list = self.render_elements_product(output_file, + startFrame, + endFrame, img_fmt) if render_elem_list: full_render_list.extend(iter(render_elem_list)) @@ -61,18 +70,24 @@ class RenderProducts(object): if renderer == "Arnold": aov_list = self.arnold_render_product(output_file, + startFrame, + endFrame, img_fmt) if aov_list: full_render_list.extend(iter(aov_list)) return full_render_list - def beauty_render_product(self, folder, fmt): - beauty_output = f"{folder}.####.{fmt}" - beauty_output = beauty_output.replace("\\", "/") - return beauty_output + def beauty_render_product(self, folder, startFrame, endFrame, fmt): + beauty_frame_range = [] + for f in range(startFrame, endFrame): + beauty_output = f"{folder}.{f}.{fmt}" + beauty_output = beauty_output.replace("\\", "/") + beauty_frame_range.append(beauty_output) + + return beauty_frame_range # TODO: Get the arnold render product - def arnold_render_product(self, folder, fmt): + def arnold_render_product(self, folder, startFrame, endFrame, fmt): """Get all the Arnold AOVs""" aovs = [] @@ -85,15 +100,17 @@ class RenderProducts(object): for i in range(aov_group_num): # get the specific AOV group for aov in aov_mgr.drivers[i].aov_list: - render_element = f"{folder}_{aov.name}.####.{fmt}" - render_element = render_element.replace("\\", "/") - aovs.append(render_element) + for f in range(startFrame, endFrame): + render_element = f"{folder}_{aov.name}.{f}.{fmt}" + render_element = render_element.replace("\\", "/") + aovs.append(render_element) + # close the AOVs manager window amw.close() return aovs - def render_elements_product(self, folder, fmt): + def render_elements_product(self, folder, startFrame, endFrame, fmt): """Get all the render element output files. """ render_dirname = [] @@ -104,9 +121,10 @@ class RenderProducts(object): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") if renderlayer_name.enabled: - render_element = f"{folder}_{renderpass}.####.{fmt}" - render_element = render_element.replace("\\", "/") - render_dirname.append(render_element) + for f in range(startFrame, endFrame): + render_element = f"{folder}_{renderpass}.{f}.{fmt}" + render_element = render_element.replace("\\", "/") + render_dirname.append(render_element) return render_dirname From fa69594c7079b8b482f649cf62f49a240da3be4a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Feb 2023 20:09:03 +0800 Subject: [PATCH 124/133] creator, validator and extractor for point cloud from tyFlow --- .../max/plugins/create/create_pointcloud.py | 26 +++ .../max/plugins/publish/extract_pointcloud.py | 170 ++++++++++++++++++ .../plugins/publish/validate_pointcloud.py | 74 ++++++++ openpype/plugins/publish/integrate.py | 1 + openpype/plugins/publish/integrate_legacy.py | 1 + .../defaults/project_settings/max.json | 15 ++ .../projects_schema/schema_project_max.json | 24 ++- 7 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 openpype/hosts/max/plugins/create/create_pointcloud.py create mode 100644 openpype/hosts/max/plugins/publish/extract_pointcloud.py create mode 100644 openpype/hosts/max/plugins/publish/validate_pointcloud.py diff --git a/openpype/hosts/max/plugins/create/create_pointcloud.py b/openpype/hosts/max/plugins/create/create_pointcloud.py new file mode 100644 index 0000000000..c83acac3df --- /dev/null +++ b/openpype/hosts/max/plugins/create/create_pointcloud.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +"""Creator plugin for creating point cloud.""" +from openpype.hosts.max.api import plugin +from openpype.pipeline import CreatedInstance + + +class CreatePointCloud(plugin.MaxCreator): + identifier = "io.openpype.creators.max.pointcloud" + label = "Point Cloud" + family = "pointcloud" + icon = "gear" + + def create(self, subset_name, instance_data, pre_create_data): + from pymxs import runtime as rt + sel_obj = list(rt.selection) + instance = super(CreatePointCloud, self).create( + subset_name, + instance_data, + pre_create_data) # type: CreatedInstance + container = rt.getNodeByName(instance.data.get("instance_node")) + # TODO: Disable "Add to Containers?" Panel + # parent the selected cameras into the container + for obj in sel_obj: + obj.parent = container + # for additional work on the node: + # instance_node = rt.getNodeByName(instance.get("instance_node")) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py new file mode 100644 index 0000000000..9c471bc09e --- /dev/null +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -0,0 +1,170 @@ +import os +import pyblish.api +from openpype.pipeline import publish +from pymxs import runtime as rt +from openpype.hosts.max.api import ( + maintained_selection +) +from openpype.settings import get_project_settings +from openpype.pipeline import legacy_io + + +def get_setting(project_setting=None): + project_setting = get_project_settings( + legacy_io.Session["AVALON_PROJECT"] + ) + return (project_setting["max"]["PointCloud"]) + + +class ExtractPointCloud(publish.Extractor): + """ + Extract PTF format with tyFlow operators + """ + + order = pyblish.api.ExtractorOrder - 0.2 + label = "Extract Point Cloud" + hosts = ["max"] + families = ["pointcloud"] + partition_start = 1 + partition_count = 100 + + + def process(self, instance): + start = str(instance.data.get("frameStartHandle", 1)) + end = str(instance.data.get("frameEndHandle", 1)) + container = instance.data["instance_node"] + + self.log.info("Extracting PRT...") + + stagingdir = self.staging_dir(instance) + filename = "{name}.prt".format(**instance.data) + path = os.path.join(stagingdir, filename) + + with maintained_selection(): + job_args = self.export_particle(container, + start, + end, + path) + for job in job_args: + rt.execute(job) + + self.log.info("Performing Extraction ...") + if "representations" not in instance.data: + instance.data["representations"] = [] + + self.log.info("Writing PRT with TyFlow Plugin...") + filenames = self.get_files(path, start, end) + self.log.info("filename: {0}".format(filenames)) + representation = { + 'name': 'prt', + 'ext': 'prt', + 'files': filenames if len(filenames) > 1 else filenames[0], + "stagingDir": stagingdir, + } + instance.data["representations"].append(representation) + self.log.info("Extracted instance '%s' to: %s" % (instance.name, + path)) + + def export_particle(self, + container, + start, + end, + filepath): + job_args = [] + opt_list = self.get_operators(container) + for operator in opt_list: + export_mode = "{0}.exportMode=2".format(operator) + job_args.append(export_mode) + start_frame = "{0}.frameStart={1}".format(operator, + start) + job_args.append(start_frame) + end_frame = "{0}.frameEnd={1}".format(operator, + end) + job_args.append(end_frame) + filepath = filepath.replace("\\", "/") + prt_filename = '{0}.PRTFilename="{1}"'.format(operator, + filepath) + + job_args.append(prt_filename) + # Partition + mode = "{0}.PRTPartitionsMode=2".format(operator) + job_args.append(mode) + + additional_args = self.get_custom_attr(operator) + for args in additional_args: + job_args.append(args) + + prt_export = "{0}.exportPRT()".format(operator) + job_args.append(prt_export) + + return job_args + + def get_operators(self, container): + """Get Export Particles Operator""" + + opt_list = [] + node = rt.getNodebyName(container) + selection_list = list(node.Children) + for sel in selection_list: + obj = sel.baseobject + # TODO: to see if it can be used maxscript instead + anim_names = rt.getsubanimnames(obj) + for anim_name in anim_names: + sub_anim = rt.getsubanim(obj, anim_name) + boolean = rt.isProperty(sub_anim, "Export_Particles") + event_name = sub_anim.name + if boolean: + opt = "${0}.{1}.export_particles".format(sel.name, + event_name) + opt_list.append(opt) + + return opt_list + + def get_custom_attr(self, operator): + """Get Custom Attributes""" + + custom_attr_list = [] + attr_settings = get_setting()["attribute"] + for key, value in attr_settings.items(): + custom_attr = "{0}.PRTChannels_{1}=True".format(operator, + value) + self.log.debug( + "{0} will be added as custom attribute".format(key) + ) + custom_attr_list.append(custom_attr) + + return custom_attr_list + + def get_files(self, + path, + start_frame, + end_frame): + """ + Note: + Set the filenames accordingly to the tyFlow file + naming extension for the publishing purpose + + Actual File Output from tyFlow: + __partof..prt + e.g. tyFlow_cloth_CCCS_blobbyFill_001__part1of1_00004.prt + Renamed Output: + ..prt + e.g. pointcloudMain.0001.prt + """ + filenames = [] + filename = os.path.basename(path) + orig_name, ext = os.path.splitext(filename) + partition_start = str(self.partition_start) + partition_count = str(self.partition_count) + for frame in range(int(start_frame), int(end_frame) + 1): + actual_name = "{}__part{:03}of{}_{:05}".format(orig_name, + partition_start, + partition_count, + frame) + actual_filename = path.replace(orig_name, actual_name) + new_name = "{}.{:04}".format(orig_name, frame) + renamed_filename = path.replace(orig_name, new_name) + os.rename(actual_filename, renamed_filename) + filenames.append(os.path.basename(renamed_filename)) + + return filenames diff --git a/openpype/hosts/max/plugins/publish/validate_pointcloud.py b/openpype/hosts/max/plugins/publish/validate_pointcloud.py new file mode 100644 index 0000000000..c6725d6126 --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_pointcloud.py @@ -0,0 +1,74 @@ +import pyblish.api +from openpype.pipeline import PublishValidationError +from pymxs import runtime as rt + + +class ValidatePointCloud(pyblish.api.InstancePlugin): + """Validate that workfile was saved.""" + + order = pyblish.api.ValidatorOrder + families = ["pointcloud"] + hosts = ["max"] + label = "Validate Point Cloud" + + def process(self, instance): + """ + Notes: + + 1. Validate the container only include tyFlow objects + 2. Validate if tyFlow operator Export Particle exists + + """ + invalid = self.get_tyFlow_object(instance) + if invalid: + raise PublishValidationError("Non tyFlow object " + "found: {}".format(invalid)) + invalid = self.get_tyFlow_operator(instance) + if invalid: + raise PublishValidationError("tyFlow ExportParticle operator " + "not found: {}".format(invalid)) + + def get_tyFlow_object(self, instance): + invalid = [] + container = instance.data["instance_node"] + self.log.info("Validating tyFlow container " + "for {}".format(container)) + + con = rt.getNodeByName(container) + selection_list = list(con.Children) + for sel in selection_list: + sel_tmp = str(sel) + if rt.classOf(sel) in [rt.tyFlow, + rt.Editable_Mesh]: + if "tyFlow" not in sel_tmp: + invalid.append(sel) + else: + invalid.append(sel) + + return invalid + + def get_tyFlow_operator(self, instance): + invalid = [] + container = instance.data["instance_node"] + self.log.info("Validating tyFlow object " + "for {}".format(container)) + + con = rt.getNodeByName(container) + selection_list = list(con.Children) + bool_list = [] + for sel in selection_list: + obj = sel.baseobject + anim_names = rt.getsubanimnames(obj) + for anim_name in anim_names: + # get all the names of the related tyFlow nodes + sub_anim = rt.getsubanim(obj, anim_name) + # check if there is export particle operator + boolean = rt.isProperty(sub_anim, "Export_Particles") + bool_list.append(str(boolean)) + # if the export_particles property is not there + # it means there is not a "Export Particle" operator + if "True" not in bool_list: + self.log.error("Operator 'Export Particles' not found!") + invalid.append(sel) + + return invalid diff --git a/openpype/plugins/publish/integrate.py b/openpype/plugins/publish/integrate.py index 69b7734c70..6a0327ec84 100644 --- a/openpype/plugins/publish/integrate.py +++ b/openpype/plugins/publish/integrate.py @@ -80,6 +80,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): order = pyblish.api.IntegratorOrder families = ["workfile", "pointcache", + "pointcloud", "proxyAbc", "camera", "animation", diff --git a/openpype/plugins/publish/integrate_legacy.py b/openpype/plugins/publish/integrate_legacy.py index 66c2c9be51..1d0177f151 100644 --- a/openpype/plugins/publish/integrate_legacy.py +++ b/openpype/plugins/publish/integrate_legacy.py @@ -76,6 +76,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): order = pyblish.api.IntegratorOrder + 0.00001 families = ["workfile", "pointcache", + "pointcloud", "proxyAbc", "camera", "animation", diff --git a/openpype/settings/defaults/project_settings/max.json b/openpype/settings/defaults/project_settings/max.json index 667b42411d..d59cdf8c4a 100644 --- a/openpype/settings/defaults/project_settings/max.json +++ b/openpype/settings/defaults/project_settings/max.json @@ -4,5 +4,20 @@ "aov_separator": "underscore", "image_format": "exr", "multipass": true + }, + "PointCloud":{ + "attribute":{ + "Age": "age", + "Radius": "radius", + "Position": "position", + "Rotation": "rotation", + "Scale": "scale", + "Velocity": "velocity", + "Color": "color", + "TextureCoordinate": "texcoord", + "MaterialID": "matid", + "custFloats": "custFloats", + "custVecs": "custVecs" + } } } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_max.json b/openpype/settings/entities/schemas/projects_schema/schema_project_max.json index 8a283c1acc..4fba9aff0a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_max.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_max.json @@ -51,6 +51,28 @@ "label": "multipass" } ] + }, + { + "type": "dict", + "collapsible": true, + "key": "PointCloud", + "label": "Point Cloud", + "children": [ + { + "type": "label", + "label": "Define the channel attribute names before exporting as PRT" + }, + { + "type": "dict-modifiable", + "collapsible": true, + "key": "attribute", + "label": "Channel Attribute", + "use_label_wrap": true, + "object_type": { + "type": "text" + } + } + ] } ] -} \ No newline at end of file +} From 7df1b215c7831c33de0c2ebf55fc8e7d39ec9fff Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Feb 2023 20:18:19 +0800 Subject: [PATCH 125/133] hound fix --- openpype/hosts/max/plugins/publish/extract_pointcloud.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py index 9c471bc09e..1ef127b73b 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -28,7 +28,6 @@ class ExtractPointCloud(publish.Extractor): partition_start = 1 partition_count = 100 - def process(self, instance): start = str(instance.data.get("frameStartHandle", 1)) end = str(instance.data.get("frameEndHandle", 1)) From 399600769483ea7b3062ec02fd4bf70680caa0ec Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Feb 2023 22:05:11 +0800 Subject: [PATCH 126/133] update validators --- .../max/plugins/publish/extract_pointcloud.py | 6 +- .../plugins/publish/validate_pointcloud.py | 121 +++++++++++++++++- 2 files changed, 121 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py index 1ef127b73b..4436c06643 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -72,8 +72,6 @@ class ExtractPointCloud(publish.Extractor): job_args = [] opt_list = self.get_operators(container) for operator in opt_list: - export_mode = "{0}.exportMode=2".format(operator) - job_args.append(export_mode) start_frame = "{0}.frameStart={1}".format(operator, start) job_args.append(start_frame) @@ -153,8 +151,8 @@ class ExtractPointCloud(publish.Extractor): filenames = [] filename = os.path.basename(path) orig_name, ext = os.path.splitext(filename) - partition_start = str(self.partition_start) - partition_count = str(self.partition_count) + partition_start = self.partition_start + partition_count = self.partition_count for frame in range(int(start_frame), int(end_frame) + 1): actual_name = "{}__part{:03}of{}_{:05}".format(orig_name, partition_start, diff --git a/openpype/hosts/max/plugins/publish/validate_pointcloud.py b/openpype/hosts/max/plugins/publish/validate_pointcloud.py index c6725d6126..ba9f2834a6 100644 --- a/openpype/hosts/max/plugins/publish/validate_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/validate_pointcloud.py @@ -1,6 +1,15 @@ import pyblish.api from openpype.pipeline import PublishValidationError from pymxs import runtime as rt +from openpype.settings import get_project_settings +from openpype.pipeline import legacy_io + + +def get_setting(project_setting=None): + project_setting = get_project_settings( + legacy_io.Session["AVALON_PROJECT"] + ) + return (project_setting["max"]["PointCloud"]) class ValidatePointCloud(pyblish.api.InstancePlugin): @@ -15,8 +24,14 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): """ Notes: - 1. Validate the container only include tyFlow objects - 2. Validate if tyFlow operator Export Particle exists + 1. Validate the container only include tyFlow objects + 2. Validate if tyFlow operator Export Particle exists + 3. Validate if the export mode of Export Particle is at PRT format + 4. Validate the partition count and range set as default value + Partition Count : 100 + Partition Range : 1 to 1 + 5. Validate if the custom attribute(s) exist as parameter(s) + of export_particle operator """ invalid = self.get_tyFlow_object(instance) @@ -28,6 +43,19 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): raise PublishValidationError("tyFlow ExportParticle operator " "not found: {}".format(invalid)) + invalid = self.validate_export_mode(instance) + if invalid: + raise PublishValidationError("The export mode is not at PRT") + + invalid = self.validate_partition_value(instance) + if invalid: + raise PublishValidationError("tyFlow Partition setting is " + "not at the default value") + invalid = self.validate_custom_attribute(instance) + if invalid: + raise PublishValidationError("Custom Attribute not found " + ":{}".format(invalid)) + def get_tyFlow_object(self, instance): invalid = [] container = instance.data["instance_node"] @@ -72,3 +100,92 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): invalid.append(sel) return invalid + + def validate_custom_attribute(self, instance): + invalid = [] + container = instance.data["instance_node"] + self.log.info("Validating tyFlow custom " + "attributes for {}".format(container)) + + con = rt.getNodeByName(container) + selection_list = list(con.Children) + for sel in selection_list: + obj = sel.baseobject + anim_names = rt.getsubanimnames(obj) + for anim_name in anim_names: + # get all the names of the related tyFlow nodes + sub_anim = rt.getsubanim(obj, anim_name) + # check if there is export particle operator + boolean = rt.isProperty(sub_anim, "Export_Particles") + event_name = sub_anim.name + if boolean: + opt = "${0}.{1}.export_particles".format(sel.name, + event_name) + attributes = get_setting()["attribute"] + for key, value in attributes.items(): + custom_attr = "{0}.PRTChannels_{1}".format(opt, + value) + try: + rt.execute(custom_attr) + except RuntimeError: + invalid.add(key) + + return invalid + + def validate_partition_value(self, instance): + invalid = [] + container = instance.data["instance_node"] + self.log.info("Validating tyFlow partition " + "value for {}".format(container)) + + con = rt.getNodeByName(container) + selection_list = list(con.Children) + for sel in selection_list: + obj = sel.baseobject + anim_names = rt.getsubanimnames(obj) + for anim_name in anim_names: + # get all the names of the related tyFlow nodes + sub_anim = rt.getsubanim(obj, anim_name) + # check if there is export particle operator + boolean = rt.isProperty(sub_anim, "Export_Particles") + event_name = sub_anim.name + if boolean: + opt = "${0}.{1}.export_particles".format(sel.name, + event_name) + count = rt.execute(f'{opt}.PRTPartitionsCount') + if count != 100: + invalid.append(count) + start = rt.execute(f'{opt}.PRTPartitionsFrom') + if start != 1: + invalid.append(start) + end = rt.execute(f'{opt}.PRTPartitionsTo') + if end != 1: + invalid.append(end) + + return invalid + + def validate_export_mode(self, instance): + invalid = [] + container = instance.data["instance_node"] + self.log.info("Validating tyFlow partition " + "value for {}".format(container)) + + con = rt.getNodeByName(container) + selection_list = list(con.Children) + for sel in selection_list: + obj = sel.baseobject + anim_names = rt.getsubanimnames(obj) + for anim_name in anim_names: + # get all the names of the related tyFlow nodes + sub_anim = rt.getsubanim(obj, anim_name) + # check if there is export particle operator + boolean = rt.isProperty(sub_anim, "Export_Particles") + event_name = sub_anim.name + if boolean: + opt = "${0}.{1}.export_particles".format(sel.name, + event_name) + export_mode = rt.execute(f'{opt}.exportMode') + if export_mode != 2: + invalid.append(export_mode) + + return invalid From 29138974b49da0d03eaf2bbbcedd3243d6420bfe Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Feb 2023 22:24:25 +0800 Subject: [PATCH 127/133] update validators --- openpype/hosts/max/plugins/publish/validate_pointcloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_pointcloud.py b/openpype/hosts/max/plugins/publish/validate_pointcloud.py index ba9f2834a6..34310eac7a 100644 --- a/openpype/hosts/max/plugins/publish/validate_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/validate_pointcloud.py @@ -167,8 +167,8 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): def validate_export_mode(self, instance): invalid = [] container = instance.data["instance_node"] - self.log.info("Validating tyFlow partition " - "value for {}".format(container)) + self.log.info("Validating tyFlow export " + "mode for {}".format(container)) con = rt.getNodeByName(container) selection_list = list(con.Children) From a4c36b9e4f1a52107010515aa28358e174658833 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 28 Feb 2023 18:14:25 +0800 Subject: [PATCH 128/133] add loaders --- .../hosts/max/plugins/load/load_pointcloud.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 openpype/hosts/max/plugins/load/load_pointcloud.py diff --git a/openpype/hosts/max/plugins/load/load_pointcloud.py b/openpype/hosts/max/plugins/load/load_pointcloud.py new file mode 100644 index 0000000000..dfa63e23f8 --- /dev/null +++ b/openpype/hosts/max/plugins/load/load_pointcloud.py @@ -0,0 +1,51 @@ +import os +from openpype.pipeline import ( + load, get_representation_path +) +from openpype.hosts.max.api.pipeline import containerise +from openpype.hosts.max.api import lib + + +class PointCloudLoader(load.LoaderPlugin): + """Point Cloud Loader""" + + families = ["pointcloud"] + representations = ["prt"] + order = -8 + icon = "code-fork" + color = "green" + + def load(self, context, name=None, namespace=None, data=None): + """load point cloud by tyCache""" + + from pymxs import runtime as rt + filepath = os.path.normpath(self.fname) + obj = rt.tyCache() + obj.filename = filepath + + prt_container = rt.getNodeByName(f"{obj.name}") + + return containerise( + name, [prt_container], context, loader=self.__class__.__name__) + + def update(self, container, representation): + """update the container""" + + from pymxs import runtime as rt + path = get_representation_path(representation) + node = rt.getNodeByName(container["instance_node"]) + + prt_objects = self.get_container_children(node) + for prt_object in prt_objects: + prt_object.source = path + + lib.imprint(container["instance_node"], { + "representation": str(representation["_id"]) + }) + + def remove(self, container): + """remove the container""" + from pymxs import runtime as rt + + node = rt.getNodeByName(container["instance_node"]) + rt.delete(node) From f95f8f6ebe4a1d32a97ca3daa14d061a31befce9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 28 Feb 2023 18:31:53 +0800 Subject: [PATCH 129/133] add loader --- openpype/hosts/max/plugins/load/load_pointcloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_pointcloud.py b/openpype/hosts/max/plugins/load/load_pointcloud.py index dfa63e23f8..27bc88b4f3 100644 --- a/openpype/hosts/max/plugins/load/load_pointcloud.py +++ b/openpype/hosts/max/plugins/load/load_pointcloud.py @@ -17,8 +17,8 @@ class PointCloudLoader(load.LoaderPlugin): def load(self, context, name=None, namespace=None, data=None): """load point cloud by tyCache""" - from pymxs import runtime as rt + filepath = os.path.normpath(self.fname) obj = rt.tyCache() obj.filename = filepath @@ -30,8 +30,8 @@ class PointCloudLoader(load.LoaderPlugin): def update(self, container, representation): """update the container""" - from pymxs import runtime as rt + path = get_representation_path(representation) node = rt.getNodeByName(container["instance_node"]) From 416b7d9b942fc34901fe03fedcfe4fb3bcd3b730 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 1 Mar 2023 15:37:30 +0800 Subject: [PATCH 130/133] add partition naming format into the extractor --- .../max/plugins/publish/extract_pointcloud.py | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py index 4436c06643..db83bf71fc 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -18,15 +18,31 @@ def get_setting(project_setting=None): class ExtractPointCloud(publish.Extractor): """ - Extract PTF format with tyFlow operators + Extract PRT format with tyFlow operators + + Notes: + Currently only works for the default partition setting + + Args: + export_particle(): sets up all job arguments for attributes + to be exported in MAXscript + + get_operators(): get the export_particle operator + + get_custom_attr(): get all custom channel attributes from the Openpype + setting and sets it as job arguments before exporting + + get_files(): get the files with tyFlow naming convention before publishing + + partition_output_name(): get the naming with partition settings. + get_partition(): get partition value + """ order = pyblish.api.ExtractorOrder - 0.2 label = "Extract Point Cloud" hosts = ["max"] families = ["pointcloud"] - partition_start = 1 - partition_count = 100 def process(self, instance): start = str(instance.data.get("frameStartHandle", 1)) @@ -52,13 +68,17 @@ class ExtractPointCloud(publish.Extractor): instance.data["representations"] = [] self.log.info("Writing PRT with TyFlow Plugin...") - filenames = self.get_files(path, start, end) - self.log.info("filename: {0}".format(filenames)) + filenames = self.get_files(container, path, start, end) + self.log.debug("filenames: {0}".format(filenames)) + + partition = self.partition_output_name(container) + representation = { 'name': 'prt', 'ext': 'prt', 'files': filenames if len(filenames) > 1 else filenames[0], "stagingDir": stagingdir, + "outputName": partition # partition value } instance.data["representations"].append(representation) self.log.info("Extracted instance '%s' to: %s" % (instance.name, @@ -133,6 +153,7 @@ class ExtractPointCloud(publish.Extractor): return custom_attr_list def get_files(self, + container, path, start_frame, end_frame): @@ -144,24 +165,43 @@ class ExtractPointCloud(publish.Extractor): Actual File Output from tyFlow: __partof..prt e.g. tyFlow_cloth_CCCS_blobbyFill_001__part1of1_00004.prt - Renamed Output: - ..prt - e.g. pointcloudMain.0001.prt """ filenames = [] filename = os.path.basename(path) orig_name, ext = os.path.splitext(filename) - partition_start = self.partition_start - partition_count = self.partition_count + partition_count, partition_start = self.get_partition(container) for frame in range(int(start_frame), int(end_frame) + 1): actual_name = "{}__part{:03}of{}_{:05}".format(orig_name, partition_start, partition_count, frame) actual_filename = path.replace(orig_name, actual_name) - new_name = "{}.{:04}".format(orig_name, frame) - renamed_filename = path.replace(orig_name, new_name) - os.rename(actual_filename, renamed_filename) - filenames.append(os.path.basename(renamed_filename)) + filenames.append(os.path.basename(actual_filename)) return filenames + + def partition_output_name(self, container): + """ + Notes: + Partition output name set for mapping + the published file output + + todo: + Customizes the setting for the output + """ + partition_count, partition_start = self.get_partition(container) + partition = "_part{:03}of{}".format(partition_start, + partition_count) + + return partition + + def get_partition(self, container): + """ + Get Partition Value + """ + opt_list = self.get_operators(container) + for operator in opt_list: + count = rt.execute(f'{operator}.PRTPartitionsCount') + start = rt.execute(f'{operator}.PRTPartitionsFrom') + + return count, start From b9ab6f634e8219c0af436895f9cc7d38f56ebca2 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 1 Mar 2023 15:39:25 +0800 Subject: [PATCH 131/133] hound fix --- openpype/hosts/max/plugins/publish/extract_pointcloud.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py index db83bf71fc..0e4f4621ea 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -29,10 +29,11 @@ class ExtractPointCloud(publish.Extractor): get_operators(): get the export_particle operator - get_custom_attr(): get all custom channel attributes from the Openpype + get_custom_attr(): get all custom channel attributes from Openpype setting and sets it as job arguments before exporting - get_files(): get the files with tyFlow naming convention before publishing + get_files(): get the files with tyFlow naming convention + before publishing partition_output_name(): get the naming with partition settings. get_partition(): get partition value @@ -78,7 +79,7 @@ class ExtractPointCloud(publish.Extractor): 'ext': 'prt', 'files': filenames if len(filenames) > 1 else filenames[0], "stagingDir": stagingdir, - "outputName": partition # partition value + "outputName": partition # partition value } instance.data["representations"].append(representation) self.log.info("Extracted instance '%s' to: %s" % (instance.name, From b1f3e114058276b65e7c21da477642422f9c49b3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 2 Mar 2023 00:05:54 +0800 Subject: [PATCH 132/133] fix the validator check on exportMode --- openpype/hosts/max/plugins/publish/validate_pointcloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/validate_pointcloud.py b/openpype/hosts/max/plugins/publish/validate_pointcloud.py index 34310eac7a..f654058648 100644 --- a/openpype/hosts/max/plugins/publish/validate_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/validate_pointcloud.py @@ -185,7 +185,7 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): opt = "${0}.{1}.export_particles".format(sel.name, event_name) export_mode = rt.execute(f'{opt}.exportMode') - if export_mode != 2: + if export_mode != 1: invalid.append(export_mode) return invalid From 341ef34e353a52644a5bd92a02992adc3c0830d5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 2 Mar 2023 23:18:33 +0800 Subject: [PATCH 133/133] update frame range --- openpype/hosts/max/plugins/publish/extract_pointcloud.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcloud.py b/openpype/hosts/max/plugins/publish/extract_pointcloud.py index 0e4f4621ea..e8d58ab713 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcloud.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcloud.py @@ -46,10 +46,9 @@ class ExtractPointCloud(publish.Extractor): families = ["pointcloud"] def process(self, instance): - start = str(instance.data.get("frameStartHandle", 1)) - end = str(instance.data.get("frameEndHandle", 1)) + start = int(instance.context.data.get("frameStart")) + end = int(instance.context.data.get("frameEnd")) container = instance.data["instance_node"] - self.log.info("Extracting PRT...") stagingdir = self.staging_dir(instance)