diff --git a/.gitmodules b/.gitmodules index 20aa3a3e8d..a282ef169d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,4 +13,4 @@ url = https://bitbucket.org/ftrack/ftrack-python-api.git [submodule "pype/modules/ftrack/python2_vendor/arrow"] path = pype/modules/ftrack/python2_vendor/arrow - url = git@github.com:arrow-py/arrow.git + url = git@github.com:arrow-py/arrow.git \ No newline at end of file diff --git a/pype/api.py b/pype/api.py index 9c0d796128..b6170a13e1 100644 --- a/pype/api.py +++ b/pype/api.py @@ -26,6 +26,14 @@ from .lib.mongo import ( get_default_components ) +from .lib.applications import ( + ApplicationManager +) + +from .lib.avalon_context import ( + BuildWorkfile +) + from . import resources from .plugin import ( @@ -63,6 +71,8 @@ __all__ = [ "decompose_url", "compose_url", "get_default_components", + "ApplicationManager", + "BuildWorkfile", # Resources "resources", diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py index e39247b983..00b3557429 100644 --- a/pype/hooks/aftereffects/pre_launch_args.py +++ b/pype/hooks/aftereffects/pre_launch_args.py @@ -20,16 +20,23 @@ class AfterEffectsPrelaunchHook(PreLaunchHook): while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) + workfile_path = self.data["last_workfile_path"] + if not os.path.exists(workfile_path): + workfile_path = "" + new_launch_args = [ self.python_executable(), "-c", ( "import avalon.aftereffects;" - "avalon.aftereffects.launch(\"{}\")" - ).format(aftereffects_executable) + "avalon.aftereffects.launch(\"{}\", \"{}\")" + ).format( + aftereffects_executable.replace("\\", "\\\\"), + workfile_path.replace("\\", "\\\\") + ) ] - # Append as whole list as these areguments should not be separated + # Append as whole list as these arguments should not be separated self.launch_context.launch_args.append(new_launch_args) if remainders: diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index 70c05eb352..a61977f4e7 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -26,7 +26,7 @@ class HarmonyPrelaunchHook(PreLaunchHook): ( "import avalon.harmony;" "avalon.harmony.launch(\"{}\")" - ).format(harmony_executable) + ).format(harmony_executable.replace("\\", "\\\\")) ] # Append as whole list as these areguments should not be separated diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index b13e7d1e0f..6bd40eb2e1 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -20,13 +20,20 @@ class PhotoshopPrelaunchHook(PreLaunchHook): while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) + workfile_path = self.data["last_workfile_path"] + if not os.path.exists(workfile_path): + workfile_path = "" + new_launch_args = [ self.python_executable(), "-c", ( "import avalon.photoshop;" - "avalon.photoshop.launch(\"{}\")" - ).format(photoshop_executable) + "avalon.photoshop.launch(\"{}\", \"{}\")" + ).format( + photoshop_executable.replace("\\", "\\\\"), + workfile_path.replace("\\", "\\\\") + ) ] # Append as whole list as these areguments should not be separated diff --git a/pype/hosts/aftereffects/template.aep b/pype/hosts/aftereffects/template.aep new file mode 100644 index 0000000000..0857e418f3 Binary files /dev/null and b/pype/hosts/aftereffects/template.aep differ diff --git a/pype/hosts/blender/__init__.py b/pype/hosts/blender/__init__.py index dafeca5107..e69de29bb2 100644 --- a/pype/hosts/blender/__init__.py +++ b/pype/hosts/blender/__init__.py @@ -1,60 +0,0 @@ -import os -import sys -import traceback - -from avalon import api as avalon -from pyblish import api as pyblish - -import bpy - -from pype import PLUGINS_DIR - -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "blender", "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "blender", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "blender", "create") - -ORIGINAL_EXCEPTHOOK = sys.excepthook - - -def pype_excepthook_handler(*args): - traceback.print_exception(*args) - - -def install(): - """Install Blender configuration for Avalon.""" - sys.excepthook = pype_excepthook_handler - pyblish.register_plugin_path(str(PUBLISH_PATH)) - avalon.register_plugin_path(avalon.Loader, str(LOAD_PATH)) - avalon.register_plugin_path(avalon.Creator, str(CREATE_PATH)) - - avalon.on("new", on_new) - avalon.on("open", on_open) - - -def uninstall(): - """Uninstall Blender configuration for Avalon.""" - sys.excepthook = ORIGINAL_EXCEPTHOOK - pyblish.deregister_plugin_path(str(PUBLISH_PATH)) - avalon.deregister_plugin_path(avalon.Loader, str(LOAD_PATH)) - avalon.deregister_plugin_path(avalon.Creator, str(CREATE_PATH)) - - -def set_start_end_frames(): - from avalon import io - - asset_name = io.Session["AVALON_ASSET"] - asset_doc = io.find_one({ - "type": "asset", - "name": asset_name - }) - - bpy.context.scene.frame_start = asset_doc["data"]["frameStart"] - bpy.context.scene.frame_end = asset_doc["data"]["frameEnd"] - - -def on_new(arg1, arg2): - set_start_end_frames() - - -def on_open(arg1, arg2): - set_start_end_frames() diff --git a/pype/hosts/blender/api/__init__.py b/pype/hosts/blender/api/__init__.py new file mode 100644 index 0000000000..7fcd09201a --- /dev/null +++ b/pype/hosts/blender/api/__init__.py @@ -0,0 +1,63 @@ +import os +import sys +import traceback + +import bpy + +from avalon import api as avalon +from pyblish import api as pyblish + +import pype.hosts.blender + +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.blender.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + +ORIGINAL_EXCEPTHOOK = sys.excepthook + + +def pype_excepthook_handler(*args): + traceback.print_exception(*args) + + +def install(): + """Install Blender configuration for Avalon.""" + sys.excepthook = pype_excepthook_handler + pyblish.register_plugin_path(str(PUBLISH_PATH)) + avalon.register_plugin_path(avalon.Loader, str(LOAD_PATH)) + avalon.register_plugin_path(avalon.Creator, str(CREATE_PATH)) + + avalon.on("new", on_new) + avalon.on("open", on_open) + + +def uninstall(): + """Uninstall Blender configuration for Avalon.""" + sys.excepthook = ORIGINAL_EXCEPTHOOK + pyblish.deregister_plugin_path(str(PUBLISH_PATH)) + avalon.deregister_plugin_path(avalon.Loader, str(LOAD_PATH)) + avalon.deregister_plugin_path(avalon.Creator, str(CREATE_PATH)) + + +def set_start_end_frames(): + from avalon import io + + asset_name = io.Session["AVALON_ASSET"] + asset_doc = io.find_one({ + "type": "asset", + "name": asset_name + }) + + bpy.context.scene.frame_start = asset_doc["data"]["frameStart"] + bpy.context.scene.frame_end = asset_doc["data"]["frameEnd"] + + +def on_new(arg1, arg2): + set_start_end_frames() + + +def on_open(arg1, arg2): + set_start_end_frames() diff --git a/pype/hosts/blender/action.py b/pype/hosts/blender/api/action.py similarity index 96% rename from pype/hosts/blender/action.py rename to pype/hosts/blender/api/action.py index 78d00f56ad..b140688670 100644 --- a/pype/hosts/blender/action.py +++ b/pype/hosts/blender/api/action.py @@ -2,7 +2,7 @@ import bpy import pyblish.api -from ...action import get_errored_instances_from_context +from pype.api import get_errored_instances_from_context class SelectInvalidAction(pyblish.api.Action): diff --git a/pype/hosts/blender/plugin.py b/pype/hosts/blender/api/plugin.py similarity index 100% rename from pype/hosts/blender/plugin.py rename to pype/hosts/blender/api/plugin.py diff --git a/pype/plugins/__init__.py b/pype/hosts/blender/plugins/__init__.py similarity index 100% rename from pype/plugins/__init__.py rename to pype/hosts/blender/plugins/__init__.py diff --git a/pype/plugins/maya/__init__.py b/pype/hosts/blender/plugins/create/__init__.py similarity index 100% rename from pype/plugins/maya/__init__.py rename to pype/hosts/blender/plugins/create/__init__.py diff --git a/pype/plugins/blender/create/create_action.py b/pype/hosts/blender/plugins/create/create_action.py similarity index 91% rename from pype/plugins/blender/create/create_action.py rename to pype/hosts/blender/plugins/create/create_action.py index f5273863c4..d402998843 100644 --- a/pype/plugins/blender/create/create_action.py +++ b/pype/hosts/blender/plugins/create/create_action.py @@ -4,7 +4,7 @@ import bpy from avalon import api from avalon.blender import Creator, lib -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateAction(Creator): @@ -19,7 +19,7 @@ class CreateAction(Creator): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_animation.py b/pype/hosts/blender/plugins/create/create_animation.py similarity index 87% rename from pype/plugins/blender/create/create_animation.py rename to pype/hosts/blender/plugins/create/create_animation.py index acfd6ac1f3..9d68768201 100644 --- a/pype/plugins/blender/create/create_animation.py +++ b/pype/hosts/blender/plugins/create/create_animation.py @@ -3,7 +3,7 @@ import bpy from avalon import api, blender -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateAnimation(blender.Creator): @@ -17,7 +17,7 @@ class CreateAnimation(blender.Creator): def process(self): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_camera.py b/pype/hosts/blender/plugins/create/create_camera.py similarity index 87% rename from pype/plugins/blender/create/create_camera.py rename to pype/hosts/blender/plugins/create/create_camera.py index 5817985053..a40ddc63d4 100644 --- a/pype/plugins/blender/create/create_camera.py +++ b/pype/hosts/blender/plugins/create/create_camera.py @@ -4,7 +4,7 @@ import bpy from avalon import api from avalon.blender import Creator, lib -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateCamera(Creator): @@ -19,7 +19,7 @@ class CreateCamera(Creator): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_layout.py b/pype/hosts/blender/plugins/create/create_layout.py similarity index 91% rename from pype/plugins/blender/create/create_layout.py rename to pype/hosts/blender/plugins/create/create_layout.py index 010eec539b..ef765d741b 100644 --- a/pype/plugins/blender/create/create_layout.py +++ b/pype/hosts/blender/plugins/create/create_layout.py @@ -4,7 +4,7 @@ import bpy from avalon import api from avalon.blender import Creator, lib -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateLayout(Creator): @@ -19,7 +19,7 @@ class CreateLayout(Creator): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_model.py b/pype/hosts/blender/plugins/create/create_model.py similarity index 87% rename from pype/plugins/blender/create/create_model.py rename to pype/hosts/blender/plugins/create/create_model.py index 59905edc41..2bf8aedb48 100644 --- a/pype/plugins/blender/create/create_model.py +++ b/pype/hosts/blender/plugins/create/create_model.py @@ -4,7 +4,7 @@ import bpy from avalon import api from avalon.blender import Creator, lib -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateModel(Creator): @@ -19,7 +19,7 @@ class CreateModel(Creator): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_rig.py b/pype/hosts/blender/plugins/create/create_rig.py similarity index 92% rename from pype/plugins/blender/create/create_rig.py rename to pype/hosts/blender/plugins/create/create_rig.py index 5c85bf969d..f3efa824f4 100644 --- a/pype/plugins/blender/create/create_rig.py +++ b/pype/hosts/blender/plugins/create/create_rig.py @@ -4,7 +4,7 @@ import bpy from avalon import api from avalon.blender import Creator, lib -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateRig(Creator): @@ -19,7 +19,7 @@ class CreateRig(Creator): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/blender/create/create_setdress.py b/pype/hosts/blender/plugins/create/create_setdress.py similarity index 84% rename from pype/plugins/blender/create/create_setdress.py rename to pype/hosts/blender/plugins/create/create_setdress.py index 06acf716e5..c918949216 100644 --- a/pype/plugins/blender/create/create_setdress.py +++ b/pype/hosts/blender/plugins/create/create_setdress.py @@ -1,7 +1,7 @@ import bpy from avalon import api, blender -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin class CreateSetDress(blender.Creator): """A grouped package of loaded content""" @@ -15,7 +15,7 @@ class CreateSetDress(blender.Creator): def process(self): asset = self.data["asset"] subset = self.data["subset"] - name = pype.hosts.blender.plugin.asset_name(asset, subset) + name = pype.hosts.blender.api.plugin.asset_name(asset, subset) collection = bpy.data.collections.new(name=name) bpy.context.scene.collection.children.link(collection) self.data['task'] = api.Session.get('AVALON_TASK') diff --git a/pype/plugins/maya/publish/__init__.py b/pype/hosts/blender/plugins/load/__init__.py similarity index 100% rename from pype/plugins/maya/publish/__init__.py rename to pype/hosts/blender/plugins/load/__init__.py diff --git a/pype/plugins/blender/load/load_action.py b/pype/hosts/blender/plugins/load/load_action.py similarity index 96% rename from pype/plugins/blender/load/load_action.py rename to pype/hosts/blender/plugins/load/load_action.py index 1f2a870640..79e42995b3 100644 --- a/pype/plugins/blender/load/load_action.py +++ b/pype/hosts/blender/plugins/load/load_action.py @@ -7,12 +7,12 @@ from typing import Dict, List, Optional from avalon import api, blender import bpy -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin logger = logging.getLogger("pype").getChild("blender").getChild("load_action") -class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader): +class BlendActionLoader(pype.hosts.blender.api.plugin.AssetLoader): """Load action from a .blend file. Warning: @@ -42,8 +42,8 @@ class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader): libpath = self.fname asset = context["asset"]["name"] subset = context["subset"]["name"] - lib_container = pype.hosts.blender.plugin.asset_name(asset, subset) - container_name = pype.hosts.blender.plugin.asset_name( + lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset) + container_name = pype.hosts.blender.api.plugin.asset_name( asset, subset, namespace ) @@ -149,7 +149,7 @@ class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader): assert libpath.is_file(), ( f"The file doesn't exist: {libpath}" ) - assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, ( + assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, ( f"Unsupported file: {libpath}" ) diff --git a/pype/plugins/blender/load/load_animation.py b/pype/hosts/blender/plugins/load/load_animation.py similarity index 95% rename from pype/plugins/blender/load/load_animation.py rename to pype/hosts/blender/plugins/load/load_animation.py index 32050eca99..a1be6e99ed 100644 --- a/pype/plugins/blender/load/load_animation.py +++ b/pype/hosts/blender/plugins/load/load_animation.py @@ -7,14 +7,14 @@ from typing import Dict, List, Optional from avalon import api, blender import bpy -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin logger = logging.getLogger("pype").getChild( "blender").getChild("load_animation") -class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader): +class BlendAnimationLoader(pype.hosts.blender.api.plugin.AssetLoader): """Load animations from a .blend file. Warning: @@ -105,8 +105,8 @@ class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader): libpath = self.fname asset = context["asset"]["name"] subset = context["subset"]["name"] - lib_container = pype.hosts.blender.plugin.asset_name(asset, subset) - container_name = pype.hosts.blender.plugin.asset_name( + lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset) + container_name = pype.hosts.blender.api.plugin.asset_name( asset, subset, namespace ) @@ -175,7 +175,7 @@ class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader): assert libpath.is_file(), ( f"The file doesn't exist: {libpath}" ) - assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, ( + assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, ( f"Unsupported file: {libpath}" ) diff --git a/pype/plugins/blender/load/load_camera.py b/pype/hosts/blender/plugins/load/load_camera.py similarity index 95% rename from pype/plugins/blender/load/load_camera.py rename to pype/hosts/blender/plugins/load/load_camera.py index eb53870d5c..e6aa11af7e 100644 --- a/pype/plugins/blender/load/load_camera.py +++ b/pype/hosts/blender/plugins/load/load_camera.py @@ -7,12 +7,12 @@ from typing import Dict, List, Optional from avalon import api, blender import bpy -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin logger = logging.getLogger("pype").getChild("blender").getChild("load_camera") -class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader): +class BlendCameraLoader(pype.hosts.blender.api.plugin.AssetLoader): """Load a camera from a .blend file. Warning: @@ -92,8 +92,8 @@ class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader): libpath = self.fname asset = context["asset"]["name"] subset = context["subset"]["name"] - lib_container = pype.hosts.blender.plugin.asset_name(asset, subset) - container_name = pype.hosts.blender.plugin.asset_name( + lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset) + container_name = pype.hosts.blender.api.plugin.asset_name( asset, subset, namespace ) @@ -162,7 +162,7 @@ class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader): assert libpath.is_file(), ( f"The file doesn't exist: {libpath}" ) - assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, ( + assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, ( f"Unsupported file: {libpath}" ) diff --git a/pype/plugins/blender/load/load_layout.py b/pype/hosts/blender/plugins/load/load_layout.py similarity index 99% rename from pype/plugins/blender/load/load_layout.py rename to pype/hosts/blender/plugins/load/load_layout.py index c8ef73aea3..6c1afafbee 100644 --- a/pype/plugins/blender/load/load_layout.py +++ b/pype/hosts/blender/plugins/load/load_layout.py @@ -11,7 +11,7 @@ from typing import Dict, List, Optional from avalon import api, blender, pipeline import bpy -import pype.hosts.blender.plugin as plugin +import pype.hosts.blender.api.plugin as plugin class BlendLayoutLoader(plugin.AssetLoader): diff --git a/pype/plugins/blender/load/load_model.py b/pype/hosts/blender/plugins/load/load_model.py similarity index 99% rename from pype/plugins/blender/load/load_model.py rename to pype/hosts/blender/plugins/load/load_model.py index 59dc00726d..f48c0f8f94 100644 --- a/pype/plugins/blender/load/load_model.py +++ b/pype/hosts/blender/plugins/load/load_model.py @@ -7,7 +7,7 @@ from typing import Dict, List, Optional from avalon import api, blender import bpy -import pype.hosts.blender.plugin as plugin +import pype.hosts.blender.api.plugin as plugin class BlendModelLoader(plugin.AssetLoader): diff --git a/pype/plugins/blender/load/load_rig.py b/pype/hosts/blender/plugins/load/load_rig.py similarity index 99% rename from pype/plugins/blender/load/load_rig.py rename to pype/hosts/blender/plugins/load/load_rig.py index 12017fdbb2..1cc722045c 100644 --- a/pype/plugins/blender/load/load_rig.py +++ b/pype/hosts/blender/plugins/load/load_rig.py @@ -7,7 +7,7 @@ from typing import Dict, List, Optional from avalon import api, blender import bpy -import pype.hosts.blender.plugin as plugin +import pype.hosts.blender.api.plugin as plugin class BlendRigLoader(plugin.AssetLoader): diff --git a/pype/hosts/blender/plugins/publish/__init__.py b/pype/hosts/blender/plugins/publish/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/blender/publish/collect_current_file.py b/pype/hosts/blender/plugins/publish/collect_current_file.py similarity index 100% rename from pype/plugins/blender/publish/collect_current_file.py rename to pype/hosts/blender/plugins/publish/collect_current_file.py diff --git a/pype/plugins/blender/publish/collect_instances.py b/pype/hosts/blender/plugins/publish/collect_instances.py similarity index 100% rename from pype/plugins/blender/publish/collect_instances.py rename to pype/hosts/blender/plugins/publish/collect_instances.py diff --git a/pype/plugins/blender/publish/extract_abc.py b/pype/hosts/blender/plugins/publish/extract_abc.py similarity index 94% rename from pype/plugins/blender/publish/extract_abc.py rename to pype/hosts/blender/plugins/publish/extract_abc.py index 41c9c268f7..949b28df51 100644 --- a/pype/plugins/blender/publish/extract_abc.py +++ b/pype/hosts/blender/plugins/publish/extract_abc.py @@ -1,7 +1,7 @@ import os import pype.api -import pype.hosts.blender.plugin +import pype.hosts.blender.api.plugin import bpy @@ -61,7 +61,8 @@ class ExtractABC(pype.api.Extractor): except: continue - new_context = pype.hosts.blender.plugin.create_blender_context(active=selected[0], selected=selected) + new_context = pype.hosts.blender.api.plugin.create_blender_context( + active=selected[0], selected=selected) # We set the scale of the scene for the export scene.unit_settings.scale_length = 0.01 diff --git a/pype/plugins/blender/publish/extract_animation_collection.py b/pype/hosts/blender/plugins/publish/extract_animation_collection.py similarity index 61% rename from pype/plugins/blender/publish/extract_animation_collection.py rename to pype/hosts/blender/plugins/publish/extract_animation_collection.py index e5e0877280..0cdd17cf1f 100644 --- a/pype/plugins/blender/publish/extract_animation_collection.py +++ b/pype/hosts/blender/plugins/publish/extract_animation_collection.py @@ -6,6 +6,7 @@ import pyblish.api import bpy + class ExtractSetDress(pype.api.Extractor): """Extract setdress.""" @@ -21,17 +22,20 @@ class ExtractSetDress(pype.api.Extractor): json_data = [] for i in instance.context: - collection = i.data.get('name') + collection = i.data.get("name") container = None for obj in bpy.data.collections[collection].objects: - if obj.type == 'ARMATURE': - container_name = obj.get('avalon').get('container_name') + if obj.type == "ARMATURE": + container_name = obj.get("avalon").get("container_name") container = bpy.data.collections[container_name] if container: - json_dict = {} - json_dict['subset'] = i.data.get('subset') - json_dict['container'] = container.name - json_dict['instance_name'] = container.get('avalon').get('instance_name') + json_dict = { + "subset": i.data.get("subset"), + "container": container.name, + } + json_dict["instance_name"] = container.get("avalon").get( + "instance_name" + ) json_data.append(json_dict) if "representations" not in instance.data: @@ -44,13 +48,14 @@ class ExtractSetDress(pype.api.Extractor): json.dump(json_data, fp=file, indent=2) json_representation = { - 'name': 'json', - 'ext': 'json', - 'files': json_filename, + "name": "json", + "ext": "json", + "files": json_filename, "stagingDir": stagingdir, } instance.data["representations"].append(json_representation) - self.log.info("Extracted instance '{}' to: {}".format( - instance.name, json_representation)) - + self.log.info( + "Extracted instance '{}' to: {}".format(instance.name, + json_representation) + ) diff --git a/pype/plugins/blender/publish/extract_blend.py b/pype/hosts/blender/plugins/publish/extract_blend.py similarity index 96% rename from pype/plugins/blender/publish/extract_blend.py rename to pype/hosts/blender/plugins/publish/extract_blend.py index a5e76dcf4e..6ba28d039a 100644 --- a/pype/plugins/blender/publish/extract_blend.py +++ b/pype/hosts/blender/plugins/publish/extract_blend.py @@ -1,47 +1,47 @@ -import os -import avalon.blender.workio - -import pype.api - - -class ExtractBlend(pype.api.Extractor): - """Extract a blend file.""" - - label = "Extract Blend" - hosts = ["blender"] - families = ["model", "camera", "rig", "action", "layout", "animation"] - optional = True - - def process(self, instance): - # Define extract output file path - - stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.blend" - filepath = os.path.join(stagingdir, filename) - - # Perform extraction - self.log.info("Performing extraction..") - - # Just save the file to a temporary location. At least for now it's no - # problem to have (possibly) extra stuff in the file. - avalon.blender.workio.save_file(filepath, copy=True) - # - # # Store reference for integration - # if "files" not in instance.data: - # instance.data["files"] = list() - # - # # instance.data["files"].append(filename) - - if "representations" not in instance.data: - instance.data["representations"] = [] - - representation = { - 'name': 'blend', - 'ext': 'blend', - 'files': filename, - "stagingDir": stagingdir, - } - instance.data["representations"].append(representation) - - self.log.info("Extracted instance '%s' to: %s", - instance.name, representation) +import os +import avalon.blender.workio + +import pype.api + + +class ExtractBlend(pype.api.Extractor): + """Extract a blend file.""" + + label = "Extract Blend" + hosts = ["blender"] + families = ["model", "camera", "rig", "action", "layout", "animation"] + optional = True + + def process(self, instance): + # Define extract output file path + + stagingdir = self.staging_dir(instance) + filename = f"{instance.name}.blend" + filepath = os.path.join(stagingdir, filename) + + # Perform extraction + self.log.info("Performing extraction..") + + # Just save the file to a temporary location. At least for now it's no + # problem to have (possibly) extra stuff in the file. + avalon.blender.workio.save_file(filepath, copy=True) + # + # # Store reference for integration + # if "files" not in instance.data: + # instance.data["files"] = list() + # + # # instance.data["files"].append(filename) + + if "representations" not in instance.data: + instance.data["representations"] = [] + + representation = { + 'name': 'blend', + 'ext': 'blend', + 'files': filename, + "stagingDir": stagingdir, + } + instance.data["representations"].append(representation) + + self.log.info("Extracted instance '%s' to: %s", + instance.name, representation) diff --git a/pype/plugins/blender/publish/extract_fbx.py b/pype/hosts/blender/plugins/publish/extract_fbx.py similarity index 100% rename from pype/plugins/blender/publish/extract_fbx.py rename to pype/hosts/blender/plugins/publish/extract_fbx.py diff --git a/pype/plugins/blender/publish/extract_fbx_animation.py b/pype/hosts/blender/plugins/publish/extract_fbx_animation.py similarity index 100% rename from pype/plugins/blender/publish/extract_fbx_animation.py rename to pype/hosts/blender/plugins/publish/extract_fbx_animation.py diff --git a/pype/plugins/blender/publish/increment_workfile_version.py b/pype/hosts/blender/plugins/publish/increment_workfile_version.py similarity index 100% rename from pype/plugins/blender/publish/increment_workfile_version.py rename to pype/hosts/blender/plugins/publish/increment_workfile_version.py diff --git a/pype/plugins/blender/publish/integrate_animation.py b/pype/hosts/blender/plugins/publish/integrate_animation.py similarity index 100% rename from pype/plugins/blender/publish/integrate_animation.py rename to pype/hosts/blender/plugins/publish/integrate_animation.py diff --git a/pype/plugins/blender/publish/validate_mesh_has_uv.py b/pype/hosts/blender/plugins/publish/validate_mesh_has_uv.py similarity index 93% rename from pype/plugins/blender/publish/validate_mesh_has_uv.py rename to pype/hosts/blender/plugins/publish/validate_mesh_has_uv.py index ea5e12918a..c415ea0e0d 100644 --- a/pype/plugins/blender/publish/validate_mesh_has_uv.py +++ b/pype/hosts/blender/plugins/publish/validate_mesh_has_uv.py @@ -3,7 +3,7 @@ from typing import List import bpy import pyblish.api -import pype.hosts.blender.action +import pype.hosts.blender.api.action class ValidateMeshHasUvs(pyblish.api.InstancePlugin): @@ -14,7 +14,7 @@ class ValidateMeshHasUvs(pyblish.api.InstancePlugin): families = ["model"] category = "geometry" label = "Mesh Has UV's" - actions = [pype.hosts.blender.action.SelectInvalidAction] + actions = [pype.hosts.blender.api.action.SelectInvalidAction] optional = True @staticmethod diff --git a/pype/plugins/blender/publish/validate_mesh_no_negative_scale.py b/pype/hosts/blender/plugins/publish/validate_mesh_no_negative_scale.py similarity index 89% rename from pype/plugins/blender/publish/validate_mesh_no_negative_scale.py rename to pype/hosts/blender/plugins/publish/validate_mesh_no_negative_scale.py index 77057c0e68..bbce37f3db 100644 --- a/pype/plugins/blender/publish/validate_mesh_no_negative_scale.py +++ b/pype/hosts/blender/plugins/publish/validate_mesh_no_negative_scale.py @@ -3,7 +3,7 @@ from typing import List import bpy import pyblish.api -import pype.hosts.blender.action +import pype.hosts.blender.api.action class ValidateMeshNoNegativeScale(pyblish.api.Validator): @@ -13,7 +13,7 @@ class ValidateMeshNoNegativeScale(pyblish.api.Validator): hosts = ["blender"] families = ["model"] label = "Mesh No Negative Scale" - actions = [pype.hosts.blender.action.SelectInvalidAction] + actions = [pype.hosts.blender.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance) -> List: diff --git a/pype/hosts/blender/startup/init.py b/pype/hosts/blender/startup/init.py new file mode 100644 index 0000000000..75fe4d30f7 --- /dev/null +++ b/pype/hosts/blender/startup/init.py @@ -0,0 +1,3 @@ +from pype.hosts.blender import api + +api.install() diff --git a/pype/hosts/celaction/__init__.py b/pype/hosts/celaction/__init__.py index 8c93d93738..e69de29bb2 100644 --- a/pype/hosts/celaction/__init__.py +++ b/pype/hosts/celaction/__init__.py @@ -1 +0,0 @@ -kwargs = None diff --git a/pype/hosts/celaction/api/__init__.py b/pype/hosts/celaction/api/__init__.py new file mode 100644 index 0000000000..8c93d93738 --- /dev/null +++ b/pype/hosts/celaction/api/__init__.py @@ -0,0 +1 @@ +kwargs = None diff --git a/pype/hosts/celaction/cli.py b/pype/hosts/celaction/api/cli.py similarity index 87% rename from pype/hosts/celaction/cli.py rename to pype/hosts/celaction/api/cli.py index 42f7a1a385..9f2d1a1fdb 100644 --- a/pype/hosts/celaction/cli.py +++ b/pype/hosts/celaction/api/cli.py @@ -11,18 +11,19 @@ import pyblish.util from pype.api import Logger import pype -from pype.hosts import celaction +import pype.hosts.celaction +from pype.hosts.celaction import api as celaction log = Logger().get_logger("Celaction_cli_publisher") publish_host = "celaction" -PUBLISH_PATH = os.path.join(pype.PLUGINS_DIR, publish_host, "publish") - -PUBLISH_PATHS = [ - PUBLISH_PATH, - os.path.join(pype.PLUGINS_DIR, "ftrack", "publish") -] +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.celaction.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") def cli(): diff --git a/pype/hosts/celaction/hooks/__init__.py b/pype/hosts/celaction/hooks/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hosts/celaction/hooks/pre_celaction_registers.py similarity index 91% rename from pype/hooks/celaction/pre_celaction_registers.py rename to pype/hosts/celaction/hooks/pre_celaction_registers.py index 04ecf82c5c..8f6b1b72bb 100644 --- a/pype/hooks/celaction/pre_celaction_registers.py +++ b/pype/hosts/celaction/hooks/pre_celaction_registers.py @@ -2,15 +2,12 @@ import os import shutil import winreg from pype.lib import PreLaunchHook -from pype.hosts import celaction +from pype.hosts.celaction import api as celaction class CelactionPrelaunchHook(PreLaunchHook): """ - This hook will check if current workfile path has Unreal - project inside. IF not, it initialize it and finally it pass - path to the project by environment variable to Unreal launcher - shell script. + Bootstrap celacion with pype """ workfile_ext = "scn" app_groups = ["celaction"] @@ -37,7 +34,7 @@ class CelactionPrelaunchHook(PreLaunchHook): "Software\\CelAction\\CelAction2D\\User Settings", 0, winreg.KEY_ALL_ACCESS) - # TODO: change to root path and pyblish standalone to premiere way + # TODO: change to pype executable pype_root_path = os.getenv("PYPE_SETUP_PATH") path = os.path.join(pype_root_path, "pype.bat") @@ -94,11 +91,12 @@ class CelactionPrelaunchHook(PreLaunchHook): if not os.path.exists(workfile_path): # TODO add ability to set different template workfile path via # settings - pype_celaction_dir = os.path.dirname( + pype_celaction_dir = os.path.dirname(os.path.dirname( os.path.abspath(celaction.__file__) - ) + )) template_path = os.path.join( pype_celaction_dir, + "resources", "celaction_template_scene.scn" ) diff --git a/pype/hosts/celaction/plugins/__init__.py b/pype/hosts/celaction/plugins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/celaction/publish/collect_audio.py b/pype/hosts/celaction/plugins/publish/collect_audio.py similarity index 97% rename from pype/plugins/celaction/publish/collect_audio.py rename to pype/hosts/celaction/plugins/publish/collect_audio.py index bab1203642..8d3c1568e6 100644 --- a/pype/plugins/celaction/publish/collect_audio.py +++ b/pype/hosts/celaction/plugins/publish/collect_audio.py @@ -1,126 +1,126 @@ -import os -import collections - -import pyblish.api -from avalon import io - -from pprint import pformat - - -class AppendCelactionAudio(pyblish.api.ContextPlugin): - - label = "Colect Audio for publishing" - order = pyblish.api.CollectorOrder + 0.1 - - def process(self, context): - self.log.info('Collecting Audio Data') - asset_doc = context.data["assetEntity"] - - # get all available representations - subsets = self.get_subsets( - asset_doc, - representations=["audio", "wav"] - ) - self.log.info(f"subsets is: {pformat(subsets)}") - - if not subsets.get("audioMain"): - raise AttributeError("`audioMain` subset does not exist") - - reprs = subsets.get("audioMain", {}).get("representations", []) - self.log.info(f"reprs is: {pformat(reprs)}") - - repr = next((r for r in reprs), None) - if not repr: - raise "Missing `audioMain` representation" - self.log.info(f"represetation is: {repr}") - - audio_file = repr.get('data', {}).get('path', "") - - if os.path.exists(audio_file): - context.data["audioFile"] = audio_file - self.log.info( - 'audio_file: {}, has been added to context'.format(audio_file)) - else: - self.log.warning("Couldn't find any audio file on Ftrack.") - - def get_subsets(self, asset_doc, representations): - """ - Query subsets with filter on name. - - The method will return all found subsets and its defined version - and subsets. Version could be specified with number. Representation - can be filtered. - - Arguments: - asset_doct (dict): Asset (shot) mongo document - representations (list): list for all representations - - Returns: - dict: subsets with version and representaions in keys - """ - - # Query all subsets for asset - subset_docs = io.find({ - "type": "subset", - "parent": asset_doc["_id"] - }) - # Collect all subset ids - subset_ids = [ - subset_doc["_id"] - for subset_doc in subset_docs - ] - - # Check if we found anything - assert subset_ids, ( - "No subsets found. Check correct filter. " - "Try this for start `r'.*'`: asset: `{}`" - ).format(asset_doc["name"]) - - # Last version aggregation - pipeline = [ - # Find all versions of those subsets - {"$match": { - "type": "version", - "parent": {"$in": subset_ids} - }}, - # Sorting versions all together - {"$sort": {"name": 1}}, - # Group them by "parent", but only take the last - {"$group": { - "_id": "$parent", - "_version_id": {"$last": "$_id"}, - "name": {"$last": "$name"} - }} - ] - last_versions_by_subset_id = dict() - for doc in io.aggregate(pipeline): - doc["parent"] = doc["_id"] - doc["_id"] = doc.pop("_version_id") - last_versions_by_subset_id[doc["parent"]] = doc - - version_docs_by_id = {} - for version_doc in last_versions_by_subset_id.values(): - version_docs_by_id[version_doc["_id"]] = version_doc - - repre_docs = io.find({ - "type": "representation", - "parent": {"$in": list(version_docs_by_id.keys())}, - "name": {"$in": representations} - }) - repre_docs_by_version_id = collections.defaultdict(list) - for repre_doc in repre_docs: - version_id = repre_doc["parent"] - repre_docs_by_version_id[version_id].append(repre_doc) - - output_dict = {} - for version_id, repre_docs in repre_docs_by_version_id.items(): - version_doc = version_docs_by_id[version_id] - subset_id = version_doc["parent"] - subset_doc = last_versions_by_subset_id[subset_id] - # Store queried docs by subset name - output_dict[subset_doc["name"]] = { - "representations": repre_docs, - "version": version_doc - } - - return output_dict +import os +import collections + +import pyblish.api +from avalon import io + +from pprint import pformat + + +class AppendCelactionAudio(pyblish.api.ContextPlugin): + + label = "Colect Audio for publishing" + order = pyblish.api.CollectorOrder + 0.1 + + def process(self, context): + self.log.info('Collecting Audio Data') + asset_doc = context.data["assetEntity"] + + # get all available representations + subsets = self.get_subsets( + asset_doc, + representations=["audio", "wav"] + ) + self.log.info(f"subsets is: {pformat(subsets)}") + + if not subsets.get("audioMain"): + raise AttributeError("`audioMain` subset does not exist") + + reprs = subsets.get("audioMain", {}).get("representations", []) + self.log.info(f"reprs is: {pformat(reprs)}") + + repr = next((r for r in reprs), None) + if not repr: + raise "Missing `audioMain` representation" + self.log.info(f"represetation is: {repr}") + + audio_file = repr.get('data', {}).get('path', "") + + if os.path.exists(audio_file): + context.data["audioFile"] = audio_file + self.log.info( + 'audio_file: {}, has been added to context'.format(audio_file)) + else: + self.log.warning("Couldn't find any audio file on Ftrack.") + + def get_subsets(self, asset_doc, representations): + """ + Query subsets with filter on name. + + The method will return all found subsets and its defined version + and subsets. Version could be specified with number. Representation + can be filtered. + + Arguments: + asset_doct (dict): Asset (shot) mongo document + representations (list): list for all representations + + Returns: + dict: subsets with version and representaions in keys + """ + + # Query all subsets for asset + subset_docs = io.find({ + "type": "subset", + "parent": asset_doc["_id"] + }) + # Collect all subset ids + subset_ids = [ + subset_doc["_id"] + for subset_doc in subset_docs + ] + + # Check if we found anything + assert subset_ids, ( + "No subsets found. Check correct filter. " + "Try this for start `r'.*'`: asset: `{}`" + ).format(asset_doc["name"]) + + # Last version aggregation + pipeline = [ + # Find all versions of those subsets + {"$match": { + "type": "version", + "parent": {"$in": subset_ids} + }}, + # Sorting versions all together + {"$sort": {"name": 1}}, + # Group them by "parent", but only take the last + {"$group": { + "_id": "$parent", + "_version_id": {"$last": "$_id"}, + "name": {"$last": "$name"} + }} + ] + last_versions_by_subset_id = dict() + for doc in io.aggregate(pipeline): + doc["parent"] = doc["_id"] + doc["_id"] = doc.pop("_version_id") + last_versions_by_subset_id[doc["parent"]] = doc + + version_docs_by_id = {} + for version_doc in last_versions_by_subset_id.values(): + version_docs_by_id[version_doc["_id"]] = version_doc + + repre_docs = io.find({ + "type": "representation", + "parent": {"$in": list(version_docs_by_id.keys())}, + "name": {"$in": representations} + }) + repre_docs_by_version_id = collections.defaultdict(list) + for repre_doc in repre_docs: + version_id = repre_doc["parent"] + repre_docs_by_version_id[version_id].append(repre_doc) + + output_dict = {} + for version_id, repre_docs in repre_docs_by_version_id.items(): + version_doc = version_docs_by_id[version_id] + subset_id = version_doc["parent"] + subset_doc = last_versions_by_subset_id[subset_id] + # Store queried docs by subset name + output_dict[subset_doc["name"]] = { + "representations": repre_docs, + "version": version_doc + } + + return output_dict diff --git a/pype/plugins/celaction/publish/collect_celaction_cli_kwargs.py b/pype/hosts/celaction/plugins/publish/collect_celaction_cli_kwargs.py similarity index 92% rename from pype/plugins/celaction/publish/collect_celaction_cli_kwargs.py rename to pype/hosts/celaction/plugins/publish/collect_celaction_cli_kwargs.py index f4a9ec341d..463805ce4b 100644 --- a/pype/plugins/celaction/publish/collect_celaction_cli_kwargs.py +++ b/pype/hosts/celaction/plugins/publish/collect_celaction_cli_kwargs.py @@ -1,23 +1,23 @@ -import pyblish.api -from pype.hosts import celaction - - -class CollectCelactionCliKwargs(pyblish.api.Collector): - """ Collects all keyword arguments passed from the terminal """ - - label = "Collect Celaction Cli Kwargs" - order = pyblish.api.Collector.order - 0.1 - - def process(self, context): - kwargs = celaction.kwargs.copy() - - self.log.info("Storing kwargs: %s" % kwargs) - context.set_data("kwargs", kwargs) - - # get kwargs onto context data as keys with values - for k, v in kwargs.items(): - self.log.info(f"Setting `{k}` to instance.data with value: `{v}`") - if k in ["frameStart", "frameEnd"]: - context.data[k] = kwargs[k] = int(v) - else: - context.data[k] = v +import pyblish.api +from pype.hosts.celaction import api as celaction + + +class CollectCelactionCliKwargs(pyblish.api.Collector): + """ Collects all keyword arguments passed from the terminal """ + + label = "Collect Celaction Cli Kwargs" + order = pyblish.api.Collector.order - 0.1 + + def process(self, context): + kwargs = celaction.kwargs.copy() + + self.log.info("Storing kwargs: %s" % kwargs) + context.set_data("kwargs", kwargs) + + # get kwargs onto context data as keys with values + for k, v in kwargs.items(): + self.log.info(f"Setting `{k}` to instance.data with value: `{v}`") + if k in ["frameStart", "frameEnd"]: + context.data[k] = kwargs[k] = int(v) + else: + context.data[k] = v diff --git a/pype/plugins/celaction/publish/collect_celaction_instances.py b/pype/hosts/celaction/plugins/publish/collect_celaction_instances.py similarity index 97% rename from pype/plugins/celaction/publish/collect_celaction_instances.py rename to pype/hosts/celaction/plugins/publish/collect_celaction_instances.py index d3d1d264c0..f393e471c4 100644 --- a/pype/plugins/celaction/publish/collect_celaction_instances.py +++ b/pype/hosts/celaction/plugins/publish/collect_celaction_instances.py @@ -1,96 +1,96 @@ -import os -from avalon import api -import pyblish.api - - -class CollectCelactionInstances(pyblish.api.ContextPlugin): - """ Adds the celaction render instances """ - - label = "Collect Celaction Instances" - order = pyblish.api.CollectorOrder + 0.1 - - def process(self, context): - task = api.Session["AVALON_TASK"] - current_file = context.data["currentFile"] - staging_dir = os.path.dirname(current_file) - scene_file = os.path.basename(current_file) - version = context.data["version"] - asset_entity = context.data["assetEntity"] - project_entity = context.data["projectEntity"] - - shared_instance_data = { - "asset": asset_entity["name"], - "frameStart": asset_entity["data"]["frameStart"], - "frameEnd": asset_entity["data"]["frameEnd"], - "handleStart": asset_entity["data"]["handleStart"], - "handleEnd": asset_entity["data"]["handleEnd"], - "fps": asset_entity["data"]["fps"], - "resolutionWidth": asset_entity["data"].get( - "resolutionWidth", - project_entity["data"]["resolutionWidth"]), - "resolutionHeight": asset_entity["data"].get( - "resolutionHeight", - project_entity["data"]["resolutionHeight"]), - "pixelAspect": 1, - "step": 1, - "version": version - } - - celaction_kwargs = context.data.get("kwargs", {}) - - if celaction_kwargs: - shared_instance_data.update(celaction_kwargs) - - # workfile instance - family = "workfile" - subset = family + task.capitalize() - # Create instance - instance = context.create_instance(subset) - - # creating instance data - instance.data.update({ - "subset": subset, - "label": scene_file, - "family": family, - "families": [family, "ftrack"], - "representations": list() - }) - - # adding basic script data - instance.data.update(shared_instance_data) - - # creating representation - representation = { - 'name': 'scn', - 'ext': 'scn', - 'files': scene_file, - "stagingDir": staging_dir, - } - - instance.data["representations"].append(representation) - - self.log.info('Publishing Celaction workfile') - - # render instance - family = "render.farm" - subset = f"render{task}Main" - instance = context.create_instance(name=subset) - # getting instance state - instance.data["publish"] = True - - # add assetEntity data into instance - instance.data.update({ - "label": "{} - farm".format(subset), - "family": family, - "families": [family], - "subset": subset - }) - - # adding basic script data - instance.data.update(shared_instance_data) - - self.log.info('Publishing Celaction render instance') - self.log.debug(f"Instance data: `{instance.data}`") - - for i in context: - self.log.debug(f"{i.data['families']}") +import os +from avalon import api +import pyblish.api + + +class CollectCelactionInstances(pyblish.api.ContextPlugin): + """ Adds the celaction render instances """ + + label = "Collect Celaction Instances" + order = pyblish.api.CollectorOrder + 0.1 + + def process(self, context): + task = api.Session["AVALON_TASK"] + current_file = context.data["currentFile"] + staging_dir = os.path.dirname(current_file) + scene_file = os.path.basename(current_file) + version = context.data["version"] + asset_entity = context.data["assetEntity"] + project_entity = context.data["projectEntity"] + + shared_instance_data = { + "asset": asset_entity["name"], + "frameStart": asset_entity["data"]["frameStart"], + "frameEnd": asset_entity["data"]["frameEnd"], + "handleStart": asset_entity["data"]["handleStart"], + "handleEnd": asset_entity["data"]["handleEnd"], + "fps": asset_entity["data"]["fps"], + "resolutionWidth": asset_entity["data"].get( + "resolutionWidth", + project_entity["data"]["resolutionWidth"]), + "resolutionHeight": asset_entity["data"].get( + "resolutionHeight", + project_entity["data"]["resolutionHeight"]), + "pixelAspect": 1, + "step": 1, + "version": version + } + + celaction_kwargs = context.data.get("kwargs", {}) + + if celaction_kwargs: + shared_instance_data.update(celaction_kwargs) + + # workfile instance + family = "workfile" + subset = family + task.capitalize() + # Create instance + instance = context.create_instance(subset) + + # creating instance data + instance.data.update({ + "subset": subset, + "label": scene_file, + "family": family, + "families": [family, "ftrack"], + "representations": list() + }) + + # adding basic script data + instance.data.update(shared_instance_data) + + # creating representation + representation = { + 'name': 'scn', + 'ext': 'scn', + 'files': scene_file, + "stagingDir": staging_dir, + } + + instance.data["representations"].append(representation) + + self.log.info('Publishing Celaction workfile') + + # render instance + family = "render.farm" + subset = f"render{task}Main" + instance = context.create_instance(name=subset) + # getting instance state + instance.data["publish"] = True + + # add assetEntity data into instance + instance.data.update({ + "label": "{} - farm".format(subset), + "family": family, + "families": [family], + "subset": subset + }) + + # adding basic script data + instance.data.update(shared_instance_data) + + self.log.info('Publishing Celaction render instance') + self.log.debug(f"Instance data: `{instance.data}`") + + for i in context: + self.log.debug(f"{i.data['families']}") diff --git a/pype/plugins/celaction/publish/collect_render_path.py b/pype/hosts/celaction/plugins/publish/collect_render_path.py similarity index 100% rename from pype/plugins/celaction/publish/collect_render_path.py rename to pype/hosts/celaction/plugins/publish/collect_render_path.py diff --git a/pype/plugins/celaction/publish/integrate_version_up.py b/pype/hosts/celaction/plugins/publish/integrate_version_up.py similarity index 96% rename from pype/plugins/celaction/publish/integrate_version_up.py rename to pype/hosts/celaction/plugins/publish/integrate_version_up.py index e15c5d5bf6..140878e2b9 100644 --- a/pype/plugins/celaction/publish/integrate_version_up.py +++ b/pype/hosts/celaction/plugins/publish/integrate_version_up.py @@ -1,20 +1,20 @@ -import shutil -import pype -import pyblish.api - - -class VersionUpScene(pyblish.api.ContextPlugin): - order = pyblish.api.IntegratorOrder + 0.5 - label = 'Version Up Scene' - families = ['workfile'] - optional = True - active = True - - def process(self, context): - current_file = context.data.get('currentFile') - v_up = pype.lib.version_up(current_file) - self.log.debug('Current file is: {}'.format(current_file)) - self.log.debug('Version up: {}'.format(v_up)) - - shutil.copy2(current_file, v_up) - self.log.info('Scene saved into new version: {}'.format(v_up)) +import shutil +import pype +import pyblish.api + + +class VersionUpScene(pyblish.api.ContextPlugin): + order = pyblish.api.IntegratorOrder + 0.5 + label = 'Version Up Scene' + families = ['workfile'] + optional = True + active = True + + def process(self, context): + current_file = context.data.get('currentFile') + v_up = pype.lib.version_up(current_file) + self.log.debug('Current file is: {}'.format(current_file)) + self.log.debug('Version up: {}'.format(v_up)) + + shutil.copy2(current_file, v_up) + self.log.info('Scene saved into new version: {}'.format(v_up)) diff --git a/pype/plugins/celaction/publish/submit_celaction_deadline.py b/pype/hosts/celaction/plugins/publish/submit_celaction_deadline.py similarity index 100% rename from pype/plugins/celaction/publish/submit_celaction_deadline.py rename to pype/hosts/celaction/plugins/publish/submit_celaction_deadline.py diff --git a/pype/hosts/celaction/celaction_template_scene.scn b/pype/hosts/celaction/resources/celaction_template_scene.scn similarity index 100% rename from pype/hosts/celaction/celaction_template_scene.scn rename to pype/hosts/celaction/resources/celaction_template_scene.scn diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index b91c0ad4b1..390ede39d9 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -9,7 +9,7 @@ import avalon.tools.sceneinventory import pyblish.api from pype import lib -from pype.api import get_current_project_settings +from pype.api import (get_current_project_settings) def set_scene_settings(settings): @@ -48,20 +48,13 @@ def get_asset_settings(): "resolutionWidth": resolution_width, "resolutionHeight": resolution_height } + settings = get_current_project_settings() try: - skip_resolution_check = ( - get_current_project_settings() - ["harmony"] - ["general"] - ["skip_resolution_check"] - ) - skip_timelines_check = ( - get_current_project_settings() - ["harmony"] - ["general"] - ["skip_timelines_check"] - ) + skip_resolution_check = \ + settings["harmony"]["general"]["skip_resolution_check"] + skip_timelines_check = \ + settings["harmony"]["general"]["skip_timelines_check"] except KeyError: skip_resolution_check = [] skip_timelines_check = [] diff --git a/pype/hosts/harmony/js/PypeHarmony.js b/pype/hosts/harmony/js/PypeHarmony.js index a98dbd52cd..9d05384461 100644 --- a/pype/hosts/harmony/js/PypeHarmony.js +++ b/pype/hosts/harmony/js/PypeHarmony.js @@ -5,7 +5,7 @@ var LD_OPENHARMONY_PATH = System.getenv('LIB_OPENHARMONY_PATH'); include(LD_OPENHARMONY_PATH + '/openHarmony.js'); -this.__proto__['$'] = $; + /** @@ -79,7 +79,8 @@ PypeHarmony.getSceneSettings = function() { scene.getStopFrame(), sound.getSoundtrackAll().path(), scene.defaultResolutionX(), - scene.defaultResolutionY() + scene.defaultResolutionY(), + scene.defaultResolutionFOV() ]; }; @@ -200,3 +201,16 @@ PypeHarmony.getDependencies = function(_node) { } return dependencies; }; + + +/** + * return version of running Harmony instance. + * @function + * @return {array} [major_version, minor_version] + */ +PypeHarmony.getVersion = function() { + return [ + about.getMajorVersion(), + about.getMinorVersion() + ]; +}; diff --git a/pype/hosts/harmony/js/publish/CollectFarmRender.js b/pype/hosts/harmony/js/publish/CollectFarmRender.js new file mode 100644 index 0000000000..153c38e868 --- /dev/null +++ b/pype/hosts/harmony/js/publish/CollectFarmRender.js @@ -0,0 +1,52 @@ +/* global PypeHarmony:writable, include */ +// *************************************************************************** +// * CollectFarmRender * +// *************************************************************************** + + +// check if PypeHarmony is defined and if not, load it. +if (typeof PypeHarmony !== 'undefined') { + var PYPE_HARMONY_JS = System.getenv('PYPE_HARMONY_JS'); + include(PYPE_HARMONY_JS + '/pype_harmony.js'); +} + + +/** + * @namespace + * @classdesc Image Sequence loader JS code. + */ +var CollectFarmRender = function() {}; + + +/** + * Get information important for render output. + * @function + * @param node {String} node name. + * @return {array} array of render info. + * + * @example + * + * var ret = [ + * file_prefix, // like foo/bar- + * type, // PNG4, ... + * leading_zeros, // 3 - for 0001 + * start // start frame + * ] + */ +CollectFarmRender.prototype.getRenderNodeSettings = function(n) { + // this will return + var output = [ + node.getTextAttr( + n, frame.current(), 'DRAWING_NAME'), + node.getTextAttr( + n, frame.current(), 'DRAWING_TYPE'), + node.getTextAttr( + n, frame.current(), 'LEADING_ZEROS'), + node.getTextAttr(n, frame.current(), 'START') + ]; + + return output; +}; + +// add self to Pype Loaders +PypeHarmony.Publish.CollectFarmRender = new CollectFarmRender(); diff --git a/pype/hosts/houdini/__init__.py b/pype/hosts/houdini/__init__.py index 1da6a7774b..e69de29bb2 100644 --- a/pype/hosts/houdini/__init__.py +++ b/pype/hosts/houdini/__init__.py @@ -1,101 +0,0 @@ -import os -import logging - -import hou - -from pyblish import api as pyblish - -from avalon import api as avalon -from avalon.houdini import pipeline as houdini - -from pype.hosts.houdini import lib - -from pype.lib import any_outdated -from pype import PLUGINS_DIR - -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "houdini", "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "houdini", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "houdini", "create") - -log = logging.getLogger("pype.hosts.houdini") - - -def install(): - - pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - avalon.register_plugin_path(avalon.Creator, CREATE_PATH) - - log.info("Installing callbacks ... ") - avalon.on("init", on_init) - avalon.before("save", before_save) - avalon.on("save", on_save) - avalon.on("open", on_open) - - pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled) - - log.info("Setting default family states for loader..") - avalon.data["familiesStateToggled"] = ["imagesequence"] - - -def on_init(*args): - houdini.on_houdini_initialize() - - -def before_save(*args): - return lib.validate_fps() - - -def on_save(*args): - - avalon.logger.info("Running callback on save..") - - nodes = lib.get_id_required_nodes() - for node, new_id in lib.generate_ids(nodes): - lib.set_id(node, new_id, overwrite=False) - - -def on_open(*args): - - avalon.logger.info("Running callback on open..") - - if any_outdated(): - from ..widgets import popup - - log.warning("Scene has outdated content.") - - # Get main window - parent = hou.ui.mainQtWindow() - if parent is None: - log.info("Skipping outdated content pop-up " - "because Maya window can't be found.") - else: - - # Show outdated pop-up - def _on_show_inventory(): - import avalon.tools.sceneinventory as tool - tool.show(parent=parent) - - dialog = popup.Popup(parent=parent) - dialog.setWindowTitle("Maya scene has outdated content") - dialog.setMessage("There are outdated containers in " - "your Maya scene.") - dialog.on_show.connect(_on_show_inventory) - dialog.show() - - -def on_pyblish_instance_toggled(instance, new_value, old_value): - """Toggle saver tool passthrough states on instance toggles.""" - - nodes = instance[:] - if not nodes: - return - - # Assume instance node is first node - instance_node = nodes[0] - - if instance_node.isBypassed() != (not old_value): - print("%s old bypass state didn't match old instance state, " - "updating anyway.." % instance_node.path()) - - instance_node.bypass(not new_value) diff --git a/pype/hosts/houdini/api/__init__.py b/pype/hosts/houdini/api/__init__.py new file mode 100644 index 0000000000..c6012d1133 --- /dev/null +++ b/pype/hosts/houdini/api/__init__.py @@ -0,0 +1,103 @@ +import os +import logging + +import hou + +from pyblish import api as pyblish + +from avalon import api as avalon +from avalon.houdini import pipeline as houdini + +import pype.hosts.houdini +from pype.hosts.houdini.api import lib + +from pype.lib import any_outdated + +log = logging.getLogger("pype.hosts.houdini") + +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.houdini.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + +def install(): + + pyblish.register_plugin_path(PUBLISH_PATH) + avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + avalon.register_plugin_path(avalon.Creator, CREATE_PATH) + + log.info("Installing callbacks ... ") + avalon.on("init", on_init) + avalon.before("save", before_save) + avalon.on("save", on_save) + avalon.on("open", on_open) + + pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled) + + log.info("Setting default family states for loader..") + avalon.data["familiesStateToggled"] = ["imagesequence"] + + +def on_init(*args): + houdini.on_houdini_initialize() + + +def before_save(*args): + return lib.validate_fps() + + +def on_save(*args): + + avalon.logger.info("Running callback on save..") + + nodes = lib.get_id_required_nodes() + for node, new_id in lib.generate_ids(nodes): + lib.set_id(node, new_id, overwrite=False) + + +def on_open(*args): + + avalon.logger.info("Running callback on open..") + + if any_outdated(): + from ..widgets import popup + + log.warning("Scene has outdated content.") + + # Get main window + parent = hou.ui.mainQtWindow() + if parent is None: + log.info("Skipping outdated content pop-up " + "because Maya window can't be found.") + else: + + # Show outdated pop-up + def _on_show_inventory(): + import avalon.tools.sceneinventory as tool + tool.show(parent=parent) + + dialog = popup.Popup(parent=parent) + dialog.setWindowTitle("Maya scene has outdated content") + dialog.setMessage("There are outdated containers in " + "your Maya scene.") + dialog.on_show.connect(_on_show_inventory) + dialog.show() + + +def on_pyblish_instance_toggled(instance, new_value, old_value): + """Toggle saver tool passthrough states on instance toggles.""" + + nodes = instance[:] + if not nodes: + return + + # Assume instance node is first node + instance_node = nodes[0] + + if instance_node.isBypassed() != (not old_value): + print("%s old bypass state didn't match old instance state, " + "updating anyway.." % instance_node.path()) + + instance_node.bypass(not new_value) diff --git a/pype/hosts/houdini/lib.py b/pype/hosts/houdini/api/lib.py similarity index 100% rename from pype/hosts/houdini/lib.py rename to pype/hosts/houdini/api/lib.py diff --git a/pype/plugins/houdini/create/create_alembic_camera.py b/pype/hosts/houdini/plugins/create/create_alembic_camera.py similarity index 100% rename from pype/plugins/houdini/create/create_alembic_camera.py rename to pype/hosts/houdini/plugins/create/create_alembic_camera.py diff --git a/pype/plugins/houdini/create/create_pointcache.py b/pype/hosts/houdini/plugins/create/create_pointcache.py similarity index 100% rename from pype/plugins/houdini/create/create_pointcache.py rename to pype/hosts/houdini/plugins/create/create_pointcache.py diff --git a/pype/plugins/houdini/create/create_vbd_cache.py b/pype/hosts/houdini/plugins/create/create_vbd_cache.py similarity index 100% rename from pype/plugins/houdini/create/create_vbd_cache.py rename to pype/hosts/houdini/plugins/create/create_vbd_cache.py diff --git a/pype/plugins/houdini/load/load_alembic.py b/pype/hosts/houdini/plugins/load/load_alembic.py similarity index 100% rename from pype/plugins/houdini/load/load_alembic.py rename to pype/hosts/houdini/plugins/load/load_alembic.py diff --git a/pype/plugins/houdini/load/load_camera.py b/pype/hosts/houdini/plugins/load/load_camera.py similarity index 100% rename from pype/plugins/houdini/load/load_camera.py rename to pype/hosts/houdini/plugins/load/load_camera.py diff --git a/pype/plugins/houdini/publish/collect_current_file.py b/pype/hosts/houdini/plugins/publish/collect_current_file.py similarity index 100% rename from pype/plugins/houdini/publish/collect_current_file.py rename to pype/hosts/houdini/plugins/publish/collect_current_file.py diff --git a/pype/plugins/houdini/publish/collect_frames.py b/pype/hosts/houdini/plugins/publish/collect_frames.py similarity index 97% rename from pype/plugins/houdini/publish/collect_frames.py rename to pype/hosts/houdini/plugins/publish/collect_frames.py index 957aedbdd3..47037f94d4 100644 --- a/pype/plugins/houdini/publish/collect_frames.py +++ b/pype/hosts/houdini/plugins/publish/collect_frames.py @@ -2,7 +2,7 @@ import os import re import pyblish.api -from pype.hosts.houdini import lib +from pype.hosts.houdini.api import lib class CollectFrames(pyblish.api.InstancePlugin): diff --git a/pype/plugins/houdini/publish/collect_instances.py b/pype/hosts/houdini/plugins/publish/collect_instances.py similarity index 100% rename from pype/plugins/houdini/publish/collect_instances.py rename to pype/hosts/houdini/plugins/publish/collect_instances.py diff --git a/pype/plugins/houdini/publish/collect_output_node.py b/pype/hosts/houdini/plugins/publish/collect_output_node.py similarity index 100% rename from pype/plugins/houdini/publish/collect_output_node.py rename to pype/hosts/houdini/plugins/publish/collect_output_node.py diff --git a/pype/plugins/houdini/publish/collect_workscene_fps.py b/pype/hosts/houdini/plugins/publish/collect_workscene_fps.py similarity index 100% rename from pype/plugins/houdini/publish/collect_workscene_fps.py rename to pype/hosts/houdini/plugins/publish/collect_workscene_fps.py diff --git a/pype/plugins/houdini/publish/extract_alembic.py b/pype/hosts/houdini/plugins/publish/extract_alembic.py similarity index 100% rename from pype/plugins/houdini/publish/extract_alembic.py rename to pype/hosts/houdini/plugins/publish/extract_alembic.py diff --git a/pype/plugins/houdini/publish/extract_vdb_cache.py b/pype/hosts/houdini/plugins/publish/extract_vdb_cache.py similarity index 100% rename from pype/plugins/houdini/publish/extract_vdb_cache.py rename to pype/hosts/houdini/plugins/publish/extract_vdb_cache.py diff --git a/pype/plugins/houdini/publish/valiate_vdb_input_node.py b/pype/hosts/houdini/plugins/publish/valiate_vdb_input_node.py similarity index 100% rename from pype/plugins/houdini/publish/valiate_vdb_input_node.py rename to pype/hosts/houdini/plugins/publish/valiate_vdb_input_node.py diff --git a/pype/plugins/houdini/publish/validate_alembic_input_node.py b/pype/hosts/houdini/plugins/publish/validate_alembic_input_node.py similarity index 100% rename from pype/plugins/houdini/publish/validate_alembic_input_node.py rename to pype/hosts/houdini/plugins/publish/validate_alembic_input_node.py diff --git a/pype/plugins/houdini/publish/validate_animation_settings.py b/pype/hosts/houdini/plugins/publish/validate_animation_settings.py similarity index 97% rename from pype/plugins/houdini/publish/validate_animation_settings.py rename to pype/hosts/houdini/plugins/publish/validate_animation_settings.py index bdb9f69335..633c13dfb6 100644 --- a/pype/plugins/houdini/publish/validate_animation_settings.py +++ b/pype/hosts/houdini/plugins/publish/validate_animation_settings.py @@ -1,6 +1,6 @@ import pyblish.api -from pype.hosts.houdini import lib +from pype.hosts.houdini.api import lib class ValidateAnimationSettings(pyblish.api.InstancePlugin): diff --git a/pype/plugins/houdini/publish/validate_bypass.py b/pype/hosts/houdini/plugins/publish/validate_bypass.py similarity index 100% rename from pype/plugins/houdini/publish/validate_bypass.py rename to pype/hosts/houdini/plugins/publish/validate_bypass.py diff --git a/pype/plugins/houdini/publish/validate_camera_rop.py b/pype/hosts/houdini/plugins/publish/validate_camera_rop.py similarity index 100% rename from pype/plugins/houdini/publish/validate_camera_rop.py rename to pype/hosts/houdini/plugins/publish/validate_camera_rop.py diff --git a/pype/plugins/houdini/publish/validate_mkpaths_toggled.py b/pype/hosts/houdini/plugins/publish/validate_mkpaths_toggled.py similarity index 100% rename from pype/plugins/houdini/publish/validate_mkpaths_toggled.py rename to pype/hosts/houdini/plugins/publish/validate_mkpaths_toggled.py diff --git a/pype/plugins/houdini/publish/validate_outnode_exists.py b/pype/hosts/houdini/plugins/publish/validate_outnode_exists.py similarity index 100% rename from pype/plugins/houdini/publish/validate_outnode_exists.py rename to pype/hosts/houdini/plugins/publish/validate_outnode_exists.py diff --git a/pype/plugins/houdini/publish/validate_output_node.py b/pype/hosts/houdini/plugins/publish/validate_output_node.py similarity index 100% rename from pype/plugins/houdini/publish/validate_output_node.py rename to pype/hosts/houdini/plugins/publish/validate_output_node.py diff --git a/pype/plugins/houdini/publish/validate_primitive_hierarchy_paths.py b/pype/hosts/houdini/plugins/publish/validate_primitive_hierarchy_paths.py similarity index 100% rename from pype/plugins/houdini/publish/validate_primitive_hierarchy_paths.py rename to pype/hosts/houdini/plugins/publish/validate_primitive_hierarchy_paths.py diff --git a/pype/plugins/houdini/publish/validate_vdb_input_node.py b/pype/hosts/houdini/plugins/publish/validate_vdb_input_node.py similarity index 100% rename from pype/plugins/houdini/publish/validate_vdb_input_node.py rename to pype/hosts/houdini/plugins/publish/validate_vdb_input_node.py diff --git a/pype/setup/houdini/MainMenuCommon.XML b/pype/hosts/houdini/startup/MainMenuCommon.XML similarity index 100% rename from pype/setup/houdini/MainMenuCommon.XML rename to pype/hosts/houdini/startup/MainMenuCommon.XML diff --git a/pype/setup/houdini/scripts/123.py b/pype/hosts/houdini/startup/scripts/123.py similarity index 100% rename from pype/setup/houdini/scripts/123.py rename to pype/hosts/houdini/startup/scripts/123.py diff --git a/pype/hosts/maya/__init__.py b/pype/hosts/maya/__init__.py index 06b3e2c63c..e69de29bb2 100644 --- a/pype/hosts/maya/__init__.py +++ b/pype/hosts/maya/__init__.py @@ -1,217 +0,0 @@ -import os -import logging -import weakref - -from maya import utils, cmds - -from avalon import api as avalon, pipeline, maya -from avalon.maya.pipeline import IS_HEADLESS -from avalon.tools import workfiles -from pyblish import api as pyblish - -from ...lib import any_outdated -from pype import PLUGINS_DIR - -from . import menu -from . import lib - -log = logging.getLogger("pype.hosts.maya") - -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "maya", "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "maya", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "maya", "create") - - -def install(): - pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - avalon.register_plugin_path(avalon.Creator, CREATE_PATH) - log.info(PUBLISH_PATH) - menu.install() - - log.info("Installing callbacks ... ") - avalon.on("init", on_init) - - # Callbacks below are not required for headless mode, the `init` however - # is important to load referenced Alembics correctly at rendertime. - if IS_HEADLESS: - log.info("Running in headless mode, skipping Colorbleed Maya " - "save/open/new callback installation..") - return - - avalon.on("save", on_save) - avalon.on("open", on_open) - avalon.on("new", on_new) - avalon.before("save", on_before_save) - - log.info("Overriding existing event 'taskChanged'") - override_event("taskChanged", on_task_changed) - - log.info("Setting default family states for loader..") - avalon.data["familiesStateToggled"] = ["imagesequence"] - - -def uninstall(): - pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) - avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) - - menu.uninstall() - - -def override_event(event, callback): - """ - Override existing event callback - Args: - event (str): name of the event - callback (function): callback to be triggered - - Returns: - None - - """ - - ref = weakref.WeakSet() - ref.add(callback) - - pipeline._registered_event_handlers[event] = ref - - -def on_init(_): - avalon.logger.info("Running callback on init..") - - def safe_deferred(fn): - """Execute deferred the function in a try-except""" - - def _fn(): - """safely call in deferred callback""" - try: - fn() - except Exception as exc: - print(exc) - - try: - utils.executeDeferred(_fn) - except Exception as exc: - print(exc) - - # Force load Alembic so referenced alembics - # work correctly on scene open - cmds.loadPlugin("AbcImport", quiet=True) - cmds.loadPlugin("AbcExport", quiet=True) - - # Force load objExport plug-in (requested by artists) - cmds.loadPlugin("objExport", quiet=True) - - from .customize import ( - override_component_mask_commands, - override_toolbox_ui - ) - safe_deferred(override_component_mask_commands) - - launch_workfiles = os.environ.get("WORKFILES_STARTUP") - - if launch_workfiles: - safe_deferred(launch_workfiles_app) - - if not IS_HEADLESS: - safe_deferred(override_toolbox_ui) - - -def launch_workfiles_app(*args): - workfiles.show(os.environ["AVALON_WORKDIR"]) - - -def on_before_save(return_code, _): - """Run validation for scene's FPS prior to saving""" - return lib.validate_fps() - - -def on_save(_): - """Automatically add IDs to new nodes - - Any transform of a mesh, without an existing ID, is given one - automatically on file save. - """ - - avalon.logger.info("Running callback on save..") - - # # Update current task for the current scene - # update_task_from_path(cmds.file(query=True, sceneName=True)) - - # Generate ids of the current context on nodes in the scene - nodes = lib.get_id_required_nodes(referenced_nodes=False) - for node, new_id in lib.generate_ids(nodes): - lib.set_id(node, new_id, overwrite=False) - - -def on_open(_): - """On scene open let's assume the containers have changed.""" - - from avalon.vendor.Qt import QtWidgets - from ...widgets import popup - - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.remove_render_layer_observer()") - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.add_render_layer_observer()") - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.add_render_layer_change_observer()") - # # Update current task for the current scene - # update_task_from_path(cmds.file(query=True, sceneName=True)) - - # Validate FPS after update_task_from_path to - # ensure it is using correct FPS for the asset - lib.validate_fps() - lib.fix_incompatible_containers() - - if any_outdated(): - log.warning("Scene has outdated content.") - - # Find maya main window - top_level_widgets = {w.objectName(): w for w in - QtWidgets.QApplication.topLevelWidgets()} - parent = top_level_widgets.get("MayaWindow", None) - - if parent is None: - log.info("Skipping outdated content pop-up " - "because Maya window can't be found.") - else: - - # Show outdated pop-up - def _on_show_inventory(): - import avalon.tools.sceneinventory as tool - tool.show(parent=parent) - - dialog = popup.Popup(parent=parent) - dialog.setWindowTitle("Maya scene has outdated content") - dialog.setMessage("There are outdated containers in " - "your Maya scene.") - dialog.on_show.connect(_on_show_inventory) - dialog.show() - - -def on_new(_): - """Set project resolution and fps when create a new file""" - avalon.logger.info("Running callback on new..") - with maya.suspended_refresh(): - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.remove_render_layer_observer()") - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.add_render_layer_observer()") - cmds.evalDeferred( - "from pype.hosts.maya import lib;lib.add_render_layer_change_observer()") - lib.set_context_settings() - - -def on_task_changed(*args): - """Wrapped function of app initialize and maya's on task changed""" - # Run - maya.pipeline._on_task_changed() - with maya.suspended_refresh(): - lib.set_context_settings() - lib.update_content_on_context_change() - - lib.show_message("Context was changed", - ("Context was changed to {}".format( - avalon.Session["AVALON_ASSET"]))) diff --git a/pype/hosts/maya/api/__init__.py b/pype/hosts/maya/api/__init__.py new file mode 100644 index 0000000000..9caca205e6 --- /dev/null +++ b/pype/hosts/maya/api/__init__.py @@ -0,0 +1,226 @@ +import os +import logging +import weakref + +from maya import utils, cmds + +from avalon import api as avalon +from avalon import pipeline +from avalon.maya import suspended_refresh +from avalon.maya.pipeline import IS_HEADLESS, _on_task_changed +from avalon.tools import workfiles +from pyblish import api as pyblish +from pype.lib import any_outdated +import pype.hosts.maya +from . import menu, lib + +log = logging.getLogger("pype.hosts.maya") + +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.maya.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + + +def install(): + pyblish.register_plugin_path(PUBLISH_PATH) + avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + avalon.register_plugin_path(avalon.Creator, CREATE_PATH) + log.info(PUBLISH_PATH) + menu.install() + + log.info("Installing callbacks ... ") + avalon.on("init", on_init) + + # Callbacks below are not required for headless mode, the `init` however + # is important to load referenced Alembics correctly at rendertime. + if IS_HEADLESS: + log.info("Running in headless mode, skipping Maya " + "save/open/new callback installation..") + return + + avalon.on("save", on_save) + avalon.on("open", on_open) + avalon.on("new", on_new) + avalon.before("save", on_before_save) + + log.info("Overriding existing event 'taskChanged'") + override_event("taskChanged", on_task_changed) + + log.info("Setting default family states for loader..") + avalon.data["familiesStateToggled"] = ["imagesequence"] + + +def uninstall(): + pyblish.deregister_plugin_path(PUBLISH_PATH) + avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) + + menu.uninstall() + + +def override_event(event, callback): + """ + Override existing event callback + Args: + event (str): name of the event + callback (function): callback to be triggered + + Returns: + None + + """ + + ref = weakref.WeakSet() + ref.add(callback) + + pipeline._registered_event_handlers[event] = ref + + +def on_init(_): + avalon.logger.info("Running callback on init..") + + def safe_deferred(fn): + """Execute deferred the function in a try-except""" + + def _fn(): + """safely call in deferred callback""" + try: + fn() + except Exception as exc: + print(exc) + + try: + utils.executeDeferred(_fn) + except Exception as exc: + print(exc) + + # Force load Alembic so referenced alembics + # work correctly on scene open + cmds.loadPlugin("AbcImport", quiet=True) + cmds.loadPlugin("AbcExport", quiet=True) + + # Force load objExport plug-in (requested by artists) + cmds.loadPlugin("objExport", quiet=True) + + from .customize import ( + override_component_mask_commands, + override_toolbox_ui + ) + safe_deferred(override_component_mask_commands) + + launch_workfiles = os.environ.get("WORKFILES_STARTUP") + + if launch_workfiles: + safe_deferred(launch_workfiles_app) + + if not IS_HEADLESS: + safe_deferred(override_toolbox_ui) + + +def launch_workfiles_app(): + workfiles.show(os.environ["AVALON_WORKDIR"]) + + +def on_before_save(return_code, _): + """Run validation for scene's FPS prior to saving""" + return lib.validate_fps() + + +def on_save(_): + """Automatically add IDs to new nodes + + Any transform of a mesh, without an existing ID, is given one + automatically on file save. + """ + + avalon.logger.info("Running callback on save..") + + # # Update current task for the current scene + # update_task_from_path(cmds.file(query=True, sceneName=True)) + + # Generate ids of the current context on nodes in the scene + nodes = lib.get_id_required_nodes(referenced_nodes=False) + for node, new_id in lib.generate_ids(nodes): + lib.set_id(node, new_id, overwrite=False) + + +def on_open(_): + """On scene open let's assume the containers have changed.""" + + from avalon.vendor.Qt import QtWidgets + from ...widgets import popup + + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.remove_render_layer_observer()") + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.add_render_layer_observer()") + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.add_render_layer_change_observer()") + # # Update current task for the current scene + # update_task_from_path(cmds.file(query=True, sceneName=True)) + + # Validate FPS after update_task_from_path to + # ensure it is using correct FPS for the asset + lib.validate_fps() + lib.fix_incompatible_containers() + + if any_outdated(): + log.warning("Scene has outdated content.") + + # Find maya main window + top_level_widgets = {w.objectName(): w for w in + QtWidgets.QApplication.topLevelWidgets()} + parent = top_level_widgets.get("MayaWindow", None) + + if parent is None: + log.info("Skipping outdated content pop-up " + "because Maya window can't be found.") + else: + + # Show outdated pop-up + def _on_show_inventory(): + import avalon.tools.sceneinventory as tool + tool.show(parent=parent) + + dialog = popup.Popup(parent=parent) + dialog.setWindowTitle("Maya scene has outdated content") + dialog.setMessage("There are outdated containers in " + "your Maya scene.") + dialog.on_show.connect(_on_show_inventory) + dialog.show() + + +def on_new(_): + """Set project resolution and fps when create a new file""" + avalon.logger.info("Running callback on new..") + with suspended_refresh(): + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.remove_render_layer_observer()") + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.add_render_layer_observer()") + cmds.evalDeferred( + "from pype.hosts.maya.api import lib;" + "lib.add_render_layer_change_observer()") + lib.set_context_settings() + + +def on_task_changed(*args): + """Wrapped function of app initialize and maya's on task changed""" + # Run + _on_task_changed() + with suspended_refresh(): + lib.set_context_settings() + lib.update_content_on_context_change() + + lib.show_message( + "Context was changed", + ("Context was changed to {}".format(avalon.Session["AVALON_ASSET"])), + ) \ No newline at end of file diff --git a/pype/hosts/maya/action.py b/pype/hosts/maya/api/action.py similarity index 98% rename from pype/hosts/maya/action.py rename to pype/hosts/maya/api/action.py index bb6815ed7d..35a57a4445 100644 --- a/pype/hosts/maya/action.py +++ b/pype/hosts/maya/api/action.py @@ -4,7 +4,7 @@ from __future__ import absolute_import import pyblish.api -from ...action import get_errored_instances_from_context +from pype.api import get_errored_instances_from_context class GenerateUUIDsOnInvalidAction(pyblish.api.Action): diff --git a/pype/hosts/maya/customize.py b/pype/hosts/maya/api/customize.py similarity index 100% rename from pype/hosts/maya/customize.py rename to pype/hosts/maya/api/customize.py diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/api/expected_files.py similarity index 86% rename from pype/hosts/maya/expected_files.py rename to pype/hosts/maya/api/expected_files.py index d39e5fa204..41463b53f8 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/api/expected_files.py @@ -29,8 +29,8 @@ Attributes: token in image prefixes. RENDERER_NAMES (dict): Renderer names mapping between reported name and *human readable* name. - ImagePrefixes (dict): Mapping between renderers and their respective - image prefix atrribute names. + IMAGE_PREFIXES (dict): Mapping between renderers and their respective + image prefix attribute names. Todo: Determine `multipart` from render instance. @@ -44,7 +44,7 @@ from abc import ABCMeta, abstractmethod import six -import pype.hosts.maya.lib as lib +import pype.hosts.maya.api.lib as lib from maya import cmds import maya.app.renderSetup.model.renderSetup as renderSetup @@ -78,7 +78,7 @@ RENDERER_NAMES = { } # not sure about the renderman image prefix -ImagePrefixes = { +IMAGE_PREFIXES = { "mentalray": "defaultRenderGlobals.imageFilePrefix", "vray": "vraySettings.fileNamePrefix", "arnold": "defaultRenderGlobals.imageFilePrefix", @@ -123,22 +123,22 @@ class ExpectedFiles: if renderer.lower() == "arnold": return self._get_files(ExpectedFilesArnold(layer, self._render_instance)) - elif renderer.lower() == "vray": + if renderer.lower() == "vray": return self._get_files(ExpectedFilesVray( layer, self._render_instance)) - elif renderer.lower() == "redshift": + if renderer.lower() == "redshift": return self._get_files(ExpectedFilesRedshift( layer, self._render_instance)) - elif renderer.lower() == "mentalray": + if renderer.lower() == "mentalray": return self._get_files(ExpectedFilesMentalray( layer, self._render_instance)) - elif renderer.lower() == "renderman": + if renderer.lower() == "renderman": return self._get_files(ExpectedFilesRenderman( layer, self._render_instance)) - else: - raise UnsupportedRendererException( - "unsupported {}".format(renderer) - ) + + raise UnsupportedRendererException( + "unsupported {}".format(renderer) + ) def _get_files(self, renderer): files = renderer.get_files() @@ -169,9 +169,9 @@ class AExpectedFiles: @abstractmethod def get_aovs(self): """To be implemented by renderer class.""" - pass - def sanitize_camera_name(self, camera): + @staticmethod + def sanitize_camera_name(camera): """Sanitize camera name. Remove Maya illegal characters from camera name. @@ -187,8 +187,7 @@ class AExpectedFiles: test_camera_01 """ - sanitized = re.sub('[^0-9a-zA-Z_]+', '_', camera) - return sanitized + return re.sub('[^0-9a-zA-Z_]+', '_', camera) def get_renderer_prefix(self): """Return prefix for specific renderer. @@ -201,12 +200,12 @@ class AExpectedFiles: Raises: :exc:`UnsupportedRendererException`: If we requested image prefix for renderer we know nothing about. - See :data:`ImagePrefixes` for mapping of renderers and + See :data:`IMAGE_PREFIXES` for mapping of renderers and image prefixes. """ try: - file_prefix = cmds.getAttr(ImagePrefixes[self.renderer]) + file_prefix = cmds.getAttr(IMAGE_PREFIXES[self.renderer]) except KeyError: raise UnsupportedRendererException( "Unsupported renderer {}".format(self.renderer) @@ -218,62 +217,32 @@ class AExpectedFiles: # ____________________/ ____________________________________________/ # 1 - get scene name /__________________/ # ____________________/ - scene_dir, scene_basename = os.path.split(cmds.file(q=True, loc=True)) + _, scene_basename = os.path.split(cmds.file(q=True, loc=True)) scene_name, _ = os.path.splitext(scene_basename) - # ______________________________________________ - # ____________________/ ____________________________________________/ - # 2 - detect renderer /__________________/ - # ____________________/ - renderer = self.renderer - - # ________________________________________________ - # __________________/ ______________________________________________/ - # 3 - image prefix /__________________/ - # __________________/ file_prefix = self.get_renderer_prefix() if not file_prefix: raise RuntimeError("Image prefix not set") - default_ext = cmds.getAttr("defaultRenderGlobals.imfPluginKey") - - # ________________________________________________ - # __________________/ ______________________________________________/ - # 4 - get renderable cameras_____________/ - # __________________/ - - # if we have token in prefix path we'll expect output for - # every renderable camera in layer. - - renderable_cameras = self.get_renderable_cameras() - # ________________________________________________ - # __________________/ ______________________________________________/ - # 5 - get AOVs /____________________/ - # __________________/ - - enabled_aovs = self.get_aovs() - layer_name = self.layer if self.layer.startswith("rs_"): layer_name = self.layer[3:] - start_frame = int(self.get_render_attribute("startFrame")) - end_frame = int(self.get_render_attribute("endFrame")) - frame_step = int(self.get_render_attribute("byFrameStep")) - padding = int(self.get_render_attribute("extensionPadding")) scene_data = { - "frameStart": start_frame, - "frameEnd": end_frame, - "frameStep": frame_step, - "padding": padding, - "cameras": renderable_cameras, + "frameStart": int(self.get_render_attribute("startFrame")), + "frameEnd": int(self.get_render_attribute("endFrame")), + "frameStep": int(self.get_render_attribute("byFrameStep")), + "padding": int(self.get_render_attribute("extensionPadding")), + # if we have token in prefix path we'll expect output for + # every renderable camera in layer. + "cameras": self.get_renderable_cameras(), "sceneName": scene_name, "layerName": layer_name, - "renderer": renderer, - "defaultExt": default_ext, + "renderer": self.renderer, + "defaultExt": cmds.getAttr("defaultRenderGlobals.imfPluginKey"), "filePrefix": file_prefix, - "enabledAOVs": enabled_aovs, + "enabledAOVs": self.get_aovs(), } return scene_data @@ -296,9 +265,9 @@ class AExpectedFiles: file_prefix = re.sub(regex, value, file_prefix) for frame in range( - int(layer_data["frameStart"]), - int(layer_data["frameEnd"]) + 1, - int(layer_data["frameStep"]), + int(layer_data["frameStart"]), + int(layer_data["frameEnd"]) + 1, + int(layer_data["frameStep"]), ): expected_files.append( "{}.{}.{}".format( @@ -331,9 +300,9 @@ class AExpectedFiles: aov_files = [] for frame in range( - int(layer_data["frameStart"]), - int(layer_data["frameEnd"]) + 1, - int(layer_data["frameStep"]), + int(layer_data["frameStart"]), + int(layer_data["frameEnd"]) + 1, + int(layer_data["frameStep"]), ): aov_files.append( "{}.{}.{}".format( @@ -388,14 +357,13 @@ class AExpectedFiles: renderable_cameras = [] for cam in cam_parents: - renderable = False if self.maya_is_true(cmds.getAttr("{}.renderable".format(cam))): - renderable = True renderable_cameras.append(cam) return renderable_cameras - def maya_is_true(self, attr_val): + @staticmethod + def maya_is_true(attr_val): """Whether a Maya attr evaluates to True. When querying an attribute value from an ambiguous object the @@ -411,12 +379,13 @@ class AExpectedFiles: """ if isinstance(attr_val, types.BooleanType): return attr_val - elif isinstance(attr_val, (types.ListType, types.GeneratorType)): + if isinstance(attr_val, (types.ListType, types.GeneratorType)): return any(attr_val) - else: - return bool(attr_val) - def get_layer_overrides(self, attr, layer): + return bool(attr_val) + + @staticmethod + def get_layer_overrides(attr): """Get overrides for attribute on given render layer. Args: @@ -491,8 +460,8 @@ class ExpectedFilesArnold(AExpectedFiles): enabled_aovs = [] try: if not ( - cmds.getAttr("defaultArnoldRenderOptions.aovMode") - and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501 + cmds.getAttr("defaultArnoldRenderOptions.aovMode") + and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501 ): # AOVs are merged in mutli-channel file self.multipart = True @@ -508,7 +477,14 @@ class ExpectedFilesArnold(AExpectedFiles): # AOVs are set to be rendered separately. We should expect # token in path. - ai_aovs = [n for n in cmds.ls(type="aiAOV")] + # handle aovs from references + use_ref_aovs = self.render_instance.data.get( + "useReferencedAovs", False) or False + + ai_aovs = cmds.ls(type="aiAOV") + if not use_ref_aovs: + ref_aovs = cmds.ls(type="aiAOV", referencedNodes=True) + ai_aovs = list(set(ai_aovs) - set(ref_aovs)) for aov in ai_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) @@ -523,7 +499,7 @@ class ExpectedFilesArnold(AExpectedFiles): raise AOVError(msg) for override in self.get_layer_overrides( - "{}.enabled".format(aov), self.layer + "{}.enabled".format(aov) ): enabled = self.maya_is_true(override) if enabled: @@ -567,7 +543,7 @@ class ExpectedFilesVray(AExpectedFiles): """Override to get vray specific extension.""" layer_data = super(ExpectedFilesVray, self)._get_layer_data() default_ext = cmds.getAttr("vraySettings.imageFormatStr") - if default_ext == "exr (multichannel)" or default_ext == "exr (deep)": + if default_ext in ["exr (multichannel)", "exr (deep)"]: default_ext = "exr" layer_data["defaultExt"] = default_ext layer_data["padding"] = cmds.getAttr("vraySettings.fileNamePadding") @@ -587,11 +563,11 @@ class ExpectedFilesVray(AExpectedFiles): # remove 'beauty' from filenames as vray doesn't output it update = {} if layer_data.get("enabledAOVs"): - for aov, seq in expected_files[0].items(): + for aov, seqs in expected_files[0].items(): if aov.startswith("beauty"): new_list = [] - for f in seq: - new_list.append(f.replace("_beauty", "")) + for seq in seqs: + new_list.append(seq.replace("_beauty", "")) update[aov] = new_list expected_files[0].update(update) @@ -609,8 +585,8 @@ class ExpectedFilesVray(AExpectedFiles): try: # really? do we set it in vray just by selecting multichannel exr? if ( - cmds.getAttr("vraySettings.imageFormatStr") - == "exr (multichannel)" # noqa: W503 + cmds.getAttr("vraySettings.imageFormatStr") + == "exr (multichannel)" # noqa: W503 ): # AOVs are merged in mutli-channel file self.multipart = True @@ -624,7 +600,7 @@ class ExpectedFilesVray(AExpectedFiles): return enabled_aovs default_ext = cmds.getAttr("vraySettings.imageFormatStr") - if default_ext == "exr (multichannel)" or default_ext == "exr (deep)": + if default_ext in ["exr (multichannel)", "exr (deep)"]: default_ext = "exr" # add beauty as default @@ -634,7 +610,7 @@ class ExpectedFilesVray(AExpectedFiles): # handle aovs from references use_ref_aovs = self.render_instance.data.get( - "vrayUseReferencedAovs", False) or False + "useReferencedAovs", False) or False # this will have list of all aovs no matter if they are coming from # reference or not. @@ -650,18 +626,18 @@ class ExpectedFilesVray(AExpectedFiles): for aov in vr_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) for override in self.get_layer_overrides( - "{}.enabled".format(aov), "rs_{}".format(self.layer) + "{}.enabled".format(aov) ): enabled = self.maya_is_true(override) if enabled: - # todo: find how vray set format for AOVs enabled_aovs.append( (self._get_vray_aov_name(aov), default_ext)) return enabled_aovs - def _get_vray_aov_name(self, node): + @staticmethod + def _get_vray_aov_name(node): """Get AOVs name from Vray. Args: @@ -762,8 +738,8 @@ class ExpectedFilesRedshift(AExpectedFiles): if aov[0].lower() == "cryptomatte": aov_name = aov[0] expected_files.append( - {aov_name: self._generate_single_file_sequence( - layer_data, aov_name=aov_name)}) + {aov_name: self._generate_single_file_sequence(layer_data)} + ) return expected_files @@ -778,7 +754,7 @@ class ExpectedFilesRedshift(AExpectedFiles): try: if self.maya_is_true( - cmds.getAttr("redshiftOptions.exrForceMultilayer") + cmds.getAttr("redshiftOptions.exrForceMultilayer") ): # AOVs are merged in mutli-channel file self.multipart = True @@ -794,13 +770,13 @@ class ExpectedFilesRedshift(AExpectedFiles): default_ext = self.ext_mapping[ cmds.getAttr("redshiftOptions.imageFormat") ] - rs_aovs = [n for n in cmds.ls(type="RedshiftAOV")] + rs_aovs = cmds.ls(type="RedshiftAOV", referencedNodes=False) # todo: find out how to detect multichannel exr for redshift for aov in rs_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) for override in self.get_layer_overrides( - "{}.enabled".format(aov), self.layer + "{}.enabled".format(aov) ): enabled = self.maya_is_true(override) @@ -809,7 +785,7 @@ class ExpectedFilesRedshift(AExpectedFiles): # is in the list of AOVs that renderer cannot (or will not) # merge into final exr. if self.maya_is_true( - cmds.getAttr("redshiftOptions.exrForceMultilayer") + cmds.getAttr("redshiftOptions.exrForceMultilayer") ): if cmds.getAttr("%s.name" % aov) in self.unmerged_aovs: enabled_aovs.append( @@ -821,7 +797,7 @@ class ExpectedFilesRedshift(AExpectedFiles): ) if self.maya_is_true( - cmds.getAttr("redshiftOptions.exrForceMultilayer") + cmds.getAttr("redshiftOptions.exrForceMultilayer") ): # AOVs are merged in mutli-channel file self.multipart = True @@ -859,7 +835,7 @@ class ExpectedFilesRenderman(AExpectedFiles): enabled = self.maya_is_true(cmds.getAttr("{}.enable".format(aov))) for override in self.get_layer_overrides( - "{}.enable".format(aov), self.layer + "{}.enable".format(aov) ): enabled = self.maya_is_true(override) @@ -908,6 +884,7 @@ class ExpectedFilesMentalray(AExpectedFiles): :exc:`UnimplementedRendererException`: as it is not implemented. """ + super(ExpectedFilesMentalray, self).__init__(layer, render_instance) raise UnimplementedRendererException("Mentalray not implemented") def get_aovs(self): @@ -923,8 +900,6 @@ class ExpectedFilesMentalray(AExpectedFiles): class AOVError(Exception): """Custom exception for determining AOVs.""" - pass - class UnsupportedRendererException(Exception): """Custom exception. @@ -932,13 +907,9 @@ class UnsupportedRendererException(Exception): Raised when requesting data from unsupported renderer. """ - pass - class UnimplementedRendererException(Exception): """Custom exception. Raised when requesting data from renderer that is not implemented yet. """ - - pass diff --git a/pype/hosts/maya/lib.py b/pype/hosts/maya/api/lib.py similarity index 99% rename from pype/hosts/maya/lib.py rename to pype/hosts/maya/api/lib.py index 37e4ccf915..3a820af814 100644 --- a/pype/hosts/maya/lib.py +++ b/pype/hosts/maya/api/lib.py @@ -114,9 +114,7 @@ def matrix_equals(a, b, tolerance=1e-10): bool : True or False """ - if not all(abs(x - y) < tolerance for x, y in zip(a, b)): - return False - return True + return all(abs(x - y) < tolerance for x, y in zip(a, b)) def float_round(num, places=0, direction=ceil): @@ -1084,7 +1082,7 @@ def get_id_required_nodes(referenced_nodes=False, nodes=None): # Check if plugin nodes are available for Maya by checking if the plugin # is loaded - if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True): + if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True): types.append("pgYetiMaya") # We *always* ignore intermediate shapes, so we filter them out directly diff --git a/pype/hosts/maya/menu.json b/pype/hosts/maya/api/menu.json similarity index 100% rename from pype/hosts/maya/menu.json rename to pype/hosts/maya/api/menu.json diff --git a/pype/hosts/maya/menu.py b/pype/hosts/maya/api/menu.py similarity index 99% rename from pype/hosts/maya/menu.py rename to pype/hosts/maya/api/menu.py index fa7690bca7..9381043511 100644 --- a/pype/hosts/maya/menu.py +++ b/pype/hosts/maya/api/menu.py @@ -4,7 +4,7 @@ import logging from avalon.vendor.Qt import QtWidgets, QtGui from avalon.maya import pipeline -from ...lib import BuildWorkfile +from pype.api import BuildWorkfile import maya.cmds as cmds self = sys.modules[__name__] diff --git a/pype/hosts/maya/menu_backup.json b/pype/hosts/maya/api/menu_backup.json similarity index 100% rename from pype/hosts/maya/menu_backup.json rename to pype/hosts/maya/api/menu_backup.json diff --git a/pype/hosts/maya/plugin.py b/pype/hosts/maya/api/plugin.py similarity index 100% rename from pype/hosts/maya/plugin.py rename to pype/hosts/maya/api/plugin.py diff --git a/pype/setdress_api.py b/pype/hosts/maya/api/setdress.py similarity index 99% rename from pype/setdress_api.py rename to pype/hosts/maya/api/setdress.py index 7c764a42df..2c4dd93b18 100644 --- a/pype/setdress_api.py +++ b/pype/hosts/maya/api/setdress.py @@ -9,7 +9,7 @@ from maya import cmds from avalon import api, io from avalon.maya.lib import unique_namespace -from pype.hosts.maya.lib import matrix_equals +from pype.hosts.maya.api.lib import matrix_equals log = logging.getLogger("PackageLoader") diff --git a/pype/hosts/maya/plugins/__init__.py b/pype/hosts/maya/plugins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/maya/create/create_animation.py b/pype/hosts/maya/plugins/create/create_animation.py similarity index 96% rename from pype/plugins/maya/create/create_animation.py rename to pype/hosts/maya/plugins/create/create_animation.py index 7bafce774c..6894fffb5d 100644 --- a/pype/plugins/maya/create/create_animation.py +++ b/pype/hosts/maya/plugins/create/create_animation.py @@ -1,5 +1,5 @@ import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreateAnimation(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_ass.py b/pype/hosts/maya/plugins/create/create_ass.py similarity index 96% rename from pype/plugins/maya/create/create_ass.py rename to pype/hosts/maya/plugins/create/create_ass.py index 7fd66e8e15..b7d5f27114 100644 --- a/pype/plugins/maya/create/create_ass.py +++ b/pype/hosts/maya/plugins/create/create_ass.py @@ -1,7 +1,7 @@ from collections import OrderedDict import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from maya import cmds diff --git a/pype/plugins/maya/create/create_assembly.py b/pype/hosts/maya/plugins/create/create_assembly.py similarity index 100% rename from pype/plugins/maya/create/create_assembly.py rename to pype/hosts/maya/plugins/create/create_assembly.py diff --git a/pype/plugins/maya/create/create_camera.py b/pype/hosts/maya/plugins/create/create_camera.py similarity index 96% rename from pype/plugins/maya/create/create_camera.py rename to pype/hosts/maya/plugins/create/create_camera.py index acff93c03c..cb438e68ba 100644 --- a/pype/plugins/maya/create/create_camera.py +++ b/pype/hosts/maya/plugins/create/create_camera.py @@ -1,5 +1,5 @@ import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreateCamera(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_layout.py b/pype/hosts/maya/plugins/create/create_layout.py similarity index 100% rename from pype/plugins/maya/create/create_layout.py rename to pype/hosts/maya/plugins/create/create_layout.py diff --git a/pype/plugins/maya/create/create_look.py b/pype/hosts/maya/plugins/create/create_look.py similarity index 94% rename from pype/plugins/maya/create/create_look.py rename to pype/hosts/maya/plugins/create/create_look.py index 5ea64cc7e4..2d8576a8b4 100644 --- a/pype/plugins/maya/create/create_look.py +++ b/pype/hosts/maya/plugins/create/create_look.py @@ -1,5 +1,5 @@ import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreateLook(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_mayaascii.py b/pype/hosts/maya/plugins/create/create_mayaascii.py similarity index 100% rename from pype/plugins/maya/create/create_mayaascii.py rename to pype/hosts/maya/plugins/create/create_mayaascii.py diff --git a/pype/plugins/maya/create/create_model.py b/pype/hosts/maya/plugins/create/create_model.py similarity index 100% rename from pype/plugins/maya/create/create_model.py rename to pype/hosts/maya/plugins/create/create_model.py diff --git a/pype/plugins/maya/create/create_pointcache.py b/pype/hosts/maya/plugins/create/create_pointcache.py similarity index 96% rename from pype/plugins/maya/create/create_pointcache.py rename to pype/hosts/maya/plugins/create/create_pointcache.py index 1eb561b5ce..271257c85e 100644 --- a/pype/plugins/maya/create/create_pointcache.py +++ b/pype/hosts/maya/plugins/create/create_pointcache.py @@ -1,5 +1,5 @@ import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreatePointCache(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_render.py b/pype/hosts/maya/plugins/create/create_render.py similarity index 99% rename from pype/plugins/maya/create/create_render.py rename to pype/hosts/maya/plugins/create/create_render.py index 2b0b0e19f7..2fd9972721 100644 --- a/pype/plugins/maya/create/create_render.py +++ b/pype/hosts/maya/plugins/create/create_render.py @@ -8,7 +8,7 @@ import requests from maya import cmds import maya.app.renderSetup.model.renderSetup as renderSetup -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from pype.api import get_system_settings import avalon.maya @@ -191,7 +191,7 @@ class CreateRender(avalon.maya.Creator): self.data["tilesX"] = 2 self.data["tilesY"] = 2 self.data["convertToScanline"] = False - self.data["vrayUseReferencedAovs"] = False + self.data["useReferencedAovs"] = False # Disable for now as this feature is not working yet # self.data["assScene"] = False diff --git a/pype/plugins/maya/create/create_rendersetup.py b/pype/hosts/maya/plugins/create/create_rendersetup.py similarity index 97% rename from pype/plugins/maya/create/create_rendersetup.py rename to pype/hosts/maya/plugins/create/create_rendersetup.py index 40e3731bf0..bbf46e2169 100644 --- a/pype/plugins/maya/create/create_rendersetup.py +++ b/pype/hosts/maya/plugins/create/create_rendersetup.py @@ -1,5 +1,5 @@ import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from maya import cmds diff --git a/pype/plugins/maya/create/create_review.py b/pype/hosts/maya/plugins/create/create_review.py similarity index 95% rename from pype/plugins/maya/create/create_review.py rename to pype/hosts/maya/plugins/create/create_review.py index bfeab33f5b..8619f90964 100644 --- a/pype/plugins/maya/create/create_review.py +++ b/pype/hosts/maya/plugins/create/create_review.py @@ -1,6 +1,6 @@ from collections import OrderedDict import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreateReview(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_rig.py b/pype/hosts/maya/plugins/create/create_rig.py similarity index 94% rename from pype/plugins/maya/create/create_rig.py rename to pype/hosts/maya/plugins/create/create_rig.py index ae1de4243e..4692997934 100644 --- a/pype/plugins/maya/create/create_rig.py +++ b/pype/hosts/maya/plugins/create/create_rig.py @@ -1,6 +1,6 @@ from maya import cmds -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib import avalon.maya diff --git a/pype/plugins/maya/create/create_setdress.py b/pype/hosts/maya/plugins/create/create_setdress.py similarity index 100% rename from pype/plugins/maya/create/create_setdress.py rename to pype/hosts/maya/plugins/create/create_setdress.py diff --git a/pype/plugins/maya/create/create_unreal_staticmesh.py b/pype/hosts/maya/plugins/create/create_unreal_staticmesh.py similarity index 100% rename from pype/plugins/maya/create/create_unreal_staticmesh.py rename to pype/hosts/maya/plugins/create/create_unreal_staticmesh.py diff --git a/pype/plugins/maya/create/create_vrayproxy.py b/pype/hosts/maya/plugins/create/create_vrayproxy.py similarity index 100% rename from pype/plugins/maya/create/create_vrayproxy.py rename to pype/hosts/maya/plugins/create/create_vrayproxy.py diff --git a/pype/plugins/maya/create/create_vrayscene.py b/pype/hosts/maya/plugins/create/create_vrayscene.py similarity index 100% rename from pype/plugins/maya/create/create_vrayscene.py rename to pype/hosts/maya/plugins/create/create_vrayscene.py diff --git a/pype/plugins/maya/create/create_yeti_cache.py b/pype/hosts/maya/plugins/create/create_yeti_cache.py similarity index 94% rename from pype/plugins/maya/create/create_yeti_cache.py rename to pype/hosts/maya/plugins/create/create_yeti_cache.py index a4b5cc537a..c9edb65d8b 100644 --- a/pype/plugins/maya/create/create_yeti_cache.py +++ b/pype/hosts/maya/plugins/create/create_yeti_cache.py @@ -1,7 +1,7 @@ from collections import OrderedDict import avalon.maya -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CreateYetiCache(avalon.maya.Creator): diff --git a/pype/plugins/maya/create/create_yeti_rig.py b/pype/hosts/maya/plugins/create/create_yeti_rig.py similarity index 93% rename from pype/plugins/maya/create/create_yeti_rig.py rename to pype/hosts/maya/plugins/create/create_yeti_rig.py index 0b954f500d..c385ca662d 100644 --- a/pype/plugins/maya/create/create_yeti_rig.py +++ b/pype/hosts/maya/plugins/create/create_yeti_rig.py @@ -1,6 +1,6 @@ from maya import cmds -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib import avalon.maya diff --git a/pype/plugins/maya/load/_load_animation.py b/pype/hosts/maya/plugins/load/_load_animation.py similarity index 93% rename from pype/plugins/maya/load/_load_animation.py rename to pype/hosts/maya/plugins/load/_load_animation.py index 597689ae21..bef97d79bb 100644 --- a/pype/plugins/maya/load/_load_animation.py +++ b/pype/hosts/maya/plugins/load/_load_animation.py @@ -1,7 +1,7 @@ -import pype.hosts.maya.plugin +import pype.hosts.maya.api.plugin -class AbcLoader(pype.hosts.maya.plugin.ReferenceLoader): +class AbcLoader(pype.hosts.maya.api.plugin.ReferenceLoader): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", diff --git a/pype/plugins/maya/load/actions.py b/pype/hosts/maya/plugins/load/actions.py similarity index 100% rename from pype/plugins/maya/load/actions.py rename to pype/hosts/maya/plugins/load/actions.py diff --git a/pype/plugins/maya/load/load_ass.py b/pype/hosts/maya/plugins/load/load_ass.py similarity index 98% rename from pype/plugins/maya/load/load_ass.py rename to pype/hosts/maya/plugins/load/load_ass.py index 9b851a3757..8aaa99369c 100644 --- a/pype/plugins/maya/load/load_ass.py +++ b/pype/hosts/maya/plugins/load/load_ass.py @@ -1,11 +1,11 @@ from avalon import api -import pype.hosts.maya.plugin +import pype.hosts.maya.api.plugin import os from pype.api import get_project_settings import clique -class AssProxyLoader(pype.hosts.maya.plugin.ReferenceLoader): +class AssProxyLoader(pype.hosts.maya.api.plugin.ReferenceLoader): """Load the Proxy""" families = ["ass"] diff --git a/pype/plugins/maya/load/load_assembly.py b/pype/hosts/maya/plugins/load/load_assembly.py similarity index 87% rename from pype/plugins/maya/load/load_assembly.py rename to pype/hosts/maya/plugins/load/load_assembly.py index 4f72ff9e13..a5f2394444 100644 --- a/pype/plugins/maya/load/load_assembly.py +++ b/pype/hosts/maya/plugins/load/load_assembly.py @@ -23,9 +23,9 @@ class AssemblyLoader(api.Loader): suffix="_", ) - from pype import setdress_api + from pype.hosts.maya.api import setdress - containers = setdress_api.load_package(filepath=self.fname, + containers = setdress.load_package(filepath=self.fname, name=name, namespace=namespace) @@ -45,19 +45,19 @@ class AssemblyLoader(api.Loader): def update(self, container, representation): - from pype import setdress_api - return setdress_api.update_package(container, + from pype import setdress + return setdress.update_package(container, representation) def remove(self, container): """Remove all sub containers""" from avalon import api - from pype import setdress_api + from pype import setdress import maya.cmds as cmds # Remove all members - member_containers = setdress_api.get_contained_containers(container) + member_containers = setdress.get_contained_containers(container) for member_container in member_containers: self.log.info("Removing container %s", member_container['objectName']) diff --git a/pype/plugins/maya/load/load_audio.py b/pype/hosts/maya/plugins/load/load_audio.py similarity index 96% rename from pype/plugins/maya/load/load_audio.py rename to pype/hosts/maya/plugins/load/load_audio.py index 81bcca48e1..73a2a4f448 100644 --- a/pype/plugins/maya/load/load_audio.py +++ b/pype/hosts/maya/plugins/load/load_audio.py @@ -1,10 +1,7 @@ -from maya import cmds, mel -import pymel.core as pc - from avalon import api, io from avalon.maya.pipeline import containerise from avalon.maya import lib - +from maya import cmds, mel class AudioLoader(api.Loader): """Specific loader of audio.""" @@ -15,7 +12,9 @@ class AudioLoader(api.Loader): icon = "volume-up" color = "orange" + def load(self, context, name, namespace, data): + start_frame = cmds.playbackOptions(query=True, min=True) sound_node = cmds.sound( file=context["representation"]["data"]["path"], offset=start_frame @@ -43,8 +42,10 @@ class AudioLoader(api.Loader): ) def update(self, container, representation): + import pymel.core as pm + audio_node = None - for node in pc.PyNode(container["objectName"]).members(): + for node in pm.PyNode(container["objectName"]).members(): if node.nodeType() == "audio": audio_node = node diff --git a/pype/plugins/maya/load/load_gpucache.py b/pype/hosts/maya/plugins/load/load_gpucache.py similarity index 98% rename from pype/plugins/maya/load/load_gpucache.py rename to pype/hosts/maya/plugins/load/load_gpucache.py index 0b3daae710..e6fde1eaa8 100644 --- a/pype/plugins/maya/load/load_gpucache.py +++ b/pype/hosts/maya/plugins/load/load_gpucache.py @@ -1,9 +1,6 @@ -from avalon import api -import pype.hosts.maya.plugin import os +from avalon import api from pype.api import get_project_settings -reload(config) - class GpuCacheLoader(api.Loader): """Load model Alembic as gpuCache""" diff --git a/pype/plugins/maya/load/load_image_plane.py b/pype/hosts/maya/plugins/load/load_image_plane.py similarity index 91% rename from pype/plugins/maya/load/load_image_plane.py rename to pype/hosts/maya/plugins/load/load_image_plane.py index 1bb29e90c4..f2640dc2eb 100644 --- a/pype/plugins/maya/load/load_image_plane.py +++ b/pype/hosts/maya/plugins/load/load_image_plane.py @@ -1,11 +1,10 @@ -import pymel.core as pc -import maya.cmds as cmds - from avalon import api, io from avalon.maya.pipeline import containerise from avalon.maya import lib from Qt import QtWidgets, QtCore +from maya import cmds + class CameraWindow(QtWidgets.QDialog): @@ -73,6 +72,8 @@ class ImagePlaneLoader(api.Loader): color = "orange" def load(self, context, name, namespace, data): + import pymel.core as pm + new_nodes = [] image_plane_depth = 1000 asset = context['asset']['name'] @@ -88,7 +89,7 @@ class ImagePlaneLoader(api.Loader): "frontShape", "perspShape", "sideShape", "topShape" ] cameras = [ - x for x in pc.ls(type="camera") if x.name() not in default_cameras + x for x in pm.ls(type="camera") if x.name() not in default_cameras ] camera_names = {x.getParent().name(): x for x in cameras} camera_names["Create new camera."] = "create_camera" @@ -97,7 +98,7 @@ class ImagePlaneLoader(api.Loader): camera = camera_names[window.camera] if camera == "create_camera": - camera = pc.createNode("camera") + camera = pm.createNode("camera") if camera is None: return @@ -109,7 +110,7 @@ class ImagePlaneLoader(api.Loader): pass # Create image plane - image_plane_transform, image_plane_shape = pc.imagePlane( + image_plane_transform, image_plane_shape = pm.imagePlane( camera=camera, showInAllViews=False ) image_plane_shape.depth.set(image_plane_depth) @@ -118,8 +119,8 @@ class ImagePlaneLoader(api.Loader): context["representation"]["data"]["path"] ) - start_frame = pc.playbackOptions(q=True, min=True) - end_frame = pc.playbackOptions(q=True, max=True) + start_frame = pm.playbackOptions(q=True, min=True) + end_frame = pm.playbackOptions(q=True, max=True) image_plane_shape.frameOffset.set(1 - start_frame) image_plane_shape.frameIn.set(start_frame) @@ -130,12 +131,12 @@ class ImagePlaneLoader(api.Loader): movie_representations = ["mov", "preview"] if context["representation"]["name"] in movie_representations: # Need to get "type" by string, because its a method as well. - pc.Attribute(image_plane_shape + ".type").set(2) + pm.Attribute(image_plane_shape + ".type").set(2) # Ask user whether to use sequence or still image. if context["representation"]["name"] == "exr": # Ensure OpenEXRLoader plugin is loaded. - pc.loadPlugin("OpenEXRLoader.mll", quiet=True) + pm.loadPlugin("OpenEXRLoader.mll", quiet=True) message = ( "Hold image sequence on first frame?" @@ -151,7 +152,7 @@ class ImagePlaneLoader(api.Loader): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - pc.delete( + pm.delete( image_plane_shape.listConnections(type="expression")[0] ) image_plane_shape.frameExtension.set(start_frame) @@ -164,7 +165,7 @@ class ImagePlaneLoader(api.Loader): ) for node in new_nodes: - pc.rename(node, "{}:{}".format(namespace, node)) + pm.rename(node, "{}:{}".format(namespace, node)) return containerise( name=name, @@ -175,8 +176,9 @@ class ImagePlaneLoader(api.Loader): ) def update(self, container, representation): + import pymel.core as pm image_plane_shape = None - for node in pc.PyNode(container["objectName"]).members(): + for node in pm.PyNode(container["objectName"]).members(): if node.nodeType() == "imagePlane": image_plane_shape = node diff --git a/pype/plugins/maya/load/load_look.py b/pype/hosts/maya/plugins/load/load_look.py similarity index 95% rename from pype/plugins/maya/load/load_look.py rename to pype/hosts/maya/plugins/load/load_look.py index c5b58c9bd5..ab8f971d62 100644 --- a/pype/plugins/maya/load/load_look.py +++ b/pype/hosts/maya/plugins/load/load_look.py @@ -1,13 +1,13 @@ -import pype.hosts.maya.plugin +import pype.hosts.maya.api.plugin from avalon import api, io import json -import pype.hosts.maya.lib +import pype.hosts.maya.api.lib from collections import defaultdict from pype.widgets.message_window import ScrollMessageBox from Qt import QtWidgets -class LookLoader(pype.hosts.maya.plugin.ReferenceLoader): +class LookLoader(pype.hosts.maya.api.plugin.ReferenceLoader): """Specific loader for lookdev""" families = ["look"] @@ -120,7 +120,7 @@ class LookLoader(pype.hosts.maya.plugin.ReferenceLoader): cmds.file(cr=reference_node) # cleanReference # reapply shading groups from json representation on orig nodes - pype.hosts.maya.lib.apply_shaders(relationships, + pype.hosts.maya.api.lib.apply_shaders(relationships, shader_nodes, orig_nodes) @@ -138,8 +138,8 @@ class LookLoader(pype.hosts.maya.plugin.ReferenceLoader): # region compute lookup nodes_by_id = defaultdict(list) for n in nodes: - nodes_by_id[pype.hosts.maya.lib.get_id(n)].append(n) - pype.hosts.maya.lib.apply_attributes(attributes, nodes_by_id) + nodes_by_id[pype.hosts.maya.api.lib.get_id(n)].append(n) + pype.hosts.maya.api.lib.apply_attributes(attributes, nodes_by_id) # Update metadata cmds.setAttr("{}.representation".format(node), diff --git a/pype/plugins/maya/load/load_matchmove.py b/pype/hosts/maya/plugins/load/load_matchmove.py similarity index 100% rename from pype/plugins/maya/load/load_matchmove.py rename to pype/hosts/maya/plugins/load/load_matchmove.py diff --git a/pype/plugins/maya/load/load_reference.py b/pype/hosts/maya/plugins/load/load_reference.py similarity index 98% rename from pype/plugins/maya/load/load_reference.py rename to pype/hosts/maya/plugins/load/load_reference.py index 23b3cedb55..d37579423c 100644 --- a/pype/plugins/maya/load/load_reference.py +++ b/pype/hosts/maya/plugins/load/load_reference.py @@ -1,11 +1,11 @@ -import pype.hosts.maya.plugin +import pype.hosts.maya.api.plugin from avalon import api, maya from maya import cmds import os from pype.api import get_project_settings -class ReferenceLoader(pype.hosts.maya.plugin.ReferenceLoader): +class ReferenceLoader(pype.hosts.maya.api.plugin.ReferenceLoader): """Load the model""" families = ["model", diff --git a/pype/plugins/maya/load/load_rendersetup.py b/pype/hosts/maya/plugins/load/load_rendersetup.py similarity index 96% rename from pype/plugins/maya/load/load_rendersetup.py rename to pype/hosts/maya/plugins/load/load_rendersetup.py index 45a314a9d1..c540c3880e 100644 --- a/pype/plugins/maya/load/load_rendersetup.py +++ b/pype/hosts/maya/plugins/load/load_rendersetup.py @@ -12,7 +12,7 @@ import sys from avalon import api from avalon.maya import lib -from pype.hosts.maya import lib as pypelib +from pype.hosts.maya.api import lib as pypelib from maya import cmds import maya.app.renderSetup.model.renderSetup as renderSetup @@ -32,7 +32,7 @@ class RenderSetupLoader(api.Loader): def load(self, context, name, namespace, data): """Load RenderSetup settings.""" from avalon.maya.pipeline import containerise - # from pype.hosts.maya.lib import namespaced + # from pype.hosts.maya.api.lib import namespaced asset = context['asset']['name'] namespace = namespace or lib.unique_namespace( diff --git a/pype/plugins/maya/load/load_vdb_to_redshift.py b/pype/hosts/maya/plugins/load/load_vdb_to_redshift.py similarity index 100% rename from pype/plugins/maya/load/load_vdb_to_redshift.py rename to pype/hosts/maya/plugins/load/load_vdb_to_redshift.py diff --git a/pype/plugins/maya/load/load_vdb_to_vray.py b/pype/hosts/maya/plugins/load/load_vdb_to_vray.py similarity index 100% rename from pype/plugins/maya/load/load_vdb_to_vray.py rename to pype/hosts/maya/plugins/load/load_vdb_to_vray.py diff --git a/pype/plugins/maya/load/load_vrayproxy.py b/pype/hosts/maya/plugins/load/load_vrayproxy.py similarity index 99% rename from pype/plugins/maya/load/load_vrayproxy.py rename to pype/hosts/maya/plugins/load/load_vrayproxy.py index 73f02b81e4..270d0f9baa 100644 --- a/pype/plugins/maya/load/load_vrayproxy.py +++ b/pype/hosts/maya/plugins/load/load_vrayproxy.py @@ -19,7 +19,7 @@ class VRayProxyLoader(api.Loader): def load(self, context, name, namespace, data): from avalon.maya.pipeline import containerise - from pype.hosts.maya.lib import namespaced + from pype.hosts.maya.api.lib import namespaced try: family = context["representation"]["context"]["family"] diff --git a/pype/plugins/maya/load/load_yeti_cache.py b/pype/hosts/maya/plugins/load/load_yeti_cache.py similarity index 99% rename from pype/plugins/maya/load/load_yeti_cache.py rename to pype/hosts/maya/plugins/load/load_yeti_cache.py index 19cf3920fe..16d51ad56d 100644 --- a/pype/plugins/maya/load/load_yeti_cache.py +++ b/pype/hosts/maya/plugins/load/load_yeti_cache.py @@ -8,7 +8,7 @@ from maya import cmds from avalon import api, io from avalon.maya import lib as avalon_lib, pipeline -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from pype.api import get_project_settings from pprint import pprint diff --git a/pype/plugins/maya/load/load_yeti_rig.py b/pype/hosts/maya/plugins/load/load_yeti_rig.py similarity index 95% rename from pype/plugins/maya/load/load_yeti_rig.py rename to pype/hosts/maya/plugins/load/load_yeti_rig.py index 3a9339c707..d025ed13cc 100644 --- a/pype/plugins/maya/load/load_yeti_rig.py +++ b/pype/hosts/maya/plugins/load/load_yeti_rig.py @@ -2,11 +2,11 @@ import os from collections import defaultdict from pype.api import get_project_settings -import pype.hosts.maya.plugin -from pype.hosts.maya import lib +import pype.hosts.maya.api.plugin +from pype.hosts.maya.api import lib -class YetiRigLoader(pype.hosts.maya.plugin.ReferenceLoader): +class YetiRigLoader(pype.hosts.maya.api.plugin.ReferenceLoader): """ This loader will load Yeti rig. You can select something in scene and if it has same ID as mesh published with rig, their shapes will be linked diff --git a/pype/hosts/maya/plugins/publish/__init__.py b/pype/hosts/maya/plugins/publish/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/maya/publish/collect_animation.py b/pype/hosts/maya/plugins/publish/collect_animation.py similarity index 100% rename from pype/plugins/maya/publish/collect_animation.py rename to pype/hosts/maya/plugins/publish/collect_animation.py diff --git a/pype/plugins/maya/publish/collect_ass.py b/pype/hosts/maya/plugins/publish/collect_ass.py similarity index 100% rename from pype/plugins/maya/publish/collect_ass.py rename to pype/hosts/maya/plugins/publish/collect_ass.py diff --git a/pype/plugins/maya/publish/collect_assembly.py b/pype/hosts/maya/plugins/publish/collect_assembly.py similarity index 98% rename from pype/plugins/maya/publish/collect_assembly.py rename to pype/hosts/maya/plugins/publish/collect_assembly.py index f9a933d8e8..be3408a0bd 100644 --- a/pype/plugins/maya/publish/collect_assembly.py +++ b/pype/hosts/maya/plugins/publish/collect_assembly.py @@ -3,7 +3,7 @@ import pyblish.api from maya import cmds, mel from avalon import maya as avalon -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib # TODO : Publish of assembly: -unique namespace for all assets, VALIDATOR! diff --git a/pype/plugins/maya/publish/collect_file_dependencies.py b/pype/hosts/maya/plugins/publish/collect_file_dependencies.py similarity index 100% rename from pype/plugins/maya/publish/collect_file_dependencies.py rename to pype/hosts/maya/plugins/publish/collect_file_dependencies.py diff --git a/pype/plugins/maya/publish/collect_ftrack_family.py b/pype/hosts/maya/plugins/publish/collect_ftrack_family.py similarity index 100% rename from pype/plugins/maya/publish/collect_ftrack_family.py rename to pype/hosts/maya/plugins/publish/collect_ftrack_family.py diff --git a/pype/plugins/maya/publish/collect_history.py b/pype/hosts/maya/plugins/publish/collect_history.py similarity index 100% rename from pype/plugins/maya/publish/collect_history.py rename to pype/hosts/maya/plugins/publish/collect_history.py diff --git a/pype/plugins/maya/publish/collect_instances.py b/pype/hosts/maya/plugins/publish/collect_instances.py similarity index 100% rename from pype/plugins/maya/publish/collect_instances.py rename to pype/hosts/maya/plugins/publish/collect_instances.py diff --git a/pype/plugins/maya/publish/collect_look.py b/pype/hosts/maya/plugins/publish/collect_look.py similarity index 99% rename from pype/plugins/maya/publish/collect_look.py rename to pype/hosts/maya/plugins/publish/collect_look.py index 7df85e4ba7..35abc5a991 100644 --- a/pype/plugins/maya/publish/collect_look.py +++ b/pype/hosts/maya/plugins/publish/collect_look.py @@ -4,7 +4,7 @@ import glob from maya import cmds import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib SHAPE_ATTRS = ["castsShadows", "receiveShadows", diff --git a/pype/plugins/maya/publish/collect_maya_units.py b/pype/hosts/maya/plugins/publish/collect_maya_units.py similarity index 100% rename from pype/plugins/maya/publish/collect_maya_units.py rename to pype/hosts/maya/plugins/publish/collect_maya_units.py diff --git a/pype/plugins/maya/publish/collect_maya_workspace.py b/pype/hosts/maya/plugins/publish/collect_maya_workspace.py similarity index 100% rename from pype/plugins/maya/publish/collect_maya_workspace.py rename to pype/hosts/maya/plugins/publish/collect_maya_workspace.py diff --git a/pype/plugins/maya/publish/collect_mayaascii.py b/pype/hosts/maya/plugins/publish/collect_mayaascii.py similarity index 100% rename from pype/plugins/maya/publish/collect_mayaascii.py rename to pype/hosts/maya/plugins/publish/collect_mayaascii.py diff --git a/pype/plugins/maya/publish/collect_model.py b/pype/hosts/maya/plugins/publish/collect_model.py similarity index 100% rename from pype/plugins/maya/publish/collect_model.py rename to pype/hosts/maya/plugins/publish/collect_model.py diff --git a/pype/plugins/maya/publish/collect_remove_marked.py b/pype/hosts/maya/plugins/publish/collect_remove_marked.py similarity index 100% rename from pype/plugins/maya/publish/collect_remove_marked.py rename to pype/hosts/maya/plugins/publish/collect_remove_marked.py diff --git a/pype/plugins/maya/publish/collect_render.py b/pype/hosts/maya/plugins/publish/collect_render.py similarity index 96% rename from pype/plugins/maya/publish/collect_render.py rename to pype/hosts/maya/plugins/publish/collect_render.py index 0853473120..fdd77815cc 100644 --- a/pype/plugins/maya/publish/collect_render.py +++ b/pype/hosts/maya/plugins/publish/collect_render.py @@ -2,7 +2,7 @@ """Collect render data. This collector will go through render layers in maya and prepare all data -needed to create instances and their representations for submition and +needed to create instances and their representations for submission and publishing on farm. Requires: @@ -49,8 +49,8 @@ import maya.app.renderSetup.model.renderSetup as renderSetup import pyblish.api from avalon import maya, api -from pype.hosts.maya.expected_files import ExpectedFiles -from pype.hosts.maya import lib +from pype.hosts.maya.api.expected_files import ExpectedFiles +from pype.hosts.maya.api import lib class CollectMayaRender(pyblish.api.ContextPlugin): @@ -248,8 +248,11 @@ class CollectMayaRender(pyblish.api.ContextPlugin): "tilesX": render_instance.data.get("tilesX") or 2, "tilesY": render_instance.data.get("tilesY") or 2, "priority": render_instance.data.get("priority"), - "convertToScanline": render_instance.data.get("convertToScanline") or False, # noqa: E501 - "vrayUseReferencedAovs": render_instance.data.get("vrayUseReferencedAovs") or False # noqa: E501 + "convertToScanline": render_instance.data.get( + "convertToScanline") or False, + "useReferencedAovs": render_instance.data.get( + "useReferencedAovs") or render_instance.data.get( + "vrayUseReferencedAovs") or False } if self.sync_workfile_version: diff --git a/pype/plugins/maya/publish/collect_render_layer_aovs.py b/pype/hosts/maya/plugins/publish/collect_render_layer_aovs.py similarity index 98% rename from pype/plugins/maya/publish/collect_render_layer_aovs.py rename to pype/hosts/maya/plugins/publish/collect_render_layer_aovs.py index ff44497d6d..d776b43907 100644 --- a/pype/plugins/maya/publish/collect_render_layer_aovs.py +++ b/pype/hosts/maya/plugins/publish/collect_render_layer_aovs.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CollectRenderLayerAOVS(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/collect_renderable_camera.py b/pype/hosts/maya/plugins/publish/collect_renderable_camera.py similarity index 95% rename from pype/plugins/maya/publish/collect_renderable_camera.py rename to pype/hosts/maya/plugins/publish/collect_renderable_camera.py index a7d613517b..893a2cab61 100644 --- a/pype/plugins/maya/publish/collect_renderable_camera.py +++ b/pype/hosts/maya/plugins/publish/collect_renderable_camera.py @@ -2,7 +2,7 @@ import pyblish.api from maya import cmds -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class CollectRenderableCamera(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/collect_review.py b/pype/hosts/maya/plugins/publish/collect_review.py similarity index 100% rename from pype/plugins/maya/publish/collect_review.py rename to pype/hosts/maya/plugins/publish/collect_review.py diff --git a/pype/plugins/maya/publish/collect_rig.py b/pype/hosts/maya/plugins/publish/collect_rig.py similarity index 100% rename from pype/plugins/maya/publish/collect_rig.py rename to pype/hosts/maya/plugins/publish/collect_rig.py diff --git a/pype/plugins/maya/publish/collect_scene.py b/pype/hosts/maya/plugins/publish/collect_scene.py similarity index 100% rename from pype/plugins/maya/publish/collect_scene.py rename to pype/hosts/maya/plugins/publish/collect_scene.py diff --git a/pype/plugins/maya/publish/collect_unreal_staticmesh.py b/pype/hosts/maya/plugins/publish/collect_unreal_staticmesh.py similarity index 100% rename from pype/plugins/maya/publish/collect_unreal_staticmesh.py rename to pype/hosts/maya/plugins/publish/collect_unreal_staticmesh.py diff --git a/pype/plugins/maya/publish/collect_workscene_fps.py b/pype/hosts/maya/plugins/publish/collect_workscene_fps.py similarity index 100% rename from pype/plugins/maya/publish/collect_workscene_fps.py rename to pype/hosts/maya/plugins/publish/collect_workscene_fps.py diff --git a/pype/plugins/maya/publish/collect_yeti_cache.py b/pype/hosts/maya/plugins/publish/collect_yeti_cache.py similarity index 98% rename from pype/plugins/maya/publish/collect_yeti_cache.py rename to pype/hosts/maya/plugins/publish/collect_yeti_cache.py index 26c3f601f6..2cfc56e486 100644 --- a/pype/plugins/maya/publish/collect_yeti_cache.py +++ b/pype/hosts/maya/plugins/publish/collect_yeti_cache.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib SETTINGS = {"renderDensity", "renderWidth", diff --git a/pype/plugins/maya/publish/collect_yeti_rig.py b/pype/hosts/maya/plugins/publish/collect_yeti_rig.py similarity index 99% rename from pype/plugins/maya/publish/collect_yeti_rig.py rename to pype/hosts/maya/plugins/publish/collect_yeti_rig.py index 73a84b0073..15bcdc51dd 100644 --- a/pype/plugins/maya/publish/collect_yeti_rig.py +++ b/pype/hosts/maya/plugins/publish/collect_yeti_rig.py @@ -5,7 +5,7 @@ from maya import cmds import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib SETTINGS = {"renderDensity", diff --git a/pype/plugins/maya/publish/determine_future_version.py b/pype/hosts/maya/plugins/publish/determine_future_version.py similarity index 100% rename from pype/plugins/maya/publish/determine_future_version.py rename to pype/hosts/maya/plugins/publish/determine_future_version.py diff --git a/pype/plugins/maya/publish/extract_animation.py b/pype/hosts/maya/plugins/publish/extract_animation.py similarity index 98% rename from pype/plugins/maya/publish/extract_animation.py rename to pype/hosts/maya/plugins/publish/extract_animation.py index f7058b34f1..f56ba2f400 100644 --- a/pype/plugins/maya/publish/extract_animation.py +++ b/pype/hosts/maya/plugins/publish/extract_animation.py @@ -4,7 +4,7 @@ from maya import cmds import avalon.maya import pype.api -from pype.hosts.maya.lib import extract_alembic +from pype.hosts.maya.api.lib import extract_alembic class ExtractAnimation(pype.api.Extractor): diff --git a/pype/plugins/maya/publish/extract_ass.py b/pype/hosts/maya/plugins/publish/extract_ass.py similarity index 100% rename from pype/plugins/maya/publish/extract_ass.py rename to pype/hosts/maya/plugins/publish/extract_ass.py diff --git a/pype/plugins/maya/publish/extract_assembly.py b/pype/hosts/maya/plugins/publish/extract_assembly.py similarity index 97% rename from pype/plugins/maya/publish/extract_assembly.py rename to pype/hosts/maya/plugins/publish/extract_assembly.py index 8c5264713d..c72f1f1835 100644 --- a/pype/plugins/maya/publish/extract_assembly.py +++ b/pype/hosts/maya/plugins/publish/extract_assembly.py @@ -3,7 +3,7 @@ import json import os import pype.api -from pype.hosts.maya.lib import extract_alembic +from pype.hosts.maya.api.lib import extract_alembic from maya import cmds diff --git a/pype/plugins/maya/publish/extract_assproxy.py b/pype/hosts/maya/plugins/publish/extract_assproxy.py similarity index 98% rename from pype/plugins/maya/publish/extract_assproxy.py rename to pype/hosts/maya/plugins/publish/extract_assproxy.py index 0f97d047c1..3579d26534 100644 --- a/pype/plugins/maya/publish/extract_assproxy.py +++ b/pype/hosts/maya/plugins/publish/extract_assproxy.py @@ -5,7 +5,6 @@ import contextlib import avalon.maya import pype.api -from pype.hosts.maya import lib class ExtractAssProxy(pype.api.Extractor): diff --git a/pype/plugins/maya/publish/extract_camera_alembic.py b/pype/hosts/maya/plugins/publish/extract_camera_alembic.py similarity index 99% rename from pype/plugins/maya/publish/extract_camera_alembic.py rename to pype/hosts/maya/plugins/publish/extract_camera_alembic.py index c0538338dc..c37f2ecb76 100644 --- a/pype/plugins/maya/publish/extract_camera_alembic.py +++ b/pype/hosts/maya/plugins/publish/extract_camera_alembic.py @@ -5,7 +5,7 @@ from maya import cmds import avalon.maya import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ExtractCameraAlembic(pype.api.Extractor): diff --git a/pype/plugins/maya/publish/extract_camera_mayaScene.py b/pype/hosts/maya/plugins/publish/extract_camera_mayaScene.py similarity index 99% rename from pype/plugins/maya/publish/extract_camera_mayaScene.py rename to pype/hosts/maya/plugins/publish/extract_camera_mayaScene.py index a1854b1db0..16ebc39419 100644 --- a/pype/plugins/maya/publish/extract_camera_mayaScene.py +++ b/pype/hosts/maya/plugins/publish/extract_camera_mayaScene.py @@ -7,7 +7,7 @@ from maya import cmds import avalon.maya import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib def massage_ma_file(path): diff --git a/pype/plugins/maya/publish/extract_fbx.py b/pype/hosts/maya/plugins/publish/extract_fbx.py similarity index 100% rename from pype/plugins/maya/publish/extract_fbx.py rename to pype/hosts/maya/plugins/publish/extract_fbx.py diff --git a/pype/plugins/maya/publish/extract_look.py b/pype/hosts/maya/plugins/publish/extract_look.py similarity index 99% rename from pype/plugins/maya/publish/extract_look.py rename to pype/hosts/maya/plugins/publish/extract_look.py index 0a7e4fb2ee..2c4837b7a7 100644 --- a/pype/plugins/maya/publish/extract_look.py +++ b/pype/hosts/maya/plugins/publish/extract_look.py @@ -14,7 +14,7 @@ import avalon.maya from avalon import io, api import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib # Modes for transfer COPY = 1 diff --git a/pype/plugins/maya/publish/extract_maya_scene_raw.py b/pype/hosts/maya/plugins/publish/extract_maya_scene_raw.py similarity index 100% rename from pype/plugins/maya/publish/extract_maya_scene_raw.py rename to pype/hosts/maya/plugins/publish/extract_maya_scene_raw.py diff --git a/pype/plugins/maya/publish/extract_model.py b/pype/hosts/maya/plugins/publish/extract_model.py similarity index 99% rename from pype/plugins/maya/publish/extract_model.py rename to pype/hosts/maya/plugins/publish/extract_model.py index 8276d1a006..1c268a9e0e 100644 --- a/pype/plugins/maya/publish/extract_model.py +++ b/pype/hosts/maya/plugins/publish/extract_model.py @@ -6,7 +6,7 @@ from maya import cmds import avalon.maya import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ExtractModel(pype.api.Extractor): diff --git a/pype/plugins/maya/publish/extract_playblast.py b/pype/hosts/maya/plugins/publish/extract_playblast.py similarity index 99% rename from pype/plugins/maya/publish/extract_playblast.py rename to pype/hosts/maya/plugins/publish/extract_playblast.py index 39b02a5a83..770b077e41 100644 --- a/pype/plugins/maya/publish/extract_playblast.py +++ b/pype/hosts/maya/plugins/publish/extract_playblast.py @@ -4,7 +4,7 @@ import contextlib import clique import capture -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib import pype.api from maya import cmds diff --git a/pype/plugins/maya/publish/extract_pointcache.py b/pype/hosts/maya/plugins/publish/extract_pointcache.py similarity index 98% rename from pype/plugins/maya/publish/extract_pointcache.py rename to pype/hosts/maya/plugins/publish/extract_pointcache.py index e43685cac8..58742c8567 100644 --- a/pype/plugins/maya/publish/extract_pointcache.py +++ b/pype/hosts/maya/plugins/publish/extract_pointcache.py @@ -4,7 +4,7 @@ from maya import cmds import avalon.maya import pype.api -from pype.hosts.maya.lib import extract_alembic +from pype.hosts.maya.api.lib import extract_alembic class ExtractAlembic(pype.api.Extractor): diff --git a/pype/plugins/maya/publish/extract_rendersetup.py b/pype/hosts/maya/plugins/publish/extract_rendersetup.py similarity index 100% rename from pype/plugins/maya/publish/extract_rendersetup.py rename to pype/hosts/maya/plugins/publish/extract_rendersetup.py diff --git a/pype/plugins/maya/publish/extract_rig.py b/pype/hosts/maya/plugins/publish/extract_rig.py similarity index 100% rename from pype/plugins/maya/publish/extract_rig.py rename to pype/hosts/maya/plugins/publish/extract_rig.py diff --git a/pype/plugins/maya/publish/extract_thumbnail.py b/pype/hosts/maya/plugins/publish/extract_thumbnail.py similarity index 99% rename from pype/plugins/maya/publish/extract_thumbnail.py rename to pype/hosts/maya/plugins/publish/extract_thumbnail.py index 6956341ffd..49511f6af6 100644 --- a/pype/plugins/maya/publish/extract_thumbnail.py +++ b/pype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -4,7 +4,7 @@ import glob import capture -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib import pype.api from maya import cmds diff --git a/pype/plugins/maya/publish/extract_vrayproxy.py b/pype/hosts/maya/plugins/publish/extract_vrayproxy.py similarity index 100% rename from pype/plugins/maya/publish/extract_vrayproxy.py rename to pype/hosts/maya/plugins/publish/extract_vrayproxy.py diff --git a/pype/plugins/maya/publish/extract_yeti_cache.py b/pype/hosts/maya/plugins/publish/extract_yeti_cache.py similarity index 100% rename from pype/plugins/maya/publish/extract_yeti_cache.py rename to pype/hosts/maya/plugins/publish/extract_yeti_cache.py diff --git a/pype/plugins/maya/publish/extract_yeti_rig.py b/pype/hosts/maya/plugins/publish/extract_yeti_rig.py similarity index 99% rename from pype/plugins/maya/publish/extract_yeti_rig.py rename to pype/hosts/maya/plugins/publish/extract_yeti_rig.py index 71d4cf6198..43908d8742 100644 --- a/pype/plugins/maya/publish/extract_yeti_rig.py +++ b/pype/hosts/maya/plugins/publish/extract_yeti_rig.py @@ -9,7 +9,7 @@ from maya import cmds import avalon.maya.lib as lib import pype.api -import pype.hosts.maya.lib as maya +import pype.hosts.maya.api.lib as maya @contextlib.contextmanager diff --git a/pype/plugins/maya/publish/increment_current_file_deadline.py b/pype/hosts/maya/plugins/publish/increment_current_file_deadline.py similarity index 100% rename from pype/plugins/maya/publish/increment_current_file_deadline.py rename to pype/hosts/maya/plugins/publish/increment_current_file_deadline.py diff --git a/pype/plugins/maya/publish/save_scene.py b/pype/hosts/maya/plugins/publish/save_scene.py similarity index 100% rename from pype/plugins/maya/publish/save_scene.py rename to pype/hosts/maya/plugins/publish/save_scene.py diff --git a/pype/plugins/maya/publish/submit_maya_muster.py b/pype/hosts/maya/plugins/publish/submit_maya_muster.py similarity index 99% rename from pype/plugins/maya/publish/submit_maya_muster.py rename to pype/hosts/maya/plugins/publish/submit_maya_muster.py index b10c4ecbbb..e31f989224 100644 --- a/pype/plugins/maya/publish/submit_maya_muster.py +++ b/pype/hosts/maya/plugins/publish/submit_maya_muster.py @@ -10,7 +10,7 @@ from avalon import api from avalon.vendor import requests import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from pype.api import get_system_settings diff --git a/pype/plugins/maya/publish/validate_animation_content.py b/pype/hosts/maya/plugins/publish/validate_animation_content.py similarity index 93% rename from pype/plugins/maya/publish/validate_animation_content.py rename to pype/hosts/maya/plugins/publish/validate_animation_content.py index 63f1135fdc..ec6f33c969 100644 --- a/pype/plugins/maya/publish/validate_animation_content.py +++ b/pype/hosts/maya/plugins/publish/validate_animation_content.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateAnimationContent(pyblish.api.InstancePlugin): @@ -15,7 +15,7 @@ class ValidateAnimationContent(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["animation"] label = "Animation Content" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @classmethod def get_invalid(cls, instance): diff --git a/pype/plugins/maya/publish/validate_animation_out_set_related_node_ids.py b/pype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py similarity index 93% rename from pype/plugins/maya/publish/validate_animation_out_set_related_node_ids.py rename to pype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py index 4fe676404c..6bea9bf856 100644 --- a/pype/plugins/maya/publish/validate_animation_out_set_related_node_ids.py +++ b/pype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py @@ -2,8 +2,8 @@ import maya.cmds as cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateOutRelatedNodeIds(pyblish.api.InstancePlugin): @@ -20,7 +20,10 @@ class ValidateOutRelatedNodeIds(pyblish.api.InstancePlugin): families = ['animation', "pointcache"] hosts = ['maya'] label = 'Animation Out Set Related Node Ids' - actions = [pype.hosts.maya.action.SelectInvalidAction, pype.api.RepairAction] + actions = [ + pype.hosts.maya.api.action.SelectInvalidAction, + pype.api.RepairAction + ] def process(self, instance): """Process all meshes""" diff --git a/pype/plugins/maya/publish/validate_ass_relative_paths.py b/pype/hosts/maya/plugins/publish/validate_ass_relative_paths.py similarity index 99% rename from pype/plugins/maya/publish/validate_ass_relative_paths.py rename to pype/hosts/maya/plugins/publish/validate_ass_relative_paths.py index 22ebf52d49..b77a0c1923 100644 --- a/pype/plugins/maya/publish/validate_ass_relative_paths.py +++ b/pype/hosts/maya/plugins/publish/validate_ass_relative_paths.py @@ -5,7 +5,7 @@ import maya.cmds as cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateAssRelativePaths(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/validate_assembly_name.py b/pype/hosts/maya/plugins/publish/validate_assembly_name.py similarity index 94% rename from pype/plugins/maya/publish/validate_assembly_name.py rename to pype/hosts/maya/plugins/publish/validate_assembly_name.py index 934275ca47..54479035c5 100644 --- a/pype/plugins/maya/publish/validate_assembly_name.py +++ b/pype/hosts/maya/plugins/publish/validate_assembly_name.py @@ -1,6 +1,6 @@ import pyblish.api import maya.cmds as cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateAssemblyName(pyblish.api.InstancePlugin): @@ -12,7 +12,7 @@ class ValidateAssemblyName(pyblish.api.InstancePlugin): label = "Validate Assembly Name" order = pyblish.api.ValidatorOrder families = ["assembly"] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] active = False @classmethod diff --git a/pype/plugins/maya/publish/validate_assembly_namespaces.py b/pype/hosts/maya/plugins/publish/validate_assembly_namespaces.py similarity index 91% rename from pype/plugins/maya/publish/validate_assembly_namespaces.py rename to pype/hosts/maya/plugins/publish/validate_assembly_namespaces.py index 50fda1a758..32f4b8db52 100644 --- a/pype/plugins/maya/publish/validate_assembly_namespaces.py +++ b/pype/hosts/maya/plugins/publish/validate_assembly_namespaces.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateAssemblyNamespaces(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateAssemblyNamespaces(pyblish.api.InstancePlugin): label = "Validate Assembly Namespaces" order = pyblish.api.ValidatorOrder families = ["assembly"] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_assembly_transforms.py b/pype/hosts/maya/plugins/publish/validate_assembly_transforms.py similarity index 95% rename from pype/plugins/maya/publish/validate_assembly_transforms.py rename to pype/hosts/maya/plugins/publish/validate_assembly_transforms.py index c033f5374a..146736ba8d 100644 --- a/pype/plugins/maya/publish/validate_assembly_transforms.py +++ b/pype/hosts/maya/plugins/publish/validate_assembly_transforms.py @@ -3,7 +3,7 @@ import pype.api from maya import cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateAssemblyModelTransforms(pyblish.api.InstancePlugin): @@ -28,7 +28,7 @@ class ValidateAssemblyModelTransforms(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder + 0.49 label = "Assembly Model Transforms" families = ["assembly"] - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] prompt_message = ("You are about to reset the matrix to the default values." @@ -44,7 +44,7 @@ class ValidateAssemblyModelTransforms(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - from pype.hosts.maya import lib + from pype.hosts.maya.api import lib # Get all transforms in the loaded containers container_roots = cmds.listRelatives(instance.data["hierarchy"], @@ -89,7 +89,7 @@ class ValidateAssemblyModelTransforms(pyblish.api.InstancePlugin): """ - from pype.hosts.maya import lib + from pype.hosts.maya.api import lib from avalon.vendor.Qt import QtWidgets # Store namespace in variable, cosmetics thingy diff --git a/pype/plugins/maya/publish/validate_attributes.py b/pype/hosts/maya/plugins/publish/validate_attributes.py similarity index 100% rename from pype/plugins/maya/publish/validate_attributes.py rename to pype/hosts/maya/plugins/publish/validate_attributes.py diff --git a/pype/plugins/maya/publish/validate_camera_attributes.py b/pype/hosts/maya/plugins/publish/validate_camera_attributes.py similarity index 95% rename from pype/plugins/maya/publish/validate_camera_attributes.py rename to pype/hosts/maya/plugins/publish/validate_camera_attributes.py index 1a1005d0f7..797244ba84 100644 --- a/pype/plugins/maya/publish/validate_camera_attributes.py +++ b/pype/hosts/maya/plugins/publish/validate_camera_attributes.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateCameraAttributes(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateCameraAttributes(pyblish.api.InstancePlugin): families = ['camera'] hosts = ['maya'] label = 'Camera Attributes' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] DEFAULTS = [ ("filmFitOffset", 0.0), diff --git a/pype/plugins/maya/publish/validate_camera_contents.py b/pype/hosts/maya/plugins/publish/validate_camera_contents.py similarity index 95% rename from pype/plugins/maya/publish/validate_camera_contents.py rename to pype/hosts/maya/plugins/publish/validate_camera_contents.py index 27e2031e87..644cfd16bf 100644 --- a/pype/plugins/maya/publish/validate_camera_contents.py +++ b/pype/hosts/maya/plugins/publish/validate_camera_contents.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateCameraContents(pyblish.api.InstancePlugin): @@ -19,7 +19,7 @@ class ValidateCameraContents(pyblish.api.InstancePlugin): families = ['camera'] hosts = ['maya'] label = 'Camera Contents' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @classmethod def get_invalid(cls, instance): diff --git a/pype/plugins/maya/publish/validate_color_sets.py b/pype/hosts/maya/plugins/publish/validate_color_sets.py similarity index 94% rename from pype/plugins/maya/publish/validate_color_sets.py rename to pype/hosts/maya/plugins/publish/validate_color_sets.py index b1d8847f77..aa5901ee0a 100644 --- a/pype/plugins/maya/publish/validate_color_sets.py +++ b/pype/hosts/maya/plugins/publish/validate_color_sets.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateColorSets(pyblish.api.Validator): @@ -18,7 +18,7 @@ class ValidateColorSets(pyblish.api.Validator): families = ['model'] category = 'geometry' label = 'Mesh ColorSets' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] optional = True diff --git a/pype/plugins/maya/publish/validate_current_renderlayer_renderable.py b/pype/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py similarity index 100% rename from pype/plugins/maya/publish/validate_current_renderlayer_renderable.py rename to pype/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py diff --git a/pype/plugins/maya/publish/validate_frame_range.py b/pype/hosts/maya/plugins/publish/validate_frame_range.py similarity index 100% rename from pype/plugins/maya/publish/validate_frame_range.py rename to pype/hosts/maya/plugins/publish/validate_frame_range.py diff --git a/pype/plugins/maya/publish/validate_instance_has_members.py b/pype/hosts/maya/plugins/publish/validate_instance_has_members.py similarity index 87% rename from pype/plugins/maya/publish/validate_instance_has_members.py rename to pype/hosts/maya/plugins/publish/validate_instance_has_members.py index 04e7e1c5eb..b28a056198 100644 --- a/pype/plugins/maya/publish/validate_instance_has_members.py +++ b/pype/hosts/maya/plugins/publish/validate_instance_has_members.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateInstanceHasMembers(pyblish.api.InstancePlugin): @@ -9,7 +9,7 @@ class ValidateInstanceHasMembers(pyblish.api.InstancePlugin): order = pype.api.ValidateContentsOrder hosts = ["maya"] label = 'Instance has members' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @classmethod def get_invalid(cls, instance): diff --git a/pype/plugins/maya/publish/validate_instance_subset.py b/pype/hosts/maya/plugins/publish/validate_instance_subset.py similarity index 100% rename from pype/plugins/maya/publish/validate_instance_subset.py rename to pype/hosts/maya/plugins/publish/validate_instance_subset.py diff --git a/pype/plugins/maya/publish/validate_instancer_content.py b/pype/hosts/maya/plugins/publish/validate_instancer_content.py similarity index 98% rename from pype/plugins/maya/publish/validate_instancer_content.py rename to pype/hosts/maya/plugins/publish/validate_instancer_content.py index a398aead02..74ed73ef53 100644 --- a/pype/plugins/maya/publish/validate_instancer_content.py +++ b/pype/hosts/maya/plugins/publish/validate_instancer_content.py @@ -1,7 +1,7 @@ import maya.cmds as cmds import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ValidateInstancerContent(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/validate_instancer_frame_ranges.py b/pype/hosts/maya/plugins/publish/validate_instancer_frame_ranges.py similarity index 100% rename from pype/plugins/maya/publish/validate_instancer_frame_ranges.py rename to pype/hosts/maya/plugins/publish/validate_instancer_frame_ranges.py diff --git a/pype/plugins/maya/publish/validate_joints_hidden.py b/pype/hosts/maya/plugins/publish/validate_joints_hidden.py similarity index 89% rename from pype/plugins/maya/publish/validate_joints_hidden.py rename to pype/hosts/maya/plugins/publish/validate_joints_hidden.py index 80ca29bfbf..61dfcd563d 100644 --- a/pype/plugins/maya/publish/validate_joints_hidden.py +++ b/pype/hosts/maya/plugins/publish/validate_joints_hidden.py @@ -2,8 +2,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateJointsHidden(pyblish.api.InstancePlugin): @@ -23,7 +23,7 @@ class ValidateJointsHidden(pyblish.api.InstancePlugin): category = 'rig' version = (0, 1, 0) label = "Joints Hidden" - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @staticmethod diff --git a/pype/plugins/maya/publish/validate_look_contents.py b/pype/hosts/maya/plugins/publish/validate_look_contents.py similarity index 97% rename from pype/plugins/maya/publish/validate_look_contents.py rename to pype/hosts/maya/plugins/publish/validate_look_contents.py index 577c88a7e3..8893fdfae8 100644 --- a/pype/plugins/maya/publish/validate_look_contents.py +++ b/pype/hosts/maya/plugins/publish/validate_look_contents.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateLookContents(pyblish.api.InstancePlugin): @@ -21,7 +21,7 @@ class ValidateLookContents(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Look Data Contents' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): """Process all the nodes in the instance""" diff --git a/pype/plugins/maya/publish/validate_look_default_shaders_connections.py b/pype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py similarity index 100% rename from pype/plugins/maya/publish/validate_look_default_shaders_connections.py rename to pype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py diff --git a/pype/plugins/maya/publish/validate_look_id_reference_edits.py b/pype/hosts/maya/plugins/publish/validate_look_id_reference_edits.py similarity index 97% rename from pype/plugins/maya/publish/validate_look_id_reference_edits.py rename to pype/hosts/maya/plugins/publish/validate_look_id_reference_edits.py index de44a3b31a..8cf5493d20 100644 --- a/pype/plugins/maya/publish/validate_look_id_reference_edits.py +++ b/pype/hosts/maya/plugins/publish/validate_look_id_reference_edits.py @@ -3,7 +3,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateLookIdReferenceEdits(pyblish.api.InstancePlugin): @@ -20,7 +20,7 @@ class ValidateLookIdReferenceEdits(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Look Id Reference Edits' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_look_members_unique.py b/pype/hosts/maya/plugins/publish/validate_look_members_unique.py similarity index 92% rename from pype/plugins/maya/publish/validate_look_members_unique.py rename to pype/hosts/maya/plugins/publish/validate_look_members_unique.py index 8b6dd60e70..0b0b50715a 100644 --- a/pype/plugins/maya/publish/validate_look_members_unique.py +++ b/pype/hosts/maya/plugins/publish/validate_look_members_unique.py @@ -2,7 +2,7 @@ from collections import defaultdict import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateUniqueRelationshipMembers(pyblish.api.InstancePlugin): @@ -25,8 +25,8 @@ class ValidateUniqueRelationshipMembers(pyblish.api.InstancePlugin): hosts = ['maya'] families = ['look'] - actions = [pype.hosts.maya.action.SelectInvalidAction, - pype.hosts.maya.action.GenerateUUIDsOnInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction, + pype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all meshes""" diff --git a/pype/plugins/maya/publish/validate_look_no_default_shaders.py b/pype/hosts/maya/plugins/publish/validate_look_no_default_shaders.py similarity index 95% rename from pype/plugins/maya/publish/validate_look_no_default_shaders.py rename to pype/hosts/maya/plugins/publish/validate_look_no_default_shaders.py index 87859d390f..0d6a1ca562 100644 --- a/pype/plugins/maya/publish/validate_look_no_default_shaders.py +++ b/pype/hosts/maya/plugins/publish/validate_look_no_default_shaders.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): @@ -27,7 +27,7 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Look No Default Shaders' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] DEFAULT_SHADERS = {"lambert1", "initialShadingGroup", "initialParticleSE", "particleCloud1"} diff --git a/pype/plugins/maya/publish/validate_look_sets.py b/pype/hosts/maya/plugins/publish/validate_look_sets.py similarity index 96% rename from pype/plugins/maya/publish/validate_look_sets.py rename to pype/hosts/maya/plugins/publish/validate_look_sets.py index 4e06b564ed..d044d8ad2e 100644 --- a/pype/plugins/maya/publish/validate_look_sets.py +++ b/pype/hosts/maya/plugins/publish/validate_look_sets.py @@ -1,5 +1,5 @@ -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib import pyblish.api import pype.api @@ -42,7 +42,7 @@ class ValidateLookSets(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Look Sets' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): """Process all the nodes in the instance""" diff --git a/pype/plugins/maya/publish/validate_look_shading_group.py b/pype/hosts/maya/plugins/publish/validate_look_shading_group.py similarity index 93% rename from pype/plugins/maya/publish/validate_look_shading_group.py rename to pype/hosts/maya/plugins/publish/validate_look_shading_group.py index e8911e3f2f..8d4e3ccf70 100644 --- a/pype/plugins/maya/publish/validate_look_shading_group.py +++ b/pype/hosts/maya/plugins/publish/validate_look_shading_group.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateShadingEngine(pyblish.api.InstancePlugin): @@ -16,7 +16,7 @@ class ValidateShadingEngine(pyblish.api.InstancePlugin): hosts = ["maya"] label = "Look Shading Engine Naming" actions = [ - pype.hosts.maya.action.SelectInvalidAction, pype.api.RepairAction + pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction ] # The default connections to check diff --git a/pype/plugins/maya/publish/validate_look_single_shader.py b/pype/hosts/maya/plugins/publish/validate_look_single_shader.py similarity index 95% rename from pype/plugins/maya/publish/validate_look_single_shader.py rename to pype/hosts/maya/plugins/publish/validate_look_single_shader.py index 600652d16d..8c4835c5bf 100644 --- a/pype/plugins/maya/publish/validate_look_single_shader.py +++ b/pype/hosts/maya/plugins/publish/validate_look_single_shader.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateSingleShader(pyblish.api.InstancePlugin): @@ -16,7 +16,7 @@ class ValidateSingleShader(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Look Single Shader Per Shape' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] # The default connections to check def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_maya_units.py b/pype/hosts/maya/plugins/publish/validate_maya_units.py similarity index 98% rename from pype/plugins/maya/publish/validate_maya_units.py rename to pype/hosts/maya/plugins/publish/validate_maya_units.py index 8712a90f44..c99b8eb813 100644 --- a/pype/plugins/maya/publish/validate_maya_units.py +++ b/pype/hosts/maya/plugins/publish/validate_maya_units.py @@ -3,7 +3,7 @@ import maya.cmds as cmds import pyblish.api import pype.api from pype import lib -import pype.hosts.maya.lib as mayalib +import pype.hosts.maya.api.lib as mayalib from math import ceil diff --git a/pype/plugins/maya/publish/validate_mesh_arnold_attributes.py b/pype/hosts/maya/plugins/publish/validate_mesh_arnold_attributes.py similarity index 96% rename from pype/plugins/maya/publish/validate_mesh_arnold_attributes.py rename to pype/hosts/maya/plugins/publish/validate_mesh_arnold_attributes.py index 04a3cf3c79..a2792693af 100644 --- a/pype/plugins/maya/publish/validate_mesh_arnold_attributes.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_arnold_attributes.py @@ -2,7 +2,7 @@ import pymel.core as pc from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action from avalon import maya @@ -19,7 +19,7 @@ class ValidateMeshArnoldAttributes(pyblish.api.InstancePlugin): category = "geometry" label = "Mesh Arnold Attributes" actions = [ - pype.hosts.maya.action.SelectInvalidAction, + pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction ] optional = True diff --git a/pype/plugins/maya/publish/validate_mesh_has_uv.py b/pype/hosts/maya/plugins/publish/validate_mesh_has_uv.py similarity index 96% rename from pype/plugins/maya/publish/validate_mesh_has_uv.py rename to pype/hosts/maya/plugins/publish/validate_mesh_has_uv.py index f7b9b8503d..ae80b6a8f2 100644 --- a/pype/plugins/maya/publish/validate_mesh_has_uv.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_has_uv.py @@ -4,7 +4,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def len_flattened(components): @@ -50,7 +50,7 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin): families = ['model'] category = 'geometry' label = 'Mesh Has UVs' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] optional = True @classmethod diff --git a/pype/plugins/maya/publish/validate_mesh_lamina_faces.py b/pype/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py similarity index 90% rename from pype/plugins/maya/publish/validate_mesh_lamina_faces.py rename to pype/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py index 5ebb41b6f9..5628008a38 100644 --- a/pype/plugins/maya/publish/validate_mesh_lamina_faces.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_lamina_faces.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMeshLaminaFaces(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateMeshLaminaFaces(pyblish.api.InstancePlugin): category = 'geometry' version = (0, 1, 0) label = 'Mesh Lamina Faces' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_mesh_no_negative_scale.py b/pype/hosts/maya/plugins/publish/validate_mesh_no_negative_scale.py similarity index 93% rename from pype/plugins/maya/publish/validate_mesh_no_negative_scale.py rename to pype/hosts/maya/plugins/publish/validate_mesh_no_negative_scale.py index 988c94e4ef..8446808459 100644 --- a/pype/plugins/maya/publish/validate_mesh_no_negative_scale.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_no_negative_scale.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMeshNoNegativeScale(pyblish.api.Validator): @@ -21,7 +21,7 @@ class ValidateMeshNoNegativeScale(pyblish.api.Validator): hosts = ['maya'] families = ['model'] label = 'Mesh No Negative Scale' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_mesh_non_manifold.py b/pype/hosts/maya/plugins/publish/validate_mesh_non_manifold.py similarity index 91% rename from pype/plugins/maya/publish/validate_mesh_non_manifold.py rename to pype/hosts/maya/plugins/publish/validate_mesh_non_manifold.py index 7559e9e17b..4a2773671d 100644 --- a/pype/plugins/maya/publish/validate_mesh_non_manifold.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_non_manifold.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMeshNonManifold(pyblish.api.Validator): @@ -17,7 +17,7 @@ class ValidateMeshNonManifold(pyblish.api.Validator): hosts = ['maya'] families = ['model'] label = 'Mesh Non-Manifold Vertices/Edges' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_mesh_non_zero_edge.py b/pype/hosts/maya/plugins/publish/validate_mesh_non_zero_edge.py similarity index 91% rename from pype/plugins/maya/publish/validate_mesh_non_zero_edge.py rename to pype/hosts/maya/plugins/publish/validate_mesh_non_zero_edge.py index 0d30312cad..0ed02328c8 100644 --- a/pype/plugins/maya/publish/validate_mesh_non_zero_edge.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_non_zero_edge.py @@ -2,8 +2,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateMeshNonZeroEdgeLength(pyblish.api.InstancePlugin): @@ -22,7 +22,7 @@ class ValidateMeshNonZeroEdgeLength(pyblish.api.InstancePlugin): category = 'geometry' version = (0, 1, 0) label = 'Mesh Edge Length Non Zero' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] optional = True __tolerance = 1e-5 diff --git a/pype/plugins/maya/publish/validate_mesh_normals_unlocked.py b/pype/hosts/maya/plugins/publish/validate_mesh_normals_unlocked.py similarity index 94% rename from pype/plugins/maya/publish/validate_mesh_normals_unlocked.py rename to pype/hosts/maya/plugins/publish/validate_mesh_normals_unlocked.py index a764611b5c..d9d740cf13 100644 --- a/pype/plugins/maya/publish/validate_mesh_normals_unlocked.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_normals_unlocked.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMeshNormalsUnlocked(pyblish.api.Validator): @@ -19,7 +19,7 @@ class ValidateMeshNormalsUnlocked(pyblish.api.Validator): category = 'geometry' version = (0, 1, 0) label = 'Mesh Normals Unlocked' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] optional = True diff --git a/pype/plugins/maya/publish/validate_mesh_overlapping_uvs.py b/pype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py similarity index 98% rename from pype/plugins/maya/publish/validate_mesh_overlapping_uvs.py rename to pype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py index c6479675d2..3619d27298 100644 --- a/pype/plugins/maya/publish/validate_mesh_overlapping_uvs.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action import math import maya.api.OpenMaya as om import pymel.core as pm @@ -235,7 +235,7 @@ class ValidateMeshHasOverlappingUVs(pyblish.api.InstancePlugin): families = ['model'] category = 'geometry' label = 'Mesh Has Overlapping UVs' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] optional = True @classmethod diff --git a/pype/plugins/maya/publish/validate_mesh_shader_connections.py b/pype/hosts/maya/plugins/publish/validate_mesh_shader_connections.py similarity index 97% rename from pype/plugins/maya/publish/validate_mesh_shader_connections.py rename to pype/hosts/maya/plugins/publish/validate_mesh_shader_connections.py index a31df7c0ae..b9542fe930 100644 --- a/pype/plugins/maya/publish/validate_mesh_shader_connections.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_shader_connections.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def pairs(iterable): @@ -77,7 +77,7 @@ class ValidateMeshShaderConnections(pyblish.api.InstancePlugin): hosts = ['maya'] families = ['model'] label = "Mesh Shader Connections" - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_mesh_single_uv_set.py b/pype/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py similarity index 93% rename from pype/plugins/maya/publish/validate_mesh_single_uv_set.py rename to pype/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py index 87d83c070e..348bcb5fad 100644 --- a/pype/plugins/maya/publish/validate_mesh_single_uv_set.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_single_uv_set.py @@ -2,8 +2,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateMeshSingleUVSet(pyblish.api.InstancePlugin): @@ -22,7 +22,7 @@ class ValidateMeshSingleUVSet(pyblish.api.InstancePlugin): optional = True version = (0, 1, 0) label = "Mesh Single UV Set" - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @staticmethod diff --git a/pype/plugins/maya/publish/validate_mesh_uv_set_map1.py b/pype/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py similarity index 96% rename from pype/plugins/maya/publish/validate_mesh_uv_set_map1.py rename to pype/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py index 8bf5c55f65..5f954ee917 100644 --- a/pype/plugins/maya/publish/validate_mesh_uv_set_map1.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_uv_set_map1.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMeshUVSetMap1(pyblish.api.InstancePlugin): @@ -20,7 +20,7 @@ class ValidateMeshUVSetMap1(pyblish.api.InstancePlugin): families = ['model'] optional = True label = "Mesh has map1 UV Set" - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @staticmethod diff --git a/pype/plugins/maya/publish/validate_mesh_vertices_have_edges.py b/pype/hosts/maya/plugins/publish/validate_mesh_vertices_have_edges.py similarity index 96% rename from pype/plugins/maya/publish/validate_mesh_vertices_have_edges.py rename to pype/hosts/maya/plugins/publish/validate_mesh_vertices_have_edges.py index 2dd65da7d2..8d39c5cae4 100644 --- a/pype/plugins/maya/publish/validate_mesh_vertices_have_edges.py +++ b/pype/hosts/maya/plugins/publish/validate_mesh_vertices_have_edges.py @@ -4,7 +4,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def len_flattened(components): @@ -62,7 +62,7 @@ class ValidateMeshVerticesHaveEdges(pyblish.api.InstancePlugin): families = ['model'] category = 'geometry' label = 'Mesh Vertices Have Edges' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @classmethod diff --git a/pype/plugins/maya/publish/validate_model_content.py b/pype/hosts/maya/plugins/publish/validate_model_content.py similarity index 96% rename from pype/plugins/maya/publish/validate_model_content.py rename to pype/hosts/maya/plugins/publish/validate_model_content.py index fd7c69ead7..9bec7187e9 100644 --- a/pype/plugins/maya/publish/validate_model_content.py +++ b/pype/hosts/maya/plugins/publish/validate_model_content.py @@ -2,8 +2,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateModelContent(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateModelContent(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["model"] label = "Model Content" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @classmethod def get_invalid(cls, instance): diff --git a/pype/plugins/maya/publish/validate_model_name.py b/pype/hosts/maya/plugins/publish/validate_model_name.py similarity index 97% rename from pype/plugins/maya/publish/validate_model_name.py rename to pype/hosts/maya/plugins/publish/validate_model_name.py index 716b7d5f98..f0004dc81e 100644 --- a/pype/plugins/maya/publish/validate_model_name.py +++ b/pype/hosts/maya/plugins/publish/validate_model_name.py @@ -1,7 +1,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action import re @@ -18,7 +18,7 @@ class ValidateModelName(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["model"] label = "Model Name" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] # path to shader names definitions # TODO: move it to preset file material_file = None diff --git a/pype/plugins/maya/publish/validate_muster_connection.py b/pype/hosts/maya/plugins/publish/validate_muster_connection.py similarity index 99% rename from pype/plugins/maya/publish/validate_muster_connection.py rename to pype/hosts/maya/plugins/publish/validate_muster_connection.py index 35acdb326f..ad1022c71d 100644 --- a/pype/plugins/maya/publish/validate_muster_connection.py +++ b/pype/hosts/maya/plugins/publish/validate_muster_connection.py @@ -5,7 +5,7 @@ import appdirs import pyblish.api from avalon.vendor import requests from pype.plugin import contextplugin_should_run -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateMusterConnection(pyblish.api.ContextPlugin): diff --git a/pype/plugins/maya/publish/validate_no_animation.py b/pype/hosts/maya/plugins/publish/validate_no_animation.py similarity index 91% rename from pype/plugins/maya/publish/validate_no_animation.py rename to pype/hosts/maya/plugins/publish/validate_no_animation.py index fc198745c0..a6daf3246e 100644 --- a/pype/plugins/maya/publish/validate_no_animation.py +++ b/pype/hosts/maya/plugins/publish/validate_no_animation.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateNoAnimation(pyblish.api.Validator): @@ -19,7 +19,7 @@ class ValidateNoAnimation(pyblish.api.Validator): hosts = ["maya"] families = ["model"] optional = True - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_no_default_camera.py b/pype/hosts/maya/plugins/publish/validate_no_default_camera.py similarity index 90% rename from pype/plugins/maya/publish/validate_no_default_camera.py rename to pype/hosts/maya/plugins/publish/validate_no_default_camera.py index 876612c076..07ec2e4325 100644 --- a/pype/plugins/maya/publish/validate_no_default_camera.py +++ b/pype/hosts/maya/plugins/publish/validate_no_default_camera.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateNoDefaultCameras(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateNoDefaultCameras(pyblish.api.InstancePlugin): families = ['camera'] version = (0, 1, 0) label = "No Default Cameras" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_no_namespace.py b/pype/hosts/maya/plugins/publish/validate_no_namespace.py similarity index 93% rename from pype/plugins/maya/publish/validate_no_namespace.py rename to pype/hosts/maya/plugins/publish/validate_no_namespace.py index 6a6c7792c5..97cd46e68a 100644 --- a/pype/plugins/maya/publish/validate_no_namespace.py +++ b/pype/hosts/maya/plugins/publish/validate_no_namespace.py @@ -3,7 +3,7 @@ import maya.cmds as cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def get_namespace(node_name): @@ -22,7 +22,7 @@ class ValidateNoNamespace(pyblish.api.InstancePlugin): category = 'cleanup' version = (0, 1, 0) label = 'No Namespaces' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @staticmethod diff --git a/pype/plugins/maya/publish/validate_no_null_transforms.py b/pype/hosts/maya/plugins/publish/validate_no_null_transforms.py similarity index 95% rename from pype/plugins/maya/publish/validate_no_null_transforms.py rename to pype/hosts/maya/plugins/publish/validate_no_null_transforms.py index aa35c47339..78f06bbbd8 100644 --- a/pype/plugins/maya/publish/validate_no_null_transforms.py +++ b/pype/hosts/maya/plugins/publish/validate_no_null_transforms.py @@ -2,7 +2,7 @@ import maya.cmds as cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def has_shape_children(node): @@ -44,7 +44,7 @@ class ValidateNoNullTransforms(pyblish.api.InstancePlugin): version = (0, 1, 0) label = 'No Empty/Null Transforms' actions = [pype.api.RepairAction, - pype.hosts.maya.action.SelectInvalidAction] + pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_no_unknown_nodes.py b/pype/hosts/maya/plugins/publish/validate_no_unknown_nodes.py similarity index 90% rename from pype/plugins/maya/publish/validate_no_unknown_nodes.py rename to pype/hosts/maya/plugins/publish/validate_no_unknown_nodes.py index 04c8fd04bc..6b2f1337d3 100644 --- a/pype/plugins/maya/publish/validate_no_unknown_nodes.py +++ b/pype/hosts/maya/plugins/publish/validate_no_unknown_nodes.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateNoUnknownNodes(pyblish.api.InstancePlugin): @@ -21,7 +21,7 @@ class ValidateNoUnknownNodes(pyblish.api.InstancePlugin): families = ['model', 'rig'] optional = True label = "Unknown Nodes" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_no_vraymesh.py b/pype/hosts/maya/plugins/publish/validate_no_vraymesh.py similarity index 100% rename from pype/plugins/maya/publish/validate_no_vraymesh.py rename to pype/hosts/maya/plugins/publish/validate_no_vraymesh.py diff --git a/pype/plugins/maya/publish/validate_node_ids.py b/pype/hosts/maya/plugins/publish/validate_node_ids.py similarity index 86% rename from pype/plugins/maya/publish/validate_node_ids.py rename to pype/hosts/maya/plugins/publish/validate_node_ids.py index 777d810c80..4942d44d70 100644 --- a/pype/plugins/maya/publish/validate_node_ids.py +++ b/pype/hosts/maya/plugins/publish/validate_node_ids.py @@ -1,8 +1,8 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ValidateNodeIDs(pyblish.api.InstancePlugin): @@ -25,8 +25,8 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin): "yetiRig", "assembly"] - actions = [pype.hosts.maya.action.SelectInvalidAction, - pype.hosts.maya.action.GenerateUUIDsOnInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction, + pype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all meshes""" diff --git a/pype/plugins/maya/publish/validate_node_ids_deformed_shapes.py b/pype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py similarity index 92% rename from pype/plugins/maya/publish/validate_node_ids_deformed_shapes.py rename to pype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py index 49b78f79bc..757414a074 100644 --- a/pype/plugins/maya/publish/validate_node_ids_deformed_shapes.py +++ b/pype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py @@ -2,8 +2,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateNodeIdsDeformedShape(pyblish.api.InstancePlugin): @@ -20,7 +20,10 @@ class ValidateNodeIdsDeformedShape(pyblish.api.InstancePlugin): families = ['look'] hosts = ['maya'] label = 'Deformed shape ids' - actions = [pype.hosts.maya.action.SelectInvalidAction, pype.api.RepairAction] + actions = [ + pype.hosts.maya.api.action.SelectInvalidAction, + pype.api.RepairAction + ] def process(self, instance): """Process all the nodes in the instance""" diff --git a/pype/plugins/maya/publish/validate_node_ids_in_database.py b/pype/hosts/maya/plugins/publish/validate_node_ids_in_database.py similarity index 89% rename from pype/plugins/maya/publish/validate_node_ids_in_database.py rename to pype/hosts/maya/plugins/publish/validate_node_ids_in_database.py index 15241411b7..154d0c1d38 100644 --- a/pype/plugins/maya/publish/validate_node_ids_in_database.py +++ b/pype/hosts/maya/plugins/publish/validate_node_ids_in_database.py @@ -3,8 +3,8 @@ import pyblish.api from avalon import io import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): @@ -23,8 +23,8 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): hosts = ['maya'] families = ["*"] - actions = [pype.hosts.maya.action.SelectInvalidAction, - pype.hosts.maya.action.GenerateUUIDsOnInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction, + pype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] def process(self, instance): invalid = self.get_invalid(instance) diff --git a/pype/plugins/maya/publish/validate_node_ids_related.py b/pype/hosts/maya/plugins/publish/validate_node_ids_related.py similarity index 88% rename from pype/plugins/maya/publish/validate_node_ids_related.py rename to pype/hosts/maya/plugins/publish/validate_node_ids_related.py index 193e53440a..390e5c157a 100644 --- a/pype/plugins/maya/publish/validate_node_ids_related.py +++ b/pype/hosts/maya/plugins/publish/validate_node_ids_related.py @@ -2,9 +2,9 @@ import pyblish.api import pype.api from avalon import io -import pype.hosts.maya.action +import pype.hosts.maya.api.action -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ValidateNodeIDsRelated(pyblish.api.InstancePlugin): @@ -20,8 +20,8 @@ class ValidateNodeIDsRelated(pyblish.api.InstancePlugin): "rig"] optional = True - actions = [pype.hosts.maya.action.SelectInvalidAction, - pype.hosts.maya.action.GenerateUUIDsOnInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction, + pype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all nodes in instance (including hierarchy)""" diff --git a/pype/plugins/maya/publish/validate_node_ids_unique.py b/pype/hosts/maya/plugins/publish/validate_node_ids_unique.py similarity index 89% rename from pype/plugins/maya/publish/validate_node_ids_unique.py rename to pype/hosts/maya/plugins/publish/validate_node_ids_unique.py index 3a66941f89..20320854f0 100644 --- a/pype/plugins/maya/publish/validate_node_ids_unique.py +++ b/pype/hosts/maya/plugins/publish/validate_node_ids_unique.py @@ -2,8 +2,8 @@ from collections import defaultdict import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): @@ -20,8 +20,8 @@ class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): "rig", "yetiRig"] - actions = [pype.hosts.maya.action.SelectInvalidAction, - pype.hosts.maya.action.GenerateUUIDsOnInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction, + pype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all meshes""" diff --git a/pype/plugins/maya/publish/validate_node_no_ghosting.py b/pype/hosts/maya/plugins/publish/validate_node_no_ghosting.py similarity index 93% rename from pype/plugins/maya/publish/validate_node_no_ghosting.py rename to pype/hosts/maya/plugins/publish/validate_node_no_ghosting.py index a4b3122b34..3acd5b027d 100644 --- a/pype/plugins/maya/publish/validate_node_no_ghosting.py +++ b/pype/hosts/maya/plugins/publish/validate_node_no_ghosting.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateNodeNoGhosting(pyblish.api.InstancePlugin): @@ -21,7 +21,7 @@ class ValidateNodeNoGhosting(pyblish.api.InstancePlugin): hosts = ['maya'] families = ['model', 'rig'] label = "No Ghosting" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] _attributes = {'ghosting': 0} diff --git a/pype/plugins/maya/publish/validate_render_image_rule.py b/pype/hosts/maya/plugins/publish/validate_render_image_rule.py similarity index 100% rename from pype/plugins/maya/publish/validate_render_image_rule.py rename to pype/hosts/maya/plugins/publish/validate_render_image_rule.py diff --git a/pype/plugins/maya/publish/validate_render_no_default_cameras.py b/pype/hosts/maya/plugins/publish/validate_render_no_default_cameras.py similarity index 91% rename from pype/plugins/maya/publish/validate_render_no_default_cameras.py rename to pype/hosts/maya/plugins/publish/validate_render_no_default_cameras.py index 8c1fb42f1a..38383310a2 100644 --- a/pype/plugins/maya/publish/validate_render_no_default_cameras.py +++ b/pype/hosts/maya/plugins/publish/validate_render_no_default_cameras.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateRenderNoDefaultCameras(pyblish.api.InstancePlugin): @@ -12,7 +12,7 @@ class ValidateRenderNoDefaultCameras(pyblish.api.InstancePlugin): hosts = ['maya'] families = ['renderlayer'] label = "No Default Cameras Renderable" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @staticmethod def get_invalid(instance): diff --git a/pype/plugins/maya/publish/validate_render_single_camera.py b/pype/hosts/maya/plugins/publish/validate_render_single_camera.py similarity index 95% rename from pype/plugins/maya/publish/validate_render_single_camera.py rename to pype/hosts/maya/plugins/publish/validate_render_single_camera.py index 482cf2fb59..268a6599e2 100644 --- a/pype/plugins/maya/publish/validate_render_single_camera.py +++ b/pype/hosts/maya/plugins/publish/validate_render_single_camera.py @@ -2,7 +2,7 @@ import re import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action from maya import cmds @@ -28,7 +28,7 @@ class ValidateRenderSingleCamera(pyblish.api.InstancePlugin): hosts = ['maya'] families = ["renderlayer", "vrayscene"] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] R_CAMERA_TOKEN = re.compile(r'%c|', re.IGNORECASE) diff --git a/pype/plugins/maya/publish/validate_renderlayer_aovs.py b/pype/hosts/maya/plugins/publish/validate_renderlayer_aovs.py similarity index 94% rename from pype/plugins/maya/publish/validate_renderlayer_aovs.py rename to pype/hosts/maya/plugins/publish/validate_renderlayer_aovs.py index aba8fdaa96..7fdd8b377c 100644 --- a/pype/plugins/maya/publish/validate_renderlayer_aovs.py +++ b/pype/hosts/maya/plugins/publish/validate_renderlayer_aovs.py @@ -1,6 +1,6 @@ import pyblish.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action from avalon import io import pype.api @@ -25,7 +25,7 @@ class ValidateRenderLayerAOVs(pyblish.api.InstancePlugin): label = "Render Passes / AOVs Are Registered" hosts = ["maya"] families = ["renderlayer"] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): invalid = self.get_invalid(instance) diff --git a/pype/plugins/maya/publish/validate_rendersettings.py b/pype/hosts/maya/plugins/publish/validate_rendersettings.py similarity index 99% rename from pype/plugins/maya/publish/validate_rendersettings.py rename to pype/hosts/maya/plugins/publish/validate_rendersettings.py index 297ead5ebb..88a386db57 100644 --- a/pype/plugins/maya/publish/validate_rendersettings.py +++ b/pype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -6,7 +6,7 @@ import pymel.core as pm import pyblish.api import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib class ValidateRenderSettings(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/validate_resources.py b/pype/hosts/maya/plugins/publish/validate_resources.py similarity index 100% rename from pype/plugins/maya/publish/validate_resources.py rename to pype/hosts/maya/plugins/publish/validate_resources.py diff --git a/pype/plugins/maya/publish/validate_rig_contents.py b/pype/hosts/maya/plugins/publish/validate_rig_contents.py similarity index 100% rename from pype/plugins/maya/publish/validate_rig_contents.py rename to pype/hosts/maya/plugins/publish/validate_rig_contents.py diff --git a/pype/plugins/maya/publish/validate_rig_controllers.py b/pype/hosts/maya/plugins/publish/validate_rig_controllers.py similarity index 97% rename from pype/plugins/maya/publish/validate_rig_controllers.py rename to pype/hosts/maya/plugins/publish/validate_rig_controllers.py index a127728155..ef0df2df7c 100644 --- a/pype/plugins/maya/publish/validate_rig_controllers.py +++ b/pype/hosts/maya/plugins/publish/validate_rig_controllers.py @@ -3,8 +3,8 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya.lib import undo_chunk +import pype.hosts.maya.api.action +from pype.hosts.maya.api.lib import undo_chunk class ValidateRigControllers(pyblish.api.InstancePlugin): @@ -30,7 +30,7 @@ class ValidateRigControllers(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["rig"] actions = [pype.api.RepairAction, - pype.hosts.maya.action.SelectInvalidAction] + pype.hosts.maya.api.action.SelectInvalidAction] # Default controller values CONTROLLER_DEFAULTS = { diff --git a/pype/plugins/maya/publish/validate_rig_controllers_arnold_attributes.py b/pype/hosts/maya/plugins/publish/validate_rig_controllers_arnold_attributes.py similarity index 95% rename from pype/plugins/maya/publish/validate_rig_controllers_arnold_attributes.py rename to pype/hosts/maya/plugins/publish/validate_rig_controllers_arnold_attributes.py index 8c1f8e4c7b..f19e3fbb61 100644 --- a/pype/plugins/maya/publish/validate_rig_controllers_arnold_attributes.py +++ b/pype/hosts/maya/plugins/publish/validate_rig_controllers_arnold_attributes.py @@ -3,8 +3,8 @@ from maya import cmds import pyblish.api import pype.api -from pype.hosts.maya import lib -import pype.hosts.maya.action +from pype.hosts.maya.api import lib +import pype.hosts.maya.api.action class ValidateRigControllersArnoldAttributes(pyblish.api.InstancePlugin): @@ -31,7 +31,7 @@ class ValidateRigControllersArnoldAttributes(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["rig"] actions = [pype.api.RepairAction, - pype.hosts.maya.action.SelectInvalidAction] + pype.hosts.maya.api.action.SelectInvalidAction] attributes = [ "rcurve", diff --git a/pype/plugins/maya/publish/validate_rig_out_set_node_ids.py b/pype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py similarity index 92% rename from pype/plugins/maya/publish/validate_rig_out_set_node_ids.py rename to pype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py index 97dca803ee..1782395d96 100644 --- a/pype/plugins/maya/publish/validate_rig_out_set_node_ids.py +++ b/pype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py @@ -2,8 +2,8 @@ import maya.cmds as cmds import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya import lib +import pype.hosts.maya.api.action +from pype.hosts.maya.api import lib class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): @@ -20,7 +20,10 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): families = ["rig"] hosts = ['maya'] label = 'Rig Out Set Node Ids' - actions = [pype.hosts.maya.action.SelectInvalidAction, pype.api.RepairAction] + actions = [ + pype.hosts.maya.api.action.SelectInvalidAction, + pype.api.RepairAction + ] def process(self, instance): """Process all meshes""" diff --git a/pype/plugins/maya/publish/validate_rig_output_ids.py b/pype/hosts/maya/plugins/publish/validate_rig_output_ids.py similarity index 95% rename from pype/plugins/maya/publish/validate_rig_output_ids.py rename to pype/hosts/maya/plugins/publish/validate_rig_output_ids.py index fe9662d9d9..37a50da910 100644 --- a/pype/plugins/maya/publish/validate_rig_output_ids.py +++ b/pype/hosts/maya/plugins/publish/validate_rig_output_ids.py @@ -3,8 +3,7 @@ import pymel.core as pc import pyblish.api import pype.api -import pype.hosts.maya.action -from pype.hosts.maya.lib import undo_chunk +import pype.hosts.maya.api.action class ValidateRigOutputIds(pyblish.api.InstancePlugin): @@ -19,7 +18,7 @@ class ValidateRigOutputIds(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["rig"] actions = [pype.api.RepairAction, - pype.hosts.maya.action.SelectInvalidAction] + pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): invalid = self.get_invalid(instance, compute=True) diff --git a/pype/plugins/maya/publish/validate_scene_set_workspace.py b/pype/hosts/maya/plugins/publish/validate_scene_set_workspace.py similarity index 100% rename from pype/plugins/maya/publish/validate_scene_set_workspace.py rename to pype/hosts/maya/plugins/publish/validate_scene_set_workspace.py diff --git a/pype/plugins/maya/publish/validate_shader_name.py b/pype/hosts/maya/plugins/publish/validate_shader_name.py similarity index 96% rename from pype/plugins/maya/publish/validate_shader_name.py rename to pype/hosts/maya/plugins/publish/validate_shader_name.py index 094ac0afe9..4a42ec6e35 100644 --- a/pype/plugins/maya/publish/validate_shader_name.py +++ b/pype/hosts/maya/plugins/publish/validate_shader_name.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action import re @@ -18,7 +18,7 @@ class ValidateShaderName(pyblish.api.InstancePlugin): families = ["look"] hosts = ['maya'] label = 'Validate Shaders Name' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] regex = r'(?P.*)_(.*)_SHD' # The default connections to check diff --git a/pype/plugins/maya/publish/validate_shape_default_names.py b/pype/hosts/maya/plugins/publish/validate_shape_default_names.py similarity index 96% rename from pype/plugins/maya/publish/validate_shape_default_names.py rename to pype/hosts/maya/plugins/publish/validate_shape_default_names.py index c0638863da..cd4e9905d9 100644 --- a/pype/plugins/maya/publish/validate_shape_default_names.py +++ b/pype/hosts/maya/plugins/publish/validate_shape_default_names.py @@ -4,7 +4,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action def short_name(node): @@ -38,7 +38,7 @@ class ValidateShapeDefaultNames(pyblish.api.InstancePlugin): optional = True version = (0, 1, 0) label = "Shape Default Naming" - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] @staticmethod diff --git a/pype/plugins/maya/publish/validate_shape_render_stats.py b/pype/hosts/maya/plugins/publish/validate_shape_render_stats.py similarity index 95% rename from pype/plugins/maya/publish/validate_shape_render_stats.py rename to pype/hosts/maya/plugins/publish/validate_shape_render_stats.py index af48d664ec..c94becabe9 100644 --- a/pype/plugins/maya/publish/validate_shape_render_stats.py +++ b/pype/hosts/maya/plugins/publish/validate_shape_render_stats.py @@ -3,7 +3,7 @@ import pype.api from maya import cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateShapeRenderStats(pyblish.api.Validator): @@ -13,7 +13,7 @@ class ValidateShapeRenderStats(pyblish.api.Validator): hosts = ['maya'] families = ['model'] label = 'Shape Default Render Stats' - actions = [pype.hosts.maya.action.SelectInvalidAction, + actions = [pype.hosts.maya.api.action.SelectInvalidAction, pype.api.RepairAction] defaults = {'castsShadows': 1, diff --git a/pype/plugins/maya/publish/validate_single_assembly.py b/pype/hosts/maya/plugins/publish/validate_single_assembly.py similarity index 100% rename from pype/plugins/maya/publish/validate_single_assembly.py rename to pype/hosts/maya/plugins/publish/validate_single_assembly.py diff --git a/pype/plugins/maya/publish/validate_skinCluster_deformer_set.py b/pype/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py similarity index 96% rename from pype/plugins/maya/publish/validate_skinCluster_deformer_set.py rename to pype/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py index 39870658ad..2d28d26b0f 100644 --- a/pype/plugins/maya/publish/validate_skinCluster_deformer_set.py +++ b/pype/hosts/maya/plugins/publish/validate_skinCluster_deformer_set.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateSkinclusterDeformerSet(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateSkinclusterDeformerSet(pyblish.api.InstancePlugin): hosts = ['maya'] families = ['fbx'] label = "Skincluster Deformer Relationships" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): """Process all the transform nodes in the instance""" diff --git a/pype/plugins/maya/publish/validate_step_size.py b/pype/hosts/maya/plugins/publish/validate_step_size.py similarity index 91% rename from pype/plugins/maya/publish/validate_step_size.py rename to pype/hosts/maya/plugins/publish/validate_step_size.py index 5e46e7df0b..502a1c37c2 100644 --- a/pype/plugins/maya/publish/validate_step_size.py +++ b/pype/hosts/maya/plugins/publish/validate_step_size.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateStepSize(pyblish.api.InstancePlugin): @@ -15,7 +15,7 @@ class ValidateStepSize(pyblish.api.InstancePlugin): families = ['camera', 'pointcache', 'animation'] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] MIN = 0.01 MAX = 1.0 diff --git a/pype/plugins/maya/publish/validate_transform_naming_suffix.py b/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py similarity index 97% rename from pype/plugins/maya/publish/validate_transform_naming_suffix.py rename to pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py index 120123af4b..14d4e7d5c8 100644 --- a/pype/plugins/maya/publish/validate_transform_naming_suffix.py +++ b/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py @@ -4,7 +4,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin): @@ -34,7 +34,7 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin): optional = True version = (0, 1, 0) label = 'Suffix Naming Conventions' - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] SUFFIX_NAMING_TABLE = {'mesh': ["_GEO", "_GES", "_GEP", "_OSD"], 'nurbsCurve': ["_CRV"], 'nurbsSurface': ["_NRB"], diff --git a/pype/plugins/maya/publish/validate_transform_zero.py b/pype/hosts/maya/plugins/publish/validate_transform_zero.py similarity index 95% rename from pype/plugins/maya/publish/validate_transform_zero.py rename to pype/hosts/maya/plugins/publish/validate_transform_zero.py index ac5517061f..0cecc3124b 100644 --- a/pype/plugins/maya/publish/validate_transform_zero.py +++ b/pype/hosts/maya/plugins/publish/validate_transform_zero.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateTransformZero(pyblish.api.Validator): @@ -20,7 +20,7 @@ class ValidateTransformZero(pyblish.api.Validator): category = "geometry" version = (0, 1, 0) label = "Transform Zero (Freeze)" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] _identity = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, diff --git a/pype/plugins/maya/publish/validate_unicode_strings.py b/pype/hosts/maya/plugins/publish/validate_unicode_strings.py similarity index 96% rename from pype/plugins/maya/publish/validate_unicode_strings.py rename to pype/hosts/maya/plugins/publish/validate_unicode_strings.py index bf44d971af..cfcba4f514 100644 --- a/pype/plugins/maya/publish/validate_unicode_strings.py +++ b/pype/hosts/maya/plugins/publish/validate_unicode_strings.py @@ -3,7 +3,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateUnicodeStrings(pyblish.api.Validator): diff --git a/pype/plugins/maya/publish/validate_unreal_mesh_triangulated.py b/pype/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py similarity index 93% rename from pype/plugins/maya/publish/validate_unreal_mesh_triangulated.py rename to pype/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py index 2cefe27019..9011b584fe 100644 --- a/pype/plugins/maya/publish/validate_unreal_mesh_triangulated.py +++ b/pype/hosts/maya/plugins/publish/validate_unreal_mesh_triangulated.py @@ -13,7 +13,7 @@ class ValidateUnrealMeshTriangulated(pyblish.api.InstancePlugin): families = ["unrealStaticMesh"] category = "geometry" label = "Mesh is Triangulated" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] @classmethod def get_invalid(cls, instance): diff --git a/pype/plugins/maya/publish/validate_unreal_staticmesh_naming.py b/pype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py similarity index 97% rename from pype/plugins/maya/publish/validate_unreal_staticmesh_naming.py rename to pype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py index 4116c5f534..8bda849b3f 100644 --- a/pype/plugins/maya/publish/validate_unreal_staticmesh_naming.py +++ b/pype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py @@ -3,7 +3,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action import re @@ -51,7 +51,7 @@ class ValidateUnrealStaticmeshName(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["unrealStaticMesh"] label = "Unreal StaticMesh Name" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] regex_mesh = r"SM_(?P.*)_(\d{2})" regex_collision = r"((UBX)|(UCP)|(USP)|(UCX))_(?P.*)_(\d{2})" diff --git a/pype/plugins/maya/publish/validate_unreal_up_axis.py b/pype/hosts/maya/plugins/publish/validate_unreal_up_axis.py similarity index 100% rename from pype/plugins/maya/publish/validate_unreal_up_axis.py rename to pype/hosts/maya/plugins/publish/validate_unreal_up_axis.py diff --git a/pype/plugins/maya/publish/validate_vray_distributed_rendering.py b/pype/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py similarity index 98% rename from pype/plugins/maya/publish/validate_vray_distributed_rendering.py rename to pype/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py index 6bec0c88dd..0c3086fee0 100644 --- a/pype/plugins/maya/publish/validate_vray_distributed_rendering.py +++ b/pype/hosts/maya/plugins/publish/validate_vray_distributed_rendering.py @@ -1,6 +1,6 @@ import pyblish.api import pype.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib from maya import cmds diff --git a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py b/pype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py similarity index 98% rename from pype/plugins/maya/publish/validate_vray_referenced_aovs.py rename to pype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py index 120677021d..f451a08b0b 100644 --- a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py +++ b/pype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py @@ -4,7 +4,7 @@ import pyblish.api import types from maya import cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin): diff --git a/pype/plugins/maya/publish/validate_vray_translator_settings.py b/pype/hosts/maya/plugins/publish/validate_vray_translator_settings.py similarity index 100% rename from pype/plugins/maya/publish/validate_vray_translator_settings.py rename to pype/hosts/maya/plugins/publish/validate_vray_translator_settings.py diff --git a/pype/plugins/maya/publish/validate_vrayproxy.py b/pype/hosts/maya/plugins/publish/validate_vrayproxy.py similarity index 100% rename from pype/plugins/maya/publish/validate_vrayproxy.py rename to pype/hosts/maya/plugins/publish/validate_vrayproxy.py diff --git a/pype/plugins/maya/publish/validate_vrayproxy_members.py b/pype/hosts/maya/plugins/publish/validate_vrayproxy_members.py similarity index 90% rename from pype/plugins/maya/publish/validate_vrayproxy_members.py rename to pype/hosts/maya/plugins/publish/validate_vrayproxy_members.py index 75946a6787..829c2d67ae 100644 --- a/pype/plugins/maya/publish/validate_vrayproxy_members.py +++ b/pype/hosts/maya/plugins/publish/validate_vrayproxy_members.py @@ -3,7 +3,7 @@ import pype.api from maya import cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateVrayProxyMembers(pyblish.api.InstancePlugin): @@ -13,7 +13,7 @@ class ValidateVrayProxyMembers(pyblish.api.InstancePlugin): label = 'VRay Proxy Members' hosts = ['maya'] families = ['vrayproxy'] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_yeti_renderscript_callbacks.py b/pype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py similarity index 100% rename from pype/plugins/maya/publish/validate_yeti_renderscript_callbacks.py rename to pype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py diff --git a/pype/plugins/maya/publish/validate_yeti_rig_cache_state.py b/pype/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py similarity index 94% rename from pype/plugins/maya/publish/validate_yeti_rig_cache_state.py rename to pype/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py index 1ed145fecd..7eb3153d1e 100644 --- a/pype/plugins/maya/publish/validate_yeti_rig_cache_state.py +++ b/pype/hosts/maya/plugins/publish/validate_yeti_rig_cache_state.py @@ -1,7 +1,7 @@ import pyblish.api import pype.action import maya.cmds as cmds -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateYetiRigCacheState(pyblish.api.InstancePlugin): @@ -18,7 +18,7 @@ class ValidateYetiRigCacheState(pyblish.api.InstancePlugin): hosts = ["maya"] families = ["yetiRig"] actions = [pype.action.RepairAction, - pype.hosts.maya.action.SelectInvalidAction] + pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): invalid = self.get_invalid(instance) diff --git a/pype/plugins/maya/publish/validate_yeti_rig_input_in_instance.py b/pype/hosts/maya/plugins/publish/validate_yeti_rig_input_in_instance.py similarity index 93% rename from pype/plugins/maya/publish/validate_yeti_rig_input_in_instance.py rename to pype/hosts/maya/plugins/publish/validate_yeti_rig_input_in_instance.py index 647a66cb57..c0bd46efc1 100644 --- a/pype/plugins/maya/publish/validate_yeti_rig_input_in_instance.py +++ b/pype/hosts/maya/plugins/publish/validate_yeti_rig_input_in_instance.py @@ -2,7 +2,7 @@ from maya import cmds import pyblish.api import pype.api -import pype.hosts.maya.action +import pype.hosts.maya.api.action class ValidateYetiRigInputShapesInInstance(pyblish.api.Validator): @@ -12,7 +12,7 @@ class ValidateYetiRigInputShapesInInstance(pyblish.api.Validator): hosts = ["maya"] families = ["yetiRig"] label = "Yeti Rig Input Shapes In Instance" - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.hosts.maya.api.action.SelectInvalidAction] def process(self, instance): diff --git a/pype/plugins/maya/publish/validate_yeti_rig_settings.py b/pype/hosts/maya/plugins/publish/validate_yeti_rig_settings.py similarity index 100% rename from pype/plugins/maya/publish/validate_yeti_rig_settings.py rename to pype/hosts/maya/plugins/publish/validate_yeti_rig_settings.py diff --git a/pype/resources/maya/workspace.mel b/pype/hosts/maya/resources/workspace.mel similarity index 100% rename from pype/resources/maya/workspace.mel rename to pype/hosts/maya/resources/workspace.mel diff --git a/pype/setup/maya/userSetup.py b/pype/hosts/maya/startup/userSetup.py similarity index 95% rename from pype/setup/maya/userSetup.py rename to pype/hosts/maya/startup/userSetup.py index 6ee008c5fc..a562d3ab9e 100644 --- a/pype/setup/maya/userSetup.py +++ b/pype/hosts/maya/startup/userSetup.py @@ -1,6 +1,6 @@ import os from pype.api import get_project_settings -import pype.hosts.maya.lib as mlib +import pype.hosts.maya.api.lib as mlib from maya import cmds diff --git a/pype/hosts/nuke/__init__.py b/pype/hosts/nuke/__init__.py index d0f3577c2e..e69de29bb2 100644 --- a/pype/hosts/nuke/__init__.py +++ b/pype/hosts/nuke/__init__.py @@ -1,144 +0,0 @@ -import os -import sys -import logging - -import nuke - -from avalon import api as avalon -from avalon.tools import workfiles -from pyblish import api as pyblish -from pype.hosts.nuke import menu -from pype.api import Logger -from pype import PLUGINS_DIR -from . import lib - - -self = sys.modules[__name__] -self.workfiles_launched = False -log = Logger().get_logger(__name__) - -AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") - -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "nuke", "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "nuke", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "nuke", "create") -INVENTORY_PATH = os.path.join(PLUGINS_DIR, "nuke", "inventory") - - -# registering pyblish gui regarding settings in presets -if os.getenv("PYBLISH_GUI", None): - pyblish.register_gui(os.getenv("PYBLISH_GUI", None)) - - -def reload_config(): - """Attempt to reload pipeline at run-time. - - CAUTION: This is primarily for development and debugging purposes. - - """ - - import importlib - - for module in ( - "{}.api".format(AVALON_CONFIG), - "{}.hosts.nuke.actions".format(AVALON_CONFIG), - "{}.hosts.nuke.presets".format(AVALON_CONFIG), - "{}.hosts.nuke.menu".format(AVALON_CONFIG), - "{}.hosts.nuke.plugin".format(AVALON_CONFIG), - "{}.hosts.nuke.lib".format(AVALON_CONFIG), - ): - log.info("Reloading module: {}...".format(module)) - - module = importlib.import_module(module) - - try: - importlib.reload(module) - except AttributeError as e: - log.warning("Cannot reload module: {}".format(e)) - reload(module) - - -def install(): - ''' Installing all requarements for Nuke host - ''' - - log.info("Registering Nuke plug-ins..") - pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - avalon.register_plugin_path(avalon.Creator, CREATE_PATH) - avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) - - # Register Avalon event for workfiles loading. - avalon.on("workio.open_file", lib.check_inventory_versions) - - pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled) - workfile_settings = lib.WorkfileSettings() - # Disable all families except for the ones we explicitly want to see - family_states = [ - "write", - "review", - "nukenodes" - "gizmo" - ] - - avalon.data["familiesStateDefault"] = False - avalon.data["familiesStateToggled"] = family_states - - # Workfiles. - launch_workfiles = os.environ.get("WORKFILES_STARTUP") - - if launch_workfiles: - nuke.addOnCreate(launch_workfiles_app, nodeClass="Root") - - # Set context settings. - nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root") - nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") - - menu.install() - - -def launch_workfiles_app(): - '''Function letting start workfiles after start of host - ''' - if not self.workfiles_launched: - self.workfiles_launched = True - workfiles.show(os.environ["AVALON_WORKDIR"]) - - -def uninstall(): - '''Uninstalling host's integration - ''' - log.info("Deregistering Nuke plug-ins..") - pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) - avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) - - pyblish.deregister_callback("instanceToggled", on_pyblish_instance_toggled) - - - reload_config() - menu.uninstall() - - -def on_pyblish_instance_toggled(instance, old_value, new_value): - """Toggle node passthrough states on instance toggles.""" - - log.info("instance toggle: {}, old_value: {}, new_value:{} ".format( - instance, old_value, new_value)) - - from avalon.nuke import ( - viewer_update_and_undo_stop, - add_publish_knob - ) - - # Whether instances should be passthrough based on new value - - with viewer_update_and_undo_stop(): - n = instance[0] - try: - n["publish"].value() - except ValueError: - n = add_publish_knob(n) - log.info(" `Publish` knob was added to write node..") - - n["publish"].setValue(new_value) diff --git a/pype/hosts/nuke/api/__init__.py b/pype/hosts/nuke/api/__init__.py new file mode 100644 index 0000000000..26a8248f01 --- /dev/null +++ b/pype/hosts/nuke/api/__init__.py @@ -0,0 +1,141 @@ +import os +import sys +import nuke + +from avalon import api as avalon +from avalon.tools import workfiles +from pyblish import api as pyblish +from pype.api import Logger +import pype.hosts.nuke +from . import lib, menu + + +self = sys.modules[__name__] +self.workfiles_launched = False +log = Logger().get_logger(__name__) + +AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.nuke.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + + +# registering pyblish gui regarding settings in presets +if os.getenv("PYBLISH_GUI", None): + pyblish.register_gui(os.getenv("PYBLISH_GUI", None)) + + +def reload_config(): + """Attempt to reload pipeline at run-time. + + CAUTION: This is primarily for development and debugging purposes. + + """ + + import importlib + + for module in ( + "{}.api".format(AVALON_CONFIG), + "{}.hosts.nuke.api.actions".format(AVALON_CONFIG), + "{}.hosts.nuke.api.menu".format(AVALON_CONFIG), + "{}.hosts.nuke.api.plugin".format(AVALON_CONFIG), + "{}.hosts.nuke.api.lib".format(AVALON_CONFIG), + ): + log.info("Reloading module: {}...".format(module)) + + module = importlib.import_module(module) + + try: + importlib.reload(module) + except AttributeError as e: + from importlib import reload + log.warning("Cannot reload module: {}".format(e)) + reload(module) + + +def install(): + ''' Installing all requarements for Nuke host + ''' + + log.info("Registering Nuke plug-ins..") + pyblish.register_plugin_path(PUBLISH_PATH) + avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + avalon.register_plugin_path(avalon.Creator, CREATE_PATH) + avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) + + # Register Avalon event for workfiles loading. + avalon.on("workio.open_file", lib.check_inventory_versions) + + pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled) + workfile_settings = lib.WorkfileSettings() + # Disable all families except for the ones we explicitly want to see + family_states = [ + "write", + "review", + "nukenodes" + "gizmo" + ] + + avalon.data["familiesStateDefault"] = False + avalon.data["familiesStateToggled"] = family_states + + # Workfiles. + launch_workfiles = os.environ.get("WORKFILES_STARTUP") + + if launch_workfiles: + nuke.addOnCreate(launch_workfiles_app, nodeClass="Root") + + # Set context settings. + nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root") + # nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") + + menu.install() + + +def launch_workfiles_app(): + '''Function letting start workfiles after start of host + ''' + if not self.workfiles_launched: + self.workfiles_launched = True + workfiles.show(os.environ["AVALON_WORKDIR"]) + + +def uninstall(): + '''Uninstalling host's integration + ''' + log.info("Deregistering Nuke plug-ins..") + pyblish.deregister_plugin_path(PUBLISH_PATH) + avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) + + pyblish.deregister_callback("instanceToggled", on_pyblish_instance_toggled) + + reload_config() + menu.uninstall() + + +def on_pyblish_instance_toggled(instance, old_value, new_value): + """Toggle node passthrough states on instance toggles.""" + + log.info("instance toggle: {}, old_value: {}, new_value:{} ".format( + instance, old_value, new_value)) + + from avalon.nuke import ( + viewer_update_and_undo_stop, + add_publish_knob + ) + + # Whether instances should be passthrough based on new value + + with viewer_update_and_undo_stop(): + n = instance[0] + try: + n["publish"].value() + except ValueError: + n = add_publish_knob(n) + log.info(" `Publish` knob was added to write node..") + + n["publish"].setValue(new_value) diff --git a/pype/hosts/nuke/actions.py b/pype/hosts/nuke/api/actions.py similarity index 96% rename from pype/hosts/nuke/actions.py rename to pype/hosts/nuke/api/actions.py index 23242262c8..f5d5ffb143 100644 --- a/pype/hosts/nuke/actions.py +++ b/pype/hosts/nuke/api/actions.py @@ -5,7 +5,7 @@ from avalon.nuke.lib import ( select_nodes ) -from ...action import get_errored_instances_from_context +from pype.api import get_errored_instances_from_context class SelectInvalidAction(pyblish.api.Action): diff --git a/pype/hosts/nuke/lib.py b/pype/hosts/nuke/api/lib.py similarity index 89% rename from pype/hosts/nuke/lib.py rename to pype/hosts/nuke/api/lib.py index bc71035139..20b00b2d7a 100644 --- a/pype/hosts/nuke/lib.py +++ b/pype/hosts/nuke/api/lib.py @@ -6,26 +6,74 @@ from collections import OrderedDict from avalon import api, io, lib import avalon.nuke from avalon.nuke import lib as anlib -import pype.api as pype +from pype.api import ( + Logger, + Anatomy, + get_version_from_path, + get_anatomy_settings, + get_hierarchy, + get_asset, + config, + ApplicationManager +) import nuke - -from .presets import ( - get_colorspace_preset, - get_node_dataflow_preset, - get_node_colorspace_preset, - get_anatomy -) - from .utils import set_context_favorites -log = pype.Logger().get_logger(__name__) +log = Logger().get_logger(__name__) self = sys.modules[__name__] self._project = None +def get_node_imageio_setting(**kwarg): + ''' Get preset data for dataflow (fileType, compression, bitDepth) + ''' + log.info(kwarg) + host = str(kwarg.get("host", "nuke")) + nodeclass = kwarg.get("nodeclass", None) + creator = kwarg.get("creator", None) + project_name = os.getenv("AVALON_PROJECT") + + assert any([host, nodeclass]), nuke.message( + "`{}`: Missing mandatory kwargs `host`, `cls`".format(__file__)) + + imageio_nodes = (get_anatomy_settings(project_name) + ["imageio"] + .get(host, None) + ["nodes"] + ["requiredNodes"] + ) + + for node in imageio_nodes: + log.info(node) + if node["nukeNodeClass"] == nodeclass: + if creator in node["plugins"]: + imageio_node = node + + log.info("ImageIO node: {}".format(imageio_node)) + return imageio_node + + +def get_imageio_input_colorspace(filename): + ''' Get input file colorspace based on regex in settings. + ''' + imageio_regex_inputs = (get_anatomy_settings(os.getenv("AVALON_PROJECT")) + ["imageio"] + ["nuke"] + ["regexInputs"] + ["inputs"] + ) + + preset_clrsp = None + for regexInput in imageio_regex_inputs: + if bool(re.search(regexInput["regex"], filename)): + preset_clrsp = str(regexInput["colorspace"]) + + return preset_clrsp + + def on_script_load(): ''' Callback for ffmpeg support ''' @@ -39,7 +87,7 @@ def on_script_load(): def check_inventory_versions(): """ - Actiual version idetifier of Loaded containers + Actual version idetifier 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 @@ -52,9 +100,9 @@ def check_inventory_versions(): container = avalon.nuke.parse_container(each) if container: - node = container["_node"] - avalon_knob_data = avalon.nuke.get_avalon_knob_data( - node, ['avalon:', 'ak:']) + node = nuke.toNode(container["objectName"]) + avalon_knob_data = avalon.nuke.read( + node) # get representation from io representation = io.find_one({ @@ -88,7 +136,7 @@ def writes_version_sync(): ''' Callback synchronizing version of publishable write nodes ''' try: - rootVersion = pype.get_version_from_path(nuke.root().name()) + rootVersion = get_version_from_path(nuke.root().name()) padding = len(rootVersion) new_version = "v" + str("{" + ":0>{}".format(padding) + "}").format( int(rootVersion) @@ -103,8 +151,8 @@ def writes_version_sync(): if "AvalonTab" not in each.knobs(): continue - avalon_knob_data = avalon.nuke.get_avalon_knob_data( - each, ['avalon:', 'ak:']) + avalon_knob_data = avalon.nuke.read( + each) try: if avalon_knob_data['families'] not in ["render"]: @@ -113,7 +161,7 @@ def writes_version_sync(): node_file = each['file'].value() - node_version = "v" + pype.get_version_from_path(node_file) + node_version = "v" + get_version_from_path(node_file) log.debug("node_version: {}".format(node_version)) node_new_file = node_file.replace(node_version, new_version) @@ -134,24 +182,40 @@ def version_up_script(): nukescripts.script_and_write_nodes_version_up() +def check_subsetname_exists(nodes, subset_name): + """ + Checking if node is not already created to secure there is no duplicity + + Arguments: + nodes (list): list of nuke.Node objects + subset_name (str): name we try to find + + Returns: + bool: True of False + """ + result = next((True for n in nodes + if subset_name in avalon.nuke.read(n).get("subset", "")), False) + return result + + def get_render_path(node): ''' Generate Render path from presets regarding avalon knob data ''' data = dict() - data['avalon'] = avalon.nuke.get_avalon_knob_data( - node, ['avalon:', 'ak:']) + data['avalon'] = avalon.nuke.read( + node) data_preset = { "class": data['avalon']['family'], "preset": data['avalon']['families'] } - nuke_dataflow_writes = get_node_dataflow_preset(**data_preset) - nuke_colorspace_writes = get_node_colorspace_preset(**data_preset) + nuke_imageio_writes = get_node_imageio_setting(**data_preset) + application = lib.get_application(os.environ["AVALON_APP_NAME"]) data.update({ - "nuke_dataflow_writes": nuke_dataflow_writes, - "nuke_colorspace_writes": nuke_colorspace_writes + "application": application, + "nuke_imageio_writes": nuke_imageio_writes }) anatomy_filled = format_anatomy(data) @@ -169,7 +233,7 @@ def format_anatomy(data): ''' # TODO: perhaps should be nonPublic - anatomy = get_anatomy() + anatomy = Anatomy() log.debug("__ anatomy.templates: {}".format(anatomy.templates)) try: @@ -192,18 +256,16 @@ def format_anatomy(data): version = data.get("version", None) if not version: file = script_name() - data["version"] = pype.get_version_from_path(file) + data["version"] = get_version_from_path(file) project_document = io.find_one({"type": "project"}) data.update({ "subset": data["avalon"]["subset"], "asset": data["avalon"]["asset"], - "task": api.Session["AVALON_TASK"], + "task": os.environ["AVALON_TASK"], "family": data["avalon"]["family"], "project": {"name": project_document["name"], "code": project_document["data"].get("code", '')}, - "representation": data["nuke_dataflow_writes"]["file_type"], - "app": api.Session["AVALON_APP"], - "hierarchy": pype.get_hierarchy(), + "hierarchy": get_hierarchy(), "frame": "#" * padding, }) return anatomy.format(data) @@ -217,11 +279,11 @@ def script_name(): def add_button_write_to_read(node): name = "createReadNode" - label = "[ Create Read ]" + label = "Cread Read From Rendered" value = "import write_to_read;write_to_read.write_to_read(nuke.thisNode())" - k = nuke.PyScript_Knob(name, label, value) - k.setFlag(0x1000) - node.addKnob(k) + knob = nuke.PyScript_Knob(name, label, value) + knob.clearFlag(nuke.STARTLINE) + node.addKnob(knob) def create_write_node(name, data, input=None, prenodes=None, review=True): @@ -254,18 +316,26 @@ def create_write_node(name, data, input=None, prenodes=None, review=True): node (obj): group node with avalon data as Knobs ''' - nuke_dataflow_writes = get_node_dataflow_preset(**data) - nuke_colorspace_writes = get_node_colorspace_preset(**data) + imageio_writes = get_node_imageio_setting(**data) + app_manager = ApplicationManager() + app_name = os.environ.get("AVALON_APP_NAME") + if app_name: + app = app_manager.applications.get(app_name) + + for knob in imageio_writes["knobs"]: + if knob["name"] == "file_type": + representation = knob["value"] try: data.update({ - "nuke_dataflow_writes": nuke_dataflow_writes, - "nuke_colorspace_writes": nuke_colorspace_writes + "app": app.host_name, + "imageio_writes": imageio_writes, + "representation": representation, }) anatomy_filled = format_anatomy(data) except Exception as e: - msg = "problem with resolving anatomy tepmlate: {}".format(e) + msg = "problem with resolving anatomy template: {}".format(e) log.error(msg) nuke.message(msg) @@ -274,7 +344,7 @@ def create_write_node(name, data, input=None, prenodes=None, review=True): fpath = data["fpath_template"].format( work=fpath, version=data["version"], subset=data["subset"], frame=data["frame"], - ext=data["nuke_dataflow_writes"]["file_type"] + ext=representation ) # create directory @@ -287,17 +357,12 @@ def create_write_node(name, data, input=None, prenodes=None, review=True): }) # adding dataflow template - log.debug("nuke_dataflow_writes: `{}`".format(nuke_dataflow_writes)) - {_data.update({k: v}) - for k, v in nuke_dataflow_writes.items() - if k not in ["_id", "_previous"]} + log.debug("imageio_writes: `{}`".format(imageio_writes)) + for knob in imageio_writes["knobs"]: + if knob["name"] not in ["_id", "_previous"]: + _data.update({knob["name"]: knob["value"]}) - # adding colorspace template - log.debug("nuke_colorspace_writes: `{}`".format(nuke_colorspace_writes)) - {_data.update({k: v}) - for k, v in nuke_colorspace_writes.items()} - - _data = avalon.nuke.lib.fix_data_for_node_create(_data) + _data = anlib.fix_data_for_node_create(_data) log.debug("_data: `{}`".format(_data)) @@ -366,7 +431,7 @@ def create_write_node(name, data, input=None, prenodes=None, review=True): prev_node = now_node # creating write node - write_node = now_node = avalon.nuke.lib.add_write_node( + write_node = now_node = anlib.add_write_node( "inside_{}".format(name), **_data ) @@ -383,30 +448,40 @@ def create_write_node(name, data, input=None, prenodes=None, review=True): now_node.setInput(0, prev_node) # imprinting group node - avalon.nuke.imprint(GN, data["avalon"]) - - # add divider - GN.addKnob(nuke.Text_Knob('')) - + anlib.set_avalon_knob_data(GN, data["avalon"]) + anlib.add_publish_knob(GN) add_rendering_knobs(GN) if review: add_review_knob(GN) # add divider - GN.addKnob(nuke.Text_Knob('')) + GN.addKnob(nuke.Text_Knob('', 'Rendering')) # Add linked knobs. - linked_knob_names = ["Render", "use_limit", "first", "last"] + linked_knob_names = [ + "_grp-start_", + "use_limit", "first", "last", + "_grp-end_", + "Render" + ] for name in linked_knob_names: - link = nuke.Link_Knob(name) - link.makeLink(write_node.name(), name) - link.setName(name) - link.setFlag(0x1000) - GN.addKnob(link) - - # add divider - GN.addKnob(nuke.Text_Knob('')) + if "_grp-start_" in name: + knob = nuke.Tab_Knob( + "rnd_attr", "Rendering attributes", nuke.TABBEGINCLOSEDGROUP) + GN.addKnob(knob) + elif "_grp-end_" in name: + knob = nuke.Tab_Knob( + "rnd_attr_end", "Rendering attributes", nuke.TABENDGROUP) + GN.addKnob(knob) + else: + link = nuke.Link_Knob("") + link.makeLink(write_node.name(), name) + link.setName(name) + if "Render" in name: + link.setLabel("Render Local") + link.setFlag(0x1000) + GN.addKnob(link) # adding write to read button add_button_write_to_read(GN) @@ -431,9 +506,9 @@ def add_rendering_knobs(node): node (obj): with added knobs ''' if "render" not in node.knobs(): - knob = nuke.Enumeration_Knob("render", "Render", [ + knob = nuke.Enumeration_Knob("render", "", [ "Use existing frames", "Local", "On farm"]) - knob.setFlag(0x1000) + knob.clearFlag(nuke.STARTLINE) node.addKnob(knob) return node @@ -538,7 +613,7 @@ class WorkfileSettings(object): self._project = kwargs.get( "project") or io.find_one({"type": "project"}) self._asset = kwargs.get("asset_name") or api.Session["AVALON_ASSET"] - self._asset_entity = pype.get_asset(self._asset) + self._asset_entity = get_asset(self._asset) self._root_node = root_node or nuke.root() self._nodes = self.get_nodes(nodes=nodes) @@ -674,7 +749,7 @@ class WorkfileSettings(object): log.error(msg) return - from avalon.nuke import get_avalon_knob_data + from avalon.nuke import read for node in nuke.allNodes(): @@ -682,7 +757,7 @@ class WorkfileSettings(object): continue # get data from avalon knob - avalon_knob_data = get_avalon_knob_data(node, ["avalon:", "ak:"]) + avalon_knob_data = read(node) if not avalon_knob_data: continue @@ -730,7 +805,7 @@ class WorkfileSettings(object): continue # load nuke presets for Read's colorspace - read_clrs_presets = get_colorspace_preset().get( + read_clrs_presets = config.get_init_presets()["colorspace"].get( "nuke", {}).get("read", {}) # check if any colorspace presets for read is mathing @@ -771,7 +846,8 @@ class WorkfileSettings(object): def set_colorspace(self): ''' Setting colorpace following presets ''' - nuke_colorspace = get_colorspace_preset().get("nuke", None) + nuke_colorspace = config.get_init_presets( + )["colorspace"].get("nuke", None) try: self.set_root_colorspace(nuke_colorspace["root"]) @@ -836,7 +912,7 @@ class WorkfileSettings(object): handle_start = data["handleStart"] handle_end = data["handleEnd"] - fps = data["fps"] + fps = float(data["fps"]) frame_start = int(data["frameStart"]) - handle_start frame_end = int(data["frameEnd"]) + handle_end @@ -863,7 +939,7 @@ class WorkfileSettings(object): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - if not avalon.nuke.imprint(self._root_node, { + if not anlib.set_avalon_knob_data(self._root_node, { "handleStart": int(handle_start), "handleEnd": int(handle_end) }): @@ -971,7 +1047,7 @@ class WorkfileSettings(object): # replace reset resolution from avalon core to pype's self.reset_frame_range_handles() # add colorspace menu item - self.set_colorspace() + # self.set_colorspace() def set_favorites(self): work_dir = os.getenv("AVALON_WORKDIR") @@ -1031,8 +1107,8 @@ def get_write_node_template_attr(node): ''' # get avalon data from node data = dict() - data['avalon'] = avalon.nuke.get_avalon_knob_data( - node, ['avalon:', 'ak:']) + data['avalon'] = avalon.nuke.read( + node) data_preset = { "class": data['avalon']['family'], "families": data['avalon']['families'], @@ -1040,25 +1116,20 @@ def get_write_node_template_attr(node): } # get template data - nuke_dataflow_writes = get_node_dataflow_preset(**data_preset) - nuke_colorspace_writes = get_node_colorspace_preset(**data_preset) + nuke_imageio_writes = get_node_imageio_setting(**data_preset) # collecting correct data correct_data = OrderedDict({ "file": get_render_path(node) }) - # adding dataflow template + # adding imageio template {correct_data.update({k: v}) - for k, v in nuke_dataflow_writes.items() + for k, v in nuke_imageio_writes.items() if k not in ["_id", "_previous"]} - # adding colorspace template - {correct_data.update({k: v}) - for k, v in nuke_colorspace_writes.items()} - # fix badly encoded data - return avalon.nuke.lib.fix_data_for_node_create(correct_data) + return anlib.fix_data_for_node_create(correct_data) class ExporterReview: @@ -1177,6 +1248,7 @@ class ExporterReviewLut(ExporterReview): """ + def __init__(self, klass, instance, @@ -1279,6 +1351,7 @@ class ExporterReviewMov(ExporterReview): instance (pyblish.instance): instance of pyblish context """ + def __init__(self, klass, instance, @@ -1298,6 +1371,7 @@ class ExporterReviewMov(ExporterReview): self.viewer_lut_raw = klass.viewer_lut_raw self.bake_colorspace_fallback = klass.bake_colorspace_fallback self.bake_colorspace_main = klass.bake_colorspace_main + self.write_colorspace = instance.data["colorspace"] self.name = name or "baked" self.ext = ext or "mov" @@ -1343,6 +1417,8 @@ class ExporterReviewMov(ExporterReview): r_node["origfirst"].setValue(self.first_frame) r_node["last"].setValue(self.last_frame) r_node["origlast"].setValue(self.last_frame) + r_node["colorspace"].setValue(self.write_colorspace) + # connect self._temp_nodes.append(r_node) self.previous_node = r_node diff --git a/pype/hosts/nuke/menu.py b/pype/hosts/nuke/api/menu.py similarity index 68% rename from pype/hosts/nuke/menu.py rename to pype/hosts/nuke/api/menu.py index a8d5090da9..8161b9024c 100644 --- a/pype/hosts/nuke/menu.py +++ b/pype/hosts/nuke/api/menu.py @@ -1,11 +1,8 @@ -import os import nuke from avalon.api import Session -from pype.hosts.nuke import lib -from ...lib import BuildWorkfile -from pype.api import Logger -from pype.tools import workfiles +from .lib import WorkfileSettings +from pype.api import Logger, BuildWorkfile log = Logger().get_logger(__name__) @@ -13,25 +10,6 @@ log = Logger().get_logger(__name__) def install(): menubar = nuke.menu("Nuke") menu = menubar.findItem(Session["AVALON_LABEL"]) - workfile_settings = lib.WorkfileSettings - - # replace reset resolution from avalon core to pype's - name = "Work Files..." - rm_item = [ - (i, item) for i, item in enumerate(menu.items()) if name in item.name() - ][0] - - log.debug("Changing Item: {}".format(rm_item)) - - menu.removeItem(rm_item[1].name()) - menu.addCommand( - name, - lambda: workfiles.show( - os.environ["AVALON_WORKDIR"] - ), - index=(rm_item[0]) - ) - # replace reset resolution from avalon core to pype's name = "Reset Resolution" new_name = "Set Resolution" @@ -44,7 +22,7 @@ def install(): menu.removeItem(rm_item[1].name()) menu.addCommand( new_name, - lambda: workfile_settings().reset_resolution(), + lambda: WorkfileSettings().reset_resolution(), index=(rm_item[0]) ) @@ -59,14 +37,14 @@ def install(): menu.removeItem(rm_item[1].name()) menu.addCommand( new_name, - lambda: workfile_settings().reset_frame_range_handles(), + lambda: WorkfileSettings().reset_frame_range_handles(), index=(rm_item[0]) ) # add colorspace menu item name = "Set Colorspace" menu.addCommand( - name, lambda: workfile_settings().set_colorspace(), + name, lambda: WorkfileSettings().set_colorspace(), index=(rm_item[0] + 2) ) log.debug("Adding menu item: {}".format(name)) @@ -83,7 +61,7 @@ def install(): name = "Apply All Settings" menu.addCommand( name, - lambda: workfile_settings().set_context_settings(), + lambda: WorkfileSettings().set_context_settings(), index=(rm_item[0] + 3) ) log.debug("Adding menu item: {}".format(name)) diff --git a/pype/hosts/nuke/api/plugin.py b/pype/hosts/nuke/api/plugin.py new file mode 100644 index 0000000000..d6799ed6ca --- /dev/null +++ b/pype/hosts/nuke/api/plugin.py @@ -0,0 +1,23 @@ +import avalon.api +import avalon.nuke +from pype.api import get_current_project_settings +from .lib import check_subsetname_exists +import nuke + + +class PypeCreator(avalon.nuke.pipeline.Creator): + """Pype Nuke Creator class wrapper + """ + def __init__(self, *args, **kwargs): + super(PypeCreator, self).__init__(*args, **kwargs) + self.presets = get_current_project_settings()["nuke"]["create"].get( + self.__class__.__name__, {} + ) + if check_subsetname_exists( + nuke.allNodes(), + self.data["subset"]): + msg = ("The subset name `{0}` is already used on a node in" + "this workfile.".format(self.data["subset"])) + self.log.error(msg + '\n\nPlease use other subset name!') + raise NameError("`{0}: {1}".format(__name__, msg)) + return diff --git a/pype/hosts/nuke/utils.py b/pype/hosts/nuke/api/utils.py similarity index 97% rename from pype/hosts/nuke/utils.py rename to pype/hosts/nuke/api/utils.py index 72c7b7bc14..e14b03d453 100644 --- a/pype/hosts/nuke/utils.py +++ b/pype/hosts/nuke/api/utils.py @@ -4,12 +4,13 @@ from avalon.nuke import lib as anlib from pype.api import resources -def set_context_favorites(favorites={}): +def set_context_favorites(favorites=None): """ Addig favorite folders to nuke's browser Argumets: favorites (dict): couples of {name:path} """ + favorites = favorites or {} icon_path = resources.get_resource("icons", "folder-favorite3.png") for name, path in favorites.items(): nuke.addFavoriteDir( diff --git a/pype/hosts/nuke/plugin.py b/pype/hosts/nuke/plugin.py deleted file mode 100644 index 5d00b19ec5..0000000000 --- a/pype/hosts/nuke/plugin.py +++ /dev/null @@ -1,13 +0,0 @@ -import re -import avalon.api -import avalon.nuke -from pype.api import get_current_project_settings - -class PypeCreator(avalon.nuke.pipeline.Creator): - """Pype Nuke Creator class wrapper - """ - def __init__(self, *args, **kwargs): - super(PypeCreator, self).__init__(*args, **kwargs) - self.presets = get_current_project_settings()["nuke"]["create"].get( - self.__class__.__name__, {} - ) diff --git a/pype/plugins/nuke/create/create_backdrop.py b/pype/hosts/nuke/plugins/create/create_backdrop.py similarity index 92% rename from pype/plugins/nuke/create/create_backdrop.py rename to pype/hosts/nuke/plugins/create/create_backdrop.py index 0d2b621e21..243b14c2d8 100644 --- a/pype/plugins/nuke/create/create_backdrop.py +++ b/pype/hosts/nuke/plugins/create/create_backdrop.py @@ -32,7 +32,7 @@ class CreateBackdrop(avalon.nuke.Creator): bckd_node["note_font_size"].setValue(24) bckd_node["label"].setValue("[{}]".format(self.name)) # add avalon knobs - instance = anlib.imprint(bckd_node, self.data) + instance = anlib.set_avalon_knob_data(bckd_node, self.data) return instance else: @@ -48,6 +48,6 @@ class CreateBackdrop(avalon.nuke.Creator): bckd_node["note_font_size"].setValue(24) bckd_node["label"].setValue("[{}]".format(self.name)) # add avalon knobs - instance = anlib.imprint(bckd_node, self.data) + instance = anlib.set_avalon_knob_data(bckd_node, self.data) return instance diff --git a/pype/plugins/nuke/create/create_camera.py b/pype/hosts/nuke/plugins/create/create_camera.py similarity index 92% rename from pype/plugins/nuke/create/create_camera.py rename to pype/hosts/nuke/plugins/create/create_camera.py index 4c668925ad..919be0ea79 100644 --- a/pype/plugins/nuke/create/create_camera.py +++ b/pype/hosts/nuke/plugins/create/create_camera.py @@ -36,7 +36,7 @@ class CreateCamera(avalon.nuke.Creator): # change node color n["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - anlib.imprint(n, data) + anlib.set_avalon_knob_data(n, data) return True else: msg = str("Please select nodes you " @@ -49,5 +49,5 @@ class CreateCamera(avalon.nuke.Creator): camera_node = nuke.createNode("Camera2") camera_node["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - instance = anlib.imprint(camera_node, self.data) + instance = anlib.set_avalon_knob_data(camera_node, self.data) return instance diff --git a/pype/plugins/nuke/create/create_gizmo.py b/pype/hosts/nuke/plugins/create/create_gizmo.py similarity index 93% rename from pype/plugins/nuke/create/create_gizmo.py rename to pype/hosts/nuke/plugins/create/create_gizmo.py index eb5b1a3fb0..19b5bead8f 100644 --- a/pype/plugins/nuke/create/create_gizmo.py +++ b/pype/hosts/nuke/plugins/create/create_gizmo.py @@ -34,7 +34,7 @@ class CreateGizmo(avalon.nuke.Creator): if node.Class() in "Group": node["name"].setValue("{}_GZM".format(self.name)) node["tile_color"].setValue(int(self.node_color, 16)) - return anlib.imprint(node, self.data) + return anlib.set_avalon_knob_data(node, self.data) else: msg = ("Please select a group node " "you wish to publish as the gizmo") @@ -57,7 +57,7 @@ class CreateGizmo(avalon.nuke.Creator): "- create User knobs on the group") # add avalon knobs - return anlib.imprint(gizmo_node, self.data) + return anlib.set_avalon_knob_data(gizmo_node, self.data) else: msg = ("Please select nodes you " @@ -80,4 +80,4 @@ class CreateGizmo(avalon.nuke.Creator): "- create User knobs on the group") # add avalon knobs - return anlib.imprint(gizmo_node, self.data) + return anlib.set_avalon_knob_data(gizmo_node, self.data) diff --git a/pype/plugins/nuke/create/create_read.py b/pype/hosts/nuke/plugins/create/create_read.py similarity index 86% rename from pype/plugins/nuke/create/create_read.py rename to pype/hosts/nuke/plugins/create/create_read.py index 70db580a7e..591f9c14a2 100644 --- a/pype/plugins/nuke/create/create_read.py +++ b/pype/hosts/nuke/plugins/create/create_read.py @@ -44,7 +44,8 @@ class CrateRead(avalon.nuke.Creator): continue avalon_data = self.data avalon_data['subset'] = "{}".format(self.name) - self.change_read_node(self.data["subset"], node, avalon_data) + avalon.nuke.lib.set_avalon_knob_data(node, avalon_data) + node['tile_color'].setValue(16744935) count_reads += 1 if count_reads < 1: @@ -52,7 +53,3 @@ class CrateRead(avalon.nuke.Creator): self.log.error(msg) nuke.message(msg) return - - def change_read_node(self, name, node, data): - node = avalon.nuke.lib.imprint(node, data) - node['tile_color'].setValue(16744935) diff --git a/pype/plugins/nuke/create/create_write_prerender.py b/pype/hosts/nuke/plugins/create/create_write_prerender.py similarity index 93% rename from pype/plugins/nuke/create/create_write_prerender.py rename to pype/hosts/nuke/plugins/create/create_write_prerender.py index 2243ba8b5c..d1969c7fba 100644 --- a/pype/plugins/nuke/create/create_write_prerender.py +++ b/pype/hosts/nuke/plugins/create/create_write_prerender.py @@ -1,7 +1,7 @@ from collections import OrderedDict -from pype.hosts.nuke import ( +from pype.hosts.nuke.api import ( plugin, - lib as pnlib) + lib) import nuke @@ -10,7 +10,7 @@ class CreateWritePrerender(plugin.PypeCreator): name = "WritePrerender" label = "Create Write Prerender" hosts = ["nuke"] - n_class = "write" + n_class = "Write" family = "prerender" icon = "sign-out" defaults = ["Key01", "Bg01", "Fg01", "Branch01", "Part01"] @@ -75,9 +75,10 @@ class CreateWritePrerender(plugin.PypeCreator): # recreate new write_data = { - "class": self.n_class, + "nodeclass": self.n_class, "families": [self.family], - "avalon": self.data + "avalon": self.data, + "creator": self.__class__.__name__ } if self.presets.get('fpath_template'): @@ -91,7 +92,9 @@ class CreateWritePrerender(plugin.PypeCreator): "fpath_template": ("{work}/prerenders/nuke/{subset}" "/{subset}.{frame}.{ext}")}) - write_node = pnlib.create_write_node( + self.log.info("write_data: {}".format(write_data)) + + write_node = lib.create_write_node( self.data["subset"], write_data, input=selected_node, diff --git a/pype/plugins/nuke/create/create_write_render.py b/pype/hosts/nuke/plugins/create/create_write_render.py similarity index 91% rename from pype/plugins/nuke/create/create_write_render.py rename to pype/hosts/nuke/plugins/create/create_write_render.py index 5a6bf57197..60db8800dd 100644 --- a/pype/plugins/nuke/create/create_write_render.py +++ b/pype/hosts/nuke/plugins/create/create_write_render.py @@ -1,7 +1,7 @@ from collections import OrderedDict -from pype.hosts.nuke import ( +from pype.hosts.nuke.api import ( plugin, - lib as pnlib) + lib) import nuke @@ -10,7 +10,7 @@ class CreateWriteRender(plugin.PypeCreator): name = "WriteRender" label = "Create Write Render" hosts = ["nuke"] - n_class = "write" + n_class = "Write" family = "render" icon = "sign-out" defaults = ["Main", "Mask"] @@ -48,6 +48,7 @@ class CreateWriteRender(plugin.PypeCreator): "or tick off `Use selection`") self.log.error(msg) nuke.message(msg) + return if len(nodes) == 0: msg = ( @@ -56,6 +57,7 @@ class CreateWriteRender(plugin.PypeCreator): ) self.log.error(msg) nuke.message(msg) + return selected_node = nodes[0] inputs = [selected_node] @@ -76,9 +78,10 @@ class CreateWriteRender(plugin.PypeCreator): # recreate new write_data = { - "class": self.n_class, + "nodeclass": self.n_class, "families": [self.family], - "avalon": self.data + "avalon": self.data, + "creator": self.__class__.__name__ } if self.presets.get('fpath_template'): @@ -92,7 +95,7 @@ class CreateWriteRender(plugin.PypeCreator): "fpath_template": ("{work}/renders/nuke/{subset}" "/{subset}.{frame}.{ext}")}) - write_node = pnlib.create_write_node( + write_node = lib.create_write_node( self.data["subset"], write_data, input=selected_node) diff --git a/pype/plugins/nuke/inventory/select_containers.py b/pype/hosts/nuke/plugins/inventory/select_containers.py similarity index 100% rename from pype/plugins/nuke/inventory/select_containers.py rename to pype/hosts/nuke/plugins/inventory/select_containers.py diff --git a/pype/plugins/nuke/inventory/set_tool_color.py b/pype/hosts/nuke/plugins/inventory/set_tool_color.py similarity index 100% rename from pype/plugins/nuke/inventory/set_tool_color.py rename to pype/hosts/nuke/plugins/inventory/set_tool_color.py diff --git a/pype/plugins/nuke/load/actions.py b/pype/hosts/nuke/plugins/load/actions.py similarity index 95% rename from pype/plugins/nuke/load/actions.py rename to pype/hosts/nuke/plugins/load/actions.py index d0c95b6b16..9741e956fa 100644 --- a/pype/plugins/nuke/load/actions.py +++ b/pype/hosts/nuke/plugins/load/actions.py @@ -25,7 +25,7 @@ class SetFrameRangeLoader(api.Loader): def load(self, context, name, namespace, data): - from pype.hosts.nuke import lib + from pype.hosts.nuke.api import lib version = context['version'] version_data = version.get("data", {}) @@ -59,7 +59,7 @@ class SetFrameRangeWithHandlesLoader(api.Loader): def load(self, context, name, namespace, data): - from pype.hosts.nuke import lib + from pype.hosts.nuke.api import lib version = context['version'] version_data = version.get("data", {}) diff --git a/pype/plugins/nuke/load/load_backdrop.py b/pype/hosts/nuke/plugins/load/load_backdrop.py similarity index 99% rename from pype/plugins/nuke/load/load_backdrop.py rename to pype/hosts/nuke/plugins/load/load_backdrop.py index 7d18893965..00bf2df47d 100644 --- a/pype/plugins/nuke/load/load_backdrop.py +++ b/pype/hosts/nuke/plugins/load/load_backdrop.py @@ -1,7 +1,7 @@ from avalon import api, style, io import nuke import nukescripts -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib from avalon.nuke import lib as anlib from avalon.nuke import containerise, update_container reload(pnlib) diff --git a/pype/plugins/nuke/load/load_camera_abc.py b/pype/hosts/nuke/plugins/load/load_camera_abc.py similarity index 100% rename from pype/plugins/nuke/load/load_camera_abc.py rename to pype/hosts/nuke/plugins/load/load_camera_abc.py diff --git a/pype/plugins/nuke/load/load_gizmo.py b/pype/hosts/nuke/plugins/load/load_gizmo.py similarity index 100% rename from pype/plugins/nuke/load/load_gizmo.py rename to pype/hosts/nuke/plugins/load/load_gizmo.py diff --git a/pype/plugins/nuke/load/load_gizmo_ip.py b/pype/hosts/nuke/plugins/load/load_gizmo_ip.py similarity index 99% rename from pype/plugins/nuke/load/load_gizmo_ip.py rename to pype/hosts/nuke/plugins/load/load_gizmo_ip.py index a2e8a6abb8..b1a9748d16 100644 --- a/pype/plugins/nuke/load/load_gizmo_ip.py +++ b/pype/hosts/nuke/plugins/load/load_gizmo_ip.py @@ -1,6 +1,6 @@ from avalon import api, style, io import nuke -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib from avalon.nuke import lib as anlib from avalon.nuke import containerise, update_container diff --git a/pype/plugins/nuke/load/load_image.py b/pype/hosts/nuke/plugins/load/load_image.py similarity index 92% rename from pype/plugins/nuke/load/load_image.py rename to pype/hosts/nuke/plugins/load/load_image.py index 377d52aa14..dcaf31c9e3 100644 --- a/pype/plugins/nuke/load/load_image.py +++ b/pype/hosts/nuke/plugins/load/load_image.py @@ -4,7 +4,9 @@ import nuke from avalon.vendor import qargparse from avalon import api, io -from pype.hosts.nuke import presets +from pype.hosts.nuke.api.lib import ( + get_imageio_input_colorspace +) class LoadImage(api.Loader): @@ -90,17 +92,10 @@ class LoadImage(api.Loader): if colorspace: r["colorspace"].setValue(str(colorspace)) - # load nuke presets for Read's colorspace - read_clrs_presets = presets.get_colorspace_preset().get( - "nuke", {}).get("read", {}) + preset_clrsp = get_imageio_input_colorspace(file) - # check if any colorspace presets for read is mathing - preset_clrsp = next((read_clrs_presets[k] - for k in read_clrs_presets - if bool(re.search(k, file))), - None) if preset_clrsp is not None: - r["colorspace"].setValue(str(preset_clrsp)) + r["colorspace"].setValue(preset_clrsp) r["origfirst"].setValue(first) r["first"].setValue(first) @@ -191,6 +186,7 @@ class LoadImage(api.Loader): last = first = int(frame_number) # Set the global in to the start frame of the sequence + node["file"].setValue(file) node["origfirst"].setValue(first) node["first"].setValue(first) node["origlast"].setValue(last) diff --git a/pype/plugins/nuke/load/load_luts.py b/pype/hosts/nuke/plugins/load/load_luts.py similarity index 100% rename from pype/plugins/nuke/load/load_luts.py rename to pype/hosts/nuke/plugins/load/load_luts.py diff --git a/pype/plugins/nuke/load/load_luts_ip.py b/pype/hosts/nuke/plugins/load/load_luts_ip.py similarity index 99% rename from pype/plugins/nuke/load/load_luts_ip.py rename to pype/hosts/nuke/plugins/load/load_luts_ip.py index 241e077659..1e2469055f 100644 --- a/pype/plugins/nuke/load/load_luts_ip.py +++ b/pype/hosts/nuke/plugins/load/load_luts_ip.py @@ -2,7 +2,7 @@ from avalon import api, style, io import nuke import json from collections import OrderedDict -from pype.hosts.nuke import lib +from pype.hosts.nuke.api import lib class LoadLutsInputProcess(api.Loader): diff --git a/pype/plugins/nuke/load/load_matchmove.py b/pype/hosts/nuke/plugins/load/load_matchmove.py similarity index 100% rename from pype/plugins/nuke/load/load_matchmove.py rename to pype/hosts/nuke/plugins/load/load_matchmove.py diff --git a/pype/plugins/nuke/load/load_mov.py b/pype/hosts/nuke/plugins/load/load_mov.py similarity index 86% rename from pype/plugins/nuke/load/load_mov.py rename to pype/hosts/nuke/plugins/load/load_mov.py index 104f59d5be..f9be675cb9 100644 --- a/pype/plugins/nuke/load/load_mov.py +++ b/pype/hosts/nuke/plugins/load/load_mov.py @@ -1,10 +1,11 @@ -import re import nuke import contextlib from avalon import api, io -from pype.hosts.nuke import presets -from pype.api import get_project_settings +from pype.api import get_current_project_settings +from pype.hosts.nuke.api.lib import ( + get_imageio_input_colorspace +) @contextlib.contextmanager @@ -73,12 +74,18 @@ def add_review_presets_config(): "families": list(), "representations": list() } - settings = get_project_settings(io.Session["AVALON_PROJECT"]) - review_presets = settings["global"]["publish"].get( - "ExtractReview", {}) + settings = get_current_project_settings() + review_profiles = ( + settings["global"] + ["publish"] + ["ExtractReview"] + ["profiles"] + ) + + outputs = {} + for profile in review_profiles: + outputs.update(profile.get("outputs", {})) - outputs = review_presets.get("outputs", {}) - # for output, properities in outputs.items(): returning["representations"].append(output) returning["families"] += properities.get("families", []) @@ -175,17 +182,10 @@ class LoadMov(api.Loader): if colorspace: read_node["colorspace"].setValue(str(colorspace)) - # load nuke presets for Read's colorspace - read_clrs_presets = presets.get_colorspace_preset().get( - "nuke", {}).get("read", {}) + preset_clrsp = get_imageio_input_colorspace(file) - # check if any colorspace presets for read is mathing - preset_clrsp = next((read_clrs_presets[k] - for k in read_clrs_presets - if bool(re.search(k, file))), - None) if preset_clrsp is not None: - read_node["colorspace"].setValue(str(preset_clrsp)) + read_node["colorspace"].setValue(preset_clrsp) # add additional metadata from the version to imprint Avalon knob add_keys = [ @@ -276,10 +276,11 @@ class LoadMov(api.Loader): colorspace = version_data.get("colorspace") if first is None: - self.log.warning("Missing start frame for updated version" - "assuming starts at frame 0 for: " - "{} ({})".format( - node['name'].value(), representation)) + self.log.warning(( + "Missing start frame for updated version" + "assuming starts at frame 0 for: " + "{} ({})").format( + node['name'].value(), representation)) first = 0 # fix handle start and end if none are available @@ -309,17 +310,10 @@ class LoadMov(api.Loader): if colorspace: node["colorspace"].setValue(str(colorspace)) - # load nuke presets for Read's colorspace - read_clrs_presets = presets.get_colorspace_preset().get( - "nuke", {}).get("read", {}) + preset_clrsp = get_imageio_input_colorspace(file) - # check if any colorspace presets for read is mathing - preset_clrsp = next((read_clrs_presets[k] - for k in read_clrs_presets - if bool(re.search(k, file))), - None) if preset_clrsp is not None: - node["colorspace"].setValue(str(preset_clrsp)) + node["colorspace"].setValue(preset_clrsp) updated_dict = {} updated_dict.update({ diff --git a/pype/plugins/nuke/load/load_script_precomp.py b/pype/hosts/nuke/plugins/load/load_script_precomp.py similarity index 100% rename from pype/plugins/nuke/load/load_script_precomp.py rename to pype/hosts/nuke/plugins/load/load_script_precomp.py diff --git a/pype/plugins/nuke/load/load_sequence.py b/pype/hosts/nuke/plugins/load/load_sequence.py similarity index 95% rename from pype/plugins/nuke/load/load_sequence.py rename to pype/hosts/nuke/plugins/load/load_sequence.py index 411aec6ad6..f99b7be52f 100644 --- a/pype/plugins/nuke/load/load_sequence.py +++ b/pype/hosts/nuke/plugins/load/load_sequence.py @@ -1,9 +1,10 @@ -import re import nuke import contextlib from avalon import api, io -from pype.hosts.nuke import presets +from pype.hosts.nuke.api.lib import ( + get_imageio_input_colorspace +) @contextlib.contextmanager @@ -142,17 +143,10 @@ class LoadSequence(api.Loader): if colorspace: r["colorspace"].setValue(str(colorspace)) - # load nuke presets for Read's colorspace - read_clrs_presets = presets.get_colorspace_preset().get( - "nuke", {}).get("read", {}) + preset_clrsp = get_imageio_input_colorspace(file) - # check if any colorspace presets for read is mathing - preset_clrsp = next((read_clrs_presets[k] - for k in read_clrs_presets - if bool(re.search(k, file))), - None) if preset_clrsp is not None: - r["colorspace"].setValue(str(preset_clrsp)) + r["colorspace"].setValue(preset_clrsp) loader_shift(r, first, relative=True) r["origfirst"].setValue(int(first)) diff --git a/pype/plugins/nuke/publish/collect_backdrop.py b/pype/hosts/nuke/plugins/publish/collect_backdrop.py similarity index 92% rename from pype/plugins/nuke/publish/collect_backdrop.py rename to pype/hosts/nuke/plugins/publish/collect_backdrop.py index 5a117c2920..7e616ea7bb 100644 --- a/pype/plugins/nuke/publish/collect_backdrop.py +++ b/pype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,8 +1,8 @@ import pyblish.api -import pype.api as pype -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib import nuke + @pyblish.api.log class CollectBackdrops(pyblish.api.InstancePlugin): """Collect Backdrop node instance and its content @@ -42,12 +42,12 @@ class CollectBackdrops(pyblish.api.InstancePlugin): # get all connections from outside of backdrop nodes = instance[1:] connections_in, connections_out = pnlib.get_dependent_nodes(nodes) - instance.data["connections_in"] = connections_in - instance.data["connections_out"] = connections_out + instance.data["nodeConnectionsIn"] = connections_in + instance.data["nodeConnectionsOut"] = connections_out # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( - bckn.name(), len(instance)-1) + bckn.name(), len(instance) - 1) instance.data["families"].append(instance.data["family"]) diff --git a/pype/plugins/nuke/publish/collect_framerate.py b/pype/hosts/nuke/plugins/publish/collect_framerate.py similarity index 100% rename from pype/plugins/nuke/publish/collect_framerate.py rename to pype/hosts/nuke/plugins/publish/collect_framerate.py diff --git a/pype/plugins/nuke/publish/collect_gizmo.py b/pype/hosts/nuke/plugins/publish/collect_gizmo.py similarity index 89% rename from pype/plugins/nuke/publish/collect_gizmo.py rename to pype/hosts/nuke/plugins/publish/collect_gizmo.py index 6436bdc562..3db26096ae 100644 --- a/pype/plugins/nuke/publish/collect_gizmo.py +++ b/pype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -1,5 +1,4 @@ import pyblish.api -import pype.api as pype import nuke @@ -29,10 +28,6 @@ class CollectGizmo(pyblish.api.InstancePlugin): first_frame = int(nuke.root()["first_frame"].getValue()) last_frame = int(nuke.root()["last_frame"].getValue()) - # get version - version = pype.get_version_from_path(nuke.root().name()) - instance.data['version'] = int(version) - # Add version data to instance version_data = { "handles": handle_start, @@ -41,7 +36,6 @@ class CollectGizmo(pyblish.api.InstancePlugin): "frameStart": first_frame + handle_start, "frameEnd": last_frame - handle_end, "colorspace": nuke.root().knob('workingSpaceLUT').value(), - "version": int(version), "families": [instance.data["family"]] + instance.data["families"], "subset": instance.data["subset"], "fps": instance.context.data["fps"] diff --git a/pype/plugins/nuke/publish/collect_reads.py b/pype/hosts/nuke/plugins/publish/collect_reads.py similarity index 98% rename from pype/plugins/nuke/publish/collect_reads.py rename to pype/hosts/nuke/plugins/publish/collect_reads.py index 7fda6334bb..45e9969eb9 100644 --- a/pype/plugins/nuke/publish/collect_reads.py +++ b/pype/hosts/nuke/plugins/publish/collect_reads.py @@ -10,7 +10,7 @@ class CollectNukeReads(pyblish.api.InstancePlugin): """Collect all read nodes.""" order = pyblish.api.CollectorOrder + 0.04 - label = "Collect Reads" + label = "Collect Source Reads" hosts = ["nuke", "nukeassist"] families = ["source"] @@ -109,7 +109,7 @@ class CollectNukeReads(pyblish.api.InstancePlugin): "handleEnd": handle_end, "frameStart": first_frame + handle_start, "frameEnd": last_frame - handle_end, - "colorspace": colorspace, + "colorspace": colorspace, "families": [instance.data["family"]], "subset": instance.data["subset"], "fps": instance.context.data["fps"] diff --git a/pype/plugins/nuke/publish/collect_slate_node.py b/pype/hosts/nuke/plugins/publish/collect_slate_node.py similarity index 100% rename from pype/plugins/nuke/publish/collect_slate_node.py rename to pype/hosts/nuke/plugins/publish/collect_slate_node.py diff --git a/pype/plugins/nuke/publish/extract_backdrop.py b/pype/hosts/nuke/plugins/publish/extract_backdrop.py similarity index 95% rename from pype/plugins/nuke/publish/extract_backdrop.py rename to pype/hosts/nuke/plugins/publish/extract_backdrop.py index 0f7198887f..92153d563e 100644 --- a/pype/plugins/nuke/publish/extract_backdrop.py +++ b/pype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -1,6 +1,6 @@ import pyblish.api from avalon.nuke import lib as anlib -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib import nuke import os import pype @@ -30,8 +30,8 @@ class ExtractBackdropNode(pype.api.Extractor): # maintain selection with anlib.maintained_selection(): # all connections outside of backdrop - connections_in = instance.data["connections_in"] - connections_out = instance.data["connections_out"] + connections_in = instance.data["nodeConnectionsIn"] + connections_out = instance.data["nodeConnectionsOut"] self.log.debug("_ connections_in: `{}`".format(connections_in)) self.log.debug("_ connections_out: `{}`".format(connections_out)) diff --git a/pype/plugins/nuke/publish/extract_camera.py b/pype/hosts/nuke/plugins/publish/extract_camera.py similarity index 100% rename from pype/plugins/nuke/publish/extract_camera.py rename to pype/hosts/nuke/plugins/publish/extract_camera.py diff --git a/pype/plugins/nuke/publish/extract_gizmo.py b/pype/hosts/nuke/plugins/publish/extract_gizmo.py similarity index 96% rename from pype/plugins/nuke/publish/extract_gizmo.py rename to pype/hosts/nuke/plugins/publish/extract_gizmo.py index 465bf9824c..32d9dd0f55 100644 --- a/pype/plugins/nuke/publish/extract_gizmo.py +++ b/pype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -1,7 +1,6 @@ import pyblish.api from avalon.nuke import lib as anlib -from pype.hosts.nuke import lib as pnlib -from pype.hosts.nuke import utils as pnutils +from pype.hosts.nuke.api import utils as pnutils import nuke import os import pype diff --git a/pype/plugins/nuke/publish/extract_ouput_node.py b/pype/hosts/nuke/plugins/publish/extract_ouput_node.py similarity index 100% rename from pype/plugins/nuke/publish/extract_ouput_node.py rename to pype/hosts/nuke/plugins/publish/extract_ouput_node.py diff --git a/pype/plugins/nuke/publish/extract_output_directory.py b/pype/hosts/nuke/plugins/publish/extract_output_directory.py similarity index 100% rename from pype/plugins/nuke/publish/extract_output_directory.py rename to pype/hosts/nuke/plugins/publish/extract_output_directory.py diff --git a/pype/plugins/nuke/publish/extract_render_local.py b/pype/hosts/nuke/plugins/publish/extract_render_local.py similarity index 100% rename from pype/plugins/nuke/publish/extract_render_local.py rename to pype/hosts/nuke/plugins/publish/extract_render_local.py diff --git a/pype/plugins/nuke/publish/extract_review_data_lut.py b/pype/hosts/nuke/plugins/publish/extract_review_data_lut.py similarity index 97% rename from pype/plugins/nuke/publish/extract_review_data_lut.py rename to pype/hosts/nuke/plugins/publish/extract_review_data_lut.py index 10fe8fa2a9..16ef7a9449 100644 --- a/pype/plugins/nuke/publish/extract_review_data_lut.py +++ b/pype/hosts/nuke/plugins/publish/extract_review_data_lut.py @@ -1,7 +1,7 @@ import os import pyblish.api from avalon.nuke import lib as anlib -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib import pype reload(pnlib) diff --git a/pype/plugins/nuke/publish/extract_review_data_mov.py b/pype/hosts/nuke/plugins/publish/extract_review_data_mov.py similarity index 97% rename from pype/plugins/nuke/publish/extract_review_data_mov.py rename to pype/hosts/nuke/plugins/publish/extract_review_data_mov.py index e9ac3c2c84..c64c7adc93 100644 --- a/pype/plugins/nuke/publish/extract_review_data_mov.py +++ b/pype/hosts/nuke/plugins/publish/extract_review_data_mov.py @@ -1,7 +1,7 @@ import os import pyblish.api from avalon.nuke import lib as anlib -from pype.hosts.nuke import lib as pnlib +from pype.hosts.nuke.api import lib as pnlib import pype diff --git a/pype/plugins/nuke/publish/extract_script_save.py b/pype/hosts/nuke/plugins/publish/extract_script_save.py similarity index 100% rename from pype/plugins/nuke/publish/extract_script_save.py rename to pype/hosts/nuke/plugins/publish/extract_script_save.py diff --git a/pype/plugins/nuke/publish/extract_slate_frame.py b/pype/hosts/nuke/plugins/publish/extract_slate_frame.py similarity index 100% rename from pype/plugins/nuke/publish/extract_slate_frame.py rename to pype/hosts/nuke/plugins/publish/extract_slate_frame.py diff --git a/pype/plugins/nuke/publish/extract_thumbnail.py b/pype/hosts/nuke/plugins/publish/extract_thumbnail.py similarity index 100% rename from pype/plugins/nuke/publish/extract_thumbnail.py rename to pype/hosts/nuke/plugins/publish/extract_thumbnail.py diff --git a/pype/plugins/nuke/publish/increment_script_version.py b/pype/hosts/nuke/plugins/publish/increment_script_version.py similarity index 100% rename from pype/plugins/nuke/publish/increment_script_version.py rename to pype/hosts/nuke/plugins/publish/increment_script_version.py diff --git a/pype/plugins/nuke/publish/collect_instances.py b/pype/hosts/nuke/plugins/publish/precollect_instances.py similarity index 73% rename from pype/plugins/nuke/publish/collect_instances.py rename to pype/hosts/nuke/plugins/publish/precollect_instances.py index 4b192bfaff..2f5edd7fe8 100644 --- a/pype/plugins/nuke/publish/collect_instances.py +++ b/pype/hosts/nuke/plugins/publish/precollect_instances.py @@ -1,19 +1,20 @@ -import os - import nuke import pyblish.api from avalon import io, api -from avalon.nuke import get_avalon_knob_data +from avalon.nuke import lib as anlib @pyblish.api.log -class CollectNukeInstances(pyblish.api.ContextPlugin): +class PreCollectNukeInstances(pyblish.api.ContextPlugin): """Collect all nodes with Avalon knob.""" - order = pyblish.api.CollectorOrder + 0.01 - label = "Collect Instances" + order = pyblish.api.CollectorOrder - 0.59 + label = "Pre-collect Instances" hosts = ["nuke", "nukeassist"] + # presets + sync_workfile_version = False + def process(self, context): asset_data = io.find_one({ "type": "asset", @@ -38,8 +39,8 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): self.log.warning(E) # get data from avalon knob - self.log.debug("node[name]: {}".format(node['name'].value())) - avalon_knob_data = get_avalon_knob_data(node, ["avalon:", "ak:"]) + avalon_knob_data = anlib.get_avalon_knob_data( + node, ["avalon:", "ak:"]) self.log.debug("avalon_knob_data: {}".format(avalon_knob_data)) @@ -55,7 +56,7 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): families = list() if families_ak: - families.append(families_ak) + families.append(families_ak.lower()) families.append(family) @@ -70,10 +71,17 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): instance = context.create_instance(subset) instance.append(node) + # get review knob value + review = False + if "review" in node.knobs(): + review = node["review"].value() + families.append("review") + families.append("ftrack") + # Add all nodes in group instances. if node.Class() == "Group": - # only alter families for render family - if "write" in families_ak: + # check if it is write node in family + if "write" in families: target = node["render"].value() if target == "Use existing frames": # Local rendering @@ -105,6 +113,17 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): resolution_height = format.height() pixel_aspect = format.pixelAspect() + # get publish knob value + if "publish" not in node.knobs(): + anlib.add_publish_knob(node) + + # sync workfile version + if not next((f for f in families + if "prerender" in f), + None) and self.sync_workfile_version: + # get version to instance for integration + instance.data['version'] = instance.context.data['version'] + instance.data.update({ "subset": subset, "asset": avalon_knob_data["asset"], @@ -114,17 +133,21 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): "family": family, "families": families, "avalonKnob": avalon_knob_data, - "publish": node.knob('publish').value(), "step": 1, + "publish": node.knob('publish').value(), "fps": nuke.root()['fps'].value(), "resolutionWidth": resolution_width, "resolutionHeight": resolution_height, "pixelAspect": pixel_aspect, + "review": review }) - self.log.info("collected instance: {}".format(instance.data)) instances.append(instance) - context.data["instances"] = instances + # create instances in context data if not are created yet + if not context.data.get("instances"): + context.data["instances"] = list() + + context.data["instances"].extend(instances) self.log.debug("context: {}".format(context)) diff --git a/pype/plugins/nuke/publish/collect_workfile.py b/pype/hosts/nuke/plugins/publish/precollect_workfile.py similarity index 74% rename from pype/plugins/nuke/publish/collect_workfile.py rename to pype/hosts/nuke/plugins/publish/precollect_workfile.py index b95edf0a93..288caa7a19 100644 --- a/pype/plugins/nuke/publish/collect_workfile.py +++ b/pype/hosts/nuke/plugins/publish/precollect_workfile.py @@ -1,33 +1,32 @@ import nuke import pyblish.api import os - -from avalon.nuke import ( - get_avalon_knob_data, - add_publish_knob -) +import pype.api as pype +from avalon.nuke import lib as anlib +reload(anlib) class CollectWorkfile(pyblish.api.ContextPlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder + 0.1 - label = "Collect Workfile" + order = pyblish.api.CollectorOrder - 0.60 + label = "Pre-collect Workfile" hosts = ['nuke'] def process(self, context): root = nuke.root() - knob_data = get_avalon_knob_data(root) + current_file = os.path.normpath(nuke.root().name()) - add_publish_knob(root) + knob_data = anlib.get_avalon_knob_data(root) + + anlib.add_publish_knob(root) family = "workfile" task = os.getenv("AVALON_TASK", None) # creating instances per write node - file_path = context.data["currentFile"] - staging_dir = os.path.dirname(file_path) - base_name = os.path.basename(file_path) + staging_dir = os.path.dirname(current_file) + base_name = os.path.basename(current_file) subset = family + task.capitalize() # Get frame range @@ -62,6 +61,12 @@ class CollectWorkfile(pyblish.api.ContextPlugin): "handleEnd": handle_end, "step": 1, "fps": root['fps'].value(), + + "currentFile": current_file, + "version": int(pype.get_version_from_path(current_file)), + + "host": pyblish.api.current_host(), + "hostVersion": nuke.NUKE_VERSION_STRING } context.data.update(script_data) @@ -90,4 +95,9 @@ class CollectWorkfile(pyblish.api.ContextPlugin): instance.data["representations"].append(representation) self.log.info('Publishing script version') + + # create instances in context data if not are created yet + if not context.data.get("instances"): + context.data["instances"] = list() + context.data["instances"].append(instance) diff --git a/pype/plugins/nuke/publish/collect_writes.py b/pype/hosts/nuke/plugins/publish/precollect_writes.py similarity index 84% rename from pype/plugins/nuke/publish/collect_writes.py rename to pype/hosts/nuke/plugins/publish/precollect_writes.py index fb00aeb1ae..9806e38633 100644 --- a/pype/plugins/nuke/publish/collect_writes.py +++ b/pype/hosts/nuke/plugins/publish/precollect_writes.py @@ -1,14 +1,16 @@ import os import nuke import pyblish.api +import pype.api as pype +from avalon import io, api @pyblish.api.log class CollectNukeWrites(pyblish.api.InstancePlugin): """Collect all write nodes.""" - order = pyblish.api.CollectorOrder + 0.1 - label = "Collect Writes" + order = pyblish.api.CollectorOrder - 0.58 + label = "Pre-collect Writes" hosts = ["nuke", "nukeassist"] families = ["write"] @@ -41,9 +43,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) last_frame = int(nuke.root()["last_frame"].getValue()) - frame_length = int( - last_frame - first_frame + 1 - ) + frame_length = int(last_frame - first_frame + 1) if node["use_limit"].getValue(): first_frame = int(node["first"].getValue()) @@ -54,14 +54,6 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): output_dir = os.path.dirname(path) self.log.debug('output dir: {}'.format(output_dir)) - if not next((f for f in families - if "prerender" in f), - None) and self.sync_workfile_version: - # get version to instance for integration - instance.data['version'] = instance.context.data["version"] - - self.log.debug('Write Version: %s' % instance.data('version')) - # create label name = node.name() # Include start and end render frame in label @@ -79,7 +71,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): representation = { 'name': ext, 'ext': ext, - "stagingDir": output_dir + "stagingDir": output_dir, + "tags": list() } try: @@ -152,6 +145,25 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): "families": [] }) + # * Add audio to instance if exists. + # Find latest versions document + version_doc = pype.get_latest_version( + instance.data["asset"], "audioMain" + ) + repre_doc = None + if version_doc: + # Try to find it's representation (Expected there is only one) + repre_doc = io.find_one( + {"type": "representation", "parent": version_doc["_id"]} + ) + + # Add audio to instance if representation was found + if repre_doc: + instance.data["audio"] = [{ + "offset": 0, + "filename": api.get_representation_path(repre_doc) + }] + self.log.debug("families: {}".format(families)) self.log.debug("instance.data: {}".format(instance.data)) diff --git a/pype/plugins/nuke/publish/remove_ouput_node.py b/pype/hosts/nuke/plugins/publish/remove_ouput_node.py similarity index 100% rename from pype/plugins/nuke/publish/remove_ouput_node.py rename to pype/hosts/nuke/plugins/publish/remove_ouput_node.py diff --git a/pype/plugins/nuke/publish/validate_backdrop.py b/pype/hosts/nuke/plugins/publish/validate_backdrop.py similarity index 85% rename from pype/plugins/nuke/publish/validate_backdrop.py rename to pype/hosts/nuke/plugins/publish/validate_backdrop.py index cf2d56087d..f280ad4af1 100644 --- a/pype/plugins/nuke/publish/validate_backdrop.py +++ b/pype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -32,8 +32,8 @@ class SelectCenterInNodeGraph(pyblish.api.Action): # collect all failed nodes xpos and ypos for instance in instances: bdn = instance[0] - xC = bdn.xpos() + bdn.screenWidth()/2 - yC = bdn.ypos() + bdn.screenHeight()/2 + xC = bdn.xpos() + bdn.screenWidth() / 2 + yC = bdn.ypos() + bdn.screenHeight() / 2 all_xC.append(xC) all_yC.append(yC) @@ -58,10 +58,11 @@ class ValidateBackdrop(pyblish.api.InstancePlugin): actions = [SelectCenterInNodeGraph] def process(self, instance): - connections_out = instance.data["connections_out"] + connections_out = instance.data["nodeConnectionsOut"] - msg_multiple_outputs = "Only one outcoming connection from \"{}\" is allowed".format( - instance.data["name"]) + msg_multiple_outputs = ( + "Only one outcoming connection from " + "\"{}\" is allowed").format(instance.data["name"]) assert len(connections_out.keys()) <= 1, msg_multiple_outputs msg_no_content = "No content on backdrop node: \"{}\"".format( diff --git a/pype/plugins/nuke/publish/validate_gizmo.py b/pype/hosts/nuke/plugins/publish/validate_gizmo.py similarity index 100% rename from pype/plugins/nuke/publish/validate_gizmo.py rename to pype/hosts/nuke/plugins/publish/validate_gizmo.py diff --git a/pype/plugins/nuke/publish/validate_knobs.py b/pype/hosts/nuke/plugins/publish/validate_knobs.py similarity index 94% rename from pype/plugins/nuke/publish/validate_knobs.py rename to pype/hosts/nuke/plugins/publish/validate_knobs.py index 34c82f4b36..ce15831c9c 100644 --- a/pype/plugins/nuke/publish/validate_knobs.py +++ b/pype/hosts/nuke/plugins/publish/validate_knobs.py @@ -54,15 +54,15 @@ class ValidateKnobs(pyblish.api.ContextPlugin): # Filter families. families = [instance.data["family"]] families += instance.data.get("families", []) - families = list(set(families) & set(self.knobs.keys())) + families = list(set(families) & set(cls.knobs.keys())) if not families: continue # Get all knobs to validate. knobs = {} for family in families: - for preset in self.knobs[family]: - knobs.update({preset: self.knobs[family][preset]}) + for preset in cls.knobs[family]: + knobs.update({preset: cls.knobs[family][preset]}) # Get invalid knobs. nodes = [] diff --git a/pype/plugins/nuke/publish/validate_output_resolution.py b/pype/hosts/nuke/plugins/publish/validate_output_resolution.py similarity index 100% rename from pype/plugins/nuke/publish/validate_output_resolution.py rename to pype/hosts/nuke/plugins/publish/validate_output_resolution.py diff --git a/pype/plugins/nuke/publish/validate_read_legacy.py b/pype/hosts/nuke/plugins/publish/validate_read_legacy.py similarity index 100% rename from pype/plugins/nuke/publish/validate_read_legacy.py rename to pype/hosts/nuke/plugins/publish/validate_read_legacy.py diff --git a/pype/plugins/nuke/publish/validate_rendered_frames.py b/pype/hosts/nuke/plugins/publish/validate_rendered_frames.py similarity index 100% rename from pype/plugins/nuke/publish/validate_rendered_frames.py rename to pype/hosts/nuke/plugins/publish/validate_rendered_frames.py diff --git a/pype/plugins/nuke/publish/validate_script.py b/pype/hosts/nuke/plugins/publish/validate_script.py similarity index 100% rename from pype/plugins/nuke/publish/validate_script.py rename to pype/hosts/nuke/plugins/publish/validate_script.py diff --git a/pype/plugins/nuke/publish/validate_write_bounding_box.py b/pype/hosts/nuke/plugins/publish/validate_write_bounding_box.py similarity index 100% rename from pype/plugins/nuke/publish/validate_write_bounding_box.py rename to pype/hosts/nuke/plugins/publish/validate_write_bounding_box.py diff --git a/pype/plugins/nuke/publish/validate_write_deadline_tab.py b/pype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py similarity index 100% rename from pype/plugins/nuke/publish/validate_write_deadline_tab.py rename to pype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py diff --git a/pype/plugins/nuke/publish/validate_write_legacy.py b/pype/hosts/nuke/plugins/publish/validate_write_legacy.py similarity index 100% rename from pype/plugins/nuke/publish/validate_write_legacy.py rename to pype/hosts/nuke/plugins/publish/validate_write_legacy.py diff --git a/pype/plugins/nuke/publish/validate_write_nodes.py b/pype/hosts/nuke/plugins/publish/validate_write_nodes.py similarity index 100% rename from pype/plugins/nuke/publish/validate_write_nodes.py rename to pype/hosts/nuke/plugins/publish/validate_write_nodes.py diff --git a/pype/hosts/nuke/presets.py b/pype/hosts/nuke/presets.py deleted file mode 100644 index e40459f400..0000000000 --- a/pype/hosts/nuke/presets.py +++ /dev/null @@ -1,75 +0,0 @@ -from pype.api import Anatomy, config, Logger -import nuke - -log = Logger().get_logger(__name__) - - -def get_anatomy(**kwarg): - return Anatomy() - - -def get_dataflow_preset(): - presets = config.get_init_presets() - return presets["dataflow"] - - -def get_colorspace_preset(): - presets = config.get_init_presets() - return presets["colorspace"] - - -def get_node_dataflow_preset(**kwarg): - ''' Get preset data for dataflow (fileType, compression, bitDepth) - ''' - log.info(kwarg) - host = kwarg.get("host", "nuke") - cls = kwarg.get("class", None) - families = kwarg.get("families", []) - preset = kwarg.get("preset", None) # omit < 2.0.0v - - assert any([host, cls]), nuke.message( - "`{}`: Missing mandatory kwargs `host`, `cls`".format(__file__)) - - nuke_dataflow = get_dataflow_preset().get(str(host), None) - nuke_dataflow_nodes = nuke_dataflow.get('nodes', None) - nuke_dataflow_node = nuke_dataflow_nodes.get(str(cls), None) - - if preset: # omit < 2.0.0v - nuke_dataflow_node = nuke_dataflow_node.get(str(preset), None) - # omit < 2.0.0v - - if families: - for family in families: - nuke_dataflow_node = nuke_dataflow_node.get(str(family), None) - - log.info("Dataflow: {}".format(nuke_dataflow_node)) - return nuke_dataflow_node - - -def get_node_colorspace_preset(**kwarg): - ''' Get preset data for colorspace - ''' - log.info(kwarg) - host = kwarg.get("host", "nuke") - cls = kwarg.get("class", None) - families = kwarg.get("families", []) - preset = kwarg.get("preset", None) # omit < 2.0.0v - - if not any([host, cls]): - msg = "`{}`: Missing mandatory kwargs `host`, `cls`".format(__file__) - log.error(msg) - nuke.message(msg) - - nuke_colorspace = get_colorspace_preset().get(str(host), None) - nuke_colorspace_node = nuke_colorspace.get(str(cls), None) - - if preset: # omit < 2.0.0v - nuke_colorspace_node = nuke_colorspace_node.get(str(preset), None) - # omit < 2.0.0v - - if families: - for family in families: - nuke_colorspace_node = nuke_colorspace_node.get(str(family), None) - - log.info("Colorspace: {}".format(nuke_colorspace_node)) - return nuke_colorspace_node diff --git a/pype/setup/nuke/nuke_path/KnobScripter/__init__.py b/pype/hosts/nuke/startup/KnobScripter/__init__.py similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/__init__.py rename to pype/hosts/nuke/startup/KnobScripter/__init__.py diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_clearConsole.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_clearConsole.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_clearConsole.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_clearConsole.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_download.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_download.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_download.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_download.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_exitnode.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_exitnode.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_exitnode.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_exitnode.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_pick.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_pick.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_pick.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_pick.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_prefs.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_prefs.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_prefs.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_prefs.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_prefs2.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_prefs2.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_prefs2.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_prefs2.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_refresh.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_refresh.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_refresh.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_refresh.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_run.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_run.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_run.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_run.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_save.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_save.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_save.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_save.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_search.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_search.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_search.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_search.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/icons/icon_snippets.png b/pype/hosts/nuke/startup/KnobScripter/icons/icon_snippets.png similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/icons/icon_snippets.png rename to pype/hosts/nuke/startup/KnobScripter/icons/icon_snippets.png diff --git a/pype/setup/nuke/nuke_path/KnobScripter/knob_scripter.py b/pype/hosts/nuke/startup/KnobScripter/knob_scripter.py similarity index 100% rename from pype/setup/nuke/nuke_path/KnobScripter/knob_scripter.py rename to pype/hosts/nuke/startup/KnobScripter/knob_scripter.py diff --git a/pype/setup/nuke/nuke_path/init.py b/pype/hosts/nuke/startup/init.py similarity index 100% rename from pype/setup/nuke/nuke_path/init.py rename to pype/hosts/nuke/startup/init.py diff --git a/pype/setup/nuke/nuke_path/menu.py b/pype/hosts/nuke/startup/menu.py similarity index 55% rename from pype/setup/nuke/nuke_path/menu.py rename to pype/hosts/nuke/startup/menu.py index d9341045a9..8e2e06a169 100644 --- a/pype/setup/nuke/nuke_path/menu.py +++ b/pype/hosts/nuke/startup/menu.py @@ -1,9 +1,4 @@ -import os -import sys -import KnobScripter - -from pype.hosts.nuke.lib import ( - writes_version_sync, +from pype.hosts.nuke.api.lib import ( on_script_load, check_inventory_versions ) @@ -11,13 +6,11 @@ from pype.hosts.nuke.lib import ( import nuke from pype.api import Logger -log = Logger().get_logger(__name__, "nuke") +log = Logger().get_logger(__name__) -# nuke.addOnScriptSave(writes_version_sync) nuke.addOnScriptSave(on_script_load) nuke.addOnScriptLoad(check_inventory_versions) nuke.addOnScriptSave(check_inventory_versions) -# nuke.addOnScriptSave(writes_version_sync) log.info('Automatic syncing of write file knob to script version') diff --git a/pype/setup/nuke/nuke_path/write_to_read.py b/pype/hosts/nuke/startup/write_to_read.py similarity index 99% rename from pype/setup/nuke/nuke_path/write_to_read.py rename to pype/hosts/nuke/startup/write_to_read.py index 58985947bd..d4556fa64c 100644 --- a/pype/setup/nuke/nuke_path/write_to_read.py +++ b/pype/hosts/nuke/startup/write_to_read.py @@ -3,7 +3,7 @@ import os import glob import nuke from pype.api import Logger -log = Logger().get_logger(__name__, "nuke") +log = Logger().get_logger(__name__) SINGLE_FILE_FORMATS = ['avi', 'mp4', 'mxf', 'mov', 'mpg', 'mpeg', 'wmv', 'm4v', 'm2v'] diff --git a/pype/hosts/photoshop/template.psd b/pype/hosts/photoshop/template.psd new file mode 100644 index 0000000000..4c731771ba Binary files /dev/null and b/pype/hosts/photoshop/template.psd differ diff --git a/pype/hosts/tvpaint/plugins/publish/extract_sequence.py b/pype/hosts/tvpaint/plugins/publish/extract_sequence.py index d315777203..eb6bc670bb 100644 --- a/pype/hosts/tvpaint/plugins/publish/extract_sequence.py +++ b/pype/hosts/tvpaint/plugins/publish/extract_sequence.py @@ -146,6 +146,10 @@ class ExtractSequence(pyblish.api.Extractor): os.path.basename(filepath) for filepath in output_files_by_frame.values() ] + # Sequence of one frame + if len(repre_files) == 1: + repre_files = repre_files[0] + new_repre = { "name": ext, "ext": ext, diff --git a/pype/hosts/unreal/__init__.py b/pype/hosts/unreal/api/__init__.py similarity index 74% rename from pype/hosts/unreal/__init__.py rename to pype/hosts/unreal/api/__init__.py index 939be48d1e..15479ba952 100644 --- a/pype/hosts/unreal/__init__.py +++ b/pype/hosts/unreal/api/__init__.py @@ -3,13 +3,16 @@ import logging from avalon import api as avalon from pyblish import api as pyblish -from pype import PLUGINS_DIR +import pype.hosts.unreal logger = logging.getLogger("pype.hosts.unreal") -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "unreal", "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "unreal", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "unreal", "create") +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.unreal.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") def install(): diff --git a/pype/hosts/unreal/lib.py b/pype/hosts/unreal/api/lib.py similarity index 100% rename from pype/hosts/unreal/lib.py rename to pype/hosts/unreal/api/lib.py diff --git a/pype/hosts/unreal/plugin.py b/pype/hosts/unreal/api/plugin.py similarity index 100% rename from pype/hosts/unreal/plugin.py rename to pype/hosts/unreal/api/plugin.py diff --git a/pype/hooks/unreal/pre_workfile_preparation.py b/pype/hosts/unreal/hooks/pre_workfile_preparation.py similarity index 98% rename from pype/hooks/unreal/pre_workfile_preparation.py rename to pype/hosts/unreal/hooks/pre_workfile_preparation.py index f0e09669dc..942cb3bdab 100644 --- a/pype/hooks/unreal/pre_workfile_preparation.py +++ b/pype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -4,7 +4,7 @@ from pype.lib import ( PreLaunchHook, ApplicationLaunchFailed ) -from pype.hosts.unreal import lib as unreal_lib +from pype.hosts.unreal.api import lib as unreal_lib class UnrealPrelaunchHook(PreLaunchHook): diff --git a/pype/hosts/unreal/plugins/__init__.py b/pype/hosts/unreal/plugins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/unreal/create/create_layout.py b/pype/hosts/unreal/plugins/create/create_layout.py similarity index 95% rename from pype/plugins/unreal/create/create_layout.py rename to pype/hosts/unreal/plugins/create/create_layout.py index 82cef43cee..e810357c8a 100644 --- a/pype/plugins/unreal/create/create_layout.py +++ b/pype/hosts/unreal/plugins/create/create_layout.py @@ -1,5 +1,5 @@ from unreal import EditorLevelLibrary as ell -from pype.hosts.unreal.plugin import Creator +from pype.hosts.unreal.api.plugin import Creator from avalon.unreal import ( instantiate, ) diff --git a/pype/plugins/unreal/create/create_staticmeshfbx.py b/pype/hosts/unreal/plugins/create/create_staticmeshfbx.py similarity index 94% rename from pype/plugins/unreal/create/create_staticmeshfbx.py rename to pype/hosts/unreal/plugins/create/create_staticmeshfbx.py index fa41590ef5..8f414ac56d 100644 --- a/pype/plugins/unreal/create/create_staticmeshfbx.py +++ b/pype/hosts/unreal/plugins/create/create_staticmeshfbx.py @@ -1,5 +1,5 @@ import unreal -from pype.hosts.unreal.plugin import Creator +from pype.hosts.unreal.api.plugin import Creator from avalon.unreal import ( instantiate, ) diff --git a/pype/plugins/unreal/load/load_animation.py b/pype/hosts/unreal/plugins/load/load_animation.py similarity index 100% rename from pype/plugins/unreal/load/load_animation.py rename to pype/hosts/unreal/plugins/load/load_animation.py diff --git a/pype/plugins/unreal/load/load_rig.py b/pype/hosts/unreal/plugins/load/load_rig.py similarity index 100% rename from pype/plugins/unreal/load/load_rig.py rename to pype/hosts/unreal/plugins/load/load_rig.py diff --git a/pype/plugins/unreal/load/load_setdress.py b/pype/hosts/unreal/plugins/load/load_setdress.py similarity index 100% rename from pype/plugins/unreal/load/load_setdress.py rename to pype/hosts/unreal/plugins/load/load_setdress.py diff --git a/pype/plugins/unreal/load/load_staticmeshfbx.py b/pype/hosts/unreal/plugins/load/load_staticmeshfbx.py similarity index 100% rename from pype/plugins/unreal/load/load_staticmeshfbx.py rename to pype/hosts/unreal/plugins/load/load_staticmeshfbx.py diff --git a/pype/plugins/unreal/publish/collect_current_file.py b/pype/hosts/unreal/plugins/publish/collect_current_file.py similarity index 100% rename from pype/plugins/unreal/publish/collect_current_file.py rename to pype/hosts/unreal/plugins/publish/collect_current_file.py diff --git a/pype/plugins/unreal/publish/collect_instances.py b/pype/hosts/unreal/plugins/publish/collect_instances.py similarity index 100% rename from pype/plugins/unreal/publish/collect_instances.py rename to pype/hosts/unreal/plugins/publish/collect_instances.py diff --git a/pype/plugins/unreal/publish/extract_layout.py b/pype/hosts/unreal/plugins/publish/extract_layout.py similarity index 100% rename from pype/plugins/unreal/publish/extract_layout.py rename to pype/hosts/unreal/plugins/publish/extract_layout.py diff --git a/pype/lib/anatomy.py b/pype/lib/anatomy.py index ad07851533..b754f4fd76 100644 --- a/pype/lib/anatomy.py +++ b/pype/lib/anatomy.py @@ -159,6 +159,15 @@ class Anatomy: """Return PYPE_ROOT_* environments for current project in dict.""" return self._roots_obj.root_environments() + def root_environmets_fill_data(self, template=None): + """Environment variable values in dictionary for rootless path. + + Args: + template (str): Template for environment variable key fill. + By default is set to `"${}"`. + """ + return self.roots_obj.root_environmets_fill_data(template) + def find_root_template_from_path(self, *args, **kwargs): """Wrapper for Roots `find_root_template_from_path`.""" return self.roots_obj.find_root_template_from_path(*args, **kwargs) @@ -264,6 +273,78 @@ class Anatomy: # NOTE does not care if there are different keys than "root" return template_path.format(**{"root": self.roots}) + @classmethod + def fill_root_with_path(cls, rootless_path, root_path): + """Fill path without filled "root" key with passed path. + + This is helper to fill root with different directory path than anatomy + has defined no matter if is single or multiroot. + + Output path is same as input path if `rootless_path` does not contain + unfilled root key. + + Args: + rootless_path (str): Path without filled "root" key. Example: + "{root[work]}/MyProject/..." + root_path (str): What should replace root key in `rootless_path`. + + Returns: + str: Path with filled root. + """ + output = str(rootless_path) + for group in re.findall(cls.root_key_regex, rootless_path): + replacement = "{" + group + "}" + output = output.replace(replacement, root_path) + + return output + + def replace_root_with_env_key(self, filepath, template=None): + """Replace root of path with environment key. + + # Example: + ## Project with roots: + ``` + { + "nas": { + "windows": P:/projects", + ... + } + ... + } + ``` + + ## Entered filepath + "P:/projects/project/asset/task/animation_v001.ma" + + ## Entered template + "<{}>" + + ## Output + "/project/asset/task/animation_v001.ma" + + Args: + filepath (str): Full file path where root should be replaced. + template (str): Optional template for environment key. Must + have one index format key. + Default value if not entered: "${}" + + Returns: + str: Path where root is replaced with environment root key. + + Raise: + ValueError: When project's roots were not found in entered path. + """ + success, rootless_path = self.find_root_template_from_path(filepath) + if not success: + raise ValueError( + "{}: Project's roots were not found in path: {}".format( + self.project_name, filepath + ) + ) + + data = self.root_environmets_fill_data(template) + return rootless_path.format(**data) + class TemplateMissingKey(Exception): """Exception for cases when key does not exist in Anatomy.""" @@ -1245,6 +1326,10 @@ class RootItem: root_paths = list(self.cleaned_data.values()) mod_path = self.clean_path(path) for root_path in root_paths: + # Skip empty paths + if not root_path: + continue + if mod_path.startswith(root_path): result = True replacement = "{" + self.full_key() + "}" @@ -1435,6 +1520,41 @@ class Roots: output.update(self._root_environments(_keys, _value)) return output + def root_environmets_fill_data(self, template=None): + """Environment variable values in dictionary for rootless path. + + Args: + template (str): Template for environment variable key fill. + By default is set to `"${}"`. + """ + if template is None: + template = "${}" + return self._root_environmets_fill_data(template) + + def _root_environmets_fill_data(self, template, keys=None, roots=None): + if keys is None and roots is None: + return { + "root": self._root_environmets_fill_data( + template, [], self.roots + ) + } + + if isinstance(roots, RootItem): + key_items = [Roots.env_prefix] + for _key in keys: + key_items.append(_key.upper()) + key = "_".join(key_items) + return template.format(key) + + output = {} + for key, value in roots.items(): + _keys = list(keys) + _keys.append(key) + output[key] = self._root_environmets_fill_data( + template, _keys, value + ) + return output + @property def project_name(self): """Return project name which will be used for loading root values.""" diff --git a/pype/modules/deadline/plugins/publish/submit_maya_deadline.py b/pype/modules/deadline/plugins/publish/submit_maya_deadline.py index 5811ff4886..08b7479350 100644 --- a/pype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/pype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -35,7 +35,7 @@ from maya import cmds from avalon import api import pyblish.api -from pype.hosts.maya import lib +from pype.hosts.maya.api import lib # Documentation for keys available at: # https://docs.thinkboxsoftware.com diff --git a/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py index 5e5efb6e62..3ef5386e82 100644 --- a/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -219,7 +219,8 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin): "PYBLISHPLUGINPATH", "NUKE_PATH", "TOOL_ENV", - "PYPE_DEV" + "PYPE_DEV", + "FOUNDRY_LICENSE" ] environment = dict({key: os.environ[key] for key in keys if key in os.environ}, **api.Session) diff --git a/pype/modules/deadline/plugins/publish/submit_publish_job.py b/pype/modules/deadline/plugins/publish/submit_publish_job.py index 969345d421..62682ad976 100644 --- a/pype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/pype/modules/deadline/plugins/publish/submit_publish_job.py @@ -128,13 +128,14 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): order = pyblish.api.IntegratorOrder + 0.2 icon = "tractor" - hosts = ["fusion", "maya", "nuke", "celaction", "aftereffects"] + hosts = ["fusion", "maya", "nuke", "celaction", "aftereffects", "harmony"] - families = ["render.farm", "prerener", + families = ["render.farm", "prerender", "renderlayer", "imagesequence", "vrayscene"] aov_filter = {"maya": [r".+(?:\.|_)([Bb]eauty)(?:\.|_).*"], "aftereffects": [r".*"], # for everything from AE + "harmony": [r".*"], # for everything from AE "celaction": [r".*"]} enviro_filter = [ diff --git a/pype/modules/ftrack/actions/action_djvview.py b/pype/modules/ftrack/actions/action_djvview.py index 6036f9a35b..dfaa1ebeb9 100644 --- a/pype/modules/ftrack/actions/action_djvview.py +++ b/pype/modules/ftrack/actions/action_djvview.py @@ -90,9 +90,7 @@ class DJVViewAction(BaseAction): items = [] base_label = "v{0} - {1} - {2}" - default_component = self.config_data.get( - 'default_component', None - ) + default_component = None last_available = None select_value = None for version in versions: @@ -152,55 +150,23 @@ class DJVViewAction(BaseAction): # Launching application if "values" not in event["data"]: return - filename = event['data']['values']['path'] + filpath = event['data']['values']['path'] - fps = entities[0].get('custom_attributes', {}).get('fps', None) - - cmd = [] - # DJV path - cmd.append(os.path.normpath(self.djv_path)) - # DJV Options Start ############################################## - # '''layer name''' - # cmd.append('-file_layer (value)') - # ''' Proxy scale: 1/2, 1/4, 1/8''' - # cmd.append('-file_proxy 1/2') - # ''' Cache: True, False.''' - # cmd.append('-file_cache True') - # ''' Start in full screen ''' - # cmd.append('-window_fullscreen') - # ''' Toolbar controls: False, True.''' - # cmd.append("-window_toolbar False") - # ''' Window controls: False, True.''' - # cmd.append("-window_playbar False") - # ''' Grid overlay: None, 1x1, 10x10, 100x100.''' - # cmd.append("-view_grid None") - # ''' Heads up display: True, False.''' - # cmd.append("-view_hud True") - ''' Playback: Stop, Forward, Reverse.''' - cmd.append("-playback Forward") - # ''' Frame.''' - # cmd.append("-playback_frame (value)") - if fps is not None: - cmd.append("-playback_speed {}".format(int(fps))) - # ''' Timer: Sleep, Timeout. Value: Sleep.''' - # cmd.append("-playback_timer (value)") - # ''' Timer resolution (seconds): 0.001.''' - # cmd.append("-playback_timer_resolution (value)") - ''' Time units: Timecode, Frames.''' - cmd.append("-time_units Frames") - # DJV Options End ################################################ - - # PATH TO COMPONENT - cmd.append(os.path.normpath(filename)) + cmd = [ + # DJV path + os.path.normpath(self.djv_path), + # PATH TO COMPONENT + os.path.normpath(filpath) + ] try: # Run DJV with these commands - subprocess.Popen(' '.join(cmd)) + subprocess.Popen(cmd) except FileNotFoundError: return { 'success': False, 'message': 'File "{}" was not found.'.format( - os.path.basename(filename) + os.path.basename(filpath) ) } diff --git a/pype/modules/ftrack/events/action_clone_review_session.py b/pype/modules/ftrack/events/action_clone_review_session.py new file mode 100644 index 0000000000..9af04b45c1 --- /dev/null +++ b/pype/modules/ftrack/events/action_clone_review_session.py @@ -0,0 +1,128 @@ +import json + +from pype.modules.ftrack.lib import ServerAction + + +def clone_review_session(session, entity): + # Create a client review with timestamp. + name = entity["name"] + review_session = session.create( + "ReviewSession", + { + "name": f"Clone of {name}", + "project": entity["project"] + } + ) + + # Add all invitees. + for invitee in entity["review_session_invitees"]: + session.create( + "ReviewSessionInvitee", + { + "name": invitee["name"], + "email": invitee["email"], + "review_session": review_session + } + ) + + # Add all objects to new review session. + for obj in entity["review_session_objects"]: + session.create( + "ReviewSessionObject", + { + "name": obj["name"], + "version": obj["version"], + "review_session": review_session, + "asset_version": obj["asset_version"] + } + ) + + session.commit() + + +class CloneReviewSession(ServerAction): + '''Generate Client Review action + `label` a descriptive string identifing your action. + `varaint` To group actions together, give them the same + label and specify a unique variant per action. + `identifier` a unique identifier for your action. + `description` a verbose descriptive text for you action + ''' + label = "Clone Review Session" + variant = None + identifier = "clone-review-session" + description = None + settings_key = "clone_review_session" + + def discover(self, session, entities, event): + '''Return true if we can handle the selected entities. + *session* is a `ftrack_api.Session` instance + *entities* is a list of tuples each containing the entity type and the + entity id. + If the entity is a hierarchical you will always get the entity + type TypedContext, once retrieved through a get operation you + will have the "real" entity type ie. example Shot, Sequence + or Asset Build. + *event* the unmodified original event + ''' + is_valid = ( + len(entities) == 1 + and entities[0].entity_type == "ReviewSession" + ) + if is_valid: + is_valid = self.valid_roles(session, entities, event) + return is_valid + + def launch(self, session, entities, event): + '''Callback method for the custom action. + return either a bool ( True if successful or False if the action + failed ) or a dictionary with they keys `message` and `success`, the + message should be a string and will be displayed as feedback to the + user, success should be a bool, True if successful or False if the + action failed. + *session* is a `ftrack_api.Session` instance + *entities* is a list of tuples each containing the entity type and the + entity id. + If the entity is a hierarchical you will always get the entity + type TypedContext, once retrieved through a get operation you + will have the "real" entity type ie. example Shot, Sequence + or Asset Build. + *event* the unmodified original event + ''' + userId = event['source']['user']['id'] + user = session.query('User where id is ' + userId).one() + job = session.create( + 'Job', + { + 'user': user, + 'status': 'running', + 'data': json.dumps({ + 'description': 'Cloning Review Session.' + }) + } + ) + session.commit() + + try: + clone_review_session(session, entities[0]) + + job['status'] = 'done' + session.commit() + except Exception: + session.rollback() + job["status"] = "failed" + session.commit() + self.log.error( + "Cloning review session failed ({})", exc_info=True + ) + + return { + 'success': True, + 'message': 'Action completed successfully' + } + + +def register(session): + '''Register action. Called when used as an event plugin.''' + + CloneReviewSession(session).register() diff --git a/pype/modules/websocket_server/stubs/photoshop_server_stub.py b/pype/modules/websocket_server/stubs/photoshop_server_stub.py index 04fb7eff0f..d223153797 100644 --- a/pype/modules/websocket_server/stubs/photoshop_server_stub.py +++ b/pype/modules/websocket_server/stubs/photoshop_server_stub.py @@ -135,13 +135,17 @@ class PhotoshopServerStub(): def group_selected_layers(self, name): """ Group selected layers into new LayerSet (eg. group) - Returns: + Returns: (Layer) """ res = self.websocketserver.call(self.client.call ('Photoshop.group_selected_layers', name=name) ) - return self._to_records(res) + res = self._to_records(res) + + if res: + return res.pop() + raise ValueError("No group record returned") def get_selected_layers(self): """ diff --git a/pype/plugins/global/load/open_djv.py b/pype/plugins/global/load/open_djv.py index a500333875..39b54364d9 100644 --- a/pype/plugins/global/load/open_djv.py +++ b/pype/plugins/global/load/open_djv.py @@ -43,54 +43,18 @@ class OpenInDJV(api.Loader): if not remainder: seqeunce = collections[0] first_image = list(seqeunce)[0] - # start = min(collections) - # end = max(collections) - # - # range = (padding % start) + '-' + (padding % end) - # filename = re.sub('%[0-9]*d', range, filename) else: first_image = self.fname filepath = os.path.normpath(os.path.join(directory, first_image)) self.log.info("Opening : {}".format(filepath)) - fps = context.get('project', {}).get('data', {}).get('fps', 24) - - cmd = [] - # DJV path - cmd.append(os.path.normpath(self.djv_path)) - # DJV Options Start ############################################## - '''layer name''' - # cmd.append('-file_layer (value)') - ''' Proxy scale: 1/2, 1/4, 1/8''' - # cmd.append('-file_proxy 1/2') - ''' Cache: True, False.''' - cmd.append('-file_cache True') - ''' Start in full screen ''' - # cmd.append('-window_fullscreen') - ''' Toolbar controls: False, True.''' - # cmd.append("-window_toolbar False") - ''' Window controls: False, True.''' - # cmd.append("-window_playbar False") - ''' Grid overlay: None, 1x1, 10x10, 100x100.''' - # cmd.append("-view_grid None") - ''' Heads up display: True, False.''' - # cmd.append("-view_hud True") - ''' Playback: Stop, Forward, Reverse.''' - cmd.append("-playback Forward") - ''' Frame.''' - # cmd.append("-playback_frame (value)") - cmd.append("-playback_speed " + str(fps)) - ''' Timer: Sleep, Timeout. Value: Sleep.''' - # cmd.append("-playback_timer (value)") - ''' Timer resolution (seconds): 0.001.''' - # cmd.append("-playback_timer_resolution (value)") - ''' Time units: Timecode, Frames.''' - cmd.append("-time_units Frames") - # DJV Options End ################################################ - - # PATH TO COMPONENT - cmd.append(os.path.normpath(filepath)) + cmd = [ + # DJV path + os.path.normpath(self.djv_path), + # PATH TO COMPONENT + os.path.normpath(filepath) + ] # Run DJV with these commands - subprocess.Popen(' '.join(cmd)) + subprocess.Popen(cmd) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index 5ba92435fd..cf267a84cf 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -674,12 +674,21 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): self.log.debug( "families. %s" % type(instance.data.get('families'))) + family = instance.data.get("family") + families = [] + if family: + families.append(family) + + for _family in (instance.data.get("families") or []): + if _family not in families: + families.append(_family) + _id = io.insert_one({ "schema": "pype:subset-3.0", "type": "subset", "name": subset_name, "data": { - "families": instance.data.get("families", []) + "families": families }, "parent": asset["_id"] }).inserted_id diff --git a/pype/plugins/harmony/create/create_farm_render.py b/pype/plugins/harmony/create/create_farm_render.py new file mode 100644 index 0000000000..e134f28f43 --- /dev/null +++ b/pype/plugins/harmony/create/create_farm_render.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +"""Create Composite node for render on farm.""" +from avalon import harmony + + +class CreateFarmRender(harmony.Creator): + """Composite node for publishing renders.""" + + name = "renderDefault" + label = "Render on Farm" + family = "renderFarm" + node_type = "WRITE" + + def __init__(self, *args, **kwargs): + """Constructor.""" + super(CreateFarmRender, self).__init__(*args, **kwargs) + + def setup_node(self, node): + """Set render node.""" + path = "render/{0}/{0}.".format(node.split("/")[-1]) + harmony.send( + { + "function": f"PypeHarmony.Creators.CreateRender.create", + "args": [node, path] + }) + harmony.send( + { + "function": f"PypeHarmony.color", + "args": [[0.9, 0.75, 0.3, 1.0]] + } + ) diff --git a/pype/plugins/harmony/create/create_render.py b/pype/plugins/harmony/create/create_render.py index f8fc2d238b..8e3408d900 100644 --- a/pype/plugins/harmony/create/create_render.py +++ b/pype/plugins/harmony/create/create_render.py @@ -8,7 +8,7 @@ class CreateRender(harmony.Creator): name = "renderDefault" label = "Render" - family = "render" + family = "renderLocal" node_type = "WRITE" def __init__(self, *args, **kwargs): @@ -18,7 +18,7 @@ class CreateRender(harmony.Creator): def setup_node(self, node): """Set render node.""" self_name = self.__class__.__name__ - path = "{0}/{0}".format(node.split("/")[-1]) + path = "render/{0}/{0}.".format(node.split("/")[-1]) harmony.send( { "function": f"PypeHarmony.Creators.{self_name}.create", diff --git a/pype/plugins/harmony/publish/collect_audio.py b/pype/plugins/harmony/publish/collect_audio.py new file mode 100644 index 0000000000..58521d6612 --- /dev/null +++ b/pype/plugins/harmony/publish/collect_audio.py @@ -0,0 +1,33 @@ +import os +import pyblish.api + + +class CollectAudio(pyblish.api.InstancePlugin): + """ + Collect relative path for audio file to instance. + + Harmony api `getSoundtrackAll` returns useless path to temp folder, + for render on farm we look into 'audio' folder and select first file. + + Correct path needs to be calculated in `submit_harmony_deadline.py` + """ + + order = pyblish.api.CollectorOrder + 0.499 + label = "Collect Audio" + hosts = ["harmony"] + families = ["renderlayer"] + + def process(self, instance): + audio_dir = os.path.join( + os.path.dirname(instance.context.data.get("currentFile")), 'audio') + if os.path.isdir(audio_dir): + for full_file_name in os.listdir(audio_dir): + file_name, file_ext = os.path.splitext(full_file_name) + + if file_ext not in ['.wav', '.mp3', '.aiff']: + self.log.error("Unsupported file {}.{}".format(file_name, + file_ext)) + + audio_file_path = os.path.join('audio', full_file_name) + self.log.debug("audio_file_path {}".format(audio_file_path)) + instance.data["audioFile"] = audio_file_path diff --git a/pype/plugins/harmony/publish/collect_farm_render.py b/pype/plugins/harmony/publish/collect_farm_render.py new file mode 100644 index 0000000000..5925dafa72 --- /dev/null +++ b/pype/plugins/harmony/publish/collect_farm_render.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- +"""Collect data to render from scene.""" +from pathlib import Path + +import attr +from avalon import harmony, api + +import pype.lib.abstract_collect_render +from pype.lib.abstract_collect_render import RenderInstance + + +@attr.s +class HarmonyRenderInstance(RenderInstance): + outputType = attr.ib(default="Image") + outputFormat = attr.ib(default="PNG4") + outputStartFrame = attr.ib(default=1) + leadingZeros = attr.ib(default=3) + + +class CollectFarmRender(pype.lib.abstract_collect_render. + AbstractCollectRender): + """Gather all publishable renders.""" + + # https://docs.toonboom.com/help/harmony-17/premium/reference/node/output/write-node-image-formats.html + ext_mapping = { + "tvg": ["TVG"], + "tga": ["TGA", "TGA4", "TGA3", "TGA1"], + "sgi": ["SGI", "SGI4", "SGA3", "SGA1", "SGIDP", "SGIDP4", "SGIDP3"], + "psd": ["PSD", "PSD1", "PSD3", "PSD4", "PSDDP", "PSDDP1", "PSDDP3", + "PSDDP4"], + "yuv": ["YUV"], + "pal": ["PAL"], + "scan": ["SCAN"], + "png": ["PNG", "PNG4", "PNGDP", "PNGDP3", "PNGDP4"], + "jpg": ["JPG"], + "bmp": ["BMP", "BMP4"], + "opt": ["OPT", "OPT1", "OPT3", "OPT4"], + "var": ["VAR"], + "tif": ["TIF"], + "dpx": ["DPX", "DPX3_8", "DPX3_10", "DPX3_12", "DPX3_16", + "DPX3_10_INVERTED_CHANNELS", "DPX3_12_INVERTED_CHANNELS", + "DPX3_16_INVERTED_CHANNELS"], + "exr": ["EXR"], + "pdf": ["PDF"], + "dtext": ["DTEX"] + } + + def get_expected_files(self, render_instance): + """Get list of expected files to be rendered from Harmony. + + This returns full path with file name determined by Write node + settings. + """ + start = render_instance.frameStart + end = render_instance.frameEnd + node = render_instance.setMembers[0] + self_name = self.__class__.__name__ + # 0 - filename / 1 - type / 2 - zeros / 3 - start + info = harmony.send( + { + "function": f"PypeHarmony.Publish.{self_name}." + "getRenderNodeSettings", + "args": node + })["result"] + + ext = None + for k, v in self.ext_mapping.items(): + if info[1] in v: + ext = k + + if not ext: + raise AssertionError( + f"Cannot determine file extension for {info[1]}") + + path = Path(render_instance.source).parent + + # is sequence start node on write node offsetting whole sequence? + expected_files = [] + + # Harmony 17 needs at least one '.' in file_prefix, but not at end + file_prefix = info[0] + file_prefix += '.temp' + + for frame in range(start, end + 1): + expected_files.append( + path / "{}{}.{}".format( + file_prefix, + str(frame).rjust(int(info[2]) + 1, "0"), + ext + ) + ) + + return expected_files + + def get_instances(self, context): + """Get instances per Write node in `renderFarm` family.""" + version = None + if self.sync_workfile_version: + version = context.data["version"] + + instances = [] + + self_name = self.__class__.__name__ + + for node in context.data["allNodes"]: + data = harmony.read(node) + + # Skip non-tagged nodes. + if not data: + continue + + # Skip containers. + if "container" in data["id"]: + continue + + if data["family"] != "renderFarm": + continue + + # 0 - filename / 1 - type / 2 - zeros / 3 - start + info = harmony.send( + { + "function": f"PypeHarmony.Publish.{self_name}." + "getRenderNodeSettings", + "args": node + })["result"] + + # TODO: handle pixel aspect and frame step + # TODO: set Deadline stuff (pools, priority, etc. by presets) + subset_name = node.split("/")[1].replace('Farm', '') + render_instance = HarmonyRenderInstance( + version=version, + time=api.time(), + source=context.data["currentFile"], + label=subset_name, + subset=subset_name, + asset=api.Session["AVALON_ASSET"], + attachTo=False, + setMembers=[node], + publish=True, + review=False, + renderer=None, + priority=50, + name=node.split("/")[1], + + family="renderlayer", + families=["renderlayer"], + + resolutionWidth=context.data["resolutionWidth"], + resolutionHeight=context.data["resolutionHeight"], + pixelAspect=1.0, + multipartExr=False, + tileRendering=False, + tilesX=0, + tilesY=0, + convertToScanline=False, + + # time settings + frameStart=context.data["frameStart"], + frameEnd=context.data["frameEnd"], + frameStep=1, + outputType="Image", + outputFormat=info[1], + outputStartFrame=info[3], + leadingZeros=info[2], + toBeRenderedOn='deadline' + + ) + self.log.debug(render_instance) + instances.append(render_instance) + + return instances + + def add_additional_data(self, instance): + instance["FOV"] = self._context.data["FOV"] + + return instance diff --git a/pype/plugins/harmony/publish/collect_instances.py b/pype/plugins/harmony/publish/collect_instances.py index 21aa00e972..c3e551271f 100644 --- a/pype/plugins/harmony/publish/collect_instances.py +++ b/pype/plugins/harmony/publish/collect_instances.py @@ -49,6 +49,10 @@ class CollectInstances(pyblish.api.ContextPlugin): if "container" in data["id"]: continue + # skip render farm family as it is collected separately + if data["family"] == "renderFarm": + continue + instance = context.create_instance(node.split("/")[-1]) instance.append(node) instance.data.update(data) diff --git a/pype/plugins/harmony/publish/collect_palettes.py b/pype/plugins/harmony/publish/collect_palettes.py index 0900f3c3ff..26b83ff171 100644 --- a/pype/plugins/harmony/publish/collect_palettes.py +++ b/pype/plugins/harmony/publish/collect_palettes.py @@ -27,6 +27,7 @@ class CollectPalettes(pyblish.api.ContextPlugin): instance.data.update({ "id": id, "family": "harmony.palette", + 'families': [], "asset": os.environ["AVALON_ASSET"], "subset": "{}{}".format("palette", name) }) diff --git a/pype/plugins/harmony/publish/collect_scene.py b/pype/plugins/harmony/publish/collect_scene.py index 2a838ca0cd..afb49369dc 100644 --- a/pype/plugins/harmony/publish/collect_scene.py +++ b/pype/plugins/harmony/publish/collect_scene.py @@ -30,9 +30,24 @@ class CollectScene(pyblish.api.ContextPlugin): context.data["audioPath"] = result[6] context.data["resolutionWidth"] = result[7] context.data["resolutionHeight"] = result[8] + context.data["FOV"] = result[9] all_nodes = harmony.send( {"function": "node.subNodes", "args": ["Top"]} )["result"] context.data["allNodes"] = all_nodes + + # collect all write nodes to be able disable them in Deadline + all_write_nodes = harmony.send( + {"function": "node.getNodes", "args": ["WRITE"]} + )["result"] + + context.data["all_write_nodes"] = all_write_nodes + + result = harmony.send( + { + f"function": "PypeHarmony.getVersion", + "args": []} + )["result"] + context.data["harmonyVersion"] = "{}.{}".format(result[0], result[1]) diff --git a/pype/plugins/harmony/publish/collect_workfile.py b/pype/plugins/harmony/publish/collect_workfile.py index 02eb38db48..63bfd5929b 100644 --- a/pype/plugins/harmony/publish/collect_workfile.py +++ b/pype/plugins/harmony/publish/collect_workfile.py @@ -26,7 +26,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): "label": basename, "name": basename, "family": family, - "families": [], + "families": [family], "representations": [], "asset": os.environ["AVALON_ASSET"] }) diff --git a/pype/plugins/harmony/publish/extract_render.py b/pype/plugins/harmony/publish/extract_render.py index c5744d43e2..84fa503f54 100644 --- a/pype/plugins/harmony/publish/extract_render.py +++ b/pype/plugins/harmony/publish/extract_render.py @@ -17,7 +17,7 @@ class ExtractRender(pyblish.api.InstancePlugin): label = "Extract Render" order = pyblish.api.ExtractorOrder hosts = ["harmony"] - families = ["render"] + families = ["renderLocal"] def process(self, instance): # Collect scene data. diff --git a/pype/plugins/harmony/publish/extract_workfile.py b/pype/plugins/harmony/publish/extract_workfile.py index 09bf0db860..be0444f0e6 100644 --- a/pype/plugins/harmony/publish/extract_workfile.py +++ b/pype/plugins/harmony/publish/extract_workfile.py @@ -10,7 +10,7 @@ import pype.hosts.harmony class ExtractWorkfile(pype.api.Extractor): - """Extract the connected nodes to the composite instance.""" + """Extract and zip complete workfile folder into zip.""" label = "Extract Workfile" hosts = ["harmony"] @@ -18,15 +18,11 @@ class ExtractWorkfile(pype.api.Extractor): def process(self, instance): """Plugin entry point.""" - # Export template. - backdrops = harmony.send( - {"function": "Backdrop.backdrops", "args": ["Top"]} - )["result"] - nodes = instance.context.data.get("allNodes") staging_dir = self.staging_dir(instance) filepath = os.path.join(staging_dir, "{}.tpl".format(instance.name)) - - pype.hosts.harmony.export_template(backdrops, nodes, filepath) + src = os.path.dirname(instance.context.data["currentFile"]) + self.log.info("Copying to {}".format(filepath)) + shutil.copytree(src, filepath) # Prep representation. os.chdir(staging_dir) diff --git a/pype/plugins/harmony/publish/submit_harmony_deadline..py b/pype/plugins/harmony/publish/submit_harmony_deadline..py new file mode 100644 index 0000000000..e40ff02d08 --- /dev/null +++ b/pype/plugins/harmony/publish/submit_harmony_deadline..py @@ -0,0 +1,411 @@ +# -*- coding: utf-8 -*- +"""Submitting render job to Deadline.""" +import os +from pathlib import Path +from collections import OrderedDict +from zipfile import ZipFile, is_zipfile +import re + +import attr +import pyblish.api + +import pype.lib.abstract_submit_deadline +from pype.lib.abstract_submit_deadline import DeadlineJobInfo +from avalon import api + + +class _ZipFile(ZipFile): + """Extended check for windows invalid characters.""" + + # this is extending default zipfile table for few invalid characters + # that can come from Mac + _windows_illegal_characters = ":<>|\"?*\r\n\x00" + _windows_illegal_name_trans_table = str.maketrans( + _windows_illegal_characters, + "_" * len(_windows_illegal_characters) + ) + + +@attr.s +class PluginInfo(object): + """Plugin info structure for Harmony Deadline plugin.""" + + SceneFile = attr.ib() + # Harmony version + Version = attr.ib() + + Camera = attr.ib(default="") + FieldOfView = attr.ib(default=41.11) + IsDatabase = attr.ib(default=False) + ResolutionX = attr.ib(default=1920) + ResolutionY = attr.ib(default=1080) + + # Resolution name preset, default + UsingResPreset = attr.ib(default=False) + ResolutionName = attr.ib(default="HDTV_1080p24") + + PreRenderInlineScript = attr.ib(default=None) + + # -------------------------------------------------- + _outputNode = attr.ib(factory=list) + + @property + def OutputNode(self): # noqa: N802 + """Return all output nodes formatted for Deadline. + + Returns: + dict: as `{'Output0Node', 'Top/renderFarmDefault'}` + + """ + out = {} + for index, v in enumerate(self._outputNode): + out["Output{}Node".format(index)] = v + return out + + @OutputNode.setter + def OutputNode(self, val): # noqa: N802 + self._outputNode.append(val) + + # -------------------------------------------------- + _outputType = attr.ib(factory=list) + + @property + def OutputType(self): # noqa: N802 + """Return output nodes type formatted for Deadline. + + Returns: + dict: as `{'Output0Type', 'Image'}` + + """ + out = {} + for index, v in enumerate(self._outputType): + out["Output{}Type".format(index)] = v + return out + + @OutputType.setter + def OutputType(self, val): # noqa: N802 + self._outputType.append(val) + + # -------------------------------------------------- + _outputLeadingZero = attr.ib(factory=list) + + @property + def OutputLeadingZero(self): # noqa: N802 + """Return output nodes type formatted for Deadline. + + Returns: + dict: as `{'Output0LeadingZero', '3'}` + + """ + out = {} + for index, v in enumerate(self._outputLeadingZero): + out["Output{}LeadingZero".format(index)] = v + return out + + @OutputLeadingZero.setter + def OutputLeadingZero(self, val): # noqa: N802 + self._outputLeadingZero.append(val) + + # -------------------------------------------------- + _outputFormat = attr.ib(factory=list) + + @property + def OutputFormat(self): # noqa: N802 + """Return output nodes format formatted for Deadline. + + Returns: + dict: as `{'Output0Type', 'PNG4'}` + + """ + out = {} + for index, v in enumerate(self._outputFormat): + out["Output{}Format".format(index)] = v + return out + + @OutputFormat.setter + def OutputFormat(self, val): # noqa: N802 + self._outputFormat.append(val) + + # -------------------------------------------------- + _outputStartFrame = attr.ib(factory=list) + + @property + def OutputStartFrame(self): # noqa: N802 + """Return start frame for output nodes formatted for Deadline. + + Returns: + dict: as `{'Output0StartFrame', '1'}` + + """ + out = {} + for index, v in enumerate(self._outputStartFrame): + out["Output{}StartFrame".format(index)] = v + return out + + @OutputStartFrame.setter + def OutputStartFrame(self, val): # noqa: N802 + self._outputStartFrame.append(val) + + # -------------------------------------------------- + _outputPath = attr.ib(factory=list) + + @property + def OutputPath(self): # noqa: N802 + """Return output paths for nodes formatted for Deadline. + + Returns: + dict: as `{'Output0Path', '/output/path'}` + + """ + out = {} + for index, v in enumerate(self._outputPath): + out["Output{}Path".format(index)] = v + return out + + @OutputPath.setter + def OutputPath(self, val): # noqa: N802 + self._outputPath.append(val) + + def set_output(self, node, image_format, output, + output_type="Image", zeros=3, start_frame=1): + """Helper to set output. + + This should be used instead of setting properties individually + as so index remain consistent. + + Args: + node (str): harmony write node name + image_format (str): format of output (PNG4, TIF, ...) + output (str): output path + output_type (str, optional): "Image" or "Movie" (not supported). + zeros (int, optional): Leading zeros (for 0001 = 3) + start_frame (int, optional): Sequence offset. + + """ + + self.OutputNode = node + self.OutputFormat = image_format + self.OutputPath = output + self.OutputType = output_type + self.OutputLeadingZero = zeros + self.OutputStartFrame = start_frame + + def serialize(self): + """Return all data serialized as dictionary. + + Returns: + OrderedDict: all serialized data. + + """ + def filter_data(a, v): + if a.name.startswith("_"): + return False + if v is None: + return False + return True + + serialized = attr.asdict( + self, dict_factory=OrderedDict, filter=filter_data) + serialized.update(self.OutputNode) + serialized.update(self.OutputFormat) + serialized.update(self.OutputPath) + serialized.update(self.OutputType) + serialized.update(self.OutputLeadingZero) + serialized.update(self.OutputStartFrame) + + return serialized + + +class HarmonySubmitDeadline( + pype.lib.abstract_submit_deadline.AbstractSubmitDeadline): + """Submit render write of Harmony scene to Deadline. + + Renders are submitted to a Deadline Web Service as + supplied via the environment variable ``DEADLINE_REST_URL``. + + Note: + If Deadline configuration is not detected, this plugin will + be disabled. + + Attributes: + use_published (bool): Use published scene to render instead of the + one in work area. + + """ + + label = "Submit to Deadline" + order = pyblish.api.IntegratorOrder + 0.1 + hosts = ["harmony"] + families = ["renderlayer"] + if not os.environ.get("DEADLINE_REST_URL"): + optional = False + active = False + else: + optional = True + + use_published = False + primary_pool = "" + secondary_pool = "" + priority = 50 + chunk_size = 1000000 + + def get_job_info(self): + job_info = DeadlineJobInfo("Harmony") + job_info.Name = self._instance.data["name"] + job_info.Plugin = "HarmonyPype" + job_info.Frames = "{}-{}".format( + self._instance.data["frameStart"], + self._instance.data["frameEnd"] + ) + # for now, get those from presets. Later on it should be + # configurable in Harmony UI directly. + job_info.Priority = self.priority + job_info.Pool = self.primary_pool + job_info.SecondaryPool = self.secondary_pool + job_info.ChunkSize = self.chunk_size + job_info.BatchName = os.path.basename(self._instance.data["source"]) + + keys = [ + "FTRACK_API_KEY", + "FTRACK_API_USER", + "FTRACK_SERVER", + "AVALON_PROJECT", + "AVALON_ASSET", + "AVALON_TASK", + "PYPE_USERNAME", + "PYPE_DEV", + "PYPE_LOG_NO_COLORS" + ] + + environment = dict({key: os.environ[key] for key in keys + if key in os.environ}, **api.Session) + for key in keys: + val = environment.get(key) + if val: + job_info.EnvironmentKeyValue = "{key}={value}".format( + key=key, + value=val) + + return job_info + + def _unzip_scene_file(self, published_scene: Path) -> Path: + """Unzip scene zip file to its directory. + + Unzip scene file (if it is zip file) to its current directory and + return path to xstage file there. Xstage file is determined by its + name. + + Args: + published_scene (Path): path to zip file. + + Returns: + Path: The path to unzipped xstage. + """ + # if not zip, bail out. + if "zip" not in published_scene.suffix or not is_zipfile( + published_scene.as_posix() + ): + self.log.error("Published scene is not in zip.") + self.log.error(published_scene) + raise AssertionError("invalid scene format") + + xstage_path = ( + published_scene.parent + / published_scene.stem + / f"{published_scene.stem}.xstage" + ) + + unzip_dir = (published_scene.parent / published_scene.stem) + with _ZipFile(published_scene, "r") as zip_ref: + zip_ref.extractall(unzip_dir.as_posix()) + + # find any xstage files in directory, prefer the one with the same name + # as directory (plus extension) + xstage_files = [] + for scene in unzip_dir.iterdir(): + if scene.suffix == ".xstage": + xstage_files.append(scene) + + # there must be at least one (but maybe not more?) xstage file + if not xstage_files: + self.log.error("No xstage files found in zip") + raise AssertionError("Invalid scene archive") + + ideal_scene = False + # find the one with the same name as zip. In case there can be more + # then one xtage file. + for scene in xstage_files: + # if /foo/bar/baz.zip == /foo/bar/baz/baz.xstage + # ^^^ ^^^ + if scene.stem == published_scene.stem: + xstage_path = scene + ideal_scene = True + + # but sometimes xstage file has different name then zip - in that case + # use that one. + if not ideal_scene: + xstage_path = xstage_files[0] + + return xstage_path + + def get_plugin_info(self): + work_scene = Path(self._instance.data["source"]) + + # this is path to published scene workfile _ZIP_. Before + # rendering, we need to unzip it. + published_scene = Path( + self.from_published_scene(False)) + self.log.info(f"Processing {published_scene.as_posix()}") + xstage_path = self._unzip_scene_file(published_scene) + render_path = xstage_path.parent / "renders" + + # for submit_publish job to create .json file in + self._instance.data["outputDir"] = render_path + new_expected_files = [] + work_path_str = str(work_scene.parent.as_posix()) + render_path_str = str(render_path.as_posix()) + for file in self._instance.data["expectedFiles"]: + _file = str(Path(file).as_posix()) + new_expected_files.append( + _file.replace(work_path_str, render_path_str) + ) + + audio_file = self._instance.data.get("audioFile") + if audio_file: + abs_path = xstage_path.parent / audio_file + self._instance.context.data["audioFile"] = str(abs_path) + + self._instance.data["source"] = str(published_scene.as_posix()) + self._instance.data["expectedFiles"] = new_expected_files + harmony_plugin_info = PluginInfo( + SceneFile=xstage_path.as_posix(), + Version=( + self._instance.context.data["harmonyVersion"].split(".")[0]), + FieldOfView=self._instance.context.data["FOV"], + ResolutionX=self._instance.data["resolutionWidth"], + ResolutionY=self._instance.data["resolutionHeight"] + ) + + pattern = '[0]{' + str(self._instance.data["leadingZeros"]) + \ + '}1\.[a-zA-Z]{3}' + render_prefix = re.sub(pattern, '', + self._instance.data["expectedFiles"][0]) + harmony_plugin_info.set_output( + self._instance.data["setMembers"][0], + self._instance.data["outputFormat"], + render_prefix, + self._instance.data["outputType"], + self._instance.data["leadingZeros"], + self._instance.data["outputStartFrame"] + ) + + all_write_nodes = self._instance.context.data["all_write_nodes"] + disable_nodes = [] + for node in all_write_nodes: + # disable all other write nodes + if node != self._instance.data["setMembers"][0]: + disable_nodes.append("node.setEnable('{}', false)" + .format(node)) + harmony_plugin_info.PreRenderInlineScript = ';'.join(disable_nodes) + + return harmony_plugin_info.serialize() diff --git a/pype/plugins/harmony/publish/validate_scene_settings.py b/pype/plugins/harmony/publish/validate_scene_settings.py index 70e6f47721..5ab1b11ec9 100644 --- a/pype/plugins/harmony/publish/validate_scene_settings.py +++ b/pype/plugins/harmony/publish/validate_scene_settings.py @@ -21,7 +21,7 @@ class ValidateSceneSettingsRepair(pyblish.api.Action): pype.hosts.harmony.set_scene_settings( pype.hosts.harmony.get_asset_settings() ) - if not os.patch.exists(context.data["scenePath"]): + if not os.path.exists(context.data["scenePath"]): self.log.info("correcting scene name") scene_dir = os.path.dirname(context.data["currentFile"]) scene_path = os.path.join( @@ -40,6 +40,8 @@ class ValidateSceneSettings(pyblish.api.InstancePlugin): actions = [ValidateSceneSettingsRepair] frame_check_filter = ["_ch_", "_pr_", "_intd_", "_extd_"] + # used for skipping resolution validation for render tasks + render_check_filter = ["render", "Render"] def process(self, instance): """Plugin entry point.""" @@ -65,6 +67,12 @@ class ValidateSceneSettings(pyblish.api.InstancePlugin): fps = float( "{:.2f}".format(instance.context.data.get("frameRate"))) + if any(string in instance.context.data['anatomyData']['task'] + for string in self.render_check_filter): + self.log.debug("Render task detected, resolution check skipped") + expected_settings.pop("resolutionWidth") + expected_settings.pop("resolutionHeight") + current_settings = { "fps": fps, "frameStart": instance.context.data.get("frameStart"), diff --git a/pype/plugins/nuke/publish/collect_current_file.py b/pype/plugins/nuke/publish/collect_current_file.py deleted file mode 100644 index 253b9a7a24..0000000000 --- a/pype/plugins/nuke/publish/collect_current_file.py +++ /dev/null @@ -1,19 +0,0 @@ -import pyblish.api - - -class CollectCurrentFile(pyblish.api.ContextPlugin): - """Inject the current working file into context""" - - order = pyblish.api.CollectorOrder - 0.5 - label = "Collect Current File" - hosts = ["nuke"] - - def process(self, context): - import os - import nuke - current_file = nuke.root().name() - - normalised = os.path.normpath(current_file) - - context.data["current_file"] = normalised - context.data["currentFile"] = normalised diff --git a/pype/plugins/nuke/publish/collect_host.py b/pype/plugins/nuke/publish/collect_host.py deleted file mode 100644 index 3ae41ab3e4..0000000000 --- a/pype/plugins/nuke/publish/collect_host.py +++ /dev/null @@ -1,14 +0,0 @@ -import pyblish.api - - -class CollectHost(pyblish.api.ContextPlugin): - """Inject the host into context""" - - order = pyblish.api.CollectorOrder - label = "Collect Host" - hosts = ["nuke"] - - def process(self, context): - import pyblish.api - - context.data["host"] = pyblish.api.current_host() diff --git a/pype/plugins/nuke/publish/collect_host_version.py b/pype/plugins/nuke/publish/collect_host_version.py deleted file mode 100644 index 8d2cb576b2..0000000000 --- a/pype/plugins/nuke/publish/collect_host_version.py +++ /dev/null @@ -1,13 +0,0 @@ -import pyblish.api - - -class CollectHostVersion(pyblish.api.ContextPlugin): - """Inject the hosts version into context""" - - order = pyblish.api.CollectorOrder - label = "Collect Host Version" - hosts = ["nuke"] - - def process(self, context): - import nuke - context.data["hostVersion"] = nuke.NUKE_VERSION_STRING diff --git a/pype/plugins/nuke/publish/collect_legacy_read.py b/pype/plugins/nuke/publish/collect_legacy_read.py deleted file mode 100644 index 6b6ce57245..0000000000 --- a/pype/plugins/nuke/publish/collect_legacy_read.py +++ /dev/null @@ -1,30 +0,0 @@ -import toml - -import nuke - -import pyblish.api - - -class CollectReadLegacy(pyblish.api.ContextPlugin): - """Collect legacy read nodes.""" - - order = pyblish.api.CollectorOrder - label = "Collect Read Legacy" - hosts = ["nuke", "nukeassist"] - - def process(self, context): - - for node in nuke.allNodes(): - if node.Class() != "Read": - continue - - if "avalon" not in node.knobs().keys(): - continue - - if not toml.loads(node["avalon"].value()): - return - - instance = context.create_instance( - node.name(), family="read.legacy" - ) - instance.append(node) diff --git a/pype/plugins/nuke/publish/collect_review.py b/pype/plugins/nuke/publish/collect_review.py deleted file mode 100644 index 42aa910917..0000000000 --- a/pype/plugins/nuke/publish/collect_review.py +++ /dev/null @@ -1,52 +0,0 @@ -import pyblish.api -import pype.api -from avalon import io, api - -import nuke - - -class CollectReview(pyblish.api.InstancePlugin): - """Collect review instance from rendered frames - """ - - order = pyblish.api.CollectorOrder + 0.3 - label = "Collect Review" - hosts = ["nuke"] - families = ["render", "render.local", "render.farm"] - - def process(self, instance): - - node = instance[0] - - if "review" not in node.knobs(): - knob = nuke.Boolean_Knob("review", "Review") - knob.setValue(True) - node.addKnob(knob) - - if not node["review"].value(): - return - - # * Add audio to instance if exists. - # Find latest versions document - version_doc = pype.api.get_latest_version( - instance.context.data["assetEntity"]["name"], "audioMain" - ) - repre_doc = None - if version_doc: - # Try to find it's representation (Expected there is only one) - repre_doc = io.find_one( - {"type": "representation", "parent": version_doc["_id"]} - ) - - # Add audio to instance if representation was found - if repre_doc: - instance.data["audio"] = [{ - "offset": 0, - "filename": api.get_representation_path(repre_doc) - }] - - instance.data["families"].append("review") - instance.data['families'].append('ftrack') - - self.log.info("Review collected: `{}`".format(instance)) - self.log.debug("__ instance.data: `{}`".format(instance.data)) diff --git a/pype/plugins/nuke/publish/collect_selection.py b/pype/plugins/nuke/publish/collect_selection.py deleted file mode 100644 index a8a4f44b1c..0000000000 --- a/pype/plugins/nuke/publish/collect_selection.py +++ /dev/null @@ -1,14 +0,0 @@ -import nuke - -import pyblish.api - - -class CollectSelection(pyblish.api.ContextPlugin): - """Collect selection.""" - - order = pyblish.api.CollectorOrder - label = "Collect Selection of Nodes" - hosts = ["nuke"] - - def process(self, context): - context.data["selection"] = nuke.selectedNodes() diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 4f5c290e9d..dec1ad1dbd 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -543,21 +543,30 @@ def burnins_from_data( ffmpeg_args = codec_data else: - codec_name = burnin._streams[0].get("codec_name") + ffprobe_data = burnin._streams[0] + codec_name = ffprobe_data.get("codec_name") if codec_name: + if codec_name == "prores": + tags = ffprobe_data.get("tags") or {} + encoder = tags.get("encoder") or "" + if encoder.endswith("prores_ks"): + codec_name = "prores_ks" + + elif encoder.endswith("prores_aw"): + codec_name = "prores_aw" ffmpeg_args.append("-codec:v {}".format(codec_name)) - profile_name = burnin._streams[0].get("profile") + profile_name = ffprobe_data.get("profile") if profile_name: # lower profile name and repalce spaces with underscore profile_name = profile_name.replace(" ", "_").lower() ffmpeg_args.append("-profile:v {}".format(profile_name)) - bit_rate = burnin._streams[0].get("bit_rate") + bit_rate = ffprobe_data.get("bit_rate") if bit_rate: ffmpeg_args.append("-b:v {}".format(bit_rate)) - pix_fmt = burnin._streams[0].get("pix_fmt") + pix_fmt = ffprobe_data.get("pix_fmt") if pix_fmt: ffmpeg_args.append("-pix_fmt {}".format(pix_fmt)) diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json index debc92f2b5..17607b6bc1 100644 --- a/pype/settings/defaults/project_settings/ftrack.json +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -26,6 +26,14 @@ "Project Manager" ] }, + "clone_review_session": { + "enabled": true, + "role_list": [ + "Pypeclub", + "Administrator", + "Project Manager" + ] + }, "thumbnail_updates": { "enabled": true, "levels": 1 diff --git a/pype/settings/defaults/project_settings/harmony.json b/pype/settings/defaults/project_settings/harmony.json index 5eca4f60eb..83d63d3392 100644 --- a/pype/settings/defaults/project_settings/harmony.json +++ b/pype/settings/defaults/project_settings/harmony.json @@ -1,7 +1,7 @@ { "publish": {}, "general": { - "skip_resolution_check": false, - "skip_timelines_check": false + "skip_resolution_check": [], + "skip_timelines_check": [] } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json index 76a95d2140..94cd712639 100644 --- a/pype/settings/defaults/project_settings/nuke.json +++ b/pype/settings/defaults/project_settings/nuke.json @@ -8,6 +8,9 @@ } }, "publish": { + "PreCollectNukeInstances": { + "sync_workfile_version": true + }, "ExtractThumbnail": { "enabled": true, "nodes": { diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index ec025abc9d..01f1536620 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -17,7 +17,7 @@ ] }, "PYTHONPATH": [ - "{PYPE_ROOT}/pype/setup/maya", + "{PYPE_ROOT}/pype/hosts/maya/startup", "{PYPE_REPOS_ROOT}/avalon-core/setup/maya", "{PYPE_REPOS_ROOT}/maya-look-assigner", "{PYTHONPATH}" @@ -240,7 +240,7 @@ ] }, "NUKE_PATH": [ - "{PYPE_ROOT}/repos/avalon-core/setup/nuke/nuke_path", + "{PYPE_REPOS_ROOT}/avalon-core/setup/nuke/nuke_path", "{PYPE_ROOT}/pype/hosts/nuke/startup", "{PYPE_STUDIO_PLUGINS}/nuke" ], @@ -365,7 +365,7 @@ ] }, "NUKE_PATH": [ - "{PYPE_ROOT}/repos/avalon-core/setup/nuke/nuke_path", + "{PYPE_REPOS_ROOT}/avalon-core/setup/nuke/nuke_path", "{PYPE_ROOT}/pype/hosts/nuke/startup", "{PYPE_STUDIO_PLUGINS}/nuke" ], @@ -864,14 +864,14 @@ ] }, "HOUDINI_PATH": { - "darwin": "{PYPE_ROOT}/setup/houdini:&", - "linux": "{PYPE_ROOT}/setup/houdini:&", - "windows": "{PYPE_ROOT}/setup/houdini;&" + "darwin": "{PYPE_ROOT}/pype/hosts/houdini/startup:&", + "linux": "{PYPE_ROOT}/pype/hosts/houdini/startup:&", + "windows": "{PYPE_ROOT}/pype/hosts/houdini/startup;&" }, "HOUDINI_MENU_PATH": { - "darwin": "{PYPE_ROOT}/setup/houdini:&", - "linux": "{PYPE_ROOT}/setup/houdini:&", - "windows": "{PYPE_ROOT}/setup/houdini;&" + "darwin": "{PYPE_ROOT}/pype/hosts/houdini/startup:&", + "linux": "{PYPE_ROOT}/pype/hosts/houdini/startup:&", + "windows": "{PYPE_ROOT}/pype/hosts/houdini/startup;&" } }, "variants": { @@ -939,7 +939,7 @@ "windows": [ [ "C:\\Program Files\\Blender Foundation\\Blender 2.90\\blender.exe", - "" + "--python-use-system-env" ] ], "darwin": [], @@ -960,7 +960,7 @@ "windows": [ [ "C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe", - "" + "--python-use-system-env" ] ], "darwin": [], diff --git a/pype/setup/blender/init.py b/pype/setup/blender/init.py deleted file mode 100644 index 8aa83e51c9..0000000000 --- a/pype/setup/blender/init.py +++ /dev/null @@ -1,3 +0,0 @@ -from pype.hosts import blender - -blender.install() diff --git a/pype/tools/pyblish_pype/app.py b/pype/tools/pyblish_pype/app.py index 1bf16ff56a..5ba0a47425 100644 --- a/pype/tools/pyblish_pype/app.py +++ b/pype/tools/pyblish_pype/app.py @@ -62,9 +62,9 @@ def install_fonts(): # In hosts, this will be called each time the GUI is shown, # potentially installing a font each time. if database.addApplicationFont(path) < 0: - sys.stderr.write("Could not install %s\n" % path) + print("Could not install %s\n" % path) else: - sys.stdout.write("Installed %s\n" % font) + print("Installed %s\n" % font) def on_destroyed(): diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index cbff26e135..508b8e870d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -104,6 +104,25 @@ } ] }, + { + "type": "dict", + "key": "clone_review_session", + "label": "Clone Review Session", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "role_list", + "label": "Roles for action", + "object_type": "text" + } + ] + }, { "type": "dict", "key": "thumbnail_updates", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json index 791a08cb8d..92ad39ac2c 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json @@ -19,14 +19,16 @@ "label": "General", "children": [ { - "type": "boolean", + "type": "list", "key": "skip_resolution_check", - "label": "Skip Resolution Check" + "object_type": "text", + "label": "Skip Resolution Check for Tasks" }, { - "type": "boolean", + "type": "list", "key": "skip_timelines_check", - "label": "Skip Timeliene Check" + "object_type": "text", + "label": "Skip Timeliene Check for Tasks" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json index 9bec54fa36..7a6960bcbd 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json @@ -47,6 +47,20 @@ "key": "publish", "label": "Publish plugins", "children": [ + { + "type": "dict", + "collapsable": true, + "key": "PreCollectNukeInstances", + "label": "PreCollectNukeInstances", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "sync_workfile_version", + "label": "Sync Version from workfile" + } + ] + }, { "type": "dict", "collapsable": true, diff --git a/repos/avalon-core b/repos/avalon-core index d269f5da0f..4427263006 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit d269f5da0f80990fe7e400d6180e3d7699b6324a +Subproject commit 44272630062ba5e440cdc6c2a5864328d736ae73 diff --git a/repos/maya-look-assigner b/repos/maya-look-assigner index baf19fe86a..7adabe8f0e 160000 --- a/repos/maya-look-assigner +++ b/repos/maya-look-assigner @@ -1 +1 @@ -Subproject commit baf19fe86a836259c0ce050b229cd521625708bf +Subproject commit 7adabe8f0e6858bfe5b6bf0b39bd428ed72d0452 diff --git a/requirements.txt b/requirements.txt index 8320b586c4..b3dee18b26 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,6 +29,7 @@ pytest-cov pytest-print pyqt5 Qt.py +setuptools==45.0.0 scandir speedcopy six