diff --git a/client/ayon_core/__init__.py b/client/ayon_core/__init__.py
index 7d95587e8a..ce5a28601c 100644
--- a/client/ayon_core/__init__.py
+++ b/client/ayon_core/__init__.py
@@ -14,3 +14,15 @@ AYON_SERVER_ENABLED = True
# Indicate if AYON entities should be used instead of OpenPype entities
USE_AYON_ENTITIES = True
# -------------------------
+
+
+__all__ = (
+ "__version__",
+
+ # Deprecated
+ "AYON_CORE_ROOT",
+ "PACKAGE_DIR",
+ "PLUGINS_DIR",
+ "AYON_SERVER_ENABLED",
+ "USE_AYON_ENTITIES",
+)
diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py
index 42b53c59e3..6bac25b8ac 100644
--- a/client/ayon_core/addon/base.py
+++ b/client/ayon_core/addon/base.py
@@ -1075,7 +1075,7 @@ class AddonsManager:
"""Print out report of time spent on addons initialization parts.
Reporting is not automated must be implemented for each initialization
- part separatelly. Reports must be stored to `_report` attribute.
+ part separately. Reports must be stored to `_report` attribute.
Print is skipped if `_report` is empty.
Attribute `_report` is dictionary where key is "label" describing
@@ -1267,7 +1267,7 @@ class TrayAddonsManager(AddonsManager):
def add_doubleclick_callback(self, addon, callback):
"""Register doubleclick callbacks on tray icon.
- Currently there is no way how to determine which is launched. Name of
+ Currently, there is no way how to determine which is launched. Name of
callback can be defined with `doubleclick_callback` attribute.
Missing feature how to define default callback.
diff --git a/client/ayon_core/cli_commands.py b/client/ayon_core/cli_commands.py
index bc0a22382c..fa90571462 100644
--- a/client/ayon_core/cli_commands.py
+++ b/client/ayon_core/cli_commands.py
@@ -3,7 +3,6 @@
import os
import sys
import json
-import warnings
class Commands:
diff --git a/client/ayon_core/hosts/aftereffects/api/__init__.py b/client/ayon_core/hosts/aftereffects/api/__init__.py
index 4c4a8cce2f..b1d83c5ad9 100644
--- a/client/ayon_core/hosts/aftereffects/api/__init__.py
+++ b/client/ayon_core/hosts/aftereffects/api/__init__.py
@@ -31,6 +31,7 @@ __all__ = [
"get_stub",
# pipeline
+ "AfterEffectsHost",
"ls",
"containerise",
diff --git a/client/ayon_core/hosts/aftereffects/plugins/publish/collect_render.py b/client/ayon_core/hosts/aftereffects/plugins/publish/collect_render.py
index afd58ca758..4134e9d593 100644
--- a/client/ayon_core/hosts/aftereffects/plugins/publish/collect_render.py
+++ b/client/ayon_core/hosts/aftereffects/plugins/publish/collect_render.py
@@ -1,14 +1,11 @@
import os
-import re
import tempfile
-import attr
+import attr
import pyblish.api
-from ayon_core.settings import get_project_settings
from ayon_core.pipeline import publish
from ayon_core.pipeline.publish import RenderInstance
-
from ayon_core.hosts.aftereffects.api import get_stub
diff --git a/client/ayon_core/hosts/blender/api/ops.py b/client/ayon_core/hosts/blender/api/ops.py
index d71ee6faf5..c03ec98d0c 100644
--- a/client/ayon_core/hosts/blender/api/ops.py
+++ b/client/ayon_core/hosts/blender/api/ops.py
@@ -191,7 +191,7 @@ def _process_app_events() -> Optional[float]:
class LaunchQtApp(bpy.types.Operator):
- """A Base class for opertors to launch a Qt app."""
+ """A Base class for operators to launch a Qt app."""
_app: QtWidgets.QApplication
_window = Union[QtWidgets.QDialog, ModuleType]
diff --git a/client/ayon_core/hosts/blender/plugins/load/load_blend.py b/client/ayon_core/hosts/blender/plugins/load/load_blend.py
index e84dddc88f..1984193a30 100644
--- a/client/ayon_core/hosts/blender/plugins/load/load_blend.py
+++ b/client/ayon_core/hosts/blender/plugins/load/load_blend.py
@@ -227,7 +227,7 @@ class BlendLoader(plugin.AssetLoader):
obj.animation_data_create()
obj.animation_data.action = actions[obj.name]
- # Restore the old data, but reset memebers, as they don't exist anymore
+ # Restore the old data, but reset members, as they don't exist anymore
# This avoids a crash, because the memory addresses of those members
# are not valid anymore
old_data["members"] = []
diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_camera_abc.py b/client/ayon_core/hosts/blender/plugins/publish/extract_camera_abc.py
index cc783e552c..c60c92dee1 100644
--- a/client/ayon_core/hosts/blender/plugins/publish/extract_camera_abc.py
+++ b/client/ayon_core/hosts/blender/plugins/publish/extract_camera_abc.py
@@ -4,7 +4,6 @@ import bpy
from ayon_core.pipeline import publish
from ayon_core.hosts.blender.api import plugin
-from ayon_core.hosts.blender.api.pipeline import AVALON_PROPERTY
class ExtractCameraABC(publish.Extractor, publish.OptionalPyblishPluginMixin):
diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_fbx.py b/client/ayon_core/hosts/blender/plugins/publish/extract_fbx.py
index 7ebda2c4cd..e6367dbc0d 100644
--- a/client/ayon_core/hosts/blender/plugins/publish/extract_fbx.py
+++ b/client/ayon_core/hosts/blender/plugins/publish/extract_fbx.py
@@ -4,7 +4,6 @@ import bpy
from ayon_core.pipeline import publish
from ayon_core.hosts.blender.api import plugin
-from ayon_core.hosts.blender.api.pipeline import AVALON_PROPERTY
class ExtractFBX(publish.Extractor, publish.OptionalPyblishPluginMixin):
diff --git a/client/ayon_core/hosts/blender/plugins/publish/validate_deadline_publish.py b/client/ayon_core/hosts/blender/plugins/publish/validate_deadline_publish.py
index b37db44cd4..a86e73ba81 100644
--- a/client/ayon_core/hosts/blender/plugins/publish/validate_deadline_publish.py
+++ b/client/ayon_core/hosts/blender/plugins/publish/validate_deadline_publish.py
@@ -32,7 +32,7 @@ class ValidateDeadlinePublish(pyblish.api.InstancePlugin,
tree = bpy.context.scene.node_tree
output_type = "CompositorNodeOutputFile"
output_node = None
- # Remove all output nodes that inlcude "AYON" in the name.
+ # Remove all output nodes that include "AYON" in the name.
# There should be only one.
for node in tree.nodes:
if node.bl_idname == output_type and "AYON" in node.name:
diff --git a/client/ayon_core/hosts/celaction/hooks/pre_celaction_setup.py b/client/ayon_core/hosts/celaction/hooks/pre_celaction_setup.py
index 73b368e4e3..d94fff8f2b 100644
--- a/client/ayon_core/hosts/celaction/hooks/pre_celaction_setup.py
+++ b/client/ayon_core/hosts/celaction/hooks/pre_celaction_setup.py
@@ -118,7 +118,7 @@ class CelactionPrelaunchHook(PreLaunchHook):
def workfile_path(self):
workfile_path = self.data["last_workfile_path"]
- # copy workfile from template if doesnt exist any on path
+ # copy workfile from template if doesn't exist any on path
if not os.path.exists(workfile_path):
# TODO add ability to set different template workfile path via
# settings
diff --git a/client/ayon_core/hosts/celaction/plugins/publish/collect_render_path.py b/client/ayon_core/hosts/celaction/plugins/publish/collect_render_path.py
index 52bb183663..1bb4d54831 100644
--- a/client/ayon_core/hosts/celaction/plugins/publish/collect_render_path.py
+++ b/client/ayon_core/hosts/celaction/plugins/publish/collect_render_path.py
@@ -38,7 +38,7 @@ class CollectRenderPath(pyblish.api.InstancePlugin):
render_path = r_template_item["path"].format_strict(anatomy_data)
self.log.debug("__ render_path: `{}`".format(render_path))
- # create dir if it doesnt exists
+ # create dir if it doesn't exists
try:
if not os.path.isdir(render_dir):
os.makedirs(render_dir, exist_ok=True)
diff --git a/client/ayon_core/hosts/flame/api/__init__.py b/client/ayon_core/hosts/flame/api/__init__.py
index e2c5ee154a..8fcf0c92b0 100644
--- a/client/ayon_core/hosts/flame/api/__init__.py
+++ b/client/ayon_core/hosts/flame/api/__init__.py
@@ -23,7 +23,7 @@ from .lib import (
reset_segment_selection,
get_segment_attributes,
get_clips_in_reels,
- get_reformated_filename,
+ get_reformatted_filename,
get_frame_from_filename,
get_padding_from_filename,
maintained_object_duplication,
@@ -101,7 +101,7 @@ __all__ = [
"reset_segment_selection",
"get_segment_attributes",
"get_clips_in_reels",
- "get_reformated_filename",
+ "get_reformatted_filename",
"get_frame_from_filename",
"get_padding_from_filename",
"maintained_object_duplication",
diff --git a/client/ayon_core/hosts/flame/api/lib.py b/client/ayon_core/hosts/flame/api/lib.py
index efa23fe01e..8bfe6348ea 100644
--- a/client/ayon_core/hosts/flame/api/lib.py
+++ b/client/ayon_core/hosts/flame/api/lib.py
@@ -607,7 +607,7 @@ def get_clips_in_reels(project):
return output_clips
-def get_reformated_filename(filename, padded=True):
+def get_reformatted_filename(filename, padded=True):
"""
Return fixed python expression path
@@ -615,10 +615,10 @@ def get_reformated_filename(filename, padded=True):
filename (str): file name
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
- get_reformated_filename("plate.1001.exr") > plate.%04d.exr
+ get_reformatted_filename("plate.1001.exr") > plate.%04d.exr
"""
found = FRAME_PATTERN.search(filename)
@@ -980,7 +980,7 @@ class MediaInfoFile(object):
@property
def file_pattern(self):
- """Clips file patter
+ """Clips file pattern.
Returns:
str: file pattern. ex. file.[1-2].exr
diff --git a/client/ayon_core/hosts/flame/api/plugin.py b/client/ayon_core/hosts/flame/api/plugin.py
index c57d021c69..e656f33052 100644
--- a/client/ayon_core/hosts/flame/api/plugin.py
+++ b/client/ayon_core/hosts/flame/api/plugin.py
@@ -644,13 +644,13 @@ class PublishableClip:
"families": [self.base_product_type, self.product_type]
}
- def _convert_to_entity(self, type, template):
+ def _convert_to_entity(self, src_type, template):
""" Converting input key to key with type. """
# convert to entity type
- entity_type = self.types.get(type, None)
+ folder_type = self.types.get(src_type, None)
- assert entity_type, "Missing entity type for `{}`".format(
- type
+ assert folder_type, "Missing folder type for `{}`".format(
+ src_type
)
# first collect formatting data to use for formatting template
@@ -661,7 +661,7 @@ class PublishableClip:
formatting_data[_k] = value
return {
- "entity_type": entity_type,
+ "folder_type": folder_type,
"entity_name": template.format(
**formatting_data
)
@@ -1018,7 +1018,7 @@ class OpenClipSolver(flib.MediaInfoFile):
self.feed_version_name))
else:
self.log.debug("adding new track element ..")
- # create new track as it doesnt exists yet
+ # create new track as it doesn't exist yet
# set current version to feeds on tmp
tmp_xml_feeds = tmp_xml_track.find('feeds')
tmp_xml_feeds.set('currentVersion', self.feed_version_name)
diff --git a/client/ayon_core/hosts/flame/otio/flame_export.py b/client/ayon_core/hosts/flame/otio/flame_export.py
index e5ea4dcf5e..cb038f9e9a 100644
--- a/client/ayon_core/hosts/flame/otio/flame_export.py
+++ b/client/ayon_core/hosts/flame/otio/flame_export.py
@@ -256,7 +256,7 @@ def create_otio_reference(clip_data, fps=None):
if not otio_ex_ref_item:
dirname, file_name = os.path.split(path)
- file_name = utils.get_reformated_filename(file_name, padded=False)
+ file_name = utils.get_reformatted_filename(file_name, padded=False)
reformated_path = os.path.join(dirname, file_name)
# in case old OTIO or video file create `ExternalReference`
otio_ex_ref_item = otio.schema.ExternalReference(
diff --git a/client/ayon_core/hosts/flame/otio/utils.py b/client/ayon_core/hosts/flame/otio/utils.py
index 7ded8e55d8..5a28263fc2 100644
--- a/client/ayon_core/hosts/flame/otio/utils.py
+++ b/client/ayon_core/hosts/flame/otio/utils.py
@@ -21,7 +21,7 @@ def frames_to_seconds(frames, framerate):
return otio.opentime.to_seconds(rt)
-def get_reformated_filename(filename, padded=True):
+def get_reformatted_filename(filename, padded=True):
"""
Return fixed python expression path
@@ -29,10 +29,10 @@ def get_reformated_filename(filename, padded=True):
filename (str): file name
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
- get_reformated_filename("plate.1001.exr") > plate.%04d.exr
+ get_reformatted_filename("plate.1001.exr") > plate.%04d.exr
"""
found = FRAME_PATTERN.search(filename)
diff --git a/client/ayon_core/hosts/flame/plugins/create/create_shot_clip.py b/client/ayon_core/hosts/flame/plugins/create/create_shot_clip.py
index e8eb2b9fab..56f5319f21 100644
--- a/client/ayon_core/hosts/flame/plugins/create/create_shot_clip.py
+++ b/client/ayon_core/hosts/flame/plugins/create/create_shot_clip.py
@@ -17,7 +17,7 @@ class CreateShotClip(opfapi.Creator):
presets = deepcopy(self.presets)
gui_inputs = self.get_gui_inputs()
- # get key pares from presets and match it on ui inputs
+ # get key pairs from presets and match it on ui inputs
for k, v in gui_inputs.items():
if v["type"] in ("dict", "section"):
# nested dictionary (only one level allowed
@@ -236,7 +236,7 @@ class CreateShotClip(opfapi.Creator):
"type": "QCheckBox",
"label": "Source resolution",
"target": "tag",
- "toolTip": "Is resloution taken from timeline or source?", # noqa
+ "toolTip": "Is resolution taken from timeline or source?", # noqa
"order": 4},
}
},
diff --git a/client/ayon_core/hosts/flame/plugins/publish/collect_timeline_instances.py b/client/ayon_core/hosts/flame/plugins/publish/collect_timeline_instances.py
index 9d6560023c..ca5475824d 100644
--- a/client/ayon_core/hosts/flame/plugins/publish/collect_timeline_instances.py
+++ b/client/ayon_core/hosts/flame/plugins/publish/collect_timeline_instances.py
@@ -37,7 +37,7 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin):
self.otio_timeline = context.data["otioTimeline"]
self.fps = context.data["fps"]
- # process all sellected
+ # process all selected
for segment in selected_segments:
# get openpype tag data
marker_data = opfapi.get_segment_data_marker(segment)
@@ -100,6 +100,12 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin):
marker_data["handleEnd"] = min(
marker_data["handleEnd"], tail)
+ # Backward compatibility fix of 'entity_type' > 'folder_type'
+ if "parents" in marker_data:
+ for parent in marker_data["parents"]:
+ if "entity_type" in parent:
+ parent["folder_type"] = parent.pop("entity_type")
+
workfile_start = self._set_workfile_start(marker_data)
with_audio = bool(marker_data.pop("audio"))
diff --git a/client/ayon_core/hosts/flame/startup/openpype_babypublisher/modules/ftrack_lib.py b/client/ayon_core/hosts/flame/startup/openpype_babypublisher/modules/ftrack_lib.py
index 0e84a5ef52..a66980493e 100644
--- a/client/ayon_core/hosts/flame/startup/openpype_babypublisher/modules/ftrack_lib.py
+++ b/client/ayon_core/hosts/flame/startup/openpype_babypublisher/modules/ftrack_lib.py
@@ -396,7 +396,7 @@ class FtrackEntityOperator:
entity = session.query(query).first()
- # if entity doesnt exist then create one
+ # if entity doesn't exist then create one
if not entity:
entity = self.create_ftrack_entity(
session,
diff --git a/client/ayon_core/hosts/fusion/api/pipeline.py b/client/ayon_core/hosts/fusion/api/pipeline.py
index 50157cfae6..dfac0640b0 100644
--- a/client/ayon_core/hosts/fusion/api/pipeline.py
+++ b/client/ayon_core/hosts/fusion/api/pipeline.py
@@ -28,7 +28,6 @@ from ayon_core.tools.utils import host_tools
from .lib import (
get_current_comp,
- comp_lock_and_undo_chunk,
validate_comp_prefs
)
diff --git a/client/ayon_core/hosts/fusion/plugins/create/create_saver.py b/client/ayon_core/hosts/fusion/plugins/create/create_saver.py
index b6cda1f302..20c7b99851 100644
--- a/client/ayon_core/hosts/fusion/plugins/create/create_saver.py
+++ b/client/ayon_core/hosts/fusion/plugins/create/create_saver.py
@@ -1,6 +1,11 @@
-from ayon_core.lib import EnumDef
+from ayon_core.lib import (
+ UILabelDef,
+ NumberDef,
+ EnumDef
+)
from ayon_core.hosts.fusion.api.plugin import GenericCreateSaver
+from ayon_core.hosts.fusion.api.lib import get_current_comp
class CreateSaver(GenericCreateSaver):
@@ -45,6 +50,7 @@ class CreateSaver(GenericCreateSaver):
self._get_reviewable_bool(),
self._get_frame_range_enum(),
self._get_image_format_enum(),
+ *self._get_custom_frame_range_attribute_defs()
]
return attr_defs
@@ -53,6 +59,7 @@ class CreateSaver(GenericCreateSaver):
"current_folder": "Current Folder context",
"render_range": "From render in/out",
"comp_range": "From composition timeline",
+ "custom_range": "Custom frame range",
}
return EnumDef(
@@ -61,3 +68,82 @@ class CreateSaver(GenericCreateSaver):
label="Frame range source",
default=self.default_frame_range_option
)
+
+ @staticmethod
+ def _get_custom_frame_range_attribute_defs() -> list:
+
+ # Define custom frame range defaults based on current comp
+ # timeline settings (if a comp is currently open)
+ comp = get_current_comp()
+ if comp is not None:
+ attrs = comp.GetAttrs()
+ frame_defaults = {
+ "frameStart": int(attrs["COMPN_GlobalStart"]),
+ "frameEnd": int(attrs["COMPN_GlobalEnd"]),
+ "handleStart": int(
+ attrs["COMPN_RenderStart"] - attrs["COMPN_GlobalStart"]
+ ),
+ "handleEnd": int(
+ attrs["COMPN_GlobalEnd"] - attrs["COMPN_RenderEnd"]
+ ),
+ }
+ else:
+ frame_defaults = {
+ "frameStart": 1001,
+ "frameEnd": 1100,
+ "handleStart": 0,
+ "handleEnd": 0
+ }
+
+ return [
+ UILabelDef(
+ label="
Custom Frame Range
"
+ "only used with 'Custom frame range' source"
+ ),
+ NumberDef(
+ "custom_frameStart",
+ label="Frame Start",
+ default=frame_defaults["frameStart"],
+ minimum=0,
+ decimals=0,
+ tooltip=(
+ "Set the start frame for the export.\n"
+ "Only used if frame range source is 'Custom frame range'."
+ )
+ ),
+ NumberDef(
+ "custom_frameEnd",
+ label="Frame End",
+ default=frame_defaults["frameEnd"],
+ minimum=0,
+ decimals=0,
+ tooltip=(
+ "Set the end frame for the export.\n"
+ "Only used if frame range source is 'Custom frame range'."
+ )
+ ),
+ NumberDef(
+ "custom_handleStart",
+ label="Handle Start",
+ default=frame_defaults["handleStart"],
+ minimum=0,
+ decimals=0,
+ tooltip=(
+ "Set the start handles for the export, this will be "
+ "added before the start frame.\n"
+ "Only used if frame range source is 'Custom frame range'."
+ )
+ ),
+ NumberDef(
+ "custom_handleEnd",
+ label="Handle End",
+ default=frame_defaults["handleEnd"],
+ minimum=0,
+ decimals=0,
+ tooltip=(
+ "Set the end handles for the export, this will be added "
+ "after the end frame.\n"
+ "Only used if frame range source is 'Custom frame range'."
+ )
+ )
+ ]
diff --git a/client/ayon_core/hosts/fusion/plugins/publish/collect_instances.py b/client/ayon_core/hosts/fusion/plugins/publish/collect_instances.py
index 51d7e68fb6..921c282877 100644
--- a/client/ayon_core/hosts/fusion/plugins/publish/collect_instances.py
+++ b/client/ayon_core/hosts/fusion/plugins/publish/collect_instances.py
@@ -57,6 +57,14 @@ class CollectInstanceData(pyblish.api.InstancePlugin):
start_with_handle = comp_start
end_with_handle = comp_end
+ if frame_range_source == "custom_range":
+ start = int(instance.data["custom_frameStart"])
+ end = int(instance.data["custom_frameEnd"])
+ handle_start = int(instance.data["custom_handleStart"])
+ handle_end = int(instance.data["custom_handleEnd"])
+ start_with_handle = start - handle_start
+ end_with_handle = end + handle_end
+
frame = instance.data["creator_attributes"].get("frame")
# explicitly publishing only single frame
if frame is not None:
diff --git a/client/ayon_core/hosts/harmony/api/lib.py b/client/ayon_core/hosts/harmony/api/lib.py
index 3c833c7b69..f9980cb65e 100644
--- a/client/ayon_core/hosts/harmony/api/lib.py
+++ b/client/ayon_core/hosts/harmony/api/lib.py
@@ -568,7 +568,7 @@ def save_scene():
"""Save the Harmony scene safely.
The built-in (to Avalon) background zip and moving of the Harmony scene
- folder, interfers with server/client communication by sending two requests
+ folder, interferes with server/client communication by sending two requests
at the same time. This only happens when sending "scene.saveAll()". This
method prevents this double request and safely saves the scene.
diff --git a/client/ayon_core/hosts/harmony/plugins/create/create_farm_render.py b/client/ayon_core/hosts/harmony/plugins/create/create_farm_render.py
index 16c403de6a..3039d56ead 100644
--- a/client/ayon_core/hosts/harmony/plugins/create/create_farm_render.py
+++ b/client/ayon_core/hosts/harmony/plugins/create/create_farm_render.py
@@ -21,12 +21,12 @@ class CreateFarmRender(plugin.Creator):
path = "render/{0}/{0}.".format(node.split("/")[-1])
harmony.send(
{
- "function": f"PypeHarmony.Creators.CreateRender.create",
+ "function": "PypeHarmony.Creators.CreateRender.create",
"args": [node, path]
})
harmony.send(
{
- "function": f"PypeHarmony.color",
+ "function": "PypeHarmony.color",
"args": [[0.9, 0.75, 0.3, 1.0]]
}
)
diff --git a/client/ayon_core/hosts/harmony/plugins/publish/collect_audio.py b/client/ayon_core/hosts/harmony/plugins/publish/collect_audio.py
index 40b4107a62..cc959a23b9 100644
--- a/client/ayon_core/hosts/harmony/plugins/publish/collect_audio.py
+++ b/client/ayon_core/hosts/harmony/plugins/publish/collect_audio.py
@@ -1,8 +1,8 @@
import os
-import pyblish.api
import pyblish.api
+
class CollectAudio(pyblish.api.InstancePlugin):
"""
Collect relative path for audio file to instance.
diff --git a/client/ayon_core/hosts/harmony/plugins/publish/collect_scene.py b/client/ayon_core/hosts/harmony/plugins/publish/collect_scene.py
index a60e44b69b..bc2ccca1be 100644
--- a/client/ayon_core/hosts/harmony/plugins/publish/collect_scene.py
+++ b/client/ayon_core/hosts/harmony/plugins/publish/collect_scene.py
@@ -17,7 +17,7 @@ class CollectScene(pyblish.api.ContextPlugin):
"""Plugin entry point."""
result = harmony.send(
{
- f"function": "PypeHarmony.getSceneSettings",
+ "function": "PypeHarmony.getSceneSettings",
"args": []}
)["result"]
@@ -62,7 +62,7 @@ class CollectScene(pyblish.api.ContextPlugin):
result = harmony.send(
{
- f"function": "PypeHarmony.getVersion",
+ "function": "PypeHarmony.getVersion",
"args": []}
)["result"]
context.data["harmonyVersion"] = "{}.{}".format(result[0], result[1])
diff --git a/client/ayon_core/hosts/hiero/api/events.py b/client/ayon_core/hosts/hiero/api/events.py
index 0e509747d5..304605e24e 100644
--- a/client/ayon_core/hosts/hiero/api/events.py
+++ b/client/ayon_core/hosts/hiero/api/events.py
@@ -1,10 +1,12 @@
import os
+
import hiero.core.events
+
from ayon_core.lib import Logger, register_event_callback
+
from .lib import (
sync_avalon_data_to_workfile,
launch_workfiles_app,
- selection_changed_timeline,
before_project_save,
)
from .tags import add_tags_to_workfile
diff --git a/client/ayon_core/hosts/hiero/api/lib.py b/client/ayon_core/hosts/hiero/api/lib.py
index 8e08e8cbf3..ecb3460fb4 100644
--- a/client/ayon_core/hosts/hiero/api/lib.py
+++ b/client/ayon_core/hosts/hiero/api/lib.py
@@ -166,7 +166,7 @@ def get_current_track(sequence, name, audio=False):
Creates new if none is found.
Args:
- sequence (hiero.core.Sequence): hiero sequene object
+ sequence (hiero.core.Sequence): hiero sequence object
name (str): name of track we want to return
audio (bool)[optional]: switch to AudioTrack
@@ -846,8 +846,8 @@ def create_nuke_workfile_clips(nuke_workfiles, seq=None):
[{
'path': 'P:/Jakub_testy_pipeline/test_v01.nk',
'name': 'test',
- 'handleStart': 15, # added asymetrically to handles
- 'handleEnd': 10, # added asymetrically to handles
+ 'handleStart': 15, # added asymmetrically to handles
+ 'handleEnd': 10, # added asymmetrically to handles
"clipIn": 16,
"frameStart": 991,
"frameEnd": 1023,
@@ -1192,7 +1192,7 @@ def get_sequence_pattern_and_padding(file):
Return:
string: any matching sequence pattern
- int: padding of sequnce numbering
+ int: padding of sequence numbering
"""
foundall = re.findall(
r"(#+)|(%\d+d)|(?<=[^a-zA-Z0-9])(\d+)(?=\.\w+$)", file)
diff --git a/client/ayon_core/hosts/hiero/api/otio/hiero_import.py b/client/ayon_core/hosts/hiero/api/otio/hiero_import.py
index 257c434011..29ff7f7325 100644
--- a/client/ayon_core/hosts/hiero/api/otio/hiero_import.py
+++ b/client/ayon_core/hosts/hiero/api/otio/hiero_import.py
@@ -90,7 +90,7 @@ def apply_transition(otio_track, otio_item, track):
if isinstance(track, hiero.core.AudioTrack):
kind = 'Audio'
- # Gather TrackItems involved in trasition
+ # Gather TrackItems involved in transition
item_in, item_out = get_neighboring_trackitems(
otio_item,
otio_track,
@@ -101,7 +101,7 @@ def apply_transition(otio_track, otio_item, track):
if transition_type == 'dissolve':
transition_func = getattr(
hiero.core.Transition,
- 'create{kind}DissolveTransition'.format(kind=kind)
+ "create{kind}DissolveTransition".format(kind=kind)
)
try:
@@ -109,7 +109,7 @@ def apply_transition(otio_track, otio_item, track):
item_in,
item_out,
otio_item.in_offset.value,
- otio_item.out_offset.value
+ otio_item.out_offset.value,
)
# Catch error raised if transition is bigger than TrackItem source
@@ -134,7 +134,7 @@ def apply_transition(otio_track, otio_item, track):
transition = transition_func(
item_out,
- otio_item.out_offset.value
+ otio_item.out_offset.value,
)
elif transition_type == 'fade_out':
@@ -183,9 +183,7 @@ def prep_url(url_in):
def create_offline_mediasource(otio_clip, path=None):
global _otio_old
- hiero_rate = hiero.core.TimeBase(
- otio_clip.source_range.start_time.rate
- )
+ hiero_rate = hiero.core.TimeBase(otio_clip.source_range.start_time.rate)
try:
legal_media_refs = (
@@ -212,7 +210,7 @@ def create_offline_mediasource(otio_clip, path=None):
source_range.start_time.value,
source_range.duration.value,
hiero_rate,
- source_range.start_time.value
+ source_range.start_time.value,
)
return media
@@ -385,7 +383,8 @@ def create_trackitem(playhead, track, otio_clip, clip):
# Only reverse effect can be applied here
if abs(time_scalar) == 1.:
trackitem.setPlaybackSpeed(
- trackitem.playbackSpeed() * time_scalar)
+ trackitem.playbackSpeed() * time_scalar
+ )
elif isinstance(effect, otio.schema.FreezeFrame):
# For freeze frame, playback speed must be set after range
@@ -397,28 +396,21 @@ def create_trackitem(playhead, track, otio_clip, clip):
source_in = source_range.end_time_inclusive().value
timeline_in = playhead + source_out
- timeline_out = (
- timeline_in +
- source_range.duration.value
- ) - 1
+ timeline_out = (timeline_in + source_range.duration.value) - 1
else:
# Normal playback speed
source_in = source_range.start_time.value
source_out = source_range.end_time_inclusive().value
timeline_in = playhead
- timeline_out = (
- timeline_in +
- source_range.duration.value
- ) - 1
+ timeline_out = (timeline_in + source_range.duration.value) - 1
# Set source and timeline in/out points
trackitem.setTimes(
timeline_in,
timeline_out,
source_in,
- source_out
-
+ source_out,
)
# Apply playback speed for freeze frames
@@ -435,7 +427,8 @@ def create_trackitem(playhead, track, otio_clip, clip):
def build_sequence(
- otio_timeline, project=None, sequence=None, track_kind=None):
+ otio_timeline, project=None, sequence=None, track_kind=None
+):
if project is None:
if sequence:
project = sequence.project()
@@ -509,10 +502,7 @@ def build_sequence(
# Create TrackItem
trackitem = create_trackitem(
- playhead,
- track,
- otio_clip,
- clip
+ playhead, track, otio_clip, clip
)
# Add markers
diff --git a/client/ayon_core/hosts/hiero/api/otio/utils.py b/client/ayon_core/hosts/hiero/api/otio/utils.py
index 4c5d46bd51..f7cb58f1e8 100644
--- a/client/ayon_core/hosts/hiero/api/otio/utils.py
+++ b/client/ayon_core/hosts/hiero/api/otio/utils.py
@@ -25,7 +25,7 @@ def get_reformated_path(path, padded=True):
path (str): path url or simple file name
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
get_reformated_path("plate.[0001-1008].exr") > plate.%04d.exr
diff --git a/client/ayon_core/hosts/hiero/api/plugin.py b/client/ayon_core/hosts/hiero/api/plugin.py
index 4878368716..1353673b31 100644
--- a/client/ayon_core/hosts/hiero/api/plugin.py
+++ b/client/ayon_core/hosts/hiero/api/plugin.py
@@ -449,7 +449,6 @@ class ClipLoader:
repr = self.context["representation"]
repr_cntx = repr["context"]
folder_path = self.context["folder"]["path"]
- folder_name = self.context["folder"]["name"]
product_name = self.context["product"]["name"]
representation = repr["name"]
self.data["clip_name"] = self.clip_name_template.format(**repr_cntx)
@@ -906,16 +905,16 @@ class PublishClip:
"hierarchyData": hierarchy_formatting_data,
"productName": self.product_name,
"productType": self.product_type,
- "families": [self.product_type, self.data["family"]]
+ "families": [self.product_type, self.data["productType"]]
}
- def _convert_to_entity(self, type, template):
+ def _convert_to_entity(self, src_type, template):
""" Converting input key to key with type. """
# convert to entity type
- entity_type = self.types.get(type, None)
+ folder_type = self.types.get(src_type, None)
- assert entity_type, "Missing entity type for `{}`".format(
- type
+ assert folder_type, "Missing folder type for `{}`".format(
+ src_type
)
# first collect formatting data to use for formatting template
@@ -926,7 +925,7 @@ class PublishClip:
formatting_data[_k] = value
return {
- "entity_type": entity_type,
+ "folder_type": folder_type,
"entity_name": template.format(
**formatting_data
)
diff --git a/client/ayon_core/hosts/hiero/api/startup/Python/Startup/SpreadsheetExport.py b/client/ayon_core/hosts/hiero/api/startup/Python/Startup/SpreadsheetExport.py
index 9c919e7cb4..6a8057ec1e 100644
--- a/client/ayon_core/hosts/hiero/api/startup/Python/Startup/SpreadsheetExport.py
+++ b/client/ayon_core/hosts/hiero/api/startup/Python/Startup/SpreadsheetExport.py
@@ -3,9 +3,11 @@
# Note: This only prints the text data that is visible in the active Spreadsheet View.
# If you've filtered text, only the visible text will be printed to the CSV file
# Usage: Copy to ~/.hiero/Python/StartupUI
+import os
+import csv
+
import hiero.core.events
import hiero.ui
-import os, csv
try:
from PySide.QtGui import *
from PySide.QtCore import *
diff --git a/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/PimpMySpreadsheet.py b/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/PimpMySpreadsheet.py
index b8dfb07b47..fcfa24310e 100644
--- a/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/PimpMySpreadsheet.py
+++ b/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/PimpMySpreadsheet.py
@@ -641,7 +641,7 @@ def _setStatus(self, status):
global gStatusTags
# Get a valid Tag object from the Global list of statuses
- if not status in gStatusTags.keys():
+ if status not in gStatusTags.keys():
print("Status requested was not a valid Status string.")
return
diff --git a/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/otioimporter/OTIOImport.py b/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/otioimporter/OTIOImport.py
index 17c044f3ec..d2fe608d99 100644
--- a/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/otioimporter/OTIOImport.py
+++ b/client/ayon_core/hosts/hiero/api/startup/Python/StartupUI/otioimporter/OTIOImport.py
@@ -90,7 +90,7 @@ def apply_transition(otio_track, otio_item, track):
kind = "Audio"
try:
- # Gather TrackItems involved in trasition
+ # Gather TrackItems involved in transition
item_in, item_out = get_neighboring_trackitems(
otio_item,
otio_track,
@@ -101,14 +101,14 @@ def apply_transition(otio_track, otio_item, track):
if transition_type == "dissolve":
transition_func = getattr(
hiero.core.Transition,
- 'create{kind}DissolveTransition'.format(kind=kind)
+ "create{kind}DissolveTransition".format(kind=kind)
)
transition = transition_func(
item_in,
item_out,
otio_item.in_offset.value,
- otio_item.out_offset.value
+ otio_item.out_offset.value,
)
elif transition_type == "fade_in":
@@ -116,20 +116,14 @@ def apply_transition(otio_track, otio_item, track):
hiero.core.Transition,
'create{kind}FadeInTransition'.format(kind=kind)
)
- transition = transition_func(
- item_out,
- otio_item.out_offset.value
- )
+ transition = transition_func(item_out, otio_item.out_offset.value)
elif transition_type == "fade_out":
transition_func = getattr(
hiero.core.Transition,
- 'create{kind}FadeOutTransition'.format(kind=kind)
- )
- transition = transition_func(
- item_in,
- otio_item.in_offset.value
+ "create{kind}FadeOutTransition".format(kind=kind)
)
+ transition = transition_func(item_in, otio_item.in_offset.value)
else:
# Unknown transition
@@ -138,11 +132,10 @@ def apply_transition(otio_track, otio_item, track):
# Apply transition to track
track.addTransition(transition)
- except Exception, e:
+ except Exception as e:
sys.stderr.write(
'Unable to apply transition "{t}": "{e}"\n'.format(
- t=otio_item,
- e=e
+ t=otio_item, e=e
)
)
@@ -153,18 +146,14 @@ def prep_url(url_in):
if url.startswith("file://localhost/"):
return url.replace("file://localhost/", "")
- url = '{url}'.format(
- sep=url.startswith(os.sep) and "" or os.sep,
- url=url.startswith(os.sep) and url[1:] or url
- )
+ if url.startswith(os.sep):
+ url = url[1:]
return url
def create_offline_mediasource(otio_clip, path=None):
- hiero_rate = hiero.core.TimeBase(
- otio_clip.source_range.start_time.rate
- )
+ hiero_rate = hiero.core.TimeBase(otio_clip.source_range.start_time.rate)
if isinstance(otio_clip.media_reference, otio.schema.ExternalReference):
source_range = otio_clip.available_range()
@@ -180,7 +169,7 @@ def create_offline_mediasource(otio_clip, path=None):
source_range.start_time.value,
source_range.duration.value,
hiero_rate,
- source_range.start_time.value
+ source_range.start_time.value,
)
return media
@@ -203,7 +192,7 @@ marker_color_map = {
"MAGENTA": "Magenta",
"BLACK": "Blue",
"WHITE": "Green",
- "MINT": "Cyan"
+ "MINT": "Cyan",
}
@@ -254,12 +243,6 @@ def add_markers(otio_item, hiero_item, tagsbin):
if _tag is None:
_tag = hiero.core.Tag(marker_color_map[marker.color])
- start = marker.marked_range.start_time.value
- end = (
- marker.marked_range.start_time.value +
- marker.marked_range.duration.value
- )
-
tag = hiero_item.addTag(_tag)
tag.setName(marker.name or marker_color_map[marker_color])
@@ -275,12 +258,12 @@ def create_track(otio_track, tracknum, track_kind):
# Create a Track
if otio_track.kind == otio.schema.TrackKind.Video:
track = hiero.core.VideoTrack(
- otio_track.name or 'Video{n}'.format(n=tracknum)
+ otio_track.name or "Video{n}".format(n=tracknum)
)
else:
track = hiero.core.AudioTrack(
- otio_track.name or 'Audio{n}'.format(n=tracknum)
+ otio_track.name or "Audio{n}".format(n=tracknum)
)
return track
@@ -315,34 +298,25 @@ def create_trackitem(playhead, track, otio_clip, clip, tagsbin):
for effect in otio_clip.effects:
if isinstance(effect, otio.schema.LinearTimeWarp):
trackitem.setPlaybackSpeed(
- trackitem.playbackSpeed() *
- effect.time_scalar
+ trackitem.playbackSpeed() * effect.time_scalar
)
# If reverse playback speed swap source in and out
if trackitem.playbackSpeed() < 0:
source_out = source_range.start_time.value
source_in = (
- source_range.start_time.value +
- source_range.duration.value
+ source_range.start_time.value + source_range.duration.value
) - 1
timeline_in = playhead + source_out
- timeline_out = (
- timeline_in +
- source_range.duration.value
- ) - 1
+ timeline_out = (timeline_in + source_range.duration.value) - 1
else:
# Normal playback speed
source_in = source_range.start_time.value
source_out = (
- source_range.start_time.value +
- source_range.duration.value
+ source_range.start_time.value + source_range.duration.value
) - 1
timeline_in = playhead
- timeline_out = (
- timeline_in +
- source_range.duration.value
- ) - 1
+ timeline_out = (timeline_in + source_range.duration.value) - 1
# Set source and timeline in/out points
trackitem.setSourceIn(source_in)
@@ -357,7 +331,8 @@ def create_trackitem(playhead, track, otio_clip, clip, tagsbin):
def build_sequence(
- otio_timeline, project=None, sequence=None, track_kind=None):
+ otio_timeline, project=None, sequence=None, track_kind=None
+):
if project is None:
if sequence:
@@ -414,8 +389,7 @@ def build_sequence(
if isinstance(otio_clip, otio.schema.Stack):
bar = hiero.ui.mainWindow().statusBar()
bar.showMessage(
- "Nested sequences are created separately.",
- timeout=3000
+ "Nested sequences are created separately.", timeout=3000
)
build_sequence(otio_clip, project, otio_track.kind)
@@ -428,11 +402,7 @@ def build_sequence(
# Create TrackItem
trackitem = create_trackitem(
- playhead,
- track,
- otio_clip,
- clip,
- tagsbin
+ playhead, track, otio_clip, clip, tagsbin
)
# Add trackitem to track
diff --git a/client/ayon_core/hosts/hiero/api/tags.py b/client/ayon_core/hosts/hiero/api/tags.py
index 32620aa2f5..5abfee75d0 100644
--- a/client/ayon_core/hosts/hiero/api/tags.py
+++ b/client/ayon_core/hosts/hiero/api/tags.py
@@ -89,7 +89,7 @@ def update_tag(tag, data):
# set all data metadata to tag metadata
for _k, _v in data_mtd.items():
value = str(_v)
- if type(_v) == dict:
+ if isinstance(_v, dict):
value = json.dumps(_v)
# set the value
diff --git a/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py b/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py
index 62e7041286..2985a81317 100644
--- a/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py
+++ b/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py
@@ -166,7 +166,7 @@ class CreateShotClip(phiero.Creator):
"type": "QCheckBox",
"label": "Source resolution",
"target": "tag",
- "toolTip": "Is resloution taken from timeline or source?", # noqa
+ "toolTip": "Is resolution taken from timeline or source?", # noqa
"order": 4},
}
},
@@ -211,7 +211,7 @@ class CreateShotClip(phiero.Creator):
presets = deepcopy(self.presets)
gui_inputs = deepcopy(self.gui_inputs)
- # get key pares from presets and match it on ui inputs
+ # get key pairs from presets and match it on ui inputs
for k, v in gui_inputs.items():
if v["type"] in ("dict", "section"):
# nested dictionary (only one level allowed
diff --git a/client/ayon_core/hosts/hiero/plugins/publish/collect_clip_effects.py b/client/ayon_core/hosts/hiero/plugins/publish/collect_clip_effects.py
index 32b4864022..bfc63f2551 100644
--- a/client/ayon_core/hosts/hiero/plugins/publish/collect_clip_effects.py
+++ b/client/ayon_core/hosts/hiero/plugins/publish/collect_clip_effects.py
@@ -1,5 +1,5 @@
-from itertools import product
import re
+
import pyblish.api
diff --git a/client/ayon_core/hosts/hiero/plugins/publish/precollect_instances.py b/client/ayon_core/hosts/hiero/plugins/publish/precollect_instances.py
index d921f37934..d6fbcd7575 100644
--- a/client/ayon_core/hosts/hiero/plugins/publish/precollect_instances.py
+++ b/client/ayon_core/hosts/hiero/plugins/publish/precollect_instances.py
@@ -43,7 +43,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
tracks_effect_items = self.collect_sub_track_items(all_tracks)
context.data["tracksEffectItems"] = tracks_effect_items
- # process all sellected timeline track items
+ # process all selected timeline track items
for track_item in selected_timeline_items:
data = {}
clip_name = track_item.name()
@@ -62,7 +62,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
}:
continue
- # get clips subtracks and anotations
+ # get clips subtracks and annotations
annotations = self.clip_annotations(source_clip)
subtracks = self.clip_subtrack(track_item)
self.log.debug("Annotations: {}".format(annotations))
@@ -84,6 +84,11 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
k: v for k, v in tag_data.items()
if k not in ("id", "applieswhole", "label")
})
+ # Backward compatibility fix of 'entity_type' > 'folder_type'
+ if "parents" in data:
+ for parent in data["parents"]:
+ if "entity_type" in parent:
+ parent["folder_type"] = parent.pop("entity_type")
asset, asset_name = self._get_folder_data(tag_data)
@@ -378,12 +383,10 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
# collect all subtrack items
sub_track_items = {}
for track in tracks:
- items = track.items()
-
- effet_items = track.subTrackItems()
+ effect_items = track.subTrackItems()
# skip if no clips on track > need track with effect only
- if not effet_items:
+ if not effect_items:
continue
# skip all disabled tracks
@@ -391,7 +394,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
continue
track_index = track.trackIndex()
- _sub_track_items = phiero.flatten(effet_items)
+ _sub_track_items = phiero.flatten(effect_items)
_sub_track_items = list(_sub_track_items)
# continue only if any subtrack items are collected
@@ -439,10 +442,10 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
for item in subTrackItems:
if "TimeWarp" in item.name():
continue
- # avoid all anotation
+ # avoid all annotation
if isinstance(item, hiero.core.Annotation):
continue
- # # avoid all not anaibled
+ # avoid all disabled
if not item.isEnabled():
continue
subtracks.append(item)
diff --git a/client/ayon_core/hosts/hiero/plugins/publish_old_workflow/precollect_retime.py b/client/ayon_core/hosts/hiero/plugins/publish_old_workflow/precollect_retime.py
index 297ffa8001..8503a0b6a7 100644
--- a/client/ayon_core/hosts/hiero/plugins/publish_old_workflow/precollect_retime.py
+++ b/client/ayon_core/hosts/hiero/plugins/publish_old_workflow/precollect_retime.py
@@ -35,10 +35,6 @@ class PrecollectRetime(api.InstancePlugin):
source_out = int(track_item.sourceOut())
speed = track_item.playbackSpeed()
- # calculate available material before retime
- available_in = int(track_item.handleInLength() * speed)
- available_out = int(track_item.handleOutLength() * speed)
-
self.log.debug((
"_BEFORE: \n timeline_in: `{0}`,\n timeline_out: `{1}`, \n "
"source_in: `{2}`,\n source_out: `{3}`,\n speed: `{4}`,\n "
diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py
index 681052a44d..a72118c276 100644
--- a/client/ayon_core/hosts/houdini/api/lib.py
+++ b/client/ayon_core/hosts/houdini/api/lib.py
@@ -3,7 +3,6 @@ import sys
import os
import errno
import re
-import uuid
import logging
import json
from contextlib import contextmanager
@@ -44,84 +43,6 @@ def get_folder_fps(folder_entity=None):
return folder_entity["attrib"]["fps"]
-def set_id(node, unique_id, overwrite=False):
- exists = node.parm("id")
- if not exists:
- imprint(node, {"id": unique_id})
-
- if not exists and overwrite:
- node.setParm("id", unique_id)
-
-
-def get_id(node):
- """Get the `cbId` attribute of the given node.
-
- Args:
- node (hou.Node): the name of the node to retrieve the attribute from
-
- Returns:
- str: cbId attribute of the node.
-
- """
-
- if node is not None:
- return node.parm("id")
-
-
-def generate_ids(nodes, folder_id=None):
- """Returns new unique ids for the given nodes.
-
- Note: This does not assign the new ids, it only generates the values.
-
- To assign new ids using this method:
- >>> nodes = ["a", "b", "c"]
- >>> for node, id in generate_ids(nodes):
- >>> set_id(node, id)
-
- To also override any existing values (and assign regenerated ids):
- >>> nodes = ["a", "b", "c"]
- >>> for node, id in generate_ids(nodes):
- >>> set_id(node, id, overwrite=True)
-
- Args:
- nodes (list): List of nodes.
- folder_id (str): Folder id . Use current folder id if is ``None``.
-
- Returns:
- list: A list of (node, id) tuples.
-
- """
-
- if folder_id is None:
- project_name = get_current_project_name()
- folder_path = get_current_folder_path()
- # Get folder id of current context folder
- folder_entity = ayon_api.get_folder_by_path(
- project_name, folder_path, fields={"id"}
- )
- if not folder_entity:
- raise ValueError("No current folder is set.")
-
- folder_id = folder_entity["id"]
-
- node_ids = []
- for node in nodes:
- _, uid = str(uuid.uuid4()).rsplit("-", 1)
- unique_id = "{}:{}".format(folder_id, uid)
- node_ids.append((node, unique_id))
-
- return node_ids
-
-
-def get_id_required_nodes():
-
- valid_types = ["geometry"]
- nodes = {n for n in hou.node("/out").children() if
- n.type().name() in valid_types}
-
- return list(nodes)
-
-
def get_output_parameter(node):
"""Return the render output parameter of the given node
@@ -526,7 +447,7 @@ def maintained_selection():
node.setSelected(on=True)
-def reset_framerange():
+def reset_framerange(fps=True, frame_range=True):
"""Set frame range and FPS to current folder."""
project_name = get_current_project_name()
@@ -535,29 +456,32 @@ def reset_framerange():
folder_entity = ayon_api.get_folder_by_path(project_name, folder_path)
folder_attributes = folder_entity["attrib"]
- # Get FPS
- fps = get_folder_fps(folder_entity)
+ # Set FPS
+ if fps:
+ fps = get_folder_fps(folder_entity)
+ print("Setting scene FPS to {}".format(int(fps)))
+ set_scene_fps(fps)
- # Get Start and End Frames
- frame_start = folder_attributes.get("frameStart")
- frame_end = folder_attributes.get("frameEnd")
+ if frame_range:
- if frame_start is None or frame_end is None:
- log.warning("No edit information found for '{}'".format(folder_path))
- return
+ # Set Start and End Frames
+ frame_start = folder_attributes.get("frameStart")
+ frame_end = folder_attributes.get("frameEnd")
- handle_start = folder_attributes.get("handleStart", 0)
- handle_end = folder_attributes.get("handleEnd", 0)
+ if frame_start is None or frame_end is None:
+ log.warning("No edit information found for '%s'", folder_path)
+ return
- frame_start -= int(handle_start)
- frame_end += int(handle_end)
+ handle_start = folder_attributes.get("handleStart", 0)
+ handle_end = folder_attributes.get("handleEnd", 0)
- # Set frame range and FPS
- print("Setting scene FPS to {}".format(int(fps)))
- set_scene_fps(fps)
- hou.playbar.setFrameRange(frame_start, frame_end)
- hou.playbar.setPlaybackRange(frame_start, frame_end)
- hou.setFrame(frame_start)
+ frame_start -= int(handle_start)
+ frame_end += int(handle_end)
+
+ # Set frame range and FPS
+ hou.playbar.setFrameRange(frame_start, frame_end)
+ hou.playbar.setPlaybackRange(frame_start, frame_end)
+ hou.setFrame(frame_start)
def get_main_window():
@@ -1072,3 +996,84 @@ def add_self_publish_button(node):
template = node.parmTemplateGroup()
template.insertBefore((0,), button_parm)
node.setParmTemplateGroup(template)
+
+
+def update_content_on_context_change():
+ """Update all Creator instances to current asset"""
+ host = registered_host()
+ context = host.get_current_context()
+
+ folder_path = context["folder_path"]
+ task = context["task_name"]
+
+ create_context = CreateContext(host, reset=True)
+
+ for instance in create_context.instances:
+ instance_folder_path = instance.get("folderPath")
+ if instance_folder_path and instance_folder_path != folder_path:
+ instance["folderPath"] = folder_path
+ instance_task = instance.get("task")
+ if instance_task and instance_task != task:
+ instance["task"] = task
+
+ create_context.save_changes()
+
+
+def prompt_reset_context():
+ """Prompt the user what context settings to reset.
+ This prompt is used on saving to a different task to allow the scene to
+ get matched to the new context.
+ """
+ # TODO: Cleanup this prototyped mess of imports and odd dialog
+ from ayon_core.tools.attribute_defs.dialog import (
+ AttributeDefinitionsDialog
+ )
+ from ayon_core.style import load_stylesheet
+ from ayon_core.lib import BoolDef, UILabelDef
+
+ definitions = [
+ UILabelDef(
+ label=(
+ "You are saving your workfile into a different folder or task."
+ "\n\n"
+ "Would you like to update some settings to the new context?\n"
+ )
+ ),
+ BoolDef(
+ "fps",
+ label="FPS",
+ tooltip="Reset workfile FPS",
+ default=True
+ ),
+ BoolDef(
+ "frame_range",
+ label="Frame Range",
+ tooltip="Reset workfile start and end frame ranges",
+ default=True
+ ),
+ BoolDef(
+ "instances",
+ label="Publish instances",
+ tooltip="Update all publish instance's folder and task to match "
+ "the new folder and task",
+ default=True
+ ),
+ ]
+
+ dialog = AttributeDefinitionsDialog(definitions)
+ dialog.setWindowTitle("Saving to different context.")
+ dialog.setStyleSheet(load_stylesheet())
+ if not dialog.exec_():
+ return None
+
+ options = dialog.get_values()
+ if options["fps"] or options["frame_range"]:
+ reset_framerange(
+ fps=options["fps"],
+ frame_range=options["frame_range"]
+ )
+
+ if options["instances"]:
+ update_content_on_context_change()
+
+ dialog.deleteLater()
\ No newline at end of file
diff --git a/client/ayon_core/hosts/houdini/api/pipeline.py b/client/ayon_core/hosts/houdini/api/pipeline.py
index d5144200cf..b9446933ac 100644
--- a/client/ayon_core/hosts/houdini/api/pipeline.py
+++ b/client/ayon_core/hosts/houdini/api/pipeline.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
"""Pipeline tools for OpenPype Houdini integration."""
import os
-import sys
import logging
import hou # noqa
@@ -39,6 +38,9 @@ LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
+# Track whether the workfile tool is about to save
+ABOUT_TO_SAVE = False
+
class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
name = "houdini"
@@ -61,10 +63,12 @@ class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
log.info("Installing callbacks ... ")
# register_event_callback("init", on_init)
self._register_callbacks()
+ register_event_callback("workfile.save.before", before_workfile_save)
register_event_callback("before.save", before_save)
register_event_callback("save", on_save)
register_event_callback("open", on_open)
register_event_callback("new", on_new)
+ register_event_callback("taskChanged", on_task_changed)
self._has_been_setup = True
@@ -166,7 +170,7 @@ class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
if not op_ctx:
op_ctx = self.create_context_node()
- lib.imprint(op_ctx, data)
+ lib.imprint(op_ctx, data, update=True)
def get_context_data(self):
op_ctx = hou.node(CONTEXT_CONTAINER)
@@ -287,6 +291,11 @@ def ls():
yield parse_container(container)
+def before_workfile_save(event):
+ global ABOUT_TO_SAVE
+ ABOUT_TO_SAVE = True
+
+
def before_save():
return lib.validate_fps()
@@ -302,6 +311,17 @@ def on_save():
for node, new_id in lib.generate_ids(nodes):
lib.set_id(node, new_id, overwrite=False)
+ # We are now starting the actual save directly
+ global ABOUT_TO_SAVE
+ ABOUT_TO_SAVE = False
+
+
+def on_task_changed():
+ global ABOUT_TO_SAVE
+ if not IS_HEADLESS and ABOUT_TO_SAVE:
+ # Let's prompt the user to update the context settings or not
+ lib.prompt_reset_context()
+
def _show_outdated_content_popup():
# Get main window
diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_redshift_rop.py b/client/ayon_core/hosts/houdini/plugins/create/create_redshift_rop.py
index ba0795a26e..1cd239e929 100644
--- a/client/ayon_core/hosts/houdini/plugins/create/create_redshift_rop.py
+++ b/client/ayon_core/hosts/houdini/plugins/create/create_redshift_rop.py
@@ -15,6 +15,7 @@ class CreateRedshiftROP(plugin.HoudiniCreator):
product_type = "redshift_rop"
icon = "magic"
ext = "exr"
+ multi_layered_mode = "No Multi-Layered EXR File"
# Default to split export and render jobs
split_render = True
@@ -55,25 +56,36 @@ class CreateRedshiftROP(plugin.HoudiniCreator):
# Set the linked rop to the Redshift ROP
ipr_rop.parm("linked_rop").set(instance_node.path())
-
ext = pre_create_data.get("image_format")
- filepath = "{renders_dir}{product_name}/{product_name}.{fmt}".format(
- renders_dir=hou.text.expandString("$HIP/pyblish/renders/"),
- product_name=product_name,
- fmt="${aov}.$F4.{ext}".format(aov="AOV", ext=ext)
- )
+ multi_layered_mode = pre_create_data.get("multi_layered_mode")
ext_format_index = {"exr": 0, "tif": 1, "jpg": 2, "png": 3}
+ multilayer_mode_index = {"No Multi-Layered EXR File": "1",
+ "Full Multi-Layered EXR File": "2" }
+
+ filepath = "{renders_dir}{product_name}/{product_name}.{fmt}".format(
+ renders_dir=hou.text.expandString("$HIP/pyblish/renders/"),
+ product_name=product_name,
+ fmt="$AOV.$F4.{ext}".format(ext=ext)
+ )
+
+ if multilayer_mode_index[multi_layered_mode] == "1":
+ multipart = False
+
+ elif multilayer_mode_index[multi_layered_mode] == "2":
+ multipart = True
parms = {
# Render frame range
"trange": 1,
# Redshift ROP settings
"RS_outputFileNamePrefix": filepath,
- "RS_outputMultilayerMode": "1", # no multi-layered exr
"RS_outputBeautyAOVSuffix": "beauty",
"RS_outputFileFormat": ext_format_index[ext],
}
+ if ext == "exr":
+ parms["RS_outputMultilayerMode"] = multilayer_mode_index[multi_layered_mode]
+ parms["RS_aovMultipart"] = multipart
if self.selected_nodes:
# set up the render camera from the selected node
@@ -111,6 +123,11 @@ class CreateRedshiftROP(plugin.HoudiniCreator):
image_format_enum = [
"exr", "tif", "jpg", "png",
]
+ multi_layered_mode = [
+ "No Multi-Layered EXR File",
+ "Full Multi-Layered EXR File"
+ ]
+
return attrs + [
BoolDef("farm",
@@ -122,5 +139,9 @@ class CreateRedshiftROP(plugin.HoudiniCreator):
EnumDef("image_format",
image_format_enum,
default=self.ext,
- label="Image Format Options")
+ label="Image Format Options"),
+ EnumDef("multi_layered_mode",
+ multi_layered_mode,
+ default=self.multi_layered_mode,
+ label="Multi-Layered EXR")
]
diff --git a/client/ayon_core/hosts/houdini/plugins/load/actions.py b/client/ayon_core/hosts/houdini/plugins/load/actions.py
index c277005919..fbd89ab9c2 100644
--- a/client/ayon_core/hosts/houdini/plugins/load/actions.py
+++ b/client/ayon_core/hosts/houdini/plugins/load/actions.py
@@ -76,8 +76,8 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin):
return
# Include handles
- start -= version_data.get("handleStart", 0)
- end += version_data.get("handleEnd", 0)
+ start -= version_attributes.get("handleStart", 0)
+ end += version_attributes.get("handleEnd", 0)
hou.playbar.setFrameRange(start, end)
hou.playbar.setPlaybackRange(start, end)
diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py
index a77d06d409..37657cbdff 100644
--- a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py
+++ b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py
@@ -59,7 +59,7 @@ class AbcLoader(load.LoaderPlugin):
normal_node.setInput(0, unpack)
- null = container.createNode("null", node_name="OUT".format(name))
+ null = container.createNode("null", node_name="OUT")
null.setInput(0, normal_node)
# Ensure display flag is on the Alembic input node and not on the OUT
diff --git a/client/ayon_core/hosts/houdini/plugins/publish/collect_redshift_rop.py b/client/ayon_core/hosts/houdini/plugins/publish/collect_redshift_rop.py
index 8437757c58..55a55bb12a 100644
--- a/client/ayon_core/hosts/houdini/plugins/publish/collect_redshift_rop.py
+++ b/client/ayon_core/hosts/houdini/plugins/publish/collect_redshift_rop.py
@@ -60,15 +60,22 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin):
instance.data["ifdFile"] = beauty_export_product
instance.data["exportFiles"] = list(export_products)
- # Default beauty AOV
+ full_exr_mode = (rop.evalParm("RS_outputMultilayerMode") == "2")
+ if full_exr_mode:
+ # Ignore beauty suffix if full mode is enabled
+ # As this is what the rop does.
+ beauty_suffix = ""
+
+ # Default beauty/main layer AOV
beauty_product = self.get_render_product_name(
prefix=default_prefix, suffix=beauty_suffix
)
render_products = [beauty_product]
files_by_aov = {
- "_": self.generate_expected_files(instance,
- beauty_product)}
-
+ beauty_suffix: self.generate_expected_files(instance,
+ beauty_product)
+ }
+
aovs_rop = rop.parm("RS_aovGetFromNode").evalAsNode()
if aovs_rop:
rop = aovs_rop
@@ -89,11 +96,14 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin):
if not aov_prefix:
aov_prefix = default_prefix
- aov_product = self.get_render_product_name(aov_prefix, aov_suffix)
- render_products.append(aov_product)
+ if rop.parm(f"RS_aovID_{i}").evalAsString() == "CRYPTOMATTE" or \
+ not full_exr_mode:
+
+ aov_product = self.get_render_product_name(aov_prefix, aov_suffix)
+ render_products.append(aov_product)
- files_by_aov[aov_suffix] = self.generate_expected_files(instance,
- aov_product) # noqa
+ files_by_aov[aov_suffix] = self.generate_expected_files(instance,
+ aov_product) # noqa
for product in render_products:
self.log.debug("Found render product: %s" % product)
@@ -121,7 +131,7 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin):
# When AOV is explicitly defined in prefix we just swap it out
# directly with the AOV suffix to embed it.
- # Note: ${AOV} seems to be evaluated in the parameter as %AOV%
+ # Note: '$AOV' seems to be evaluated in the parameter as '%AOV%'
has_aov_in_prefix = "%AOV%" in prefix
if has_aov_in_prefix:
# It seems that when some special separator characters are present
diff --git a/client/ayon_core/hosts/houdini/plugins/publish/validate_cop_output_node.py b/client/ayon_core/hosts/houdini/plugins/publish/validate_cop_output_node.py
index 95414ae7f1..fdf03d5cba 100644
--- a/client/ayon_core/hosts/houdini/plugins/publish/validate_cop_output_node.py
+++ b/client/ayon_core/hosts/houdini/plugins/publish/validate_cop_output_node.py
@@ -71,6 +71,8 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin):
# the isinstance check above should be stricter than this category
if output_node.type().category().name() != "Cop2":
raise PublishValidationError(
- ("Output node %s is not of category Cop2. "
- "This is a bug...").format(output_node.path()),
+ (
+ "Output node {} is not of category Cop2."
+ " This is a bug..."
+ ).format(output_node.path()),
title=cls.label)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
index 4f8a22af07..2330dbfc24 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
@@ -7,7 +7,6 @@ from ayon_core.hosts.max.api.lib import (
maintained_selection,
object_transform_set
)
-from ayon_core.hosts.max.api.lib import maintained_selection
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_camera_contents.py b/client/ayon_core/hosts/max/plugins/publish/validate_camera_contents.py
index 0473fd4a8a..334e7dcec9 100644
--- a/client/ayon_core/hosts/max/plugins/publish/validate_camera_contents.py
+++ b/client/ayon_core/hosts/max/plugins/publish/validate_camera_contents.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import pyblish.api
+
from ayon_core.pipeline import PublishValidationError
-from pymxs import runtime as rt
class ValidateCameraContent(pyblish.api.InstancePlugin):
diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_renderpasses.py b/client/ayon_core/hosts/max/plugins/publish/validate_renderpasses.py
index ba948747b9..394d3119c4 100644
--- a/client/ayon_core/hosts/max/plugins/publish/validate_renderpasses.py
+++ b/client/ayon_core/hosts/max/plugins/publish/validate_renderpasses.py
@@ -140,7 +140,7 @@ class ValidateRenderPasses(OptionalPyblishPluginMixin,
invalid = []
if instance.name not in file_name:
cls.log.error("The renderpass filename should contain the instance name.")
- invalid.append((f"Invalid instance name",
+ invalid.append(("Invalid instance name",
file_name))
if renderpass is not None:
if not file_name.rstrip(".").endswith(renderpass):
diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py
index 8ca898f621..acfac760e6 100644
--- a/client/ayon_core/hosts/maya/api/lib.py
+++ b/client/ayon_core/hosts/maya/api/lib.py
@@ -131,7 +131,7 @@ def get_main_window():
def suspended_refresh(suspend=True):
"""Suspend viewport refreshes
- cmds.ogs(pause=True) is a toggle so we cant pass False.
+ cmds.ogs(pause=True) is a toggle so we can't pass False.
"""
if IS_HEADLESS:
yield
@@ -583,7 +583,7 @@ def pairwise(iterable):
def collect_animation_defs(fps=False):
- """Get the basic animation attribute defintions for the publisher.
+ """Get the basic animation attribute definitions for the publisher.
Returns:
OrderedDict
@@ -2152,9 +2152,13 @@ def get_related_sets(node):
sets = cmds.ls(sets)
# Ignore `avalon.container`
- sets = [s for s in sets if
- not cmds.attributeQuery("id", node=s, exists=True) or
- not cmds.getAttr("%s.id" % s) in ignored]
+ sets = [
+ s for s in sets
+ if (
+ not cmds.attributeQuery("id", node=s, exists=True)
+ or cmds.getAttr(f"{s}.id") not in ignored
+ )
+ ]
# Exclude deformer sets (`type=2` for `maya.cmds.listSets`)
deformer_sets = cmds.listSets(object=node,
@@ -3834,7 +3838,7 @@ def get_color_management_output_transform():
def image_info(file_path):
# type: (str) -> dict
- """Based on tha texture path, get its bit depth and format information.
+ """Based on the texture path, get its bit depth and format information.
Take reference from makeTx.py in Arnold:
ImageInfo(filename): Get Image Information for colorspace
AiTextureGetFormat(filename): Get Texture Format
diff --git a/client/ayon_core/hosts/maya/plugins/create/convert_legacy.py b/client/ayon_core/hosts/maya/plugins/create/convert_legacy.py
index 685602ef0b..81cf9613b4 100644
--- a/client/ayon_core/hosts/maya/plugins/create/convert_legacy.py
+++ b/client/ayon_core/hosts/maya/plugins/create/convert_legacy.py
@@ -83,7 +83,7 @@ class MayaLegacyConvertor(ProductConvertorPlugin,
).format(product_type))
continue
- creator_id = product_type_to_id[family]
+ creator_id = product_type_to_id[product_type]
creator = self.create_context.creators[creator_id]
data["creator_identifier"] = creator_id
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_unreal_skeletalmesh.py b/client/ayon_core/hosts/maya/plugins/create/create_unreal_skeletalmesh.py
index 9ded28b812..a32e94971e 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_unreal_skeletalmesh.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_unreal_skeletalmesh.py
@@ -20,13 +20,6 @@ class CreateUnrealSkeletalMesh(plugin.MayaCreator):
# Defined in settings
joint_hints = set()
- def apply_settings(self, project_settings):
- """Apply project settings to creator"""
- settings = (
- project_settings["maya"]["create"]["CreateUnrealSkeletalMesh"]
- )
- self.joint_hints = set(settings.get("joint_hints", []))
-
def get_dynamic_data(
self,
project_name,
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_unreal_staticmesh.py b/client/ayon_core/hosts/maya/plugins/create/create_unreal_staticmesh.py
index 1991f92915..76c33f00cc 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_unreal_staticmesh.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_unreal_staticmesh.py
@@ -15,11 +15,6 @@ class CreateUnrealStaticMesh(plugin.MayaCreator):
# Defined in settings
collision_prefixes = []
- def apply_settings(self, project_settings):
- """Apply project settings to creator"""
- settings = project_settings["maya"]["create"]["CreateUnrealStaticMesh"]
- self.collision_prefixes = settings["collision_prefixes"]
-
def get_dynamic_data(
self,
project_name,
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_unreal_yeticache.py b/client/ayon_core/hosts/maya/plugins/create/create_unreal_yeticache.py
index 1eac8a5ea9..dea64b40fb 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_unreal_yeticache.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_unreal_yeticache.py
@@ -5,7 +5,7 @@ from ayon_core.hosts.maya.api import (
from ayon_core.lib import NumberDef
-class CreateYetiCache(plugin.MayaCreator):
+class CreateUnrealYetiCache(plugin.MayaCreator):
"""Output for procedural plugin nodes of Yeti """
identifier = "io.openpype.creators.maya.unrealyeticache"
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py
index 920ad762b3..7170c30422 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py
@@ -12,7 +12,6 @@ from ayon_core.hosts.maya.api.lib import (
unique_namespace,
get_attribute_input,
maintained_selection,
- convert_to_maya_fps
)
from ayon_core.hosts.maya.api.pipeline import containerise
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
index 494bc7cfc6..9689282ae9 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
@@ -1,5 +1,3 @@
-import os
-
import maya.cmds as cmds
from ayon_core.hosts.maya.api.pipeline import containerise
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_image.py b/client/ayon_core/hosts/maya/plugins/load/load_image.py
index 4976c46d7f..3641655d49 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_image.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_image.py
@@ -1,10 +1,8 @@
-import os
import copy
from ayon_core.lib import EnumDef
from ayon_core.pipeline import (
load,
- get_representation_context,
get_current_host_name,
)
from ayon_core.pipeline.load.utils import get_representation_path_from_context
diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_render.py b/client/ayon_core/hosts/maya/plugins/publish/collect_render.py
index 13eb8fd49e..ff959afabc 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/collect_render.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/collect_render.py
@@ -78,7 +78,6 @@ class CollectMayaRender(pyblish.api.InstancePlugin):
layer = instance.data["transientData"]["layer"]
objset = instance.data.get("instance_node")
filepath = context.data["currentFile"].replace("\\", "/")
- workspace = context.data["workspaceDir"]
# check if layer is renderable
if not layer.isRenderable():
@@ -314,7 +313,7 @@ class CollectMayaRender(pyblish.api.InstancePlugin):
if not extend_frames:
instance.data["overrideExistingFrame"] = False
- # Update the instace
+ # Update the instance
instance.data.update(data)
@staticmethod
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py b/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py
index 8b88bfb9f8..1a389f3d33 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
"""Create Unreal Skeletal Mesh data to be extracted as FBX."""
import os
-from contextlib import contextmanager
from maya import cmds # noqa
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py b/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py
index edbb5f845e..6292afcf41 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py
@@ -74,7 +74,7 @@ class ExtractUnrealSkeletalMeshFbx(publish.Extractor):
renamed_to_extract.append("|".join(node_path))
with renamed(original_parent, parent_node):
- self.log.debug("Extracting: {}".format(renamed_to_extract, path))
+ self.log.debug("Extracting: {}".format(renamed_to_extract))
fbx_exporter.export(renamed_to_extract, path)
if "representations" not in instance.data:
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_workfile_xgen.py b/client/ayon_core/hosts/maya/plugins/publish/extract_workfile_xgen.py
index d305b8dc6c..d799486184 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_workfile_xgen.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_workfile_xgen.py
@@ -7,7 +7,6 @@ from maya import cmds
import pyblish.api
from ayon_core.hosts.maya.api.lib import extract_alembic
from ayon_core.pipeline import publish
-from ayon_core.lib import StringTemplate
class ExtractWorkfileXgen(publish.Extractor):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_xgen.py b/client/ayon_core/hosts/maya/plugins/publish/extract_xgen.py
index 73668da28d..b672089a63 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_xgen.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_xgen.py
@@ -9,7 +9,6 @@ from ayon_core.pipeline import publish
from ayon_core.hosts.maya.api.lib import (
maintained_selection, attribute_values, write_xgen_file, delete_after
)
-from ayon_core.lib import StringTemplate
class ExtractXgen(publish.Extractor):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_subset.py b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_subset.py
index da3a194e58..df9ca0bf13 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_subset.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_subset.py
@@ -36,18 +36,18 @@ class ValidateSubsetName(pyblish.api.InstancePlugin):
)
if not isinstance(product_name, six.string_types):
- raise TypeError((
+ raise PublishValidationError((
"Instance product name must be string, got: {0} ({1})"
).format(product_name, type(product_name)))
# Ensure is not empty product
if not product_name:
- raise ValueError(
+ raise PublishValidationError(
"Instance product name is empty: {0}".format(product_name)
)
# Validate product characters
if not validate_name(product_name):
- raise ValueError((
+ raise PublishValidationError((
"Instance product name contains invalid characters: {0}"
).format(product_name))
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_empty.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_empty.py
index 934cbae327..c95e1ec816 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_empty.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_empty.py
@@ -51,5 +51,5 @@ class ValidateMeshEmpty(pyblish.api.InstancePlugin):
invalid = self.get_invalid(instance)
if invalid:
raise PublishValidationError(
- "Meshes found in instance without any vertices: %s" % invalid
+ "Meshes found without any vertices: %s" % invalid
)
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py
index 8f80b689fd..bfb4257f23 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py
@@ -2,7 +2,11 @@ from maya import cmds
import pyblish.api
import ayon_core.hosts.maya.api.action
-from ayon_core.pipeline.publish import ValidateMeshOrder, OptionalPyblishPluginMixin
+from ayon_core.pipeline.publish import (
+ ValidateMeshOrder,
+ OptionalPyblishPluginMixin,
+ PublishValidationError
+)
class ValidateMeshLaminaFaces(pyblish.api.InstancePlugin,
@@ -20,6 +24,16 @@ class ValidateMeshLaminaFaces(pyblish.api.InstancePlugin,
actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction]
optional = True
+ description = (
+ "## Meshes with Lamina Faces\n"
+ "Detected meshes with lamina faces. Lamina faces are faces "
+ "that share all of their edges and thus are merged together on top of "
+ "each other.\n\n"
+ "### How to repair?\n"
+ "You can repair them by using Maya's modeling tool `Mesh > Cleanup..` "
+ "and select to cleanup matching polygons for lamina faces."
+ )
+
@staticmethod
def get_invalid(instance):
meshes = cmds.ls(instance, type='mesh', long=True)
@@ -36,5 +50,6 @@ class ValidateMeshLaminaFaces(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Meshes found with lamina faces: "
- "{0}".format(invalid))
+ raise PublishValidationError(
+ "Meshes found with lamina faces: {0}".format(invalid),
+ description=self.description)
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_ngons.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_ngons.py
index 5f107b7f7e..b6d3dc73fd 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_ngons.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_ngons.py
@@ -5,7 +5,8 @@ import ayon_core.hosts.maya.api.action
from ayon_core.hosts.maya.api import lib
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
@@ -27,6 +28,15 @@ class ValidateMeshNgons(pyblish.api.Validator,
actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction]
optional = True
+ description = (
+ "## Meshes with NGONs Faces\n"
+ "Detected meshes with NGON faces. **NGONS** are faces that "
+ "with more than four sides.\n\n"
+ "### How to repair?\n"
+ "You can repair them by usings Maya's modeling tool Mesh > Cleanup.. "
+ "and select to cleanup matching polygons for lamina faces."
+ )
+
@staticmethod
def get_invalid(instance):
@@ -49,5 +59,6 @@ class ValidateMeshNgons(pyblish.api.Validator,
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Meshes found with n-gons"
- "values: {0}".format(invalid))
+ raise PublishValidationError(
+ "Meshes found with n-gons: {0}".format(invalid),
+ description=self.description)
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_shader_connections.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_shader_connections.py
index 8672ac13dd..70ede83f2d 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_shader_connections.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_shader_connections.py
@@ -107,8 +107,9 @@ class ValidateMeshShaderConnections(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
- raise PublishValidationError("Shapes found with invalid shader "
- "connections: {0}".format(invalid))
+ raise PublishValidationError(
+ "Shapes found with invalid shader connections: "
+ "{0}".format(invalid))
@staticmethod
def get_invalid(instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py
index 8dbd0ca264..21697cd903 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py
@@ -6,7 +6,8 @@ from ayon_core.hosts.maya.api import lib
from ayon_core.pipeline.publish import (
RepairAction,
ValidateMeshOrder,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
@@ -66,7 +67,7 @@ class ValidateMeshSingleUVSet(pyblish.api.InstancePlugin,
if allowed:
self.log.warning(message)
else:
- raise ValueError(message)
+ raise PublishValidationError(message)
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py
index c7f405b0cf..a139b65169 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py
@@ -5,7 +5,8 @@ import ayon_core.hosts.maya.api.action
from ayon_core.pipeline.publish import (
RepairAction,
ValidateMeshOrder,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
@@ -55,8 +56,8 @@ class ValidateMeshUVSetMap1(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Meshes found without 'map1' "
- "UV set: {0}".format(invalid))
+ raise PublishValidationError(
+ "Meshes found without 'map1' UV set: {0}".format(invalid))
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_no_ghosting.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_no_ghosting.py
index 73701f8d83..10cbbc9a88 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_no_ghosting.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_no_ghosting.py
@@ -5,10 +5,12 @@ import pyblish.api
import ayon_core.hosts.maya.api.action
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
- OptionalPyblishPluginMixin
-
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
-class ValidateNodeNoGhosting(pyblish.api.InstancePlugin.
+
+
+class ValidateNodeNoGhosting(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Ensure nodes do not have ghosting enabled.
@@ -55,5 +57,5 @@ class ValidateNodeNoGhosting(pyblish.api.InstancePlugin.
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Nodes with ghosting enabled found: "
- "{0}".format(invalid))
+ raise PublishValidationError(
+ "Nodes with ghosting enabled found: {0}".format(invalid))
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_setdress_root.py b/client/ayon_core/hosts/maya/plugins/publish/validate_setdress_root.py
index 906f6fbd1a..f88e33fdfb 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_setdress_root.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_setdress_root.py
@@ -1,5 +1,8 @@
import pyblish.api
-from ayon_core.pipeline.publish import ValidateContentsOrder
+from ayon_core.pipeline.publish import (
+ ValidateContentsOrder,
+ PublishValidationError
+)
class ValidateSetdressRoot(pyblish.api.InstancePlugin):
@@ -20,4 +23,6 @@ class ValidateSetdressRoot(pyblish.api.InstancePlugin):
root = cmds.ls(set_member, assemblies=True, long=True)
if not root or root[0] not in set_member:
- raise Exception("Setdress top root node is not being published.")
+ raise PublishValidationError(
+ "Setdress top root node is not being published."
+ )
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_shape_default_names.py b/client/ayon_core/hosts/maya/plugins/publish/validate_shape_default_names.py
index 2f0811a73e..c4c4c909d3 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_shape_default_names.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_shape_default_names.py
@@ -8,7 +8,8 @@ import ayon_core.hosts.maya.api.action
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
RepairAction,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
@@ -84,8 +85,8 @@ class ValidateShapeDefaultNames(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Incorrectly named shapes "
- "found: {0}".format(invalid))
+ raise PublishValidationError(
+ "Incorrectly named shapes found: {0}".format(invalid))
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_single_assembly.py b/client/ayon_core/hosts/maya/plugins/publish/validate_single_assembly.py
index 1987f93e32..f5d73553d3 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_single_assembly.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_single_assembly.py
@@ -1,5 +1,8 @@
import pyblish.api
-from ayon_core.pipeline.publish import ValidateContentsOrder
+from ayon_core.pipeline.publish import (
+ ValidateContentsOrder,
+ PublishValidationError
+)
class ValidateSingleAssembly(pyblish.api.InstancePlugin):
@@ -30,7 +33,11 @@ class ValidateSingleAssembly(pyblish.api.InstancePlugin):
# ensure unique (somehow `maya.cmds.ls` doesn't manage that)
assemblies = set(assemblies)
- assert len(assemblies) > 0, (
- "One assembly required for: %s (currently empty?)" % instance)
- assert len(assemblies) < 2, (
- 'Multiple assemblies found: %s' % assemblies)
+ if len(assemblies) == 0:
+ raise PublishValidationError(
+ "One assembly required for: %s (currently empty?)" % instance
+ )
+ elif len(assemblies) > 1:
+ raise PublishValidationError(
+ 'Multiple assemblies found: %s' % assemblies
+ )
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py b/client/ayon_core/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py
index 48d8e63553..a548e12f33 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py
@@ -3,7 +3,11 @@ from maya import cmds
import pyblish.api
import ayon_core.hosts.maya.api.action
-from ayon_core.pipeline.publish import ValidateContentsOrder,OptionalPyblishPluginMixin
+from ayon_core.pipeline.publish import (
+ ValidateContentsOrder,
+ OptionalPyblishPluginMixin,
+ PublishValidationError
+)
class ValidateSkinclusterDeformerSet(pyblish.api.InstancePlugin,
@@ -30,8 +34,10 @@ class ValidateSkinclusterDeformerSet(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Invalid skinCluster relationships "
- "found on meshes: {0}".format(invalid))
+ raise PublishValidationError(
+ "Invalid skinCluster relationships found on meshes: {0}"
+ .format(invalid)
+ )
@classmethod
def get_invalid(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_unique_names.py b/client/ayon_core/hosts/maya/plugins/publish/validate_unique_names.py
index 8ec704ddd1..72c3c7dc72 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_unique_names.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_unique_names.py
@@ -4,9 +4,11 @@ import pyblish.api
import ayon_core.hosts.maya.api.action
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
+
class ValidateUniqueNames(pyblish.api.Validator,
OptionalPyblishPluginMixin):
"""transform names should be unique
@@ -40,5 +42,5 @@ class ValidateUniqueNames(pyblish.api.Validator,
return
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Nodes found with none unique names. "
- "values: {0}".format(invalid))
+ raise PublishValidationError(
+ "Nodes found with non-unique names:\n{0}".format(invalid))
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py
index 101bd5bf04..6440c00eae 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py
@@ -5,7 +5,8 @@ import pyblish.api
from ayon_core.pipeline.publish import (
ValidateMeshOrder,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
import ayon_core.hosts.maya.api.action
@@ -26,8 +27,8 @@ class ValidateUnrealMeshTriangulated(pyblish.api.InstancePlugin,
invalid = []
meshes = cmds.ls(instance, type="mesh", long=True)
for mesh in meshes:
- faces = cmds.polyEvaluate(mesh, f=True)
- tris = cmds.polyEvaluate(mesh, t=True)
+ faces = cmds.polyEvaluate(mesh, face=True)
+ tris = cmds.polyEvaluate(mesh, triangle=True)
if faces != tris:
invalid.append(mesh)
@@ -37,5 +38,5 @@ class ValidateUnrealMeshTriangulated(pyblish.api.InstancePlugin,
if not self.is_active(instance.data):
return
invalid = self.get_invalid(instance)
- assert len(invalid) == 0, (
- "Found meshes without triangles")
+ if invalid:
+ raise PublishValidationError("Found meshes without triangles")
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_up_axis.py b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_up_axis.py
index ef7296e628..f7acd41cea 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_up_axis.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_up_axis.py
@@ -6,7 +6,8 @@ import pyblish.api
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
RepairAction,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
@@ -26,9 +27,10 @@ class ValidateUnrealUpAxis(pyblish.api.ContextPlugin,
if not self.is_active(context.data):
return
- assert cmds.upAxis(q=True, axis=True) == "z", (
- "Invalid axis set as up axis"
- )
+ if cmds.upAxis(q=True, axis=True) != "z":
+ raise PublishValidationError(
+ "Invalid axis set as up axis"
+ )
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_visible_only.py b/client/ayon_core/hosts/maya/plugins/publish/validate_visible_only.py
index af6c9a64c6..1fdb476dba 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_visible_only.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_visible_only.py
@@ -34,8 +34,9 @@ class ValidateAlembicVisibleOnly(pyblish.api.InstancePlugin,
invalid = self.get_invalid(instance)
if invalid:
start, end = self.get_frame_range(instance)
- raise PublishValidationError("No visible nodes found in "
- "frame range {}-{}.".format(start, end))
+ raise PublishValidationError(
+ f"No visible nodes found in frame range {start}-{end}."
+ )
@classmethod
def get_invalid(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py b/client/ayon_core/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py
index b35508d635..b3978b8483 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py
@@ -3,6 +3,7 @@ from maya import cmds
from ayon_core.hosts.maya.api import lib
from ayon_core.pipeline.publish import (
+ KnownPublishError,
PublishValidationError,
RepairAction,
ValidateContentsOrder,
@@ -35,11 +36,14 @@ class ValidateVRayDistributedRendering(pyblish.api.InstancePlugin,
if not self.is_active(instance.data):
return
if instance.data.get("renderer") != "vray":
- # If not V-Ray ignore..
+ # If not V-Ray, ignore
return
vray_settings = cmds.ls("vraySettings", type="VRaySettingsNode")
- assert vray_settings, "Please ensure a VRay Settings Node is present"
+ if not vray_settings:
+ raise KnownPublishError(
+ "Please ensure a VRay Settings Node is present"
+ )
renderlayer = instance.data['renderlayer']
@@ -51,8 +55,8 @@ class ValidateVRayDistributedRendering(pyblish.api.InstancePlugin,
# during batch mode we invalidate the instance
if not lib.get_attr_in_layer(self.ignored_attr, layer=renderlayer):
raise PublishValidationError(
- ("Renderlayer has distributed rendering enabled "
- "but is not set to ignore in batch mode."))
+ "Renderlayer has distributed rendering enabled "
+ "but is not set to ignore in batch mode.")
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py b/client/ayon_core/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py
index 7c480a6bf7..9df5fb8488 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py
@@ -6,9 +6,11 @@ from maya import cmds
from ayon_core.pipeline.publish import (
RepairContextAction,
- OptionalPyblishPluginMixin
+ OptionalPyblishPluginMixin,
+ PublishValidationError
)
+
class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validate whether the V-Ray Render Elements (AOVs) include references.
@@ -60,7 +62,7 @@ class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin,
self.log.error((
"'Use referenced' not enabled in Vray Render Settings."
))
- raise AssertionError("Invalid render settings")
+ raise PublishValidationError("Invalid render settings")
@classmethod
def repair(cls, context):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_vrayproxy.py b/client/ayon_core/hosts/maya/plugins/publish/validate_vrayproxy.py
index 29b8be411c..0288d4b865 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_vrayproxy.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_vrayproxy.py
@@ -1,7 +1,10 @@
import pyblish.api
-from ayon_core.pipeline import KnownPublishError
-from ayon_core.pipeline.publish import OptionalPyblishPluginMixin
+from ayon_core.pipeline.publish import (
+ OptionalPyblishPluginMixin,
+ PublishValidationError
+)
+
class ValidateVrayProxy(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
@@ -17,18 +20,18 @@ class ValidateVrayProxy(pyblish.api.InstancePlugin,
if not self.is_active(data):
return
if not data["setMembers"]:
- raise KnownPublishError(
- "'%s' is empty! This is a bug" % instance.name
+ raise PublishValidationError(
+ f"Instance '{instance.name}' is empty."
)
if data["animation"]:
if data["frameEnd"] < data["frameStart"]:
- raise KnownPublishError(
+ raise PublishValidationError(
"End frame is smaller than start frame"
)
if not data["vrmesh"] and not data["alembic"]:
- raise KnownPublishError(
+ raise PublishValidationError(
"Both vrmesh and alembic are off. Needs at least one to"
" publish."
)
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_xgen.py b/client/ayon_core/hosts/maya/plugins/publish/validate_xgen.py
index e2c006be9f..7e0f01c482 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_xgen.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_xgen.py
@@ -34,7 +34,7 @@ class ValidateXgen(pyblish.api.InstancePlugin):
" Node type found: {}".format(node_type)
)
- # Cant have inactive modifiers in collection cause Xgen will try and
+ # Can't have inactive modifiers in collection cause Xgen will try and
# look for them when loading.
palette = instance.data["xgmPalette"].replace("|", "")
inactive_modifiers = {}
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py b/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py
index 35b2443718..086cb7b1f5 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py
@@ -3,9 +3,11 @@ from maya import cmds
import pyblish.api
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
+ PublishValidationError,
OptionalPyblishPluginMixin
)
+
class ValidateYetiRenderScriptCallbacks(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Check if the render script callbacks will be used during the rendering
@@ -45,8 +47,8 @@ class ValidateYetiRenderScriptCallbacks(pyblish.api.InstancePlugin,
return
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Invalid render callbacks found for '%s'!"
- % instance.name)
+ raise PublishValidationError(
+ f"Invalid render callbacks found for '{instance.name}'.")
@classmethod
def get_invalid(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py b/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py
index d81534192a..84614fc0be 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py
@@ -1,3 +1,5 @@
+import inspect
+
import pyblish.api
import maya.cmds as cmds
import ayon_core.hosts.maya.api.action
@@ -8,7 +10,6 @@ from ayon_core.pipeline.publish import (
)
-
class ValidateYetiRigCacheState(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validate the I/O attributes of the node
@@ -32,7 +33,10 @@ class ValidateYetiRigCacheState(pyblish.api.InstancePlugin,
return
invalid = self.get_invalid(instance)
if invalid:
- raise PublishValidationError("Nodes have incorrect I/O settings")
+ raise PublishValidationError(
+ "Nodes have incorrect I/O settings",
+ description=inspect.getdoc(self)
+ )
@classmethod
def get_invalid(cls, instance):
diff --git a/client/ayon_core/hosts/maya/tools/mayalookassigner/models.py b/client/ayon_core/hosts/maya/tools/mayalookassigner/models.py
index f5dad25ff0..b0807be6a6 100644
--- a/client/ayon_core/hosts/maya/tools/mayalookassigner/models.py
+++ b/client/ayon_core/hosts/maya/tools/mayalookassigner/models.py
@@ -29,7 +29,8 @@ class AssetModel(models.TreeModel):
self.beginResetModel()
# Add the items sorted by label
- sorter = lambda x: x["label"]
+ def sorter(x):
+ return x["label"]
for item in sorted(items, key=sorter):
diff --git a/client/ayon_core/hosts/nuke/api/lib.py b/client/ayon_core/hosts/nuke/api/lib.py
index 1bb0ff79e0..4fcba8d2d4 100644
--- a/client/ayon_core/hosts/nuke/api/lib.py
+++ b/client/ayon_core/hosts/nuke/api/lib.py
@@ -389,7 +389,13 @@ def imprint(node, data, tab=None):
"""
for knob in create_knobs(data, tab):
- node.addKnob(knob)
+ # If knob name exists we set the value. Technically there could be
+ # multiple knobs with the same name, but the intent is not to have
+ # duplicated knobs so we do not account for that.
+ if knob.name() in node.knobs().keys():
+ node[knob.name()].setValue(knob.value())
+ else:
+ node.addKnob(knob)
@deprecated
@@ -814,7 +820,7 @@ def on_script_load():
def check_inventory_versions():
"""
- Actual version idetifier of Loaded containers
+ Actual version identifier of Loaded containers
Any time this function is run it will check all nodes and filter only
Loader nodes for its version. It will get all versions from database
@@ -921,7 +927,7 @@ def writes_version_sync():
for each in nuke.allNodes(filter="Write"):
# check if the node is avalon tracked
- if _NODE_TAB_NAME not in each.knobs():
+ if NODE_TAB_NAME not in each.knobs():
continue
avalon_knob_data = read_avalon_data(each)
@@ -2381,7 +2387,7 @@ def launch_workfiles_app():
Context.workfiles_launched = True
- # get all imortant settings
+ # get all important settings
open_at_start = env_value_to_bool(
env_key="AYON_WORKFILE_TOOL_ON_START",
default=None)
diff --git a/client/ayon_core/hosts/nuke/api/pipeline.py b/client/ayon_core/hosts/nuke/api/pipeline.py
index 2255276c56..0d44aba2f9 100644
--- a/client/ayon_core/hosts/nuke/api/pipeline.py
+++ b/client/ayon_core/hosts/nuke/api/pipeline.py
@@ -30,13 +30,11 @@ from ayon_core.tools.utils import host_tools
from ayon_core.hosts.nuke import NUKE_ROOT_DIR
from ayon_core.tools.workfile_template_build import open_template_ui
-from .command import viewer_update_and_undo_stop
from .lib import (
Context,
ROOT_DATA_KNOB,
INSTANCE_DATA_KNOB,
get_main_window,
- add_publish_knob,
WorkfileSettings,
# TODO: remove this once workfile builder will be removed
process_workfile_builder,
diff --git a/client/ayon_core/hosts/nuke/api/plugin.py b/client/ayon_core/hosts/nuke/api/plugin.py
index 7f016d9c66..d9cae934d7 100644
--- a/client/ayon_core/hosts/nuke/api/plugin.py
+++ b/client/ayon_core/hosts/nuke/api/plugin.py
@@ -6,7 +6,6 @@ import six
import random
import string
from collections import OrderedDict, defaultdict
-from abc import abstractmethod
from ayon_core.settings import get_current_project_settings
from ayon_core.lib import (
@@ -14,7 +13,6 @@ from ayon_core.lib import (
EnumDef
)
from ayon_core.pipeline import (
- LegacyCreator,
LoaderPlugin,
CreatorError,
Creator as NewCreator,
@@ -34,18 +32,13 @@ from ayon_core.lib.transcoding import (
from .lib import (
INSTANCE_DATA_KNOB,
Knobby,
- check_product_name_exists,
maintained_selection,
get_avalon_knob_data,
- set_avalon_knob_data,
- add_publish_knob,
- get_nuke_imageio_settings,
set_node_knobs_from_settings,
set_node_data,
get_node_data,
get_view_process_node,
get_viewer_config_from_string,
- deprecated,
get_filenames_without_hash,
link_knobs
)
@@ -910,7 +903,7 @@ class ExporterReviewMov(ExporterReview):
self._connect_to_above_nodes(
node, product_name, "Reposition node... `{}`"
)
- # append reformated tag
+ # append reformatted tag
add_tags.append("reformated")
# only create colorspace baking if toggled on
@@ -1114,7 +1107,7 @@ def convert_to_valid_instaces():
transfer_data["active"] = (
node["publish"].value())
- # add idetifier
+ # add identifier
transfer_data["creator_identifier"] = product_type_to_identifier(
product_type
)
diff --git a/client/ayon_core/hosts/nuke/plugins/publish/extract_camera.py b/client/ayon_core/hosts/nuke/plugins/publish/extract_camera.py
index 1f5a8c73e1..a1a5acb63b 100644
--- a/client/ayon_core/hosts/nuke/plugins/publish/extract_camera.py
+++ b/client/ayon_core/hosts/nuke/plugins/publish/extract_camera.py
@@ -1,6 +1,5 @@
import os
import math
-from pprint import pformat
import nuke
diff --git a/client/ayon_core/hosts/nuke/plugins/publish/validate_knobs.py b/client/ayon_core/hosts/nuke/plugins/publish/validate_knobs.py
index 281e172788..8bcde9609d 100644
--- a/client/ayon_core/hosts/nuke/plugins/publish/validate_knobs.py
+++ b/client/ayon_core/hosts/nuke/plugins/publish/validate_knobs.py
@@ -1,3 +1,5 @@
+import json
+
import nuke
import six
import pyblish.api
diff --git a/client/ayon_core/hosts/nuke/plugins/publish/validate_rendered_frames.py b/client/ayon_core/hosts/nuke/plugins/publish/validate_rendered_frames.py
index 852267f68c..76ac7e97ad 100644
--- a/client/ayon_core/hosts/nuke/plugins/publish/validate_rendered_frames.py
+++ b/client/ayon_core/hosts/nuke/plugins/publish/validate_rendered_frames.py
@@ -1,6 +1,6 @@
-import os
import pyblish.api
import clique
+
from ayon_core.pipeline import PublishXmlValidationError
from ayon_core.pipeline.publish import get_errored_instances_from_context
diff --git a/client/ayon_core/hosts/photoshop/api/launch_logic.py b/client/ayon_core/hosts/photoshop/api/launch_logic.py
index d0823646d7..c388f93044 100644
--- a/client/ayon_core/hosts/photoshop/api/launch_logic.py
+++ b/client/ayon_core/hosts/photoshop/api/launch_logic.py
@@ -11,7 +11,7 @@ from wsrpc_aiohttp import (
import ayon_api
from qtpy import QtCore
-from ayon_core.lib import Logger, StringTemplate
+from ayon_core.lib import Logger
from ayon_core.pipeline import (
registered_host,
Anatomy,
diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py
index 25b22f53a4..73e8c3683c 100644
--- a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py
+++ b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py
@@ -19,7 +19,7 @@ class ImageFromSequenceLoader(photoshop.PhotoshopLoader):
This loader will be triggered multiple times, but selected name will
match only to proper path.
- Loader doesnt do containerization as there is currently no data model
+ Loader doesn't do containerization as there is currently no data model
of 'frame of rendered files' (only rendered sequence), update would be
difficult.
"""
diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/closePS.py b/client/ayon_core/hosts/photoshop/plugins/publish/closePS.py
index 6f86d98580..68c3b5b249 100644
--- a/client/ayon_core/hosts/photoshop/plugins/publish/closePS.py
+++ b/client/ayon_core/hosts/photoshop/plugins/publish/closePS.py
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
"""Close PS after publish. For Webpublishing only."""
-import os
-
import pyblish.api
from ayon_core.hosts.photoshop import api as photoshop
diff --git a/client/ayon_core/hosts/resolve/api/lib.py b/client/ayon_core/hosts/resolve/api/lib.py
index a60f3cd4ec..b9ad81c79d 100644
--- a/client/ayon_core/hosts/resolve/api/lib.py
+++ b/client/ayon_core/hosts/resolve/api/lib.py
@@ -925,7 +925,7 @@ def get_reformated_path(path, padded=False, first=False):
path (str): path url or simple file name
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
get_reformated_path("plate.[0001-1008].exr") > plate.%04d.exr
diff --git a/client/ayon_core/hosts/resolve/api/plugin.py b/client/ayon_core/hosts/resolve/api/plugin.py
index d4c2d919a2..0b339cdf7c 100644
--- a/client/ayon_core/hosts/resolve/api/plugin.py
+++ b/client/ayon_core/hosts/resolve/api/plugin.py
@@ -875,14 +875,14 @@ class PublishClip:
def _convert_to_entity(self, key):
""" Converting input key to key with type. """
# convert to entity type
- entity_type = self.types.get(key)
+ folder_type = self.types.get(key)
- assert entity_type, "Missing entity type for `{}`".format(
+ assert folder_type, "Missing folder type for `{}`".format(
key
)
return {
- "entity_type": entity_type,
+ "folder_type": folder_type,
"entity_name": self.hierarchy_data[key]["value"].format(
**self.timeline_item_default_data
)
diff --git a/client/ayon_core/hosts/resolve/otio/utils.py b/client/ayon_core/hosts/resolve/otio/utils.py
index 7d8089e055..c03305ff23 100644
--- a/client/ayon_core/hosts/resolve/otio/utils.py
+++ b/client/ayon_core/hosts/resolve/otio/utils.py
@@ -25,7 +25,7 @@ def get_reformated_path(path, padded=True, first=False):
path (str): path url or simple file name
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
get_reformated_path("plate.[0001-1008].exr") > plate.%04d.exr
diff --git a/client/ayon_core/hosts/resolve/plugins/create/create_shot_clip.py b/client/ayon_core/hosts/resolve/plugins/create/create_shot_clip.py
index 3a2a0345ea..cbc03da3b6 100644
--- a/client/ayon_core/hosts/resolve/plugins/create/create_shot_clip.py
+++ b/client/ayon_core/hosts/resolve/plugins/create/create_shot_clip.py
@@ -166,7 +166,7 @@ class CreateShotClip(plugin.Creator):
"type": "QCheckBox",
"label": "Source resolution",
"target": "tag",
- "toolTip": "Is resloution taken from timeline or source?", # noqa
+ "toolTip": "Is resolution taken from timeline or source?", # noqa
"order": 4},
}
},
@@ -207,7 +207,7 @@ class CreateShotClip(plugin.Creator):
presets = None
def process(self):
- # get key pares from presets and match it on ui inputs
+ # get key pairs from presets and match it on ui inputs
for k, v in self.gui_inputs.items():
if v["type"] in ("dict", "section"):
# nested dictionary (only one level allowed
diff --git a/client/ayon_core/hosts/resolve/plugins/publish/precollect_instances.py b/client/ayon_core/hosts/resolve/plugins/publish/precollect_instances.py
index 72ecd3669d..caa79c85c0 100644
--- a/client/ayon_core/hosts/resolve/plugins/publish/precollect_instances.py
+++ b/client/ayon_core/hosts/resolve/plugins/publish/precollect_instances.py
@@ -64,6 +64,11 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
})
folder_path = tag_data["folder_path"]
+ # Backward compatibility fix of 'entity_type' > 'folder_type'
+ if "parents" in data:
+ for parent in data["parents"]:
+ if "entity_type" in parent:
+ parent["folder_type"] = parent.pop("entity_type")
# TODO: remove backward compatibility
product_name = tag_data.get("productName")
diff --git a/client/ayon_core/hosts/substancepainter/api/pipeline.py b/client/ayon_core/hosts/substancepainter/api/pipeline.py
index c75cc3135a..23d629533c 100644
--- a/client/ayon_core/hosts/substancepainter/api/pipeline.py
+++ b/client/ayon_core/hosts/substancepainter/api/pipeline.py
@@ -12,17 +12,14 @@ import substance_painter.project
import pyblish.api
from ayon_core.host import HostBase, IWorkfileHost, ILoadHost, IPublishHost
-from ayon_core.settings import (
- get_current_project_settings,
- get_project_settings,
-)
+from ayon_core.settings import get_current_project_settings
from ayon_core.pipeline.template_data import get_template_data_with_names
from ayon_core.pipeline import (
register_creator_plugin_path,
register_loader_plugin_path,
AVALON_CONTAINER_ID,
- Anatomy
+ Anatomy,
)
from ayon_core.lib import (
StringTemplate,
diff --git a/client/ayon_core/hosts/traypublisher/api/editorial.py b/client/ayon_core/hosts/traypublisher/api/editorial.py
index 8dedec7398..c71dae336c 100644
--- a/client/ayon_core/hosts/traypublisher/api/editorial.py
+++ b/client/ayon_core/hosts/traypublisher/api/editorial.py
@@ -186,14 +186,15 @@ class ShotMetadataSolver:
# in case first parent is project then start parents from start
if (
_index == 0
- and parent_token_type == "project"
+ and parent_token_type.lower() == "project"
):
project_parent = parents[0]
parents = [project_parent]
continue
parents.append({
- "entity_type": parent_token_type,
+ "entity_type": "folder",
+ "folder_type": parent_token_type.lower(),
"entity_name": parent_name
})
@@ -264,7 +265,8 @@ class ShotMetadataSolver:
}]
for entity in folders_hierarchy:
output.append({
- "entity_type": entity["folderType"],
+ "entity_type": "folder",
+ "folder_type": entity["folderType"],
"entity_name": entity["name"]
})
return output
diff --git a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
index a9ee343dfb..843729786c 100644
--- a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
+++ b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
@@ -675,7 +675,7 @@ or updating already created. Publishing will create OTIO file.
base_instance_data = {
"shotName": shot_name,
"variant": variant_name,
- "task": "",
+ "task": None,
"newAssetPublishing": True,
"trackStartFrame": track_start_frame,
"timelineOffset": timeline_offset,
diff --git a/client/ayon_core/hosts/traypublisher/plugins/publish/collect_shot_instances.py b/client/ayon_core/hosts/traypublisher/plugins/publish/collect_shot_instances.py
index edcbb27cb3..5a2f5cbc20 100644
--- a/client/ayon_core/hosts/traypublisher/plugins/publish/collect_shot_instances.py
+++ b/client/ayon_core/hosts/traypublisher/plugins/publish/collect_shot_instances.py
@@ -154,8 +154,9 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
handle_end = int(instance.data["handleEnd"])
in_info = {
- "entity_type": "Shot",
- "custom_attributes": {
+ "entity_type": "folder",
+ "folder_type": "Shot",
+ "attributes": {
"handleStart": handle_start,
"handleEnd": handle_end,
"frameStart": instance.data["frameStart"],
@@ -174,13 +175,13 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
for parent in reversed(parents):
parent_name = parent["entity_name"]
- next_dict = {
- parent_name: {
- "entity_type": parent["entity_type"],
- "childs": actual
- }
+ parent_info = {
+ "entity_type": parent["entity_type"],
+ "children": actual,
}
- actual = next_dict
+ if parent_info["entity_type"] == "folder":
+ parent_info["folder_type"] = parent["folder_type"]
+ actual = {parent_name: parent_info}
final_context = self._update_dict(final_context, actual)
diff --git a/client/ayon_core/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/client/ayon_core/hosts/traypublisher/plugins/publish/validate_frame_ranges.py
index e5bf034d00..4f11571efe 100644
--- a/client/ayon_core/hosts/traypublisher/plugins/publish/validate_frame_ranges.py
+++ b/client/ayon_core/hosts/traypublisher/plugins/publish/validate_frame_ranges.py
@@ -20,7 +20,7 @@ class ValidateFrameRange(OptionalPyblishPluginMixin,
optional = True
# published data might be sequence (.mov, .mp4) in that counting files
- # doesnt make sense
+ # doesn't make sense
check_extensions = ["exr", "dpx", "jpg", "jpeg", "png", "tiff", "tga",
"gif", "svg"]
skip_timelines_check = [] # skip for specific task names (regex)
diff --git a/client/ayon_core/hosts/tvpaint/plugins/create/create_render.py b/client/ayon_core/hosts/tvpaint/plugins/create/create_render.py
index 8d91afc74e..dc9c2466e0 100644
--- a/client/ayon_core/hosts/tvpaint/plugins/create/create_render.py
+++ b/client/ayon_core/hosts/tvpaint/plugins/create/create_render.py
@@ -599,7 +599,7 @@ class CreateRenderPass(TVPaintCreator):
if filtered_layers:
self.log.info((
"Changing group of "
- f"{','.join([l['name'] for l in filtered_layers])}"
+ f"{','.join([layer['name'] for layer in filtered_layers])}"
f" to {group_id}"
))
george_lines = [
@@ -760,7 +760,9 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
grg_lines: list[str] = []
for group_id, group_name in new_group_name_by_id.items():
group: dict[str, Any] = groups_by_id[group_id]
- grg_line: str = "tv_layercolor \"setcolor\" {} {} {} {} {}".format(
+ grg_line: str = (
+ "tv_layercolor \"setcolor\" {} {} {} {} {} \"{}\""
+ ).format(
group["clip_id"],
group_id,
group["red"],
diff --git a/client/ayon_core/hosts/unreal/api/tools_ui.py b/client/ayon_core/hosts/unreal/api/tools_ui.py
index 084da9a0f0..efae5bb702 100644
--- a/client/ayon_core/hosts/unreal/api/tools_ui.py
+++ b/client/ayon_core/hosts/unreal/api/tools_ui.py
@@ -125,7 +125,7 @@ class WindowCache:
@classmethod
def _before_show(cls):
- """Create QApplication if does not exists yet."""
+ """Create QApplication if does not exist yet."""
if not cls._first_show:
return
diff --git a/client/ayon_core/hosts/unreal/lib.py b/client/ayon_core/hosts/unreal/lib.py
index fe9e239ed5..37122b2096 100644
--- a/client/ayon_core/hosts/unreal/lib.py
+++ b/client/ayon_core/hosts/unreal/lib.py
@@ -216,10 +216,8 @@ def create_unreal_project(project_name: str,
since 3.16.0
"""
- env = env or os.environ
preset = get_project_settings(project_name)["unreal"]["project_setup"]
- ue_id = ".".join(ue_version.split(".")[:2])
# get unreal engine identifier
# -------------------------------------------------------------------------
# FIXME (antirotor): As of 4.26 this is problem with UE4 built from
@@ -238,10 +236,12 @@ def create_unreal_project(project_name: str,
project_file = pr_dir / f"{unreal_project_name}.uproject"
print("--- Generating a new project ...")
- commandlet_cmd = [f'{ue_editor_exe.as_posix()}',
- f'{cmdlet_project.as_posix()}',
- f'-run=AyonGenerateProject',
- f'{project_file.resolve().as_posix()}']
+ commandlet_cmd = [
+ ue_editor_exe.as_posix(),
+ cmdlet_project.as_posix(),
+ "-run=AyonGenerateProject",
+ project_file.resolve().as_posix()
+ ]
if dev_mode or preset["dev_mode"]:
commandlet_cmd.append('-GenerateCode')
@@ -268,7 +268,7 @@ def create_unreal_project(project_name: str,
pf.seek(0)
json.dump(pf_json, pf, indent=4)
pf.truncate()
- print(f'--- Engine ID has been written into the project file')
+ print("--- Engine ID has been written into the project file")
if dev_mode or preset["dev_mode"]:
u_build_tool = get_path_to_ubt(engine_path, ue_version)
@@ -282,17 +282,25 @@ def create_unreal_project(project_name: str,
# we need to test this out
arch = "Mac"
- command1 = [u_build_tool.as_posix(), "-projectfiles",
- f"-project={project_file}", "-progress"]
+ command1 = [
+ u_build_tool.as_posix(),
+ "-projectfiles",
+ f"-project={project_file}",
+ "-progress"
+ ]
subprocess.run(command1)
- command2 = [u_build_tool.as_posix(),
- f"-ModuleWithSuffix={unreal_project_name},3555", arch,
- "Development", "-TargetType=Editor",
- f'-Project={project_file}',
- f'{project_file}',
- "-IgnoreJunk"]
+ command2 = [
+ u_build_tool.as_posix(),
+ f"-ModuleWithSuffix={unreal_project_name},3555",
+ arch,
+ "Development",
+ "-TargetType=Editor",
+ f"-Project={project_file}",
+ project_file,
+ "-IgnoreJunk"
+ ]
subprocess.run(command2)
diff --git a/client/ayon_core/hosts/unreal/plugins/create/create_render.py b/client/ayon_core/hosts/unreal/plugins/create/create_render.py
index cbec84c543..5a96d9809c 100644
--- a/client/ayon_core/hosts/unreal/plugins/create/create_render.py
+++ b/client/ayon_core/hosts/unreal/plugins/create/create_render.py
@@ -50,7 +50,7 @@ class CreateRender(UnrealAssetCreator):
# If the option to create a new level sequence is selected,
# create a new level sequence and a master level.
- root = f"/Game/Ayon/Sequences"
+ root = "/Game/Ayon/Sequences"
# Create a new folder for the sequence in root
sequence_dir_name = create_folder(root, product_name)
@@ -166,7 +166,7 @@ class CreateRender(UnrealAssetCreator):
master_lvl = levels[0].get_asset().get_path_name()
except IndexError:
raise RuntimeError(
- f"Could not find the hierarchy for the selected sequence.")
+ "Could not find the hierarchy for the selected sequence.")
# If the selected asset is the master sequence, we get its data
# and then we create the instance for the master sequence.
diff --git a/client/ayon_core/hosts/unreal/plugins/publish/collect_render_instances.py b/client/ayon_core/hosts/unreal/plugins/publish/collect_render_instances.py
index ea53f221ea..ce2a03155b 100644
--- a/client/ayon_core/hosts/unreal/plugins/publish/collect_render_instances.py
+++ b/client/ayon_core/hosts/unreal/plugins/publish/collect_render_instances.py
@@ -1,12 +1,11 @@
-import os
from pathlib import Path
import unreal
+import pyblish.api
from ayon_core.pipeline import get_current_project_name
from ayon_core.pipeline import Anatomy
from ayon_core.hosts.unreal.api import pipeline
-import pyblish.api
class CollectRenderInstances(pyblish.api.InstancePlugin):
diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py
index 9eba3d1ed1..fd255c997f 100644
--- a/client/ayon_core/lib/local_settings.py
+++ b/client/ayon_core/lib/local_settings.py
@@ -524,7 +524,7 @@ def get_ayon_appdirs(*args):
def get_local_site_id():
"""Get local site identifier.
- Identifier is created if does not exists yet.
+ Identifier is created if does not exist yet.
"""
# used for background syncing
site_id = os.environ.get("AYON_SITE_ID")
diff --git a/client/ayon_core/lib/path_templates.py b/client/ayon_core/lib/path_templates.py
index 09d11ea1de..a766dbd9c1 100644
--- a/client/ayon_core/lib/path_templates.py
+++ b/client/ayon_core/lib/path_templates.py
@@ -102,7 +102,7 @@ class StringTemplate(object):
""" Figure out with whole formatting.
Separate advanced keys (*Like '{project[name]}') from string which must
- be formatted separatelly in case of missing or incomplete keys in data.
+ be formatted separately in case of missing or incomplete keys in data.
Args:
data (dict): Containing keys to be filled into template.
diff --git a/client/ayon_core/modules/base.py b/client/ayon_core/modules/base.py
index 8a78edf961..3f2a7d4ea5 100644
--- a/client/ayon_core/modules/base.py
+++ b/client/ayon_core/modules/base.py
@@ -1,3 +1,5 @@
+# Backwards compatibility support
+# - TODO should be removed before release 1.0.0
from ayon_core.addon import (
AYONAddon,
AddonsManager,
@@ -12,3 +14,16 @@ from ayon_core.addon.base import (
ModulesManager = AddonsManager
TrayModulesManager = TrayAddonsManager
load_modules = load_addons
+
+
+__all__ = (
+ "AYONAddon",
+ "AddonsManager",
+ "TrayAddonsManager",
+ "load_addons",
+ "OpenPypeModule",
+ "OpenPypeAddOn",
+ "ModulesManager",
+ "TrayModulesManager",
+ "load_modules",
+)
diff --git a/client/ayon_core/modules/clockify/clockify_api.py b/client/ayon_core/modules/clockify/clockify_api.py
index f8c9c537ee..2e1d8f008f 100644
--- a/client/ayon_core/modules/clockify/clockify_api.py
+++ b/client/ayon_core/modules/clockify/clockify_api.py
@@ -1,6 +1,4 @@
import os
-import re
-import time
import json
import datetime
import requests
diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py
index 0e871eb90e..5602b02707 100644
--- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py
+++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py
@@ -651,7 +651,6 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
return job_info, attr.asdict(plugin_info)
def _get_arnold_render_payload(self, data):
- from maya import cmds
# Job Info
job_info = copy.deepcopy(self.job_info)
job_info.Name = self._job_info_label("Render")
@@ -856,10 +855,10 @@ def _format_tiles(
"""
# Math used requires integers for correct output - as such
# we ensure our inputs are correct.
- assert type(tiles_x) is int, "tiles_x must be an integer"
- assert type(tiles_y) is int, "tiles_y must be an integer"
- assert type(width) is int, "width must be an integer"
- assert type(height) is int, "height must be an integer"
+ assert isinstance(tiles_x, int), "tiles_x must be an integer"
+ assert isinstance(tiles_y, int), "tiles_y must be an integer"
+ assert isinstance(width, int), "width must be an integer"
+ assert isinstance(height, int), "height must be an integer"
out = {"JobInfo": {}, "PluginInfo": {}}
cfg = OrderedDict()
diff --git a/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
index de0a2c6d7a..bb7f932013 100644
--- a/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
+++ b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
@@ -7,7 +7,6 @@ from Deadline.Plugins import PluginType, DeadlinePlugin
from Deadline.Scripting import (
StringUtils,
FileUtils,
- DirectoryUtils,
RepositoryUtils
)
diff --git a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
index 1565b2c496..8df96b425e 100644
--- a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
+++ b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
@@ -12,7 +12,6 @@ from Deadline.Scripting import (
RepositoryUtils,
FileUtils,
DirectoryUtils,
- ProcessUtils,
)
__version__ = "1.0.1"
VERSION_REGEX = re.compile(
diff --git a/client/ayon_core/modules/royalrender/lib.py b/client/ayon_core/modules/royalrender/lib.py
index d552e7fb19..5392803710 100644
--- a/client/ayon_core/modules/royalrender/lib.py
+++ b/client/ayon_core/modules/royalrender/lib.py
@@ -2,7 +2,6 @@
"""Submitting render job to RoyalRender."""
import os
import json
-import platform
import re
import tempfile
import uuid
diff --git a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py
index 5d177fec07..662913cadf 100644
--- a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py
+++ b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py
@@ -198,7 +198,7 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin,
priority = self.priority or instance.data.get("priority", 50)
- # rr requires absolut path or all jobs won't show up in rControl
+ # rr requires absolute path or all jobs won't show up in rrControl
abs_metadata_path = self.anatomy.fill_root(rootless_metadata_path)
# command line set in E01__OpenPype__PublishJob.cfg, here only
diff --git a/client/ayon_core/modules/royalrender/plugins/publish/submit_jobs_to_royalrender.py b/client/ayon_core/modules/royalrender/plugins/publish/submit_jobs_to_royalrender.py
index 54de943428..09c1dc4a54 100644
--- a/client/ayon_core/modules/royalrender/plugins/publish/submit_jobs_to_royalrender.py
+++ b/client/ayon_core/modules/royalrender/plugins/publish/submit_jobs_to_royalrender.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
"""Submit jobs to RoyalRender."""
import tempfile
-import platform
import pyblish.api
from ayon_core.modules.royalrender.api import (
diff --git a/client/ayon_core/pipeline/create/context.py b/client/ayon_core/pipeline/create/context.py
index 8c6a7f1bb6..ca9896fb3f 100644
--- a/client/ayon_core/pipeline/create/context.py
+++ b/client/ayon_core/pipeline/create/context.py
@@ -529,7 +529,7 @@ class AttributeValues(object):
Has dictionary like methods. Not all of them are allowed all the time.
Args:
- attr_defs(AbstractAttrDef): Defintions of value type and properties.
+ attr_defs(AbstractAttrDef): Definitions of value type and properties.
values(dict): Values after possible conversion.
origin_data(dict): Values loaded from host before conversion.
"""
diff --git a/client/ayon_core/pipeline/create/creator_plugins.py b/client/ayon_core/pipeline/create/creator_plugins.py
index 5505427d7e..e0b30763d0 100644
--- a/client/ayon_core/pipeline/create/creator_plugins.py
+++ b/client/ayon_core/pipeline/create/creator_plugins.py
@@ -347,7 +347,7 @@ class BaseCreator:
Returns:
str: Group label that can be used for grouping of instances in UI.
- Group label can be overriden by instance itself.
+ Group label can be overridden by instance itself.
"""
if self._cached_group_label is None:
@@ -607,18 +607,19 @@ class Creator(BaseCreator):
"""
# GUI Purposes
- # - default_variants may not be used if `get_default_variants` is overriden
+ # - default_variants may not be used if `get_default_variants`
+ # is overridden
default_variants = []
# Default variant used in 'get_default_variant'
_default_variant = None
# Short description of product type
- # - may not be used if `get_description` is overriden
+ # - may not be used if `get_description` is overridden
description = None
# Detailed description of product type for artists
- # - may not be used if `get_detail_description` is overriden
+ # - may not be used if `get_detail_description` is overridden
detailed_description = None
# It does make sense to change context on creation
diff --git a/client/ayon_core/pipeline/create/product_name.py b/client/ayon_core/pipeline/create/product_name.py
index 74e268fbb3..fecda867e5 100644
--- a/client/ayon_core/pipeline/create/product_name.py
+++ b/client/ayon_core/pipeline/create/product_name.py
@@ -1,5 +1,3 @@
-import ayon_api
-
from ayon_core.settings import get_project_settings
from ayon_core.lib import filter_profiles, prepare_template_data
diff --git a/client/ayon_core/pipeline/editorial.py b/client/ayon_core/pipeline/editorial.py
index 564d78ea6f..84bffbe1ec 100644
--- a/client/ayon_core/pipeline/editorial.py
+++ b/client/ayon_core/pipeline/editorial.py
@@ -64,7 +64,7 @@ def convert_to_padded_path(path, padding):
padding (int): number of padding
Returns:
- type: string with reformated path
+ type: string with reformatted path
Example:
convert_to_padded_path("plate.%d.exr") > plate.%04d.exr
diff --git a/client/ayon_core/pipeline/farm/pyblish_functions.pyi b/client/ayon_core/pipeline/farm/pyblish_functions.pyi
index 16c11aa480..fe0ae57da0 100644
--- a/client/ayon_core/pipeline/farm/pyblish_functions.pyi
+++ b/client/ayon_core/pipeline/farm/pyblish_functions.pyi
@@ -1,6 +1,6 @@
import pyblish.api
from ayon_core.pipeline import Anatomy
-from typing import Tuple, Union, List
+from typing import Tuple, List
class TimeData:
diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py
index 91f839ebf3..064af4ddc1 100644
--- a/client/ayon_core/pipeline/load/plugins.py
+++ b/client/ayon_core/pipeline/load/plugins.py
@@ -2,7 +2,6 @@ import os
import logging
from ayon_core.settings import get_project_settings
-from ayon_core.pipeline import schema
from ayon_core.pipeline.plugin_discover import (
discover,
register_plugin,
@@ -116,7 +115,7 @@ class LoaderPlugin(list):
def is_compatible_loader(cls, context):
"""Return whether a loader is compatible with a context.
- On override make sure it is overriden as class or static method.
+ On override make sure it is overridden as class or static method.
This checks the product type and the representation for the given
loader plugin.
diff --git a/client/ayon_core/pipeline/publish/publish_plugins.py b/client/ayon_core/pipeline/publish/publish_plugins.py
index 2386558091..6b1984d92b 100644
--- a/client/ayon_core/pipeline/publish/publish_plugins.py
+++ b/client/ayon_core/pipeline/publish/publish_plugins.py
@@ -2,7 +2,6 @@ import inspect
from abc import ABCMeta
import pyblish.api
from pyblish.plugin import MetaPlugin, ExplicitMetaPlugin
-from ayon_core.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS
from ayon_core.lib import BoolDef
from .lib import (
diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py
index 1d7b5ed5a7..5e63ba444a 100644
--- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py
+++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py
@@ -1865,7 +1865,7 @@ class PlaceholderCreateMixin(object):
self.log.debug("Clean up of placeholder is not implemented.")
def _before_instance_create(self, placeholder):
- """Can be overriden. Is called before instance is created."""
+ """Can be overridden. Is called before instance is created."""
pass
diff --git a/client/ayon_core/plugins/publish/collect_anatomy_instance_data.py b/client/ayon_core/plugins/publish/collect_anatomy_instance_data.py
index e3b27a0db5..f8cc81e718 100644
--- a/client/ayon_core/plugins/publish/collect_anatomy_instance_data.py
+++ b/client/ayon_core/plugins/publish/collect_anatomy_instance_data.py
@@ -465,7 +465,11 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
current_data = hierarchy_context.get(project_name, {})
for key in folder_path.split("/"):
if key:
- current_data = current_data.get("childs", {}).get(key, {})
+ current_data = (
+ current_data
+ .get("children", {})
+ .get(key, {})
+ )
tasks_info = current_data.get("tasks", {})
task_info = tasks_info.get(task_name, {})
@@ -529,5 +533,5 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
return item[folder_name].get("tasks") or {}
for subitem in item.values():
- hierarchy_queue.extend(subitem.get("childs") or [])
+ hierarchy_queue.extend(subitem.get("children") or [])
return {}
diff --git a/client/ayon_core/plugins/publish/collect_hierarchy.py b/client/ayon_core/plugins/publish/collect_hierarchy.py
index 7387b1865b..2ae3cc67f3 100644
--- a/client/ayon_core/plugins/publish/collect_hierarchy.py
+++ b/client/ayon_core/plugins/publish/collect_hierarchy.py
@@ -17,17 +17,18 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
hosts = ["resolve", "hiero", "flame"]
def process(self, context):
- temp_context = {}
project_name = context.data["projectName"]
- final_context = {}
- final_context[project_name] = {}
- final_context[project_name]["entity_type"] = "project"
-
+ final_context = {
+ project_name: {
+ "entity_type": "project",
+ "children": {}
+ },
+ }
+ temp_context = {}
for instance in context:
self.log.debug("Processing instance: `{}` ...".format(instance))
# shot data dict
- shot_data = {}
product_type = instance.data["productType"]
families = instance.data["families"]
@@ -41,34 +42,38 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
if not instance.data.get("heroTrack"):
continue
- # suppose that all instances are Shots
- shot_data['entity_type'] = 'Shot'
- shot_data['tasks'] = instance.data.get("tasks") or {}
- shot_data["comments"] = instance.data.get("comments", [])
-
- shot_data['custom_attributes'] = {
- "handleStart": instance.data["handleStart"],
- "handleEnd": instance.data["handleEnd"],
- "frameStart": instance.data["frameStart"],
- "frameEnd": instance.data["frameEnd"],
- "clipIn": instance.data["clipIn"],
- "clipOut": instance.data["clipOut"],
- "fps": instance.data["fps"],
- "resolutionWidth": instance.data["resolutionWidth"],
- "resolutionHeight": instance.data["resolutionHeight"],
- "pixelAspect": instance.data["pixelAspect"]
+ shot_data = {
+ "entity_type": "folder",
+ # WARNING Default folder type is hardcoded
+ # suppose that all instances are Shots
+ "folder_type": "Shot",
+ "tasks": instance.data.get("tasks") or {},
+ "comments": instance.data.get("comments", []),
+ "attributes": {
+ "handleStart": instance.data["handleStart"],
+ "handleEnd": instance.data["handleEnd"],
+ "frameStart": instance.data["frameStart"],
+ "frameEnd": instance.data["frameEnd"],
+ "clipIn": instance.data["clipIn"],
+ "clipOut": instance.data["clipOut"],
+ "fps": instance.data["fps"],
+ "resolutionWidth": instance.data["resolutionWidth"],
+ "resolutionHeight": instance.data["resolutionHeight"],
+ "pixelAspect": instance.data["pixelAspect"],
+ },
}
# Split by '/' for AYON where asset is a path
name = instance.data["folderPath"].split("/")[-1]
actual = {name: shot_data}
for parent in reversed(instance.data["parents"]):
- next_dict = {}
- parent_name = parent["entity_name"]
- next_dict[parent_name] = {}
- next_dict[parent_name]["entity_type"] = parent[
- "entity_type"].capitalize()
- next_dict[parent_name]["childs"] = actual
+ next_dict = {
+ parent["entity_name"]: {
+ "entity_type": "folder",
+ "folder_type": parent["folder_type"],
+ "children": actual,
+ }
+ }
actual = next_dict
temp_context = self._update_dict(temp_context, actual)
@@ -77,7 +82,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
if not temp_context:
return
- final_context[project_name]['childs'] = temp_context
+ final_context[project_name]["children"] = temp_context
# adding hierarchy context to context
context.data["hierarchyContext"] = final_context
@@ -85,8 +90,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
context.data["hierarchyContext"]))
def _update_dict(self, parent_dict, child_dict):
- """
- Nesting each children into its parent.
+ """Nesting each child into its parent.
Args:
parent_dict (dict): parent dict wich should be nested with children
diff --git a/client/ayon_core/plugins/publish/extract_hierarchy_to_ayon.py b/client/ayon_core/plugins/publish/extract_hierarchy_to_ayon.py
index 59a15af299..60c92aa8b1 100644
--- a/client/ayon_core/plugins/publish/extract_hierarchy_to_ayon.py
+++ b/client/ayon_core/plugins/publish/extract_hierarchy_to_ayon.py
@@ -115,6 +115,10 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
entity_hub = EntityHub(project_name)
project = entity_hub.project_entity
+ folder_type_name_by_low_name = {
+ folder_type_item["name"].lower(): folder_type_item["name"]
+ for folder_type_item in project.get_folder_types()
+ }
hierarchy_match_queue = collections.deque()
hierarchy_match_queue.append((project, hierarchy_context))
@@ -167,8 +171,18 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
# TODO check if existing entity have 'folder' type
child_entity = children_by_low_name.get(child_name.lower())
if child_entity is None:
+ folder_type = folder_type_name_by_low_name.get(
+ child_info["folder_type"].lower()
+ )
+ if folder_type is None:
+ # TODO add validator for folder type validations
+ self.log.warning((
+ "Couldn't find folder type '{}'"
+ ).format(child_info["folder_type"]))
+ folder_type = "Folder"
+
child_entity = entity_hub.add_new_folder(
- child_info["entity_type"],
+ folder_type,
parent_id=entity.id,
name=child_name
)
@@ -223,12 +237,11 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
# filter only the active publishing instances
active_folder_paths = set()
for instance in context:
- if instance.data.get("publish") is not False:
+ if instance.data.get("publish", True) is not False:
active_folder_paths.add(instance.data.get("folderPath"))
active_folder_paths.discard(None)
- self.log.debug("Active folder paths: {}".format(active_folder_paths))
if not active_folder_paths:
return None
@@ -237,11 +250,11 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
hierarchy_context = copy.deepcopy(context.data["hierarchyContext"])
for key, value in hierarchy_context.items():
project_item = copy.deepcopy(value)
- project_children_context = project_item.pop("childs", None)
+ project_children_context = project_item.pop("children", None)
project_item["name"] = key
project_item["tasks"] = []
project_item["attributes"] = project_item.pop(
- "custom_attributes", {}
+ "attributes", {}
)
project_item["children"] = []
@@ -265,22 +278,23 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
folder_path = "{}/{}".format(parent_path, folder_name)
if (
folder_path not in active_folder_paths
- and not folder_info.get("childs")
+ and not folder_info.get("children")
):
continue
item_id = uuid.uuid4().hex
new_item = copy.deepcopy(folder_info)
+ new_children_context = new_item.pop("children", None)
+ tasks = new_item.pop("tasks", {})
+
new_item["name"] = folder_name
new_item["children"] = []
- new_children_context = new_item.pop("childs", None)
- tasks = new_item.pop("tasks", {})
task_items = []
for task_name, task_info in tasks.items():
task_info["name"] = task_name
task_items.append(task_info)
new_item["tasks"] = task_items
- new_item["attributes"] = new_item.pop("custom_attributes", {})
+ new_item["attributes"] = new_item.pop("attributes", {})
items_by_id[item_id] = new_item
parent_id_by_item_id[item_id] = parent_id
diff --git a/client/ayon_core/plugins/publish/extract_otio_audio_tracks.py b/client/ayon_core/plugins/publish/extract_otio_audio_tracks.py
index a19b5b9090..98723beffa 100644
--- a/client/ayon_core/plugins/publish/extract_otio_audio_tracks.py
+++ b/client/ayon_core/plugins/publish/extract_otio_audio_tracks.py
@@ -80,7 +80,7 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
# create duration
duration = (timeline_out_h - timeline_in_h) + 1
- # ffmpeg generate new file only if doesnt exists already
+ # ffmpeg generate new file only if doesn't exists already
if not recycling_file:
# convert to seconds
start_sec = float(timeline_in_h / fps)
diff --git a/client/ayon_core/plugins/publish/validate_editorial_asset_name.py b/client/ayon_core/plugins/publish/validate_editorial_asset_name.py
deleted file mode 100644
index 9b6794a0c4..0000000000
--- a/client/ayon_core/plugins/publish/validate_editorial_asset_name.py
+++ /dev/null
@@ -1,122 +0,0 @@
-from pprint import pformat
-
-import ayon_api
-import pyblish.api
-
-from ayon_core.pipeline import KnownPublishError
-
-
-class ValidateEditorialAssetName(pyblish.api.ContextPlugin):
- """ Validating if editorial's folder names are not already created in db.
-
- Checking variations of names with different size of caps or with
- or without underscores.
- """
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Editorial Folder Name"
- hosts = [
- "hiero",
- "resolve",
- "flame",
- "traypublisher"
- ]
-
- def process(self, context):
-
- folder_and_parents = self.get_parents(context)
- self.log.debug("__ folder_and_parents: {}".format(folder_and_parents))
-
- project_name = context.data["projectName"]
- folder_entities = list(ayon_api.get_folders(
- project_name, fields={"path"}
- ))
- self.log.debug("__ folder_entities: {}".format(folder_entities))
-
- existing_folder_paths = {
- folder_entity["path"]: (
- folder_entity["path"].lstrip("/").rsplit("/")[0]
- )
- for folder_entity in folder_entities
- }
-
- self.log.debug("__ project_entities: {}".format(
- pformat(existing_folder_paths)))
-
- folders_missing_name = {}
- folders_wrong_parent = {}
- for folder_path in folder_and_parents.keys():
- if folder_path not in existing_folder_paths.keys():
- # add to some nonexistent list for next layer of check
- folders_missing_name[folder_path] = (
- folder_and_parents[folder_path]
- )
- continue
-
- existing_parents = existing_folder_paths[folder_path]
- if folder_and_parents[folder_path] != existing_parents:
- # add to some nonexistent list for next layer of check
- folders_wrong_parent[folder_path] = {
- "required": folder_and_parents[folder_path],
- "already_in_db": existing_folder_paths[folder_path]
- }
- continue
-
- self.log.debug("correct folder: {}".format(folder_path))
-
- if folders_missing_name:
- wrong_names = {}
- self.log.debug(
- ">> folders_missing_name: {}".format(folders_missing_name))
-
- # This will create set of folder paths
- folder_paths = {
- folder_path.lower().replace("_", "")
- for folder_path in existing_folder_paths
- }
-
- for folder_path in folders_missing_name:
- _folder_path = folder_path.lower().replace("_", "")
- if _folder_path in folder_paths:
- wrong_names[folder_path].update(
- {
- "required_name": folder_path,
- "used_variants_in_db": [
- p
- for p in existing_folder_paths
- if p.lower().replace("_", "") == _folder_path
- ]
- }
- )
-
- if wrong_names:
- self.log.debug(
- ">> wrong_names: {}".format(wrong_names))
- raise Exception(
- "Some already existing folder name variants `{}`".format(
- wrong_names))
-
- if folders_wrong_parent:
- self.log.debug(
- ">> folders_wrong_parent: {}".format(folders_wrong_parent))
- raise KnownPublishError(
- "Wrong parents on folders `{}`".format(folders_wrong_parent))
-
- def get_parents(self, context):
- output = {}
- for instance in context:
- folder_path = instance.data["folderPath"]
- families = instance.data.get("families", []) + [
- instance.data["family"]
- ]
- # filter out non-shot families
- if "shot" not in families:
- continue
-
- parents = instance.data["parents"]
-
- output[folder_path] = [
- str(p["entity_name"]) for p in parents
- if p["entity_type"].lower() != "project"
- ]
- return output
diff --git a/client/ayon_core/scripts/slates/slate_base/api.py b/client/ayon_core/scripts/slates/slate_base/api.py
index cd64c68134..d1b4b22979 100644
--- a/client/ayon_core/scripts/slates/slate_base/api.py
+++ b/client/ayon_core/scripts/slates/slate_base/api.py
@@ -13,3 +13,21 @@ from .items import (
)
from .lib import create_slates
from .example import example
+
+
+__all__ = (
+ "FontFactory",
+ "BaseObj",
+ "load_default_style",
+ "MainFrame",
+ "Layer",
+ "BaseItem",
+ "ItemImage",
+ "ItemRectangle",
+ "ItemPlaceHolder",
+ "ItemText",
+ "ItemTable",
+ "TableField",
+ "create_slates",
+ "example",
+)
diff --git a/client/ayon_core/tools/common_models/thumbnails.py b/client/ayon_core/tools/common_models/thumbnails.py
index 138cee4ea2..1c3aadc49f 100644
--- a/client/ayon_core/tools/common_models/thumbnails.py
+++ b/client/ayon_core/tools/common_models/thumbnails.py
@@ -112,7 +112,7 @@ class ThumbnailsCache:
"""
thumbnails_dir = self.get_thumbnails_dir()
- # Skip if thumbnails dir does not exists yet
+ # Skip if thumbnails dir does not exist yet
if not os.path.exists(thumbnails_dir):
return
diff --git a/client/ayon_core/tools/publisher/widgets/create_context_widgets.py b/client/ayon_core/tools/publisher/widgets/create_context_widgets.py
index 61223bbe75..235a778d0f 100644
--- a/client/ayon_core/tools/publisher/widgets/create_context_widgets.py
+++ b/client/ayon_core/tools/publisher/widgets/create_context_widgets.py
@@ -1,4 +1,4 @@
-from qtpy import QtWidgets, QtCore, QtGui
+from qtpy import QtWidgets, QtCore
from ayon_core.lib.events import QueuedEventSystem
from ayon_core.tools.utils import PlaceholderLineEdit, GoToCurrentButton
diff --git a/client/ayon_core/tools/publisher/widgets/folders_dialog.py b/client/ayon_core/tools/publisher/widgets/folders_dialog.py
index 03336e10a6..8dce7aba3a 100644
--- a/client/ayon_core/tools/publisher/widgets/folders_dialog.py
+++ b/client/ayon_core/tools/publisher/widgets/folders_dialog.py
@@ -1,4 +1,4 @@
-from qtpy import QtWidgets, QtCore, QtGui
+from qtpy import QtWidgets
from ayon_core.lib.events import QueuedEventSystem
from ayon_core.tools.utils import PlaceholderLineEdit, FoldersWidget
diff --git a/client/ayon_core/tools/publisher/widgets/publish_frame.py b/client/ayon_core/tools/publisher/widgets/publish_frame.py
index d423f97047..ee65c69c19 100644
--- a/client/ayon_core/tools/publisher/widgets/publish_frame.py
+++ b/client/ayon_core/tools/publisher/widgets/publish_frame.py
@@ -1,7 +1,3 @@
-import os
-import json
-import time
-
from qtpy import QtWidgets, QtCore
from .widgets import (
diff --git a/client/ayon_core/tools/publisher/widgets/tasks_model.py b/client/ayon_core/tools/publisher/widgets/tasks_model.py
index e36de80fcf..78b1f23b17 100644
--- a/client/ayon_core/tools/publisher/widgets/tasks_model.py
+++ b/client/ayon_core/tools/publisher/widgets/tasks_model.py
@@ -1,4 +1,4 @@
-from qtpy import QtWidgets, QtCore, QtGui
+from qtpy import QtCore, QtGui
from ayon_core.style import get_default_entity_icon_color
from ayon_core.tools.utils import get_qt_icon
diff --git a/client/ayon_core/tools/pyblish_pype/util.py b/client/ayon_core/tools/pyblish_pype/util.py
index 8126637060..09a370c6e4 100644
--- a/client/ayon_core/tools/pyblish_pype/util.py
+++ b/client/ayon_core/tools/pyblish_pype/util.py
@@ -7,8 +7,6 @@ from __future__ import (
import os
import sys
-import numbers
-import copy
import collections
from qtpy import QtCore
@@ -39,7 +37,7 @@ def defer(delay, func):
This aids in keeping the GUI responsive, but complicates logic
when producing tests. To combat this, the environment variable ensures
- that every operation is synchonous.
+ that every operation is synchronous.
Arguments:
delay (float): Delay multiplier; default 1, 0 means no delay
diff --git a/client/ayon_core/tools/utils/lib.py b/client/ayon_core/tools/utils/lib.py
index 4b7ca5425e..d56b370d75 100644
--- a/client/ayon_core/tools/utils/lib.py
+++ b/client/ayon_core/tools/utils/lib.py
@@ -7,7 +7,6 @@ from qtpy import QtWidgets, QtCore, QtGui
import qtawesome
from ayon_core.style import (
- get_default_entity_icon_color,
get_objected_colors,
get_app_icon_path,
)
diff --git a/client/ayon_core/tools/utils/models.py b/client/ayon_core/tools/utils/models.py
index 92bed16e98..9b32cc5710 100644
--- a/client/ayon_core/tools/utils/models.py
+++ b/client/ayon_core/tools/utils/models.py
@@ -2,7 +2,7 @@ import re
import logging
import qtpy
-from qtpy import QtCore, QtGui
+from qtpy import QtCore
log = logging.getLogger(__name__)
diff --git a/client/ayon_core/vendor/python/common/pysync.py b/client/ayon_core/vendor/python/common/pysync.py
deleted file mode 100644
index 14a6dda34c..0000000000
--- a/client/ayon_core/vendor/python/common/pysync.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/local/bin/python3
-# https://github.com/snullp/pySync/blob/master/pySync.py
-
-import sys
-import shutil
-import os
-import time
-import configparser
-from os.path import (
- getsize,
- getmtime,
- isfile,
- isdir,
- join,
- abspath,
- expanduser,
- realpath
-)
-import logging
-
-log = logging.getLogger(__name__)
-
-ignoreFiles = ("Thumbs.db", ".DS_Store")
-
-# this feature is not yet implemented
-ignorePaths = []
-
-if os.name == 'nt':
- # msvcrt can't function correctly in IDLE
- if 'idlelib.run' in sys.modules:
- print("Please don't run this script in IDLE.")
- sys.exit(0)
- import msvcrt
-
- def flush_input(str, set=None):
- if not set:
- while msvcrt.kbhit():
- ch = msvcrt.getch()
- if ch == '\xff':
- print("msvcrt is broken, this is weird.")
- sys.exit(0)
- return input(str)
- else:
- return set
-else:
- import select
-
- def flush_input(str, set=None):
- if not set:
- while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0:
- os.read(sys.stdin.fileno(), 4096)
- return input(str)
- else:
- return set
-
-
-def compare(fa, fb, options_input=[]):
- if isfile(fa) == isfile(fb):
- if isdir(fa):
- walktree(fa, fb, options_input)
- elif isfile(fa):
- if getsize(fa) != getsize(fb) \
- or int(getmtime(fa)) != int(getmtime(fb)):
- log.info(str((fa, ': size=', getsize(fa), 'mtime=',
- time.asctime(time.localtime(getmtime(fa))))))
- log.info(str((fb, ': size=', getsize(fb), 'mtime=',
- time.asctime(time.localtime(getmtime(fb))))))
- if getmtime(fa) > getmtime(fb):
- act = '>'
- else:
- act = '<'
-
- set = [i for i in options_input if i in [">", "<"]][0]
-
- s = flush_input('What to do?(>,<,r,n)[' + act + ']', set=set)
- if len(s) > 0:
- act = s[0]
- if act == '>':
- shutil.copy2(fa, fb)
- elif act == '<':
- shutil.copy2(fb, fa)
- elif act == 'r':
- if isdir(fa):
- shutil.rmtree(fa)
- elif isfile(fa):
- os.remove(fa)
- else:
- log.info(str(('Remove: Skipping', fa)))
- if isdir(fb):
- shutil.rmtree(fb)
- elif isfile(fb):
- os.remove(fb)
- else:
- log.info(str(('Remove: Skipping', fb)))
-
- else:
- log.debug(str(('Compare: Skipping non-dir and non-file', fa)))
- else:
- log.error(str(('Error:', fa, ',', fb, 'have different file type')))
-
-
-def copy(fa, fb, options_input=[]):
- set = [i for i in options_input if i in ["y"]][0]
- s = flush_input('Copy ' + fa + ' to another side?(r,y,n)[y]', set=set)
- if len(s) > 0:
- act = s[0]
- else:
- act = 'y'
- if act == 'y':
- if isdir(fa):
- shutil.copytree(fa, fb)
- elif isfile(fa):
- shutil.copy2(fa, fb)
- else:
- log.debug(str(('Copy: Skipping ', fa)))
- elif act == 'r':
- if isdir(fa):
- shutil.rmtree(fa)
- elif isfile(fa):
- os.remove(fa)
- else:
- log.debug(str(('Remove: Skipping ', fa)))
-
-
-stoentry = []
-tarentry = []
-
-
-def walktree(source, target, options_input=[]):
- srclist = os.listdir(source)
- tarlist = os.listdir(target)
- if '!sync' in srclist:
- return
- if '!sync' in tarlist:
- return
- # files in source dir...
- for f in srclist:
- if f in ignoreFiles:
- continue
- spath = join(source, f)
- tpath = join(target, f)
- if spath in ignorePaths:
- continue
- if spath in stoentry:
- # just in case target also have this one
- if f in tarlist:
- del tarlist[tarlist.index(f)]
- continue
-
- # if also exists in target dir
- if f in tarlist:
- del tarlist[tarlist.index(f)]
- compare(spath, tpath, options_input)
-
- # exists in source dir only
- else:
- copy(spath, tpath, options_input)
-
- # exists in target dir only
- set = [i for i in options_input if i in ["<"]]
-
- for f in tarlist:
- if f in ignoreFiles:
- continue
- spath = join(source, f)
- tpath = join(target, f)
- if tpath in ignorePaths:
- continue
- if tpath in tarentry:
- continue
- if set:
- copy(tpath, spath, options_input)
- else:
- print("REMOVING: {}".format(f))
- if os.path.isdir(tpath):
- shutil.rmtree(tpath)
- else:
- os.remove(tpath)
- print("REMOVING: {}".format(f))
-
-
-if __name__ == '__main__':
- stoconf = configparser.RawConfigParser()
- tarconf = configparser.RawConfigParser()
- stoconf.read("pySync.ini")
- tarconf.read(expanduser("~/.pysync"))
- stoname = stoconf.sections()[0]
- tarname = tarconf.sections()[0]
-
- # calculate storage's base folder
- if stoconf.has_option(stoname, 'BASE'):
- stobase = abspath(stoconf.get(stoname, 'BASE'))
- stoconf.remove_option(stoname, 'BASE')
- else:
- stobase = os.getcwd()
-
- # same, for target's base folder
- if tarconf.has_option(tarname, 'BASE'):
- tarbase = abspath(tarconf.get(tarname, 'BASE'))
- tarconf.remove_option(tarname, 'BASE')
- else:
- tarbase = expanduser('~/')
-
- print("Syncing between", stoname, "and", tarname)
- sto_content = {x: realpath(join(stobase, stoconf.get(stoname, x)))
- for x in stoconf.options(stoname)}
- tar_content = {x: realpath(join(tarbase, tarconf.get(tarname, x)))
- for x in tarconf.options(tarname)}
- stoentry = [sto_content[x] for x in sto_content]
- tarentry = [tar_content[x] for x in tar_content]
-
- for folder in sto_content:
- if folder in tar_content:
- print('Processing', folder)
- walktree(sto_content[folder], tar_content[folder], options_input)
- print("Done.")
diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py
index 9b5f3ae571..e61bf6986b 100644
--- a/server/settings/publish_plugins.py
+++ b/server/settings/publish_plugins.py
@@ -9,7 +9,7 @@ from ayon_server.settings import (
task_types_enum,
)
-from ayon_server.types import ColorRGB_uint8, ColorRGBA_uint8
+from ayon_server.types import ColorRGBA_uint8
class ValidateBaseModel(BaseSettingsModel):
@@ -221,7 +221,12 @@ class OIIOToolArgumentsModel(BaseSettingsModel):
class ExtractOIIOTranscodeOutputModel(BaseSettingsModel):
_layout = "expanded"
- name: str = SettingsField("", title="Name")
+ name: str = SettingsField(
+ "",
+ title="Name",
+ description="Output name (no space)",
+ regex=r"[a-zA-Z0-9_]([a-zA-Z0-9_\.\-]*[a-zA-Z0-9_])?$",
+ )
extension: str = SettingsField("", title="Extension")
transcoding_type: str = SettingsField(
"colorspace",
@@ -424,7 +429,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel):
title="Scale pixel aspect",
description=(
"Rescale input when it's pixel aspect ratio is not 1."
- " Usefull for anamorph reviews."
+ " Useful for anamorphic reviews."
)
)
bg_color: ColorRGBA_uint8 = SettingsField(
diff --git a/server_addon/create_ayon_addons.py b/server_addon/create_ayon_addons.py
index 9553980f5d..c2686199be 100644
--- a/server_addon/create_ayon_addons.py
+++ b/server_addon/create_ayon_addons.py
@@ -1,7 +1,6 @@
import os
import sys
import re
-import json
import shutil
import argparse
import zipfile
@@ -220,7 +219,6 @@ def main(
addons=None,
):
current_dir = Path(os.path.dirname(os.path.abspath(__file__)))
- root_dir = current_dir.parent
create_zip = not skip_zip
if output_dir:
diff --git a/server_addon/nuke/server/settings/main.py b/server_addon/nuke/server/settings/main.py
index 2b269f1fce..936686d6ce 100644
--- a/server_addon/nuke/server/settings/main.py
+++ b/server_addon/nuke/server/settings/main.py
@@ -1,7 +1,6 @@
from ayon_server.settings import (
BaseSettingsModel,
SettingsField,
- ensure_unique_names
)
from .general import (
diff --git a/server_addon/tvpaint/server/settings/main.py b/server_addon/tvpaint/server/settings/main.py
index c6b6c9ab12..f20e9ecc9c 100644
--- a/server_addon/tvpaint/server/settings/main.py
+++ b/server_addon/tvpaint/server/settings/main.py
@@ -1,7 +1,6 @@
from ayon_server.settings import (
BaseSettingsModel,
SettingsField,
- ensure_unique_names,
)
from .imageio import TVPaintImageIOModel