diff --git a/openpype/__init__.py b/openpype/__init__.py index 7720c9dfb89..99629a42573 100644 --- a/openpype/__init__.py +++ b/openpype/__init__.py @@ -75,7 +75,10 @@ def install(): """Install Pype to Avalon.""" from pyblish.lib import MessageHandler from openpype.modules import load_modules - from openpype.pipeline import LegacyCreator + from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + ) from avalon import pipeline # Make sure modules are loaded @@ -91,7 +94,7 @@ def modified_emit(obj, record): log.info("Registering global plug-ins..") pyblish.register_plugin_path(PUBLISH_PATH) pyblish.register_discovery_filter(filter_pyblish_plugins) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) project_name = os.environ.get("AVALON_PROJECT") @@ -119,7 +122,7 @@ def modified_emit(obj, record): continue pyblish.register_plugin_path(path) - avalon.register_plugin_path(avalon.Loader, path) + register_loader_plugin_path(path) avalon.register_plugin_path(LegacyCreator, path) avalon.register_plugin_path(avalon.InventoryAction, path) @@ -139,10 +142,12 @@ def _on_task_change(): @import_wrapper def uninstall(): """Uninstall Pype from Avalon.""" + from openpype.pipeline import deregister_loader_plugin_path + log.info("Deregistering global plug-ins..") pyblish.deregister_plugin_path(PUBLISH_PATH) pyblish.deregister_discovery_filter(filter_pyblish_plugins) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) log.info("Global plug-ins unregistred") # restore original discover diff --git a/openpype/hosts/aftereffects/api/pipeline.py b/openpype/hosts/aftereffects/api/pipeline.py index 41d24178183..681f1c51a7b 100644 --- a/openpype/hosts/aftereffects/api/pipeline.py +++ b/openpype/hosts/aftereffects/api/pipeline.py @@ -9,7 +9,11 @@ from openpype import lib from openpype.api import Logger -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) import openpype.hosts.aftereffects from openpype.lib import register_event_callback @@ -67,7 +71,7 @@ def install(): pyblish.api.register_host("aftereffects") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) log.info(PUBLISH_PATH) @@ -80,7 +84,7 @@ def install(): def uninstall(): pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) diff --git a/openpype/hosts/aftereffects/api/plugin.py b/openpype/hosts/aftereffects/api/plugin.py index fbe07663dd6..29705cc5be2 100644 --- a/openpype/hosts/aftereffects/api/plugin.py +++ b/openpype/hosts/aftereffects/api/plugin.py @@ -1,9 +1,8 @@ -import avalon.api +from openpype.pipeline import LoaderPlugin from .launch_logic import get_stub -class AfterEffectsLoader(avalon.api.Loader): +class AfterEffectsLoader(LoaderPlugin): @staticmethod def get_stub(): return get_stub() - diff --git a/openpype/hosts/aftereffects/plugins/load/load_background.py b/openpype/hosts/aftereffects/plugins/load/load_background.py index 1a2d6fc432c..be43cae44ef 100644 --- a/openpype/hosts/aftereffects/plugins/load/load_background.py +++ b/openpype/hosts/aftereffects/plugins/load/load_background.py @@ -1,11 +1,10 @@ import re -import avalon.api - from openpype.lib import ( get_background_layers, get_unique_layer_name ) +from openpype.pipeline import get_representation_path from openpype.hosts.aftereffects.api import ( AfterEffectsLoader, containerise @@ -78,7 +77,7 @@ def update(self, container, representation): else: # switching version - keep same name comp_name = container["namespace"] - path = avalon.api.get_representation_path(representation) + path = get_representation_path(representation) layers = get_background_layers(path) comp = stub.reload_background(container["members"][1], diff --git a/openpype/hosts/aftereffects/plugins/load/load_file.py b/openpype/hosts/aftereffects/plugins/load/load_file.py index 9dbbf7aae14..9eb9e80a2cc 100644 --- a/openpype/hosts/aftereffects/plugins/load/load_file.py +++ b/openpype/hosts/aftereffects/plugins/load/load_file.py @@ -1,8 +1,8 @@ import re -import avalon.api from openpype import lib +from openpype.pipeline import get_representation_path from openpype.hosts.aftereffects.api import ( AfterEffectsLoader, containerise @@ -92,7 +92,7 @@ def update(self, container, representation): "{}_{}".format(context["asset"], context["subset"])) else: # switching version - keep same name layer_name = container["namespace"] - path = avalon.api.get_representation_path(representation) + path = get_representation_path(representation) # with aftereffects.maintained_selection(): # TODO stub.replace_item(layer.id, path, stub.LOADED_ICON + layer_name) stub.imprint( diff --git a/openpype/hosts/blender/api/pipeline.py b/openpype/hosts/blender/api/pipeline.py index efa08ba59ec..07a7509dd73 100644 --- a/openpype/hosts/blender/api/pipeline.py +++ b/openpype/hosts/blender/api/pipeline.py @@ -14,7 +14,11 @@ from avalon import io, schema from avalon.pipeline import AVALON_CONTAINER_ID -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from openpype.api import Logger from openpype.lib import ( register_event_callback, @@ -50,7 +54,7 @@ def install(): pyblish.api.register_host("blender") pyblish.api.register_plugin_path(str(PUBLISH_PATH)) - avalon.api.register_plugin_path(avalon.api.Loader, str(LOAD_PATH)) + register_loader_plugin_path(str(LOAD_PATH)) avalon.api.register_plugin_path(LegacyCreator, str(CREATE_PATH)) lib.append_user_scripts() @@ -72,7 +76,7 @@ def uninstall(): pyblish.api.deregister_host("blender") pyblish.api.deregister_plugin_path(str(PUBLISH_PATH)) - avalon.api.deregister_plugin_path(avalon.api.Loader, str(LOAD_PATH)) + deregister_loader_plugin_path(str(LOAD_PATH)) avalon.api.deregister_plugin_path(LegacyCreator, str(CREATE_PATH)) if not IS_HEADLESS: diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index 20d1e4c8db3..3207f543b77 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -5,8 +5,10 @@ import bpy -import avalon.api -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) from .pipeline import AVALON_CONTAINERS from .ops import ( MainThreadItem, @@ -145,13 +147,13 @@ def process(self): return collection -class Loader(avalon.api.Loader): +class Loader(LoaderPlugin): """Base class for Loader plug-ins.""" hosts = ["blender"] -class AssetLoader(avalon.api.Loader): +class AssetLoader(LoaderPlugin): """A basic AssetLoader for Blender This will implement the basic logic for linking/appending assets diff --git a/openpype/hosts/blender/plugins/load/load_abc.py b/openpype/hosts/blender/plugins/load/load_abc.py index 07800521c95..3daaeceffe3 100644 --- a/openpype/hosts/blender/plugins/load/load_abc.py +++ b/openpype/hosts/blender/plugins/load/load_abc.py @@ -6,7 +6,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, AVALON_PROPERTY, @@ -178,7 +178,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_action.py b/openpype/hosts/blender/plugins/load/load_action.py index a9d85222205..3c8fe988f0d 100644 --- a/openpype/hosts/blender/plugins/load/load_action.py +++ b/openpype/hosts/blender/plugins/load/load_action.py @@ -5,9 +5,13 @@ from pprint import pformat from typing import Dict, List, Optional -from avalon import api, blender import bpy +from openpype.pipeline import get_representation_path import openpype.hosts.blender.api.plugin +from openpype.hosts.blender.api.pipeline import ( + containerise_existing, + AVALON_PROPERTY, +) logger = logging.getLogger("openpype").getChild("blender").getChild("load_action") @@ -49,7 +53,7 @@ def process_asset( container = bpy.data.collections.new(lib_container) container.name = container_name - blender.pipeline.containerise_existing( + containerise_existing( container, name, namespace, @@ -57,8 +61,7 @@ def process_asset( self.__class__.__name__, ) - container_metadata = container.get( - blender.pipeline.AVALON_PROPERTY) + container_metadata = container.get(AVALON_PROPERTY) container_metadata["libpath"] = libpath container_metadata["lib_container"] = lib_container @@ -90,16 +93,16 @@ def process_asset( anim_data.action.make_local() - if not obj.get(blender.pipeline.AVALON_PROPERTY): + if not obj.get(AVALON_PROPERTY): - obj[blender.pipeline.AVALON_PROPERTY] = dict() + obj[AVALON_PROPERTY] = dict() - avalon_info = obj[blender.pipeline.AVALON_PROPERTY] + avalon_info = obj[AVALON_PROPERTY] avalon_info.update({"container_name": container_name}) objects_list.append(obj) - animation_container.pop(blender.pipeline.AVALON_PROPERTY) + animation_container.pop(AVALON_PROPERTY) # Save the list of objects in the metadata container container_metadata["objects"] = objects_list @@ -128,7 +131,7 @@ def update(self, container: Dict, representation: Dict): container["objectName"] ) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() logger.info( @@ -153,8 +156,7 @@ def update(self, container: Dict, representation: Dict): f"Unsupported file: {libpath}" ) - collection_metadata = collection.get( - blender.pipeline.AVALON_PROPERTY) + collection_metadata = collection.get(AVALON_PROPERTY) collection_libpath = collection_metadata["libpath"] normalized_collection_libpath = ( @@ -225,16 +227,16 @@ def update(self, container: Dict, representation: Dict): strip.action = anim_data.action strip.action_frame_end = anim_data.action.frame_range[1] - if not obj.get(blender.pipeline.AVALON_PROPERTY): + if not obj.get(AVALON_PROPERTY): - obj[blender.pipeline.AVALON_PROPERTY] = dict() + obj[AVALON_PROPERTY] = dict() - avalon_info = obj[blender.pipeline.AVALON_PROPERTY] + avalon_info = obj[AVALON_PROPERTY] avalon_info.update({"container_name": collection.name}) objects_list.append(obj) - anim_container.pop(blender.pipeline.AVALON_PROPERTY) + anim_container.pop(AVALON_PROPERTY) # Save the list of objects in the metadata container collection_metadata["objects"] = objects_list @@ -266,8 +268,7 @@ def remove(self, container: Dict) -> bool: "Nested collections are not supported." ) - collection_metadata = collection.get( - blender.pipeline.AVALON_PROPERTY) + collection_metadata = collection.get(AVALON_PROPERTY) objects = collection_metadata["objects"] lib_container = collection_metadata["lib_container"] diff --git a/openpype/hosts/blender/plugins/load/load_audio.py b/openpype/hosts/blender/plugins/load/load_audio.py index e065150c152..b95c5db2701 100644 --- a/openpype/hosts/blender/plugins/load/load_audio.py +++ b/openpype/hosts/blender/plugins/load/load_audio.py @@ -6,7 +6,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -102,7 +102,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) self.log.info( "Container: %s\nRepresentation: %s", diff --git a/openpype/hosts/blender/plugins/load/load_camera_blend.py b/openpype/hosts/blender/plugins/load/load_camera_blend.py index 61955f124d7..6ed2e8a5750 100644 --- a/openpype/hosts/blender/plugins/load/load_camera_blend.py +++ b/openpype/hosts/blender/plugins/load/load_camera_blend.py @@ -7,7 +7,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -155,7 +155,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_camera_fbx.py b/openpype/hosts/blender/plugins/load/load_camera_fbx.py index 175ddacf9fa..626ed44f08f 100644 --- a/openpype/hosts/blender/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/blender/plugins/load/load_camera_fbx.py @@ -6,7 +6,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin, lib from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -143,7 +143,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_fbx.py b/openpype/hosts/blender/plugins/load/load_fbx.py index c6e6af55925..2d249ef6471 100644 --- a/openpype/hosts/blender/plugins/load/load_fbx.py +++ b/openpype/hosts/blender/plugins/load/load_fbx.py @@ -6,7 +6,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin, lib from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -187,7 +187,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_layout_blend.py b/openpype/hosts/blender/plugins/load/load_layout_blend.py index 7f8ae610c64..d87df3c010f 100644 --- a/openpype/hosts/blender/plugins/load/load_layout_blend.py +++ b/openpype/hosts/blender/plugins/load/load_layout_blend.py @@ -6,9 +6,11 @@ import bpy -from avalon import api from openpype import lib -from openpype.pipeline import legacy_create +from openpype.pipeline import ( + legacy_create, + get_representation_path, +) from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -309,7 +311,7 @@ def update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_layout_json.py b/openpype/hosts/blender/plugins/load/load_layout_json.py index 5b5f9ab83d1..0693937fec2 100644 --- a/openpype/hosts/blender/plugins/load/load_layout_json.py +++ b/openpype/hosts/blender/plugins/load/load_layout_json.py @@ -7,7 +7,13 @@ import bpy -from avalon import api +from openpype.pipeline import ( + discover_loader_plugins, + remove_container, + load_container, + get_representation_path, + loaders_from_representation, +) from openpype.hosts.blender.api.pipeline import ( AVALON_INSTANCES, AVALON_CONTAINERS, @@ -33,7 +39,7 @@ def _remove(self, asset_group): objects = list(asset_group.children) for obj in objects: - api.remove(obj.get(AVALON_PROPERTY)) + remove_container(obj.get(AVALON_PROPERTY)) def _remove_animation_instances(self, asset_group): instances = bpy.data.collections.get(AVALON_INSTANCES) @@ -66,13 +72,13 @@ def _process(self, libpath, asset, asset_group, actions): with open(libpath, "r") as fp: data = json.load(fp) - all_loaders = api.discover(api.Loader) + all_loaders = discover_loader_plugins() for element in data: reference = element.get('reference') family = element.get('family') - loaders = api.loaders_from_representation(all_loaders, reference) + loaders = loaders_from_representation(all_loaders, reference) loader = self._get_loader(loaders, family) if not loader: @@ -102,7 +108,7 @@ def _process(self, libpath, asset, asset_group, actions): # at this time it will not return anything. The assets will be # loaded in the next Blender cycle, so we use the options to # set the transform, parent and assign the action, if there is one. - api.load( + load_container( loader, reference, namespace=instance_name, @@ -188,7 +194,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_look.py b/openpype/hosts/blender/plugins/load/load_look.py index 066ec0101b2..70d1b95f02c 100644 --- a/openpype/hosts/blender/plugins/load/load_look.py +++ b/openpype/hosts/blender/plugins/load/load_look.py @@ -8,7 +8,7 @@ import json import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.pipeline import ( containerise_existing, @@ -140,7 +140,7 @@ def process_asset( def update(self, container: Dict, representation: Dict): collection = bpy.data.collections.get(container["objectName"]) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_model.py b/openpype/hosts/blender/plugins/load/load_model.py index 04ece0b338e..18d01dcb295 100644 --- a/openpype/hosts/blender/plugins/load/load_model.py +++ b/openpype/hosts/blender/plugins/load/load_model.py @@ -6,7 +6,7 @@ import bpy -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, @@ -195,7 +195,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/blender/plugins/load/load_rig.py b/openpype/hosts/blender/plugins/load/load_rig.py index eacabd34476..cec088076c2 100644 --- a/openpype/hosts/blender/plugins/load/load_rig.py +++ b/openpype/hosts/blender/plugins/load/load_rig.py @@ -6,11 +6,15 @@ import bpy -from avalon import api -from avalon.blender import lib as avalon_lib from openpype import lib -from openpype.pipeline import legacy_create -from openpype.hosts.blender.api import plugin +from openpype.pipeline import ( + legacy_create, + get_representation_path, +) +from openpype.hosts.blender.api import ( + plugin, + get_selection, +) from openpype.hosts.blender.api.pipeline import ( AVALON_CONTAINERS, AVALON_PROPERTY, @@ -263,7 +267,7 @@ def process_asset( if anim_file: bpy.ops.import_scene.fbx(filepath=anim_file, anim_offset=0.0) - imported = avalon_lib.get_selection() + imported = get_selection() armature = [ o for o in asset_group.children if o.type == 'ARMATURE'][0] @@ -307,7 +311,7 @@ def exec_update(self, container: Dict, representation: Dict): """ object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(api.get_representation_path(representation)) + libpath = Path(get_representation_path(representation)) extension = libpath.suffix.lower() self.log.info( diff --git a/openpype/hosts/flame/api/pipeline.py b/openpype/hosts/flame/api/pipeline.py index f802cf160bf..930c6abe29d 100644 --- a/openpype/hosts/flame/api/pipeline.py +++ b/openpype/hosts/flame/api/pipeline.py @@ -7,7 +7,11 @@ from avalon.pipeline import AVALON_CONTAINER_ID from pyblish import api as pyblish from openpype.api import Logger -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from .lib import ( set_segment_data_marker, set_publish_attribute, @@ -33,7 +37,7 @@ def install(): pyblish.register_host("flame") pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) log.info("OpenPype Flame plug-ins registred ...") @@ -48,7 +52,7 @@ def uninstall(): log.info("Deregistering Flame plug-ins..") pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH) avalon.deregister_plugin_path(avalon.InventoryAction, INVENTORY_PATH) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index 5221701a2f3..4c9d3c53838 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -7,9 +7,11 @@ import qargparse from Qt import QtWidgets, QtCore import openpype.api as openpype -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) from openpype import style -import avalon.api as avalon from . import ( lib as flib, pipeline as fpipeline, @@ -660,7 +662,7 @@ def _create_parents(self): # Publishing plugin functions # Loader plugin functions -class ClipLoader(avalon.Loader): +class ClipLoader(LoaderPlugin): """A basic clip loader for Flame This will implement the basic behavior for a loader to inherit from that diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index 8ba01d6937a..8980f72cb87 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -172,7 +172,7 @@ def _get_segment_from_clip(self, clip): # version_name = version.get("name", None) # colorspace = version_data.get("colorspace", None) # object_name = "{}_{}".format(name, namespace) - # file = api.get_representation_path(representation).replace("\\", "/") + # file = get_representation_path(representation).replace("\\", "/") # clip = track_item.source() # # reconnect media to new path diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index 5d97f83032c..2bb5ea8aae5 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -5,8 +5,8 @@ from Qt import QtGui -import avalon.api from avalon import io +from openpype.pipeline import switch_container from .pipeline import get_current_comp, comp_lock_and_undo_chunk self = sys.modules[__name__] @@ -142,7 +142,7 @@ def switch_item(container, assert representation, ("Could not find representation in the database " "with the name '%s'" % representation_name) - avalon.api.switch(container, representation) + switch_container(container, representation) return representation diff --git a/openpype/hosts/fusion/api/pipeline.py b/openpype/hosts/fusion/api/pipeline.py index 5ac56fcbedb..92e54ad6f5b 100644 --- a/openpype/hosts/fusion/api/pipeline.py +++ b/openpype/hosts/fusion/api/pipeline.py @@ -11,7 +11,11 @@ from avalon.pipeline import AVALON_CONTAINER_ID from openpype.api import Logger -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) import openpype.hosts.fusion log = Logger().get_logger(__name__) @@ -63,7 +67,7 @@ def install(): pyblish.api.register_plugin_path(PUBLISH_PATH) log.info("Registering Fusion plug-ins..") - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH) @@ -87,7 +91,7 @@ def uninstall(): pyblish.api.deregister_plugin_path(PUBLISH_PATH) log.info("Deregistering Fusion plug-ins..") - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) avalon.api.deregister_plugin_path( avalon.api.InventoryAction, INVENTORY_PATH diff --git a/openpype/hosts/fusion/plugins/load/actions.py b/openpype/hosts/fusion/plugins/load/actions.py index 6af99e4c562..bc59cec77f9 100644 --- a/openpype/hosts/fusion/plugins/load/actions.py +++ b/openpype/hosts/fusion/plugins/load/actions.py @@ -2,10 +2,10 @@ """ -from avalon import api +from openpype.pipeline import load -class FusionSetFrameRangeLoader(api.Loader): +class FusionSetFrameRangeLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", @@ -39,7 +39,7 @@ def load(self, context, name, namespace, data): lib.update_frame_range(start, end) -class FusionSetFrameRangeWithHandlesLoader(api.Loader): +class FusionSetFrameRangeWithHandlesLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", diff --git a/openpype/hosts/fusion/plugins/load/load_sequence.py b/openpype/hosts/fusion/plugins/load/load_sequence.py index ea118585bf0..075820de351 100644 --- a/openpype/hosts/fusion/plugins/load/load_sequence.py +++ b/openpype/hosts/fusion/plugins/load/load_sequence.py @@ -1,8 +1,12 @@ import os import contextlib -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.fusion.api import ( imprint_container, get_current_comp, @@ -117,7 +121,7 @@ def loader_shift(loader, frame, relative=True): return int(shift) -class FusionLoadSequence(api.Loader): +class FusionLoadSequence(load.LoaderPlugin): """Load image sequence into Fusion""" families = ["imagesequence", "review", "render"] @@ -204,7 +208,7 @@ def update(self, container, representation): assert tool.ID == "Loader", "Must be Loader" comp = tool.Comp() - root = os.path.dirname(api.get_representation_path(representation)) + root = os.path.dirname(get_representation_path(representation)) path = self._get_first_image(root) # Get start frame from version data diff --git a/openpype/hosts/harmony/api/README.md b/openpype/hosts/harmony/api/README.md index a8d182736af..e8d354e1e64 100644 --- a/openpype/hosts/harmony/api/README.md +++ b/openpype/hosts/harmony/api/README.md @@ -575,7 +575,7 @@ replace_files = """function %s_replace_files(args) """ % (signature, signature) -class ImageSequenceLoader(api.Loader): +class ImageSequenceLoader(load.LoaderPlugin): """Load images Stores the imported asset in a container named after the asset. """ diff --git a/openpype/hosts/harmony/api/pipeline.py b/openpype/hosts/harmony/api/pipeline.py index 928bf926ffa..f967da15ca4 100644 --- a/openpype/hosts/harmony/api/pipeline.py +++ b/openpype/hosts/harmony/api/pipeline.py @@ -10,7 +10,11 @@ from openpype import lib from openpype.lib import register_event_callback -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) import openpype.hosts.harmony import openpype.hosts.harmony.api as harmony @@ -180,7 +184,7 @@ def install(): pyblish.api.register_host("harmony") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) log.info(PUBLISH_PATH) @@ -194,7 +198,7 @@ def install(): def uninstall(): pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) diff --git a/openpype/hosts/harmony/plugins/load/load_audio.py b/openpype/hosts/harmony/plugins/load/load_audio.py index 57ea8ae312b..e18a6de0972 100644 --- a/openpype/hosts/harmony/plugins/load/load_audio.py +++ b/openpype/hosts/harmony/plugins/load/load_audio.py @@ -1,4 +1,7 @@ -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony sig = harmony.signature() @@ -29,7 +32,7 @@ """ % (sig, sig) -class ImportAudioLoader(api.Loader): +class ImportAudioLoader(load.LoaderPlugin): """Import audio.""" families = ["shot", "audio"] @@ -37,7 +40,7 @@ class ImportAudioLoader(api.Loader): label = "Import Audio" def load(self, context, name=None, namespace=None, data=None): - wav_file = api.get_representation_path(context["representation"]) + wav_file = get_representation_path(context["representation"]) harmony.send( {"function": func, "args": [context["subset"]["name"], wav_file]} ) diff --git a/openpype/hosts/harmony/plugins/load/load_background.py b/openpype/hosts/harmony/plugins/load/load_background.py index 686d6b5b7b9..9c01fe3cd82 100644 --- a/openpype/hosts/harmony/plugins/load/load_background.py +++ b/openpype/hosts/harmony/plugins/load/load_background.py @@ -1,7 +1,10 @@ import os import json -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony import openpype.lib @@ -226,7 +229,7 @@ """ -class BackgroundLoader(api.Loader): +class BackgroundLoader(load.LoaderPlugin): """Load images Stores the imported asset in a container named after the asset. """ @@ -278,7 +281,7 @@ def load(self, context, name=None, namespace=None, data=None): def update(self, container, representation): - path = api.get_representation_path(representation) + path = get_representation_path(representation) with open(path) as json_file: data = json.load(json_file) @@ -297,7 +300,7 @@ def update(self, container, representation): bg_folder = os.path.dirname(path) - path = api.get_representation_path(representation) + path = get_representation_path(representation) print(container) diff --git a/openpype/hosts/harmony/plugins/load/load_imagesequence.py b/openpype/hosts/harmony/plugins/load/load_imagesequence.py index 310f9bdb61d..18695438d5a 100644 --- a/openpype/hosts/harmony/plugins/load/load_imagesequence.py +++ b/openpype/hosts/harmony/plugins/load/load_imagesequence.py @@ -6,12 +6,15 @@ import clique -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony import openpype.lib -class ImageSequenceLoader(api.Loader): +class ImageSequenceLoader(load.LoaderPlugin): """Load image sequences. Stores the imported asset in a container named after the asset. @@ -79,7 +82,7 @@ def update(self, container, representation): self_name = self.__class__.__name__ node = container.get("nodes").pop() - path = api.get_representation_path(representation) + path = get_representation_path(representation) collections, remainder = clique.assemble( os.listdir(os.path.dirname(path)) ) diff --git a/openpype/hosts/harmony/plugins/load/load_palette.py b/openpype/hosts/harmony/plugins/load/load_palette.py index 2e0f70d135c..1da3e61e1b2 100644 --- a/openpype/hosts/harmony/plugins/load/load_palette.py +++ b/openpype/hosts/harmony/plugins/load/load_palette.py @@ -1,11 +1,14 @@ import os import shutil -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony -class ImportPaletteLoader(api.Loader): +class ImportPaletteLoader(load.LoaderPlugin): """Import palettes.""" families = ["palette", "harmony.palette"] @@ -31,7 +34,7 @@ def load_palette(self, representation): scene_path = harmony.send( {"function": "scene.currentProjectPath"} )["result"] - src = api.get_representation_path(representation) + src = get_representation_path(representation) dst = os.path.join( scene_path, "palette-library", diff --git a/openpype/hosts/harmony/plugins/load/load_template.py b/openpype/hosts/harmony/plugins/load/load_template.py index 112e613ae6e..c6dc9d913bf 100644 --- a/openpype/hosts/harmony/plugins/load/load_template.py +++ b/openpype/hosts/harmony/plugins/load/load_template.py @@ -6,12 +6,15 @@ import shutil import uuid -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony import openpype.lib -class TemplateLoader(api.Loader): +class TemplateLoader(load.LoaderPlugin): """Load Harmony template as container. .. todo:: @@ -38,7 +41,7 @@ def load(self, context, name=None, namespace=None, data=None): # Load template. self_name = self.__class__.__name__ temp_dir = tempfile.mkdtemp() - zip_file = api.get_representation_path(context["representation"]) + zip_file = get_representation_path(context["representation"]) template_path = os.path.join(temp_dir, "temp.tpl") with zipfile.ZipFile(zip_file, "r") as zip_ref: zip_ref.extractall(template_path) diff --git a/openpype/hosts/harmony/plugins/load/load_template_workfile.py b/openpype/hosts/harmony/plugins/load/load_template_workfile.py index c21b8194b18..2b84a43b35e 100644 --- a/openpype/hosts/harmony/plugins/load/load_template_workfile.py +++ b/openpype/hosts/harmony/plugins/load/load_template_workfile.py @@ -3,11 +3,14 @@ import os import shutil -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) import openpype.hosts.harmony.api as harmony -class ImportTemplateLoader(api.Loader): +class ImportTemplateLoader(load.LoaderPlugin): """Import templates.""" families = ["harmony.template", "workfile"] @@ -17,7 +20,7 @@ class ImportTemplateLoader(api.Loader): def load(self, context, name=None, namespace=None, data=None): # Import template. temp_dir = tempfile.mkdtemp() - zip_file = api.get_representation_path(context["representation"]) + zip_file = get_representation_path(context["representation"]) template_path = os.path.join(temp_dir, "temp.tpl") with zipfile.ZipFile(zip_file, "r") as zip_ref: zip_ref.extractall(template_path) diff --git a/openpype/hosts/hiero/api/pipeline.py b/openpype/hosts/hiero/api/pipeline.py index 5cb23ea355b..eff126c0b6c 100644 --- a/openpype/hosts/hiero/api/pipeline.py +++ b/openpype/hosts/hiero/api/pipeline.py @@ -9,7 +9,11 @@ from avalon import schema from pyblish import api as pyblish from openpype.api import Logger -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from openpype.tools.utils import host_tools from . import lib, menu, events @@ -45,7 +49,7 @@ def install(): log.info("Registering Hiero plug-ins..") pyblish.register_host("hiero") pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) @@ -67,7 +71,7 @@ def uninstall(): log.info("Deregistering Hiero plug-ins..") pyblish.deregister_host("hiero") pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH) # register callback for switching publishable diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 53928aca41d..54e66bf99ab 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -6,9 +6,9 @@ from Qt import QtWidgets, QtCore import qargparse -import avalon.api as avalon + import openpype.api as openpype -from openpype.pipeline import LegacyCreator +from openpype.pipeline import LoaderPlugin, LegacyCreator from . import lib log = openpype.Logger().get_logger(__name__) @@ -306,7 +306,7 @@ def get_reference_node_parents(ref): return parents -class SequenceLoader(avalon.Loader): +class SequenceLoader(LoaderPlugin): """A basic SequenceLoader for Resolve This will implement the basic behavior for a loader to inherit from that diff --git a/openpype/hosts/hiero/plugins/load/load_clip.py b/openpype/hosts/hiero/plugins/load/load_clip.py index b905dd44315..d3908695a2d 100644 --- a/openpype/hosts/hiero/plugins/load/load_clip.py +++ b/openpype/hosts/hiero/plugins/load/load_clip.py @@ -1,4 +1,5 @@ -from avalon import io, api +from avalon import io +from openpype.pipeline import get_representation_path import openpype.hosts.hiero.api as phiero # from openpype.hosts.hiero.api import plugin, lib # reload(lib) @@ -112,7 +113,7 @@ def update(self, container, representation): version_name = version.get("name", None) colorspace = version_data.get("colorspace", None) object_name = "{}_{}".format(name, namespace) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") clip = track_item.source() # reconnect media to new path diff --git a/openpype/hosts/houdini/api/pipeline.py b/openpype/hosts/houdini/api/pipeline.py index 6cfb7136619..7d4e58efb73 100644 --- a/openpype/hosts/houdini/api/pipeline.py +++ b/openpype/hosts/houdini/api/pipeline.py @@ -11,7 +11,10 @@ from avalon.pipeline import AVALON_CONTAINER_ID from avalon.lib import find_submodule -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, +) import openpype.hosts.houdini from openpype.hosts.houdini.api import lib @@ -50,7 +53,7 @@ def install(): pyblish.api.register_host("hpython") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) log.info("Installing callbacks ... ") diff --git a/openpype/hosts/houdini/plugins/load/actions.py b/openpype/hosts/houdini/plugins/load/actions.py index acdb998c16e..63d74c39a59 100644 --- a/openpype/hosts/houdini/plugins/load/actions.py +++ b/openpype/hosts/houdini/plugins/load/actions.py @@ -2,10 +2,10 @@ """ -from avalon import api +from openpype.pipeline import load -class SetFrameRangeLoader(api.Loader): +class SetFrameRangeLoader(load.LoaderPlugin): """Set Houdini frame range""" families = [ @@ -43,7 +43,7 @@ def load(self, context, name, namespace, data): hou.playbar.setPlaybackRange(start, end) -class SetFrameRangeWithHandlesLoader(api.Loader): +class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): """Set Maya frame range including pre- and post-handles""" families = [ diff --git a/openpype/hosts/houdini/plugins/load/load_alembic.py b/openpype/hosts/houdini/plugins/load/load_alembic.py index eaab81f3962..0214229d5ab 100644 --- a/openpype/hosts/houdini/plugins/load/load_alembic.py +++ b/openpype/hosts/houdini/plugins/load/load_alembic.py @@ -1,10 +1,12 @@ import os -from avalon import api - +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import pipeline -class AbcLoader(api.Loader): +class AbcLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["model", "animation", "pointcache", "gpuCache"] @@ -90,7 +92,7 @@ def update(self, container, representation): return # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") alembic_node.setParms({"fileName": file_path}) diff --git a/openpype/hosts/houdini/plugins/load/load_ass.py b/openpype/hosts/houdini/plugins/load/load_ass.py index 8c272044eca..0144bbaefd6 100644 --- a/openpype/hosts/houdini/plugins/load/load_ass.py +++ b/openpype/hosts/houdini/plugins/load/load_ass.py @@ -1,11 +1,15 @@ import os -from avalon import api -from avalon.houdini import pipeline import clique +from openpype.pipeline import ( + load, + get_representation_path, +) +from openpype.hosts.houdini.api import pipeline -class AssLoader(api.Loader): + +class AssLoader(load.LoaderPlugin): """Load .ass with Arnold Procedural""" families = ["ass"] @@ -88,7 +92,7 @@ def get_path(self, path): def update(self, container, representation): # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") procedural = container["node"] diff --git a/openpype/hosts/houdini/plugins/load/load_camera.py b/openpype/hosts/houdini/plugins/load/load_camera.py index 8916d3b9b7c..ef57d115da6 100644 --- a/openpype/hosts/houdini/plugins/load/load_camera.py +++ b/openpype/hosts/houdini/plugins/load/load_camera.py @@ -1,4 +1,7 @@ -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import pipeline @@ -74,7 +77,7 @@ def transfer_non_default_values(src, dest, ignore=None): dest_parm.setFromParm(parm) -class CameraLoader(api.Loader): +class CameraLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["camera"] @@ -129,7 +132,7 @@ def update(self, container, representation): node = container["node"] # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") # Update attributes diff --git a/openpype/hosts/houdini/plugins/load/load_hda.py b/openpype/hosts/houdini/plugins/load/load_hda.py index f5f2fb74810..2438570c6e2 100644 --- a/openpype/hosts/houdini/plugins/load/load_hda.py +++ b/openpype/hosts/houdini/plugins/load/load_hda.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- -from avalon import api - +import os +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import pipeline -class HdaLoader(api.Loader): +class HdaLoader(load.LoaderPlugin): """Load Houdini Digital Asset file.""" families = ["hda"] @@ -15,7 +18,6 @@ class HdaLoader(api.Loader): color = "orange" def load(self, context, name=None, namespace=None, data=None): - import os import hou # Format file name, Houdini only wants forward slashes @@ -49,7 +51,7 @@ def update(self, container, representation): import hou hda_node = container["node"] - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") hou.hda.installFile(file_path) defs = hda_node.type().allInstalledDefinitions() diff --git a/openpype/hosts/houdini/plugins/load/load_image.py b/openpype/hosts/houdini/plugins/load/load_image.py index 39f583677be..bd9ea3eee3a 100644 --- a/openpype/hosts/houdini/plugins/load/load_image.py +++ b/openpype/hosts/houdini/plugins/load/load_image.py @@ -1,6 +1,9 @@ import os -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import lib, pipeline import hou @@ -37,7 +40,7 @@ def get_image_avalon_container(): return image_container -class ImageLoader(api.Loader): +class ImageLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["colorbleed.imagesequence"] @@ -87,7 +90,7 @@ def update(self, container, representation): node = container["node"] # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") file_path = self._get_file_sequence(file_path) diff --git a/openpype/hosts/houdini/plugins/load/load_usd_layer.py b/openpype/hosts/houdini/plugins/load/load_usd_layer.py index 0d4378b480c..d803e6abfe9 100644 --- a/openpype/hosts/houdini/plugins/load/load_usd_layer.py +++ b/openpype/hosts/houdini/plugins/load/load_usd_layer.py @@ -1,8 +1,11 @@ -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import lib, pipeline -class USDSublayerLoader(api.Loader): +class USDSublayerLoader(load.LoaderPlugin): """Sublayer USD file in Solaris""" families = [ @@ -57,7 +60,7 @@ def update(self, container, representation): node = container["node"] # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") # Update attributes diff --git a/openpype/hosts/houdini/plugins/load/load_usd_reference.py b/openpype/hosts/houdini/plugins/load/load_usd_reference.py index 0edd8d9af60..fdb443f4cf6 100644 --- a/openpype/hosts/houdini/plugins/load/load_usd_reference.py +++ b/openpype/hosts/houdini/plugins/load/load_usd_reference.py @@ -1,8 +1,11 @@ -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import lib, pipeline -class USDReferenceLoader(api.Loader): +class USDReferenceLoader(load.LoaderPlugin): """Reference USD file in Solaris""" families = [ @@ -57,7 +60,7 @@ def update(self, container, representation): node = container["node"] # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = file_path.replace("\\", "/") # Update attributes diff --git a/openpype/hosts/houdini/plugins/load/load_vdb.py b/openpype/hosts/houdini/plugins/load/load_vdb.py index 40aa7a1d187..06bb9e45e47 100644 --- a/openpype/hosts/houdini/plugins/load/load_vdb.py +++ b/openpype/hosts/houdini/plugins/load/load_vdb.py @@ -1,11 +1,14 @@ import os import re -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.houdini.api import pipeline -class VdbLoader(api.Loader): +class VdbLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["vdbcache"] @@ -96,7 +99,7 @@ def update(self, container, representation): return # Update the file path - file_path = api.get_representation_path(representation) + file_path = get_representation_path(representation) file_path = self.format_path(file_path) file_node.setParms({"fileName": file_path}) diff --git a/openpype/hosts/houdini/plugins/load/show_usdview.py b/openpype/hosts/houdini/plugins/load/show_usdview.py index f23974094ec..8066615181e 100644 --- a/openpype/hosts/houdini/plugins/load/show_usdview.py +++ b/openpype/hosts/houdini/plugins/load/show_usdview.py @@ -1,7 +1,7 @@ -from avalon import api +from openpype.pipeline import load -class ShowInUsdview(api.Loader): +class ShowInUsdview(load.LoaderPlugin): """Open USD file in usdview""" families = ["colorbleed.usd"] diff --git a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py index 645bd05d4b9..3e842ae7663 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py +++ b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py @@ -7,6 +7,7 @@ import pyblish.api import openpype.api +from openpype.pipeline import get_representation_path import openpype.hosts.houdini.api.usd as hou_usdlib from openpype.hosts.houdini.api.lib import render_rop @@ -308,7 +309,7 @@ def _compare_with_latest_publish(self, dependency, new_file): self.log.debug("No existing representation..") return False - old_file = api.get_representation_path(representation) + old_file = get_representation_path(representation) if not os.path.exists(old_file): return False diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 41c67a6209f..9f97eef2f11 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -17,10 +17,16 @@ from maya import cmds, mel import maya.api.OpenMaya as om -from avalon import api, io, pipeline +from avalon import api, io from openpype import lib from openpype.api import get_anatomy_settings +from openpype.pipeline import ( + discover_loader_plugins, + loaders_from_representation, + get_representation_path, + load_container, +) from .commands import reset_frame_range @@ -1580,21 +1586,21 @@ def assign_look_by_version(nodes, version_id): log.info("Using look for the first time ..") # Load file - loaders = api.loaders_from_representation(api.discover(api.Loader), - representation_id) + _loaders = discover_loader_plugins() + loaders = loaders_from_representation(_loaders, representation_id) Loader = next((i for i in loaders if i.__name__ == "LookLoader"), None) if Loader is None: raise RuntimeError("Could not find LookLoader, this is a bug") # Reference the look file with maintained_selection(): - container_node = pipeline.load(Loader, look_representation) + container_node = load_container(Loader, look_representation) # Get container members shader_nodes = get_container_members(container_node) # Load relationships - shader_relation = api.get_representation_path(json_representation) + shader_relation = get_representation_path(json_representation) with open(shader_relation, "r") as f: relationships = json.load(f) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index bdb4e5dfa88..5cdc3ff4fd6 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -20,7 +20,11 @@ emit_event ) from openpype.lib.path_tools import HostDirmap -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from openpype.hosts.maya.lib import copy_workspace_mel from . import menu, lib @@ -53,7 +57,7 @@ def install(): pyblish.api.register_host("mayapy") pyblish.api.register_host("maya") - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH) log.info(PUBLISH_PATH) @@ -182,7 +186,7 @@ def uninstall(): pyblish.api.deregister_host("mayapy") pyblish.api.deregister_host("maya") - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) avalon.api.deregister_plugin_path( avalon.api.InventoryAction, INVENTORY_PATH diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 48d7c465ece..84379bc145d 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -4,9 +4,12 @@ import qargparse -from avalon import api from avalon.pipeline import AVALON_CONTAINER_ID -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, + get_representation_path, +) from .pipeline import containerise from . import lib @@ -95,7 +98,7 @@ def process(self): return instance -class Loader(api.Loader): +class Loader(LoaderPlugin): hosts = ["maya"] @@ -194,7 +197,7 @@ def update(self, container, representation): node = container["objectName"] - path = api.get_representation_path(representation) + path = get_representation_path(representation) # Get reference node from container members members = get_container_members(node) diff --git a/openpype/hosts/maya/api/setdress.py b/openpype/hosts/maya/api/setdress.py index 1a7c3933a12..96a9700b886 100644 --- a/openpype/hosts/maya/api/setdress.py +++ b/openpype/hosts/maya/api/setdress.py @@ -8,7 +8,15 @@ import six from maya import cmds -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + discover_loader_plugins, + loaders_from_representation, + load_container, + update_container, + remove_container, + get_representation_path, +) from openpype.hosts.maya.api.lib import ( matrix_equals, unique_namespace @@ -120,12 +128,13 @@ def load_package(filepath, name, namespace=None): root = "{}:{}".format(namespace, name) containers = [] - all_loaders = api.discover(api.Loader) + all_loaders = discover_loader_plugins() for representation_id, instances in data.items(): # Find the compatible loaders - loaders = api.loaders_from_representation(all_loaders, - representation_id) + loaders = loaders_from_representation( + all_loaders, representation_id + ) for instance in instances: container = _add(instance=instance, @@ -180,9 +189,11 @@ def _add(instance, representation_id, loaders, namespace, root="|"): instance['loader'], instance) raise RuntimeError("Loader is missing.") - container = api.load(Loader, - representation_id, - namespace=instance['namespace']) + container = load_container( + Loader, + representation_id, + namespace=instance['namespace'] + ) # Get the root from the loaded container loaded_root = get_container_transforms({"objectName": container}, @@ -320,13 +331,13 @@ def update_package(set_container, representation): "type": "representation" }) - current_file = api.get_representation_path(current_representation) + current_file = get_representation_path(current_representation) assert current_file.endswith(".json") with open(current_file, "r") as fp: current_data = json.load(fp) # Load the new package data - new_file = api.get_representation_path(representation) + new_file = get_representation_path(representation) assert new_file.endswith(".json") with open(new_file, "r") as fp: new_data = json.load(fp) @@ -460,12 +471,12 @@ def update_scene(set_container, containers, current_data, new_data, new_file): # considered as new element and added afterwards. processed_containers.pop() processed_namespaces.remove(container_ns) - api.remove(container) + remove_container(container) continue # Check whether the conversion can be done by the Loader. # They *must* use the same asset, subset and Loader for - # `api.update` to make sense. + # `update_container` to make sense. old = io.find_one({ "_id": io.ObjectId(representation_current) }) @@ -479,20 +490,21 @@ def update_scene(set_container, containers, current_data, new_data, new_file): continue new_version = new["context"]["version"] - api.update(container, version=new_version) + update_container(container, version=new_version) else: # Remove this container because it's not in the new data log.warning("Removing content: %s", container_ns) - api.remove(container) + remove_container(container) # Add new assets - all_loaders = api.discover(api.Loader) + all_loaders = discover_loader_plugins() for representation_id, instances in new_data.items(): # Find the compatible loaders - loaders = api.loaders_from_representation(all_loaders, - representation_id) + loaders = loaders_from_representation( + all_loaders, representation_id + ) for instance in instances: # Already processed in update functionality @@ -517,7 +529,7 @@ def update_scene(set_container, containers, current_data, new_data, new_file): def compare_representations(old, new): """Check if the old representation given can be updated - Due to limitations of the `api.update` function we cannot allow + Due to limitations of the `update_container` function we cannot allow differences in the following data: * Representation name (extension) diff --git a/openpype/hosts/maya/plugins/inventory/import_modelrender.py b/openpype/hosts/maya/plugins/inventory/import_modelrender.py index 119edccb7ad..c5d3d0c8f46 100644 --- a/openpype/hosts/maya/plugins/inventory/import_modelrender.py +++ b/openpype/hosts/maya/plugins/inventory/import_modelrender.py @@ -1,5 +1,9 @@ import json -from avalon import api, io, pipeline +from avalon import api, io +from openpype.pipeline import ( + get_representation_context, + get_representation_path_from_context, +) from openpype.hosts.maya.api.lib import ( maintained_selection, apply_shaders @@ -73,11 +77,11 @@ def assign_model_render_by_version(self, nodes, version_id): "name": self.look_data_type, }) - context = pipeline.get_representation_context(look_repr["_id"]) - maya_file = pipeline.get_representation_path_from_context(context) + context = get_representation_context(look_repr["_id"]) + maya_file = get_representation_path_from_context(context) - context = pipeline.get_representation_context(json_repr["_id"]) - json_file = pipeline.get_representation_path_from_context(context) + context = get_representation_context(json_repr["_id"]) + json_file = get_representation_path_from_context(context) # Import the look file with maintained_selection(): diff --git a/openpype/hosts/maya/plugins/load/actions.py b/openpype/hosts/maya/plugins/load/actions.py index 1cb63c8a7ac..483ad324020 100644 --- a/openpype/hosts/maya/plugins/load/actions.py +++ b/openpype/hosts/maya/plugins/load/actions.py @@ -2,14 +2,14 @@ """ -from avalon import api +from openpype.pipeline import load from openpype.hosts.maya.api.lib import ( maintained_selection, unique_namespace ) -class SetFrameRangeLoader(api.Loader): +class SetFrameRangeLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", @@ -43,7 +43,7 @@ def load(self, context, name, namespace, data): animationEndTime=end) -class SetFrameRangeWithHandlesLoader(api.Loader): +class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", @@ -81,7 +81,7 @@ def load(self, context, name, namespace, data): animationEndTime=end) -class ImportMayaLoader(api.Loader): +class ImportMayaLoader(load.LoaderPlugin): """Import action for Maya (unmanaged) Warning: diff --git a/openpype/hosts/maya/plugins/load/load_ass.py b/openpype/hosts/maya/plugins/load/load_ass.py index 18b34d22338..18de4df3b14 100644 --- a/openpype/hosts/maya/plugins/load/load_ass.py +++ b/openpype/hosts/maya/plugins/load/load_ass.py @@ -1,8 +1,11 @@ import os import clique -from avalon import api from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) import openpype.hosts.maya.api.plugin from openpype.hosts.maya.api.plugin import get_reference_node from openpype.hosts.maya.api.lib import ( @@ -106,7 +109,7 @@ def update(self, container, representation): node = container["objectName"] representation["context"].pop("frame", None) - path = api.get_representation_path(representation) + path = get_representation_path(representation) print(path) # path = self.fname print(self.fname) @@ -164,7 +167,7 @@ def update(self, container, representation): type="string") -class AssStandinLoader(api.Loader): +class AssStandinLoader(load.LoaderPlugin): """Load .ASS file as standin""" families = ["ass"] @@ -240,7 +243,7 @@ def update(self, container, representation): import pymel.core as pm - path = api.get_representation_path(representation) + path = get_representation_path(representation) files_in_path = os.listdir(os.path.split(path)[0]) sequence = 0 diff --git a/openpype/hosts/maya/plugins/load/load_assembly.py b/openpype/hosts/maya/plugins/load/load_assembly.py index 0151da72534..902f38695c3 100644 --- a/openpype/hosts/maya/plugins/load/load_assembly.py +++ b/openpype/hosts/maya/plugins/load/load_assembly.py @@ -1,7 +1,10 @@ -from avalon import api +from openpype.pipeline import ( + load, + remove_container +) -class AssemblyLoader(api.Loader): +class AssemblyLoader(load.LoaderPlugin): families = ["assembly"] representations = ["json"] @@ -48,13 +51,11 @@ def load(self, context, name, namespace, data): def update(self, container, representation): from openpype import setdress - return setdress.update_package(container, - representation) + return setdress.update_package(container, representation) def remove(self, container): """Remove all sub containers""" - from avalon import api from openpype import setdress import maya.cmds as cmds @@ -63,7 +64,7 @@ def remove(self, container): for member_container in member_containers: self.log.info("Removing container %s", member_container['objectName']) - api.remove(member_container) + remove_container(member_container) # Remove alembic hierarchy reference # TODO: Check whether removing all contained references is safe enough diff --git a/openpype/hosts/maya/plugins/load/load_audio.py b/openpype/hosts/maya/plugins/load/load_audio.py index 99f1f7c1722..d8844ffea6b 100644 --- a/openpype/hosts/maya/plugins/load/load_audio.py +++ b/openpype/hosts/maya/plugins/load/load_audio.py @@ -1,10 +1,14 @@ from maya import cmds, mel -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api.pipeline import containerise from openpype.hosts.maya.api.lib import unique_namespace -class AudioLoader(api.Loader): +class AudioLoader(load.LoaderPlugin): """Specific loader of audio.""" families = ["audio"] @@ -51,7 +55,7 @@ def update(self, container, representation): assert audio_node is not None, "Audio node not found." - path = api.get_representation_path(representation) + path = get_representation_path(representation) audio_node.filename.set(path) cmds.setAttr( container["objectName"] + ".representation", diff --git a/openpype/hosts/maya/plugins/load/load_gpucache.py b/openpype/hosts/maya/plugins/load/load_gpucache.py index 2e0b7bb8103..591e568e4c2 100644 --- a/openpype/hosts/maya/plugins/load/load_gpucache.py +++ b/openpype/hosts/maya/plugins/load/load_gpucache.py @@ -1,9 +1,13 @@ import os -from avalon import api + +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.api import get_project_settings -class GpuCacheLoader(api.Loader): +class GpuCacheLoader(load.LoaderPlugin): """Load model Alembic as gpuCache""" families = ["model"] @@ -73,7 +77,7 @@ def update(self, container, representation): import maya.cmds as cmds - path = api.get_representation_path(representation) + path = get_representation_path(representation) # Update the cache members = cmds.sets(container['objectName'], query=True) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 8e33f51389e..b250986489b 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -1,6 +1,10 @@ from Qt import QtWidgets, QtCore -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api.pipeline import containerise from openpype.hosts.maya.api.lib import unique_namespace @@ -74,7 +78,7 @@ def on_cancel_pressed(self): self.close() -class ImagePlaneLoader(api.Loader): +class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" families = ["image", "plate", "render"] @@ -203,7 +207,7 @@ def update(self, container, representation): assert image_plane_shape is not None, "Image plane not found." - path = api.get_representation_path(representation) + path = get_representation_path(representation) image_plane_shape.imageName.set(path) cmds.setAttr( container["objectName"] + ".representation", diff --git a/openpype/hosts/maya/plugins/load/load_look.py b/openpype/hosts/maya/plugins/load/load_look.py index 96c1ecbb206..8f02ed59b8b 100644 --- a/openpype/hosts/maya/plugins/load/load_look.py +++ b/openpype/hosts/maya/plugins/load/load_look.py @@ -5,7 +5,8 @@ from Qt import QtWidgets -from avalon import api, io +from avalon import io +from openpype.pipeline import get_representation_path import openpype.hosts.maya.api.plugin from openpype.hosts.maya.api import lib from openpype.widgets.message_window import ScrollMessageBox @@ -77,7 +78,7 @@ def update(self, container, representation): }) # Load relationships - shader_relation = api.get_representation_path(json_representation) + shader_relation = get_representation_path(json_representation) with open(shader_relation, "r") as f: json_data = json.load(f) diff --git a/openpype/hosts/maya/plugins/load/load_matchmove.py b/openpype/hosts/maya/plugins/load/load_matchmove.py index abc702cde8d..ee3332bd09f 100644 --- a/openpype/hosts/maya/plugins/load/load_matchmove.py +++ b/openpype/hosts/maya/plugins/load/load_matchmove.py @@ -1,8 +1,8 @@ -from avalon import api from maya import mel +from openpype.pipeline import load -class MatchmoveLoader(api.Loader): +class MatchmoveLoader(load.LoaderPlugin): """ This will run matchmove script to create track in scene. diff --git a/openpype/hosts/maya/plugins/load/load_redshift_proxy.py b/openpype/hosts/maya/plugins/load/load_redshift_proxy.py index fd2ae0f1d39..d93a9f02a20 100644 --- a/openpype/hosts/maya/plugins/load/load_redshift_proxy.py +++ b/openpype/hosts/maya/plugins/load/load_redshift_proxy.py @@ -5,8 +5,11 @@ import maya.cmds as cmds -from avalon import api from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api.lib import ( namespaced, maintained_selection, @@ -15,7 +18,7 @@ from openpype.hosts.maya.api.pipeline import containerise -class RedshiftProxyLoader(api.Loader): +class RedshiftProxyLoader(load.LoaderPlugin): """Load Redshift proxy""" families = ["redshiftproxy"] @@ -78,7 +81,7 @@ def update(self, container, representation): rs_meshes = cmds.ls(members, type="RedshiftProxyMesh") assert rs_meshes, "Cannot find RedshiftProxyMesh in container" - filename = api.get_representation_path(representation) + filename = get_representation_path(representation) for rs_mesh in rs_meshes: cmds.setAttr("{}.fileName".format(rs_mesh), diff --git a/openpype/hosts/maya/plugins/load/load_rendersetup.py b/openpype/hosts/maya/plugins/load/load_rendersetup.py index efeff2f1938..7a2d8b1002c 100644 --- a/openpype/hosts/maya/plugins/load/load_rendersetup.py +++ b/openpype/hosts/maya/plugins/load/load_rendersetup.py @@ -7,10 +7,13 @@ """ import json -import six import sys +import six -from avalon import api +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api import lib from openpype.hosts.maya.api.pipeline import containerise @@ -18,7 +21,7 @@ import maya.app.renderSetup.model.renderSetup as renderSetup -class RenderSetupLoader(api.Loader): +class RenderSetupLoader(load.LoaderPlugin): """Load json preset for RenderSetup overwriting current one.""" families = ["rendersetup"] @@ -87,7 +90,7 @@ def update(self, container, representation): "Render setup setting will be overwritten by new version. All " "setting specified by user not included in loaded version " "will be lost.") - path = api.get_representation_path(representation) + path = get_representation_path(representation) with open(path, "r") as file: try: renderSetup.instance().decode( diff --git a/openpype/hosts/maya/plugins/load/load_vdb_to_redshift.py b/openpype/hosts/maya/plugins/load/load_vdb_to_redshift.py index 3e1d67ae9a2..70bd9d22e2a 100644 --- a/openpype/hosts/maya/plugins/load/load_vdb_to_redshift.py +++ b/openpype/hosts/maya/plugins/load/load_vdb_to_redshift.py @@ -1,9 +1,10 @@ import os -from avalon import api + from openpype.api import get_project_settings +from openpype.pipeline import load -class LoadVDBtoRedShift(api.Loader): +class LoadVDBtoRedShift(load.LoaderPlugin): """Load OpenVDB in a Redshift Volume Shape""" families = ["vdbcache"] diff --git a/openpype/hosts/maya/plugins/load/load_vdb_to_vray.py b/openpype/hosts/maya/plugins/load/load_vdb_to_vray.py index 6d5544103d1..4f14235bfbb 100644 --- a/openpype/hosts/maya/plugins/load/load_vdb_to_vray.py +++ b/openpype/hosts/maya/plugins/load/load_vdb_to_vray.py @@ -1,6 +1,10 @@ import os -from avalon import api + from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) from maya import cmds @@ -69,7 +73,7 @@ def _fix_duplicate_vvg_callbacks(): matched.add(callback) -class LoadVDBtoVRay(api.Loader): +class LoadVDBtoVRay(load.LoaderPlugin): families = ["vdbcache"] representations = ["vdb"] @@ -252,7 +256,7 @@ def _get_filename_from_folder(path): def update(self, container, representation): - path = api.get_representation_path(representation) + path = get_representation_path(representation) # Find VRayVolumeGrid members = cmds.sets(container['objectName'], query=True) diff --git a/openpype/hosts/maya/plugins/load/load_vrayproxy.py b/openpype/hosts/maya/plugins/load/load_vrayproxy.py index ac2fe635b39..5b79b1efb36 100644 --- a/openpype/hosts/maya/plugins/load/load_vrayproxy.py +++ b/openpype/hosts/maya/plugins/load/load_vrayproxy.py @@ -9,8 +9,12 @@ import maya.cmds as cmds -from avalon import api, io +from avalon import io from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api.lib import ( maintained_selection, namespaced, @@ -19,7 +23,7 @@ from openpype.hosts.maya.api.pipeline import containerise -class VRayProxyLoader(api.Loader): +class VRayProxyLoader(load.LoaderPlugin): """Load VRay Proxy with Alembic or VrayMesh.""" families = ["vrayproxy", "model", "pointcache", "animation"] @@ -100,7 +104,10 @@ def update(self, container, representation): assert vraymeshes, "Cannot find VRayMesh in container" # get all representations for this version - filename = self._get_abc(representation["parent"]) or api.get_representation_path(representation) # noqa: E501 + filename = ( + self._get_abc(representation["parent"]) + or get_representation_path(representation) + ) for vray_mesh in vraymeshes: cmds.setAttr("{}.fileName".format(vray_mesh), @@ -185,7 +192,7 @@ def _get_abc(self, version_id): if abc_rep: self.log.debug("Found, we'll link alembic to vray proxy.") - file_name = api.get_representation_path(abc_rep) + file_name = get_representation_path(abc_rep) self.log.debug("File: {}".format(self.fname)) return file_name diff --git a/openpype/hosts/maya/plugins/load/load_vrayscene.py b/openpype/hosts/maya/plugins/load/load_vrayscene.py index dfe2b85edc3..61132088ccc 100644 --- a/openpype/hosts/maya/plugins/load/load_vrayscene.py +++ b/openpype/hosts/maya/plugins/load/load_vrayscene.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- import os import maya.cmds as cmds # noqa -from avalon import api from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api.lib import ( maintained_selection, namespaced, @@ -11,7 +14,7 @@ from openpype.hosts.maya.api.pipeline import containerise -class VRaySceneLoader(api.Loader): +class VRaySceneLoader(load.LoaderPlugin): """Load Vray scene""" families = ["vrayscene_layer"] @@ -78,7 +81,7 @@ def update(self, container, representation): vraymeshes = cmds.ls(members, type="VRayScene") assert vraymeshes, "Cannot find VRayScene in container" - filename = api.get_representation_path(representation) + filename = get_representation_path(representation) for vray_mesh in vraymeshes: cmds.setAttr("{}.FilePath".format(vray_mesh), diff --git a/openpype/hosts/maya/plugins/load/load_yeti_cache.py b/openpype/hosts/maya/plugins/load/load_yeti_cache.py index dfe75173acb..c64e1c540b2 100644 --- a/openpype/hosts/maya/plugins/load/load_yeti_cache.py +++ b/openpype/hosts/maya/plugins/load/load_yeti_cache.py @@ -7,13 +7,17 @@ from maya import cmds -from avalon import api, io +from avalon import io from openpype.api import get_project_settings +from openpype.pipeline import ( + load, + get_representation_path +) from openpype.hosts.maya.api import lib from openpype.hosts.maya.api.pipeline import containerise -class YetiCacheLoader(api.Loader): +class YetiCacheLoader(load.LoaderPlugin): families = ["yeticache", "yetiRig"] representations = ["fur"] @@ -121,8 +125,8 @@ def update(self, container, representation): "cannot find fursettings representation" ) - settings_fname = api.get_representation_path(fur_settings) - path = api.get_representation_path(representation) + settings_fname = get_representation_path(fur_settings) + path = get_representation_path(representation) # Get all node data with open(settings_fname, "r") as fp: settings = json.load(fp) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 348c9680b23..fd2e16b8d3b 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -15,7 +15,11 @@ get_current_project_settings ) from openpype.lib import register_event_callback -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from openpype.tools.utils import host_tools from .command import viewer_update_and_undo_stop @@ -99,7 +103,7 @@ def install(): log.info("Registering Nuke plug-ins..") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH) @@ -125,7 +129,7 @@ def uninstall(): log.info("Deregistering Nuke plug-ins..") pyblish.deregister_host("nuke") pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) pyblish.api.deregister_callback( diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index ff186cd6859..d0bb45a05d6 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -4,10 +4,11 @@ import nuke -import avalon.api - from openpype.api import get_current_project_settings -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) from .lib import ( Knobby, check_subsetname_exists, @@ -85,7 +86,7 @@ def get_review_presets_config(): return [str(name) for name, _prop in outputs.items()] -class NukeLoader(avalon.api.Loader): +class NukeLoader(LoaderPlugin): container_id_knob = "containerId" container_id = None diff --git a/openpype/hosts/nuke/plugins/load/actions.py b/openpype/hosts/nuke/plugins/load/actions.py index 07dcf2d8e18..81840b3a38f 100644 --- a/openpype/hosts/nuke/plugins/load/actions.py +++ b/openpype/hosts/nuke/plugins/load/actions.py @@ -2,13 +2,13 @@ """ -from avalon import api from openpype.api import Logger +from openpype.pipeline import load log = Logger().get_logger(__name__) -class SetFrameRangeLoader(api.Loader): +class SetFrameRangeLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", @@ -42,7 +42,7 @@ def load(self, context, name, namespace, data): lib.update_frame_range(start, end) -class SetFrameRangeWithHandlesLoader(api.Loader): +class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): """Specific loader of Alembic for the avalon.animation family""" families = ["animation", diff --git a/openpype/hosts/nuke/plugins/load/load_backdrop.py b/openpype/hosts/nuke/plugins/load/load_backdrop.py index 58ebcc7d491..36cec6f4c51 100644 --- a/openpype/hosts/nuke/plugins/load/load_backdrop.py +++ b/openpype/hosts/nuke/plugins/load/load_backdrop.py @@ -1,7 +1,11 @@ -from avalon import api, io +from avalon import io import nuke import nukescripts +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import ( find_free_space_to_paste_nodes, maintained_selection, @@ -14,7 +18,7 @@ from openpype.hosts.nuke.api import containerise, update_container -class LoadBackdropNodes(api.Loader): +class LoadBackdropNodes(load.LoaderPlugin): """Loading Published Backdrop nodes (workfile, nukenodes)""" representations = ["nk"] @@ -191,7 +195,7 @@ def update(self, container, representation): # get corresponding node GN = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") context = representation["context"] name = container['name'] version_data = version.get("data", {}) diff --git a/openpype/hosts/nuke/plugins/load/load_camera_abc.py b/openpype/hosts/nuke/plugins/load/load_camera_abc.py index 9610940619f..fb5f7f8ede8 100644 --- a/openpype/hosts/nuke/plugins/load/load_camera_abc.py +++ b/openpype/hosts/nuke/plugins/load/load_camera_abc.py @@ -1,6 +1,10 @@ import nuke -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api import ( containerise, update_container, @@ -11,7 +15,7 @@ ) -class AlembicCameraLoader(api.Loader): +class AlembicCameraLoader(load.LoaderPlugin): """ This will load alembic camera into script. """ @@ -127,7 +131,7 @@ def update(self, container, representation): data_imprint.update({k: version_data[k]}) # getting file path - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") with maintained_selection(): camera_node = nuke.toNode(object_name) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index a253ba4a9d7..2b4315a830b 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -1,7 +1,8 @@ import nuke import qargparse -from avalon import api, io +from avalon import io +from openpype.pipeline import get_representation_path from openpype.hosts.nuke.api.lib import ( get_imageio_input_colorspace, maintained_selection @@ -41,6 +42,9 @@ class LoadClip(plugin.NukeLoader): icon = "file-video-o" color = "white" + # Loaded from settings + _representations = [] + script_start = int(nuke.root()["first_frame"].value()) # option gui @@ -186,7 +190,7 @@ def update(self, container, representation): is_sequence = len(representation["files"]) > 1 read_node = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") start_at_workfile = bool("start at" in read_node['frame_mode'].value()) diff --git a/openpype/hosts/nuke/plugins/load/load_effects.py b/openpype/hosts/nuke/plugins/load/load_effects.py index 4d83da1a784..68c39529424 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects.py +++ b/openpype/hosts/nuke/plugins/load/load_effects.py @@ -1,8 +1,13 @@ import json from collections import OrderedDict import nuke -from avalon import api, io +from avalon import io + +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api import ( containerise, update_container, @@ -10,7 +15,7 @@ ) -class LoadEffects(api.Loader): +class LoadEffects(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" representations = ["effectJson"] @@ -150,7 +155,7 @@ def update(self, container, representation): # get corresponding node GN = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") name = container['name'] version_data = version.get("data", {}) vname = version.get("name", None) diff --git a/openpype/hosts/nuke/plugins/load/load_effects_ip.py b/openpype/hosts/nuke/plugins/load/load_effects_ip.py index 4d30e0f93c7..9c4fd4c2c61 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects_ip.py +++ b/openpype/hosts/nuke/plugins/load/load_effects_ip.py @@ -3,8 +3,12 @@ import nuke -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api import lib from openpype.hosts.nuke.api import ( containerise, @@ -13,7 +17,7 @@ ) -class LoadEffectsInputProcess(api.Loader): +class LoadEffectsInputProcess(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" representations = ["effectJson"] @@ -157,7 +161,7 @@ def update(self, container, representation): # get corresponding node GN = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") name = container['name'] version_data = version.get("data", {}) vname = version.get("name", None) diff --git a/openpype/hosts/nuke/plugins/load/load_gizmo.py b/openpype/hosts/nuke/plugins/load/load_gizmo.py index 9c726d8fe6d..6f2b191be9f 100644 --- a/openpype/hosts/nuke/plugins/load/load_gizmo.py +++ b/openpype/hosts/nuke/plugins/load/load_gizmo.py @@ -1,6 +1,11 @@ import nuke -from avalon import api, io +from avalon import io + +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import ( maintained_selection, get_avalon_knob_data, @@ -13,7 +18,7 @@ ) -class LoadGizmo(api.Loader): +class LoadGizmo(load.LoaderPlugin): """Loading nuke Gizmo""" representations = ["gizmo"] @@ -104,7 +109,7 @@ def update(self, container, representation): # get corresponding node GN = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") name = container['name'] version_data = version.get("data", {}) vname = version.get("name", None) diff --git a/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py b/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py index 78d26257586..87bebce15b5 100644 --- a/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py +++ b/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py @@ -1,6 +1,11 @@ -from avalon import api, io import nuke +from avalon import io + +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import ( maintained_selection, create_backdrop, @@ -14,7 +19,7 @@ ) -class LoadGizmoInputProcess(api.Loader): +class LoadGizmoInputProcess(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" representations = ["gizmo"] @@ -110,7 +115,7 @@ def update(self, container, representation): # get corresponding node GN = nuke.toNode(container['objectName']) - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") name = container['name'] version_data = version.get("data", {}) vname = version.get("name", None) diff --git a/openpype/hosts/nuke/plugins/load/load_image.py b/openpype/hosts/nuke/plugins/load/load_image.py index 27c634ec574..9a175a0cba2 100644 --- a/openpype/hosts/nuke/plugins/load/load_image.py +++ b/openpype/hosts/nuke/plugins/load/load_image.py @@ -1,8 +1,12 @@ import nuke import qargparse -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import ( get_imageio_input_colorspace ) @@ -13,7 +17,7 @@ ) -class LoadImage(api.Loader): +class LoadImage(load.LoaderPlugin): """Load still image into Nuke""" families = [ @@ -32,6 +36,9 @@ class LoadImage(api.Loader): icon = "image" color = "white" + # Loaded from settings + _representations = [] + node_name_template = "{class_name}_{ext}" options = [ @@ -161,7 +168,7 @@ def update(self, container, representation): repr_cont = representation["context"] - file = api.get_representation_path(representation) + file = get_representation_path(representation) if not file: repr_id = representation["_id"] diff --git a/openpype/hosts/nuke/plugins/load/load_matchmove.py b/openpype/hosts/nuke/plugins/load/load_matchmove.py index 60d5dc026f7..f5a90706c75 100644 --- a/openpype/hosts/nuke/plugins/load/load_matchmove.py +++ b/openpype/hosts/nuke/plugins/load/load_matchmove.py @@ -1,8 +1,8 @@ -from avalon import api import nuke +from openpype.pipeline import load -class MatchmoveLoader(api.Loader): +class MatchmoveLoader(load.LoaderPlugin): """ This will run matchmove script to create track in script. """ diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 2b52bbf00f1..e445beca050 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -1,5 +1,9 @@ import nuke -from avalon import api, io +from avalon import io +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import maintained_selection from openpype.hosts.nuke.api import ( containerise, @@ -8,7 +12,7 @@ ) -class AlembicModelLoader(api.Loader): +class AlembicModelLoader(load.LoaderPlugin): """ This will load alembic model into script. """ @@ -124,7 +128,7 @@ def update(self, container, representation): data_imprint.update({k: version_data[k]}) # getting file path - file = api.get_representation_path(representation).replace("\\", "/") + file = get_representation_path(representation).replace("\\", "/") with maintained_selection(): model_node = nuke.toNode(object_name) diff --git a/openpype/hosts/nuke/plugins/load/load_script_precomp.py b/openpype/hosts/nuke/plugins/load/load_script_precomp.py index 48bf0b889f5..779f1016829 100644 --- a/openpype/hosts/nuke/plugins/load/load_script_precomp.py +++ b/openpype/hosts/nuke/plugins/load/load_script_precomp.py @@ -1,6 +1,11 @@ import nuke -from avalon import api, io +from avalon import io + +from openpype.pipeline import ( + load, + get_representation_path, +) from openpype.hosts.nuke.api.lib import get_avalon_knob_data from openpype.hosts.nuke.api import ( containerise, @@ -9,7 +14,7 @@ ) -class LinkAsGroup(api.Loader): +class LinkAsGroup(load.LoaderPlugin): """Copy the published file to be pasted at the desired location""" representations = ["nk"] @@ -109,7 +114,7 @@ def update(self, container, representation): """ node = nuke.toNode(container['objectName']) - root = api.get_representation_path(representation).replace("\\", "/") + root = get_representation_path(representation).replace("\\", "/") # Get start frame from version data version = io.find_one({ diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/precollect_writes.py index 189f28f7c67..85e98db7ede 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_writes.py @@ -3,8 +3,9 @@ from pprint import pformat import nuke import pyblish.api +from avalon import io import openpype.api as pype -from avalon import io, api +from openpype.pipeline import get_representation_path @pyblish.api.log @@ -182,7 +183,7 @@ def process(self, instance): if repre_doc: instance.data["audio"] = [{ "offset": 0, - "filename": api.get_representation_path(repre_doc) + "filename": get_representation_path(repre_doc) }] self.log.debug("instance.data: {}".format(pformat(instance.data))) diff --git a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py index 22a9b3678eb..2bf1ff81f87 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py @@ -1,12 +1,16 @@ import os -import toml import nuke +import toml import pyblish.api -from avalon import api from bson.objectid import ObjectId +from openpype.pipeline import ( + discover_loader_plugins, + load_container, +) + class RepairReadLegacyAction(pyblish.api.Action): @@ -49,13 +53,13 @@ def process(self, context, plugin): loader_name = "LoadMov" loader_plugin = None - for Loader in api.discover(api.Loader): + for Loader in discover_loader_plugins(): if Loader.__name__ != loader_name: continue loader_plugin = Loader - api.load( + load_container( Loader=loader_plugin, representation=ObjectId(data["representation"]) ) diff --git a/openpype/hosts/photoshop/api/README.md b/openpype/hosts/photoshop/api/README.md index b958f538033..80792a4da02 100644 --- a/openpype/hosts/photoshop/api/README.md +++ b/openpype/hosts/photoshop/api/README.md @@ -195,11 +195,12 @@ class ExtractImage(openpype.api.Extractor): #### Loader Plugin ```python from avalon import api, photoshop +from openpype.pipeline import load, get_representation_path stub = photoshop.stub() -class ImageLoader(api.Loader): +class ImageLoader(load.LoaderPlugin): """Load images Stores the imported asset in a container named after the asset. @@ -227,7 +228,7 @@ class ImageLoader(api.Loader): with photoshop.maintained_selection(): stub.replace_smart_object( - layer, api.get_representation_path(representation) + layer, get_representation_path(representation) ) stub.imprint( @@ -245,7 +246,7 @@ https://community.adobe.com/t5/download-install/adobe-extension-debuger-problem/ Add --enable-blink-features=ShadowDOMV0,CustomElementsV0 when starting Chrome then localhost:8078 (port set in `photoshop\extension\.debug`) -Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01 +Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01 Or install CEF client from https://github.com/Adobe-CEP/CEP-Resources/tree/master/CEP_9.x ## Resources diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 1be8129aa11..e814e1ca4d1 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -6,9 +6,12 @@ from avalon import pipeline, io from openpype.api import Logger - from openpype.lib import register_event_callback -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) import openpype.hosts.photoshop from . import lib @@ -69,7 +72,7 @@ def install(): pyblish.api.register_host("photoshop") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) log.info(PUBLISH_PATH) @@ -82,7 +85,7 @@ def install(): def uninstall(): pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) diff --git a/openpype/hosts/photoshop/api/plugin.py b/openpype/hosts/photoshop/api/plugin.py index c577c67d82a..c80e6bbd063 100644 --- a/openpype/hosts/photoshop/api/plugin.py +++ b/openpype/hosts/photoshop/api/plugin.py @@ -1,6 +1,6 @@ import re -import avalon.api +from openpype.pipeline import LoaderPlugin from .launch_logic import stub @@ -29,7 +29,7 @@ def get_unique_layer_name(layers, asset_name, subset_name): return "{}_{:0>3d}".format(name, occurrences + 1) -class PhotoshopLoader(avalon.api.Loader): +class PhotoshopLoader(LoaderPlugin): @staticmethod def get_stub(): return stub() diff --git a/openpype/hosts/photoshop/plugins/load/load_image.py b/openpype/hosts/photoshop/plugins/load/load_image.py index 3b1cfe96360..0a9421b8f29 100644 --- a/openpype/hosts/photoshop/plugins/load/load_image.py +++ b/openpype/hosts/photoshop/plugins/load/load_image.py @@ -1,6 +1,6 @@ import re -from avalon import api +from openpype.pipeline import get_representation_path from openpype.hosts.photoshop import api as photoshop from openpype.hosts.photoshop.api import get_unique_layer_name @@ -54,7 +54,7 @@ def update(self, container, representation): else: # switching version - keep same name layer_name = container["namespace"] - path = api.get_representation_path(representation) + path = get_representation_path(representation) with photoshop.maintained_selection(): stub.replace_smart_object( layer, path, layer_name diff --git a/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py b/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py index 12e0503dfcd..5f39121ae15 100644 --- a/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py +++ b/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py @@ -1,8 +1,8 @@ import os import qargparse -from avalon.pipeline import get_representation_path_from_context +from openpype.pipeline import get_representation_path_from_context from openpype.hosts.photoshop import api as photoshop from openpype.hosts.photoshop.api import get_unique_layer_name diff --git a/openpype/hosts/photoshop/plugins/load/load_reference.py b/openpype/hosts/photoshop/plugins/load/load_reference.py index 60142d4a1ff..f5f0545d394 100644 --- a/openpype/hosts/photoshop/plugins/load/load_reference.py +++ b/openpype/hosts/photoshop/plugins/load/load_reference.py @@ -1,7 +1,6 @@ import re -from avalon import api - +from openpype.pipeline import get_representation_path from openpype.hosts.photoshop import api as photoshop from openpype.hosts.photoshop.api import get_unique_layer_name @@ -55,7 +54,7 @@ def update(self, container, representation): else: # switching version - keep same name layer_name = container["namespace"] - path = api.get_representation_path(representation) + path = get_representation_path(representation) with photoshop.maintained_selection(): stub.replace_smart_object( layer, path, layer_name diff --git a/openpype/hosts/resolve/api/pipeline.py b/openpype/hosts/resolve/api/pipeline.py index c82545268b9..fa309e3503a 100644 --- a/openpype/hosts/resolve/api/pipeline.py +++ b/openpype/hosts/resolve/api/pipeline.py @@ -9,7 +9,11 @@ from avalon.pipeline import AVALON_CONTAINER_ID from pyblish import api as pyblish from openpype.api import Logger -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from . import lib from . import PLUGINS_DIR from openpype.tools.utils import host_tools @@ -42,7 +46,7 @@ def install(): pyblish.register_plugin_path(PUBLISH_PATH) log.info("Registering DaVinci Resovle plug-ins..") - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.register_plugin_path(LegacyCreator, CREATE_PATH) avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) @@ -67,7 +71,7 @@ def uninstall(): pyblish.deregister_plugin_path(PUBLISH_PATH) log.info("Deregistering DaVinci Resovle plug-ins..") - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH) avalon.deregister_plugin_path(avalon.InventoryAction, INVENTORY_PATH) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index e7793d6e95d..8e1436021c8 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -4,14 +4,15 @@ import qargparse from Qt import QtWidgets, QtCore -from avalon import api import openpype.api as pype -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) from openpype.hosts import resolve from . import lib - class CreatorWidget(QtWidgets.QDialog): # output items @@ -292,7 +293,7 @@ def __init__(self, cls, context, **options): """ Initialize object Arguments: - cls (avalon.api.Loader): plugin object + cls (openpype.pipeline.load.LoaderPlugin): plugin object context (dict): loader plugin context options (dict)[optional]: possible keys: projectBinPath: "path/to/binItem" @@ -448,7 +449,7 @@ def update(self, timeline_item): return timeline_item -class TimelineItemLoader(api.Loader): +class TimelineItemLoader(LoaderPlugin): """A basic SequenceLoader for Resolve This will implement the basic behavior for a loader to inherit from that diff --git a/openpype/hosts/resolve/plugins/load/load_clip.py b/openpype/hosts/resolve/plugins/load/load_clip.py index e20384ee6c3..71850d95f61 100644 --- a/openpype/hosts/resolve/plugins/load/load_clip.py +++ b/openpype/hosts/resolve/plugins/load/load_clip.py @@ -1,11 +1,14 @@ -from avalon import io, api -from openpype.hosts import resolve from copy import deepcopy from importlib import reload + +from avalon import io +from openpype.hosts import resolve +from openpype.pipeline import get_representation_path from openpype.hosts.resolve.api import lib, plugin reload(plugin) reload(lib) + class LoadClip(resolve.TimelineItemLoader): """Load a subset to timeline as clip @@ -99,7 +102,7 @@ def update(self, container, representation): version_name = version.get("name", None) colorspace = version_data.get("colorspace", None) object_name = "{}_{}".format(name, namespace) - self.fname = api.get_representation_path(representation) + self.fname = get_representation_path(representation) context["version"] = {"data": version_data} loader = resolve.ClipLoader(self, context) diff --git a/openpype/hosts/tvpaint/api/pipeline.py b/openpype/hosts/tvpaint/api/pipeline.py index 836a0b4ed1e..46c9d3a1dd0 100644 --- a/openpype/hosts/tvpaint/api/pipeline.py +++ b/openpype/hosts/tvpaint/api/pipeline.py @@ -15,7 +15,11 @@ from openpype.hosts import tvpaint from openpype.api import get_current_project_settings from openpype.lib import register_event_callback -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from .lib import ( execute_george, @@ -77,7 +81,7 @@ def install(): pyblish.api.register_host("tvpaint") pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + register_loader_plugin_path(LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) registered_callbacks = ( @@ -99,7 +103,7 @@ def uninstall(): log.info("OpenPype - Uninstalling TVPaint integration") pyblish.api.deregister_host("tvpaint") pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + deregister_loader_plugin_path(LOAD_PATH) avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH) diff --git a/openpype/hosts/tvpaint/api/plugin.py b/openpype/hosts/tvpaint/api/plugin.py index 8510794f06d..15ad8905e0e 100644 --- a/openpype/hosts/tvpaint/api/plugin.py +++ b/openpype/hosts/tvpaint/api/plugin.py @@ -1,9 +1,10 @@ import re import uuid -import avalon.api - -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) from openpype.hosts.tvpaint.api import ( pipeline, lib @@ -74,7 +75,7 @@ def process(self): self.write_instances(data) -class Loader(avalon.api.Loader): +class Loader(LoaderPlugin): hosts = ["tvpaint"] @staticmethod diff --git a/openpype/hosts/unreal/api/pipeline.py b/openpype/hosts/unreal/api/pipeline.py index 8ab19bd697b..9ec11b942df 100644 --- a/openpype/hosts/unreal/api/pipeline.py +++ b/openpype/hosts/unreal/api/pipeline.py @@ -7,7 +7,11 @@ from avalon.pipeline import AVALON_CONTAINER_ID from avalon import api -from openpype.pipeline import LegacyCreator +from openpype.pipeline import ( + LegacyCreator, + register_loader_plugin_path, + deregister_loader_plugin_path, +) from openpype.tools.utils import host_tools import openpype.hosts.unreal @@ -44,7 +48,7 @@ def install(): print("-=" * 40) logger.info("installing OpenPype for Unreal") pyblish.api.register_plugin_path(str(PUBLISH_PATH)) - api.register_plugin_path(api.Loader, str(LOAD_PATH)) + register_loader_plugin_path(str(LOAD_PATH)) api.register_plugin_path(LegacyCreator, str(CREATE_PATH)) _register_callbacks() _register_events() @@ -53,7 +57,7 @@ def install(): def uninstall(): """Uninstall Unreal configuration for Avalon.""" pyblish.api.deregister_plugin_path(str(PUBLISH_PATH)) - api.deregister_plugin_path(api.Loader, str(LOAD_PATH)) + deregister_loader_plugin_path(str(LOAD_PATH)) api.deregister_plugin_path(LegacyCreator, str(CREATE_PATH)) diff --git a/openpype/hosts/unreal/api/plugin.py b/openpype/hosts/unreal/api/plugin.py index dd2e7750f03..b24bab831d6 100644 --- a/openpype/hosts/unreal/api/plugin.py +++ b/openpype/hosts/unreal/api/plugin.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- from abc import ABC -from openpype.pipeline import LegacyCreator -import avalon.api +from openpype.pipeline import ( + LegacyCreator, + LoaderPlugin, +) class Creator(LegacyCreator): @@ -10,6 +12,6 @@ class Creator(LegacyCreator): defaults = ['Main'] -class Loader(avalon.api.Loader, ABC): +class Loader(LoaderPlugin, ABC): """This serves as skeleton for future OpenPype specific functionality""" pass diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_geometrycache.py b/openpype/hosts/unreal/plugins/load/load_alembic_geometrycache.py index 027e9f4cd37..3508fe5ed76 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_geometrycache.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_geometrycache.py @@ -2,7 +2,8 @@ """Loader for published alembics.""" import os -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline @@ -140,7 +141,7 @@ def load(self, context, name, namespace, data): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = self.get_task(source_path, destination_path, name, True) diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py index 0236bab1382..180942de51d 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py @@ -2,7 +2,8 @@ """Load Skeletal Mesh alembics.""" import os -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline import unreal # noqa @@ -104,7 +105,7 @@ def load(self, context, name, namespace, data): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = unreal.AssetImportTask() diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py index 3bcc8b476f1..4e00af1d97c 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py @@ -2,7 +2,8 @@ """Loader for Static Mesh alembics.""" import os -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline import unreal # noqa @@ -123,7 +124,7 @@ def load(self, context, name, namespace, data): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = self.get_task(source_path, destination_path, name, True) diff --git a/openpype/hosts/unreal/plugins/load/load_animation.py b/openpype/hosts/unreal/plugins/load/load_animation.py index 63c734b9695..8ef81f78512 100644 --- a/openpype/hosts/unreal/plugins/load/load_animation.py +++ b/openpype/hosts/unreal/plugins/load/load_animation.py @@ -3,7 +3,8 @@ import os import json -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline import unreal # noqa @@ -173,7 +174,7 @@ def load(self, context, name, namespace, options=None): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = unreal.AssetImportTask() diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index b802f5940a5..19ee179d204 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -11,7 +11,13 @@ from unreal import FBXImportType from unreal import MathLibrary as umath -from avalon import api, pipeline +from avalon.pipeline import AVALON_CONTAINER_ID +from openpype.pipeline import ( + discover_loader_plugins, + loaders_from_representation, + load_container, + get_representation_path, +) from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline @@ -205,7 +211,7 @@ def _process(self, lib_path, asset_dir, loaded=None): with open(lib_path, "r") as fp: data = json.load(fp) - all_loaders = api.discover(api.Loader) + all_loaders = discover_loader_plugins() if not loaded: loaded = [] @@ -235,7 +241,7 @@ def _process(self, lib_path, asset_dir, loaded=None): loaded.append(reference) family = element.get('family') - loaders = api.loaders_from_representation( + loaders = loaders_from_representation( all_loaders, reference) loader = None @@ -252,7 +258,7 @@ def _process(self, lib_path, asset_dir, loaded=None): "asset_dir": asset_dir } - assets = api.load( + assets = load_container( loader, reference, namespace=instance_name, @@ -387,7 +393,7 @@ def load(self, context, name, namespace, options): data = { "schema": "openpype:container-2.0", - "id": pipeline.AVALON_CONTAINER_ID, + "id": AVALON_CONTAINER_ID, "asset": asset, "namespace": asset_dir, "container_name": container_name, @@ -411,9 +417,9 @@ def load(self, context, name, namespace, options): def update(self, container, representation): ar = unreal.AssetRegistryHelpers.get_asset_registry() - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] - lib_path = Path(api.get_representation_path(representation)) + lib_path = Path(get_representation_path(representation)) self._remove_actors(destination_path) diff --git a/openpype/hosts/unreal/plugins/load/load_rig.py b/openpype/hosts/unreal/plugins/load/load_rig.py index a7ecb0ef7df..3d5616364cf 100644 --- a/openpype/hosts/unreal/plugins/load/load_rig.py +++ b/openpype/hosts/unreal/plugins/load/load_rig.py @@ -2,7 +2,8 @@ """Load Skeletal Meshes form FBX.""" import os -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline import unreal # noqa @@ -124,7 +125,7 @@ def load(self, context, name, namespace, options): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = unreal.AssetImportTask() diff --git a/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py b/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py index c8a6964ffb5..587fc83a77e 100644 --- a/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py +++ b/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py @@ -2,7 +2,8 @@ """Load Static meshes form FBX.""" import os -from avalon import api, pipeline +from avalon import pipeline +from openpype.pipeline import get_representation_path from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline import unreal # noqa @@ -118,7 +119,7 @@ def load(self, context, name, namespace, options): def update(self, container, representation): name = container["asset_name"] - source_path = api.get_representation_path(representation) + source_path = get_representation_path(representation) destination_path = container["namespace"] task = self.get_task(source_path, destination_path, name, True) diff --git a/openpype/hosts/webpublisher/api/__init__.py b/openpype/hosts/webpublisher/api/__init__.py index a0eaef03ef0..dbeb6280735 100644 --- a/openpype/hosts/webpublisher/api/__init__.py +++ b/openpype/hosts/webpublisher/api/__init__.py @@ -5,7 +5,6 @@ from avalon import io from pyblish import api as pyblish import openpype.hosts.webpublisher -from openpype.pipeline import LegacyCreator log = logging.getLogger("openpype.hosts.webpublisher") @@ -13,16 +12,12 @@ openpype.hosts.webpublisher.__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") def install(): print("Installing Pype config...") pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - avalon.register_plugin_path(LegacyCreator, CREATE_PATH) log.info(PUBLISH_PATH) io.install() @@ -30,8 +25,6 @@ def install(): def uninstall(): pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) - avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH) # to have required methods for interface diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 03ad69a5e60..26beba41ee2 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -980,6 +980,8 @@ def build_workfile(self): ... }] """ + from openpype.pipeline import discover_loader_plugins + # Get current asset name and entity current_asset_name = avalon.io.Session["AVALON_ASSET"] current_asset_entity = avalon.io.find_one({ @@ -996,7 +998,7 @@ def build_workfile(self): # Prepare available loaders loaders_by_name = {} - for loader in avalon.api.discover(avalon.api.Loader): + for loader in discover_loader_plugins(): loader_name = loader.__name__ if loader_name in loaders_by_name: raise KeyError( @@ -1390,6 +1392,11 @@ def _load_containers( Returns: (list) Objects of loaded containers. """ + from openpype.pipeline import ( + IncompatibleLoaderError, + load_container, + ) + loaded_containers = [] # Get subset id order from build presets. @@ -1451,7 +1458,7 @@ def _load_containers( if not loader: continue try: - container = avalon.api.load( + container = load_container( loader, repre["_id"], name=subset_name @@ -1460,7 +1467,7 @@ def _load_containers( is_loaded = True except Exception as exc: - if exc == avalon.pipeline.IncompatibleLoaderError: + if exc == IncompatibleLoaderError: self.log.info(( "Loader `{}` is not compatible with" " representation `{}`" diff --git a/openpype/lib/path_templates.py b/openpype/lib/path_templates.py index 62bfdf774a3..14e5fe59f8e 100644 --- a/openpype/lib/path_templates.py +++ b/openpype/lib/path_templates.py @@ -187,6 +187,16 @@ def format_strict(self, *args, **kwargs): result.validate() return result + @classmethod + def format_template(cls, template, data): + objected_template = cls(template) + return objected_template.format(data) + + @classmethod + def format_strict_template(cls, template, data): + objected_template = cls(template) + return objected_template.format_strict(data) + @staticmethod def find_optional_parts(parts): new_parts = [] diff --git a/openpype/lib/plugin_tools.py b/openpype/lib/plugin_tools.py index 19765a6f4a9..f11ba56865d 100644 --- a/openpype/lib/plugin_tools.py +++ b/openpype/lib/plugin_tools.py @@ -280,6 +280,7 @@ def set_plugin_attributes_from_settings( project_name (str): Name of project for which settings will be loaded. Value from environment `AVALON_PROJECT` is used if not entered. """ + from openpype.pipeline import LegacyCreator, LoaderPlugin # determine host application to use for finding presets if host_name is None: @@ -289,11 +290,11 @@ def set_plugin_attributes_from_settings( project_name = os.environ.get("AVALON_PROJECT") # map plugin superclass to preset json. Currently supported is load and - # create (avalon.api.Loader and avalon.api.Creator) + # create (LoaderPlugin and LegacyCreator) plugin_type = None - if superclass.__name__.split(".")[-1] in ("Loader", "SubsetLoader"): + if superclass is LoaderPlugin or issubclass(superclass, LoaderPlugin): plugin_type = "load" - elif superclass.__name__.split(".")[-1] in ("Creator", "LegacyCreator"): + elif superclass is LegacyCreator or issubclass(superclass, LegacyCreator): plugin_type = "create" if not host_name or not project_name or plugin_type is None: diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 1de1c375759..19d504b6c98 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -13,6 +13,8 @@ import pyblish.api +from openpype.pipeline import get_representation_path + def get_resources(version, extension=None): """Get the files from the specific version.""" @@ -23,7 +25,7 @@ def get_resources(version, extension=None): representation = io.find_one(query) assert representation, "This is a bug" - directory = api.get_representation_path(representation) + directory = get_representation_path(representation) print("Source: ", directory) resources = sorted( [ diff --git a/openpype/modules/ftrack/event_handlers_user/action_rv.py b/openpype/modules/ftrack/event_handlers_user/action_rv.py index 71d790f7e76..bdb0eaf2502 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_rv.py +++ b/openpype/modules/ftrack/event_handlers_user/action_rv.py @@ -3,9 +3,10 @@ import traceback import json -from openpype_modules.ftrack.lib import BaseAction, statics_icon import ftrack_api from avalon import io, api +from openpype.pipeline import get_representation_path +from openpype_modules.ftrack.lib import BaseAction, statics_icon class RVAction(BaseAction): @@ -307,7 +308,7 @@ def get_file_paths(self, session, event): "name": "preview" } ) - paths.append(api.get_representation_path(representation)) + paths.append(get_representation_path(representation)) return paths diff --git a/openpype/pipeline/__init__.py b/openpype/pipeline/__init__.py index 7147e56dd20..e204eea2394 100644 --- a/openpype/pipeline/__init__.py +++ b/openpype/pipeline/__init__.py @@ -12,6 +12,27 @@ legacy_create, ) +from .load import ( + HeroVersionType, + IncompatibleLoaderError, + LoaderPlugin, + SubsetLoaderPlugin, + + discover_loader_plugins, + register_loader_plugin, + deregister_loader_plugin_path, + register_loader_plugin_path, + deregister_loader_plugin, + + load_container, + remove_container, + update_container, + switch_container, + + loaders_from_representation, + get_representation_path, +) + from .publish import ( PublishValidationError, PublishXmlValidationError, @@ -23,6 +44,7 @@ __all__ = ( "attribute_definitions", + # --- Create --- "BaseCreator", "Creator", "AutoCreator", @@ -30,10 +52,31 @@ "CreatorError", - # Legacy creation + # - legacy creation "LegacyCreator", "legacy_create", + # --- Load --- + "HeroVersionType", + "IncompatibleLoaderError", + "LoaderPlugin", + "SubsetLoaderPlugin", + + "discover_loader_plugins", + "register_loader_plugin", + "deregister_loader_plugin_path", + "register_loader_plugin_path", + "deregister_loader_plugin", + + "load_container", + "remove_container", + "update_container", + "switch_container", + + "loaders_from_representation", + "get_representation_path", + + # --- Publish --- "PublishValidationError", "PublishXmlValidationError", "KnownPublishError", diff --git a/openpype/pipeline/create/legacy_create.py b/openpype/pipeline/create/legacy_create.py index d05cdff6899..cf6629047eb 100644 --- a/openpype/pipeline/create/legacy_create.py +++ b/openpype/pipeline/create/legacy_create.py @@ -21,6 +21,7 @@ class LegacyCreator(object): dynamic_subset_keys = [] log = logging.getLogger("LegacyCreator") + log.propagate = True def __init__(self, name, asset, options=None, data=None): self.name = name # For backwards compatibility diff --git a/openpype/pipeline/load/__init__.py b/openpype/pipeline/load/__init__.py new file mode 100644 index 00000000000..6e7612d4c1b --- /dev/null +++ b/openpype/pipeline/load/__init__.py @@ -0,0 +1,78 @@ +from .utils import ( + HeroVersionType, + IncompatibleLoaderError, + + get_repres_contexts, + get_subset_contexts, + get_representation_context, + + load_with_repre_context, + load_with_subset_context, + load_with_subset_contexts, + + load_container, + remove_container, + update_container, + switch_container, + + get_loader_identifier, + + get_representation_path_from_context, + get_representation_path, + + is_compatible_loader, + + loaders_from_repre_context, + loaders_from_representation, +) + +from .plugins import ( + LoaderPlugin, + SubsetLoaderPlugin, + + discover_loader_plugins, + register_loader_plugin, + deregister_loader_plugin_path, + register_loader_plugin_path, + deregister_loader_plugin, +) + + +__all__ = ( + # utils.py + "HeroVersionType", + "IncompatibleLoaderError", + + "get_repres_contexts", + "get_subset_contexts", + "get_representation_context", + + "load_with_repre_context", + "load_with_subset_context", + "load_with_subset_contexts", + + "load_container", + "remove_container", + "update_container", + "switch_container", + + "get_loader_identifier", + + "get_representation_path_from_context", + "get_representation_path", + + "is_compatible_loader", + + "loaders_from_repre_context", + "loaders_from_representation", + + # plugins.py + "LoaderPlugin", + "SubsetLoaderPlugin", + + "discover_loader_plugins", + "register_loader_plugin", + "deregister_loader_plugin_path", + "register_loader_plugin_path", + "deregister_loader_plugin", +) diff --git a/openpype/pipeline/load/plugins.py b/openpype/pipeline/load/plugins.py new file mode 100644 index 00000000000..601ad3b2583 --- /dev/null +++ b/openpype/pipeline/load/plugins.py @@ -0,0 +1,130 @@ +import logging + +from .utils import get_representation_path_from_context + + +class LoaderPlugin(list): + """Load representation into host application + + Arguments: + context (dict): avalon-core:context-1.0 + name (str, optional): Use pre-defined name + namespace (str, optional): Use pre-defined namespace + + .. versionadded:: 4.0 + This class was introduced + + """ + + families = list() + representations = list() + order = 0 + is_multiple_contexts_compatible = False + + options = [] + + log = logging.getLogger("SubsetLoader") + log.propagate = True + + def __init__(self, context): + self.fname = self.filepath_from_context(context) + + @classmethod + def get_representations(cls): + return cls.representations + + def filepath_from_context(self, context): + return get_representation_path_from_context(context) + + def load(self, context, name=None, namespace=None, options=None): + """Load asset via database + + Arguments: + context (dict): Full parenthood of representation to load + name (str, optional): Use pre-defined name + namespace (str, optional): Use pre-defined namespace + options (dict, optional): Additional settings dictionary + + """ + raise NotImplementedError("Loader.load() must be " + "implemented by subclass") + + def update(self, container, representation): + """Update `container` to `representation` + + Arguments: + container (avalon-core:container-1.0): Container to update, + from `host.ls()`. + representation (dict): Update the container to this representation. + + """ + raise NotImplementedError("Loader.update() must be " + "implemented by subclass") + + def remove(self, container): + """Remove a container + + Arguments: + container (avalon-core:container-1.0): Container to remove, + from `host.ls()`. + + Returns: + bool: Whether the container was deleted + + """ + + raise NotImplementedError("Loader.remove() must be " + "implemented by subclass") + + @classmethod + def get_options(cls, contexts): + """ + Returns static (cls) options or could collect from 'contexts'. + + Args: + contexts (list): of repre or subset contexts + Returns: + (list) + """ + return cls.options or [] + + +class SubsetLoaderPlugin(LoaderPlugin): + """Load subset into host application + Arguments: + context (dict): avalon-core:context-1.0 + name (str, optional): Use pre-defined name + namespace (str, optional): Use pre-defined namespace + """ + + def __init__(self, context): + pass + + +def discover_loader_plugins(): + import avalon.api + + return avalon.api.discover(LoaderPlugin) + + +def register_loader_plugin(plugin): + import avalon.api + + return avalon.api.register_plugin(LoaderPlugin, plugin) + + +def deregister_loader_plugin_path(path): + import avalon.api + + avalon.api.deregister_plugin_path(LoaderPlugin, path) + + +def register_loader_plugin_path(path): + import avalon.api + + return avalon.api.register_plugin_path(LoaderPlugin, path) + + +def deregister_loader_plugin(plugin): + import avalon.api + avalon.api.deregister_plugin(LoaderPlugin, plugin) diff --git a/openpype/pipeline/load/utils.py b/openpype/pipeline/load/utils.py new file mode 100644 index 00000000000..ae47cb9ce95 --- /dev/null +++ b/openpype/pipeline/load/utils.py @@ -0,0 +1,706 @@ +import os +import platform +import copy +import getpass +import logging +import inspect +import numbers + +import six + +from avalon import io, schema +from avalon.api import Session, registered_root + +from openpype.lib import Anatomy + +log = logging.getLogger(__name__) + + +class HeroVersionType(object): + def __init__(self, version): + assert isinstance(version, numbers.Integral), ( + "Version is not an integer. \"{}\" {}".format( + version, str(type(version)) + ) + ) + self.version = version + + def __str__(self): + return str(self.version) + + def __int__(self): + return int(self.version) + + def __format__(self, format_spec): + return self.version.__format__(format_spec) + + +class IncompatibleLoaderError(ValueError): + """Error when Loader is incompatible with a representation.""" + pass + + +def get_repres_contexts(representation_ids, dbcon=None): + """Return parenthood context for representation. + + Args: + representation_ids (list): The representation ids. + dbcon (AvalonMongoDB): Mongo connection object. `avalon.io` used when + not entered. + + Returns: + dict: The full representation context by representation id. + keys are repre_id, value is dictionary with full: + asset_doc + version_doc + subset_doc + repre_doc + + """ + if not dbcon: + dbcon = io + + contexts = {} + if not representation_ids: + return contexts + + _representation_ids = [] + for repre_id in representation_ids: + if isinstance(repre_id, six.string_types): + repre_id = io.ObjectId(repre_id) + _representation_ids.append(repre_id) + + repre_docs = dbcon.find({ + "type": "representation", + "_id": {"$in": _representation_ids} + }) + repre_docs_by_id = {} + version_ids = set() + for repre_doc in repre_docs: + version_ids.add(repre_doc["parent"]) + repre_docs_by_id[repre_doc["_id"]] = repre_doc + + version_docs = dbcon.find({ + "type": {"$in": ["version", "hero_version"]}, + "_id": {"$in": list(version_ids)} + }) + + version_docs_by_id = {} + hero_version_docs = [] + versions_for_hero = set() + subset_ids = set() + for version_doc in version_docs: + if version_doc["type"] == "hero_version": + hero_version_docs.append(version_doc) + versions_for_hero.add(version_doc["version_id"]) + version_docs_by_id[version_doc["_id"]] = version_doc + subset_ids.add(version_doc["parent"]) + + if versions_for_hero: + _version_docs = dbcon.find({ + "type": "version", + "_id": {"$in": list(versions_for_hero)} + }) + _version_data_by_id = { + version_doc["_id"]: version_doc["data"] + for version_doc in _version_docs + } + + for hero_version_doc in hero_version_docs: + hero_version_id = hero_version_doc["_id"] + version_id = hero_version_doc["version_id"] + version_data = copy.deepcopy(_version_data_by_id[version_id]) + version_docs_by_id[hero_version_id]["data"] = version_data + + subset_docs = dbcon.find({ + "type": "subset", + "_id": {"$in": list(subset_ids)} + }) + subset_docs_by_id = {} + asset_ids = set() + for subset_doc in subset_docs: + subset_docs_by_id[subset_doc["_id"]] = subset_doc + asset_ids.add(subset_doc["parent"]) + + asset_docs = dbcon.find({ + "type": "asset", + "_id": {"$in": list(asset_ids)} + }) + asset_docs_by_id = { + asset_doc["_id"]: asset_doc + for asset_doc in asset_docs + } + + project_doc = dbcon.find_one({"type": "project"}) + + for repre_id, repre_doc in repre_docs_by_id.items(): + version_doc = version_docs_by_id[repre_doc["parent"]] + subset_doc = subset_docs_by_id[version_doc["parent"]] + asset_doc = asset_docs_by_id[subset_doc["parent"]] + context = { + "project": { + "name": project_doc["name"], + "code": project_doc["data"].get("code") + }, + "asset": asset_doc, + "subset": subset_doc, + "version": version_doc, + "representation": repre_doc, + } + contexts[repre_id] = context + + return contexts + + +def get_subset_contexts(subset_ids, dbcon=None): + """Return parenthood context for subset. + + Provides context on subset granularity - less detail than + 'get_repre_contexts'. + Args: + subset_ids (list): The subset ids. + dbcon (AvalonMongoDB): Mongo connection object. `avalon.io` used when + not entered. + Returns: + dict: The full representation context by representation id. + """ + if not dbcon: + dbcon = io + + contexts = {} + if not subset_ids: + return contexts + + _subset_ids = set() + for subset_id in subset_ids: + if isinstance(subset_id, six.string_types): + subset_id = io.ObjectId(subset_id) + _subset_ids.add(subset_id) + + subset_docs = dbcon.find({ + "type": "subset", + "_id": {"$in": list(_subset_ids)} + }) + subset_docs_by_id = {} + asset_ids = set() + for subset_doc in subset_docs: + subset_docs_by_id[subset_doc["_id"]] = subset_doc + asset_ids.add(subset_doc["parent"]) + + asset_docs = dbcon.find({ + "type": "asset", + "_id": {"$in": list(asset_ids)} + }) + asset_docs_by_id = { + asset_doc["_id"]: asset_doc + for asset_doc in asset_docs + } + + project_doc = dbcon.find_one({"type": "project"}) + + for subset_id, subset_doc in subset_docs_by_id.items(): + asset_doc = asset_docs_by_id[subset_doc["parent"]] + context = { + "project": { + "name": project_doc["name"], + "code": project_doc["data"].get("code") + }, + "asset": asset_doc, + "subset": subset_doc + } + contexts[subset_id] = context + + return contexts + + +def get_representation_context(representation): + """Return parenthood context for representation. + + Args: + representation (str or io.ObjectId or dict): The representation id + or full representation as returned by the database. + + Returns: + dict: The full representation context. + + """ + + assert representation is not None, "This is a bug" + + if isinstance(representation, (six.string_types, io.ObjectId)): + representation = io.find_one( + {"_id": io.ObjectId(str(representation))}) + + version, subset, asset, project = io.parenthood(representation) + + assert all([representation, version, subset, asset, project]), ( + "This is a bug" + ) + + context = { + "project": { + "name": project["name"], + "code": project["data"].get("code", '') + }, + "asset": asset, + "subset": subset, + "version": version, + "representation": representation, + } + + return context + + +def load_with_repre_context( + Loader, repre_context, namespace=None, name=None, options=None, **kwargs +): + + # Ensure the Loader is compatible for the representation + if not is_compatible_loader(Loader, repre_context): + raise IncompatibleLoaderError( + "Loader {} is incompatible with {}".format( + Loader.__name__, repre_context["subset"]["name"] + ) + ) + + # Ensure options is a dictionary when no explicit options provided + if options is None: + options = kwargs.get("data", dict()) # "data" for backward compat + + assert isinstance(options, dict), "Options must be a dictionary" + + # Fallback to subset when name is None + if name is None: + name = repre_context["subset"]["name"] + + log.info( + "Running '%s' on '%s'" % ( + Loader.__name__, repre_context["asset"]["name"] + ) + ) + + loader = Loader(repre_context) + return loader.load(repre_context, name, namespace, options) + + +def load_with_subset_context( + Loader, subset_context, namespace=None, name=None, options=None, **kwargs +): + + # Ensure options is a dictionary when no explicit options provided + if options is None: + options = kwargs.get("data", dict()) # "data" for backward compat + + assert isinstance(options, dict), "Options must be a dictionary" + + # Fallback to subset when name is None + if name is None: + name = subset_context["subset"]["name"] + + log.info( + "Running '%s' on '%s'" % ( + Loader.__name__, subset_context["asset"]["name"] + ) + ) + + loader = Loader(subset_context) + return loader.load(subset_context, name, namespace, options) + + +def load_with_subset_contexts( + Loader, subset_contexts, namespace=None, name=None, options=None, **kwargs +): + + # Ensure options is a dictionary when no explicit options provided + if options is None: + options = kwargs.get("data", dict()) # "data" for backward compat + + assert isinstance(options, dict), "Options must be a dictionary" + + # Fallback to subset when name is None + joined_subset_names = " | ".join( + context["subset"]["name"] + for context in subset_contexts + ) + if name is None: + name = joined_subset_names + + log.info( + "Running '{}' on '{}'".format(Loader.__name__, joined_subset_names) + ) + + loader = Loader(subset_contexts) + return loader.load(subset_contexts, name, namespace, options) + + +def load_container( + Loader, representation, namespace=None, name=None, options=None, **kwargs +): + """Use Loader to load a representation. + + Args: + Loader (Loader): The loader class to trigger. + representation (str or io.ObjectId or dict): The representation id + or full representation as returned by the database. + namespace (str, Optional): The namespace to assign. Defaults to None. + name (str, Optional): The name to assign. Defaults to subset name. + options (dict, Optional): Additional options to pass on to the loader. + + Returns: + The return of the `loader.load()` method. + + Raises: + IncompatibleLoaderError: When the loader is not compatible with + the representation. + + """ + + context = get_representation_context(representation) + return load_with_repre_context( + Loader, + context, + namespace=namespace, + name=name, + options=options, + **kwargs + ) + + +def get_loader_identifier(loader): + """Loader identifier from loader plugin or object. + + Identifier should be stored to container for future management. + """ + if not inspect.isclass(loader): + loader = loader.__class__ + return loader.__name__ + + +def _get_container_loader(container): + """Return the Loader corresponding to the container""" + from .plugins import discover_loader_plugins + + loader = container["loader"] + for Plugin in discover_loader_plugins(): + # TODO: Ensure the loader is valid + if get_loader_identifier(Plugin) == loader: + return Plugin + return None + + +def remove_container(container): + """Remove a container""" + + Loader = _get_container_loader(container) + if not Loader: + raise RuntimeError("Can't remove container. See log for details.") + + loader = Loader(get_representation_context(container["representation"])) + return loader.remove(container) + + +def update_container(container, version=-1): + """Update a container""" + + # Compute the different version from 'representation' + current_representation = io.find_one({ + "_id": io.ObjectId(container["representation"]) + }) + + assert current_representation is not None, "This is a bug" + + current_version, subset, asset, project = io.parenthood( + current_representation) + + if version == -1: + new_version = io.find_one({ + "type": "version", + "parent": subset["_id"] + }, sort=[("name", -1)]) + else: + if isinstance(version, HeroVersionType): + version_query = { + "parent": subset["_id"], + "type": "hero_version" + } + else: + version_query = { + "parent": subset["_id"], + "type": "version", + "name": version + } + new_version = io.find_one(version_query) + + assert new_version is not None, "This is a bug" + + new_representation = io.find_one({ + "type": "representation", + "parent": new_version["_id"], + "name": current_representation["name"] + }) + + assert new_representation is not None, "Representation wasn't found" + + path = get_representation_path(new_representation) + assert os.path.exists(path), "Path {} doesn't exist".format(path) + + # Run update on the Loader for this container + Loader = _get_container_loader(container) + if not Loader: + raise RuntimeError("Can't update container. See log for details.") + + loader = Loader(get_representation_context(container["representation"])) + return loader.update(container, new_representation) + + +def switch_container(container, representation, loader_plugin=None): + """Switch a container to representation + + Args: + container (dict): container information + representation (dict): representation data from document + + Returns: + function call + """ + + # Get the Loader for this container + if loader_plugin is None: + loader_plugin = _get_container_loader(container) + + if not loader_plugin: + raise RuntimeError("Can't switch container. See log for details.") + + if not hasattr(loader_plugin, "switch"): + # Backwards compatibility (classes without switch support + # might be better to just have "switch" raise NotImplementedError + # on the base class of Loader\ + raise RuntimeError("Loader '{}' does not support 'switch'".format( + loader_plugin.label + )) + + # Get the new representation to switch to + new_representation = io.find_one({ + "type": "representation", + "_id": representation["_id"], + }) + + new_context = get_representation_context(new_representation) + if not is_compatible_loader(loader_plugin, new_context): + raise AssertionError("Must be compatible Loader") + + loader = loader_plugin(new_context) + + return loader.switch(container, new_representation) + + +def get_representation_path_from_context(context): + """Preparation wrapper using only context as a argument""" + representation = context['representation'] + project_doc = context.get("project") + root = None + session_project = Session.get("AVALON_PROJECT") + if project_doc and project_doc["name"] != session_project: + anatomy = Anatomy(project_doc["name"]) + root = anatomy.roots_obj + + return get_representation_path(representation, root) + + +def get_representation_path(representation, root=None, dbcon=None): + """Get filename from representation document + + There are three ways of getting the path from representation which are + tried in following sequence until successful. + 1. Get template from representation['data']['template'] and data from + representation['context']. Then format template with the data. + 2. Get template from project['config'] and format it with default data set + 3. Get representation['data']['path'] and use it directly + + Args: + representation(dict): representation document from the database + + Returns: + str: fullpath of the representation + + """ + + from openpype.lib import StringTemplate + + if dbcon is None: + dbcon = io + + if root is None: + root = registered_root() + + def path_from_represenation(): + try: + template = representation["data"]["template"] + except KeyError: + return None + + try: + context = representation["context"] + context["root"] = root + template_obj = StringTemplate(template) + path = str(template_obj.format(context)) + # Force replacing backslashes with forward slashed if not on + # windows + if platform.system().lower() != "windows": + path = path.replace("\\", "/") + except KeyError: + # Template references unavailable data + return None + + if not path: + return path + + normalized_path = os.path.normpath(path) + if os.path.exists(normalized_path): + return normalized_path + return path + + def path_from_config(): + try: + version_, subset, asset, project = dbcon.parenthood(representation) + except ValueError: + log.debug( + "Representation %s wasn't found in database, " + "like a bug" % representation["name"] + ) + return None + + try: + template = project["config"]["template"]["publish"] + except KeyError: + log.debug( + "No template in project %s, " + "likely a bug" % project["name"] + ) + return None + + # default list() in get would not discover missing parents on asset + parents = asset.get("data", {}).get("parents") + if parents is not None: + hierarchy = "/".join(parents) + + # Cannot fail, required members only + data = { + "root": root, + "project": { + "name": project["name"], + "code": project.get("data", {}).get("code") + }, + "asset": asset["name"], + "silo": asset.get("silo"), + "hierarchy": hierarchy, + "subset": subset["name"], + "version": version_["name"], + "representation": representation["name"], + "family": representation.get("context", {}).get("family"), + "user": dbcon.Session.get("AVALON_USER", getpass.getuser()), + "app": dbcon.Session.get("AVALON_APP", ""), + "task": dbcon.Session.get("AVALON_TASK", "") + } + + try: + template_obj = StringTemplate(template) + path = str(template_obj.format(data)) + # Force replacing backslashes with forward slashed if not on + # windows + if platform.system().lower() != "windows": + path = path.replace("\\", "/") + + except KeyError as e: + log.debug("Template references unavailable data: %s" % e) + return None + + normalized_path = os.path.normpath(path) + if os.path.exists(normalized_path): + return normalized_path + return path + + def path_from_data(): + if "path" not in representation["data"]: + return None + + path = representation["data"]["path"] + # Force replacing backslashes with forward slashed if not on + # windows + if platform.system().lower() != "windows": + path = path.replace("\\", "/") + + if os.path.exists(path): + return os.path.normpath(path) + + dir_path, file_name = os.path.split(path) + if not os.path.exists(dir_path): + return + + base_name, ext = os.path.splitext(file_name) + file_name_items = None + if "#" in base_name: + file_name_items = [part for part in base_name.split("#") if part] + elif "%" in base_name: + file_name_items = base_name.split("%") + + if not file_name_items: + return + + filename_start = file_name_items[0] + + for _file in os.listdir(dir_path): + if _file.startswith(filename_start) and _file.endswith(ext): + return os.path.normpath(path) + + return ( + path_from_represenation() or + path_from_config() or + path_from_data() + ) + + +def is_compatible_loader(Loader, context): + """Return whether a loader is compatible with a context. + + This checks the version's families and the representation for the given + Loader. + + Returns: + bool + + """ + maj_version, _ = schema.get_schema_version(context["subset"]["schema"]) + if maj_version < 3: + families = context["version"]["data"].get("families", []) + else: + families = context["subset"]["data"]["families"] + + representation = context["representation"] + has_family = ( + "*" in Loader.families or any( + family in Loader.families for family in families + ) + ) + representations = Loader.get_representations() + has_representation = ( + "*" in representations or representation["name"] in representations + ) + return has_family and has_representation + + +def loaders_from_repre_context(loaders, repre_context): + """Return compatible loaders for by representaiton's context.""" + + return [ + loader + for loader in loaders + if is_compatible_loader(loader, repre_context) + ] + + +def loaders_from_representation(loaders, representation): + """Return all compatible loaders for a representation.""" + + context = get_representation_context(representation) + return loaders_from_repre_context(loaders, context) diff --git a/openpype/plugins/load/add_site.py b/openpype/plugins/load/add_site.py index 09448d553ca..95001691e20 100644 --- a/openpype/plugins/load/add_site.py +++ b/openpype/plugins/load/add_site.py @@ -1,8 +1,8 @@ -from avalon import api from openpype.modules import ModulesManager +from openpype.pipeline import load -class AddSyncSite(api.Loader): +class AddSyncSite(load.LoaderPlugin): """Add sync site to representation""" representations = ["*"] families = ["*"] diff --git a/openpype/plugins/load/copy_file.py b/openpype/plugins/load/copy_file.py index bdcb4fec796..60db094cfbb 100644 --- a/openpype/plugins/load/copy_file.py +++ b/openpype/plugins/load/copy_file.py @@ -1,8 +1,8 @@ -from avalon import api from openpype.style import get_default_entity_icon_color +from openpype.pipeline import load -class CopyFile(api.Loader): +class CopyFile(load.LoaderPlugin): """Copy the published file to be pasted at the desired location""" representations = ["*"] diff --git a/openpype/plugins/load/copy_file_path.py b/openpype/plugins/load/copy_file_path.py index 2041c79f6df..565d8d1ff18 100644 --- a/openpype/plugins/load/copy_file_path.py +++ b/openpype/plugins/load/copy_file_path.py @@ -1,9 +1,9 @@ import os -from avalon import api +from openpype.pipeline import load -class CopyFilePath(api.Loader): +class CopyFilePath(load.LoaderPlugin): """Copy published file path to clipboard""" representations = ["*"] families = ["*"] diff --git a/openpype/plugins/load/delete_old_versions.py b/openpype/plugins/load/delete_old_versions.py index fb8be0ed334..692acdec020 100644 --- a/openpype/plugins/load/delete_old_versions.py +++ b/openpype/plugins/load/delete_old_versions.py @@ -8,14 +8,14 @@ import qargparse from Qt import QtWidgets, QtCore -from avalon import api from avalon.api import AvalonMongoDB -import avalon.pipeline from openpype import style +from openpype.pipeline import load +from openpype.lib import StringTemplate from openpype.api import Anatomy -class DeleteOldVersions(api.SubsetLoader): +class DeleteOldVersions(load.SubsetLoaderPlugin): """Deletes specific number of old version""" is_multiple_contexts_compatible = True @@ -90,16 +90,12 @@ def path_from_representation(self, representation, anatomy): try: context = representation["context"] context["root"] = anatomy.roots - path = avalon.pipeline.format_template_with_optional_keys( - context, template - ) + path = str(StringTemplate.format_template(template, context)) if "frame" in context: context["frame"] = self.sequence_splitter - sequence_path = os.path.normpath( - avalon.pipeline.format_template_with_optional_keys( - context, template - ) - ) + sequence_path = os.path.normpath(str( + StringTemplate.format_template(template, context) + )) except KeyError: # Template references unavailable data diff --git a/openpype/plugins/load/delivery.py b/openpype/plugins/load/delivery.py index 1037d6dc165..04080053e3a 100644 --- a/openpype/plugins/load/delivery.py +++ b/openpype/plugins/load/delivery.py @@ -3,9 +3,9 @@ from Qt import QtWidgets, QtCore, QtGui -from avalon import api from avalon.api import AvalonMongoDB +from openpype.pipeline import load from openpype.api import Anatomy, config from openpype import resources, style @@ -20,7 +20,7 @@ ) -class Delivery(api.SubsetLoader): +class Delivery(load.SubsetLoaderPlugin): """Export selected versions to folder structure from Template""" is_multiple_contexts_compatible = True diff --git a/openpype/plugins/load/open_djv.py b/openpype/plugins/load/open_djv.py index 4b0e8411c89..273c77c93fd 100644 --- a/openpype/plugins/load/open_djv.py +++ b/openpype/plugins/load/open_djv.py @@ -1,6 +1,6 @@ import os -from avalon import api from openpype.api import ApplicationManager +from openpype.pipeline import load def existing_djv_path(): @@ -13,7 +13,8 @@ def existing_djv_path(): return djv_list -class OpenInDJV(api.Loader): + +class OpenInDJV(load.LoaderPlugin): """Open Image Sequence with system default""" djv_list = existing_djv_path() diff --git a/openpype/plugins/load/open_file.py b/openpype/plugins/load/open_file.py index 4133a64eb37..f21cd07c7f2 100644 --- a/openpype/plugins/load/open_file.py +++ b/openpype/plugins/load/open_file.py @@ -2,7 +2,7 @@ import os import subprocess -from avalon import api +from openpype.pipeline import load def open(filepath): @@ -15,7 +15,7 @@ def open(filepath): subprocess.call(('xdg-open', filepath)) -class Openfile(api.Loader): +class Openfile(load.LoaderPlugin): """Open Image Sequence with system default""" families = ["render2d"] diff --git a/openpype/plugins/load/remove_site.py b/openpype/plugins/load/remove_site.py index aedb5d1f2fd..adffec9986d 100644 --- a/openpype/plugins/load/remove_site.py +++ b/openpype/plugins/load/remove_site.py @@ -1,8 +1,8 @@ -from avalon import api from openpype.modules import ModulesManager +from openpype.pipeline import load -class RemoveSyncSite(api.Loader): +class RemoveSyncSite(load.LoaderPlugin): """Remove sync site and its files on representation""" representations = ["*"] families = ["*"] diff --git a/openpype/tools/loader/model.py b/openpype/tools/loader/model.py index 10073559895..6cc6fae1fb9 100644 --- a/openpype/tools/loader/model.py +++ b/openpype/tools/loader/model.py @@ -7,7 +7,7 @@ import qtawesome from avalon import schema -from avalon.lib import HeroVersionType +from openpype.pipeline import HeroVersionType from openpype.style import get_default_entity_icon_color from openpype.tools.utils.models import TreeModel, Item diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index f145756cc5a..b14bdd0e939 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -1,6 +1,5 @@ import os import sys -import inspect import datetime import pprint import traceback @@ -9,8 +8,19 @@ from Qt import QtWidgets, QtCore, QtGui from avalon import api, pipeline -from avalon.lib import HeroVersionType +from openpype.pipeline import HeroVersionType +from openpype.pipeline.load import ( + discover_loader_plugins, + SubsetLoaderPlugin, + loaders_from_repre_context, + get_repres_contexts, + get_subset_contexts, + load_with_repre_context, + load_with_subset_context, + load_with_subset_contexts, + IncompatibleLoaderError, +) from openpype.tools.utils import ( ErrorMessageBox, lib as tools_lib @@ -425,7 +435,7 @@ def on_context_menu(self, point): # Get all representation->loader combinations available for the # index under the cursor, so we can list the user the options. - available_loaders = api.discover(api.Loader) + available_loaders = discover_loader_plugins() if self.tool_name: available_loaders = lib.remove_tool_name_from_loaders( available_loaders, self.tool_name @@ -435,7 +445,7 @@ def on_context_menu(self, point): subset_loaders = [] for loader in available_loaders: # Skip if its a SubsetLoader. - if api.SubsetLoader in inspect.getmro(loader): + if issubclass(loader, SubsetLoaderPlugin): subset_loaders.append(loader) else: repre_loaders.append(loader) @@ -459,7 +469,7 @@ def on_context_menu(self, point): repre_docs = repre_docs_by_version_id[version_id] for repre_doc in repre_docs: repre_context = repre_context_by_id[repre_doc["_id"]] - for loader in pipeline.loaders_from_repre_context( + for loader in loaders_from_repre_context( repre_loaders, repre_context ): @@ -515,7 +525,7 @@ def on_context_menu(self, point): action = lib.get_no_loader_action(menu, one_item_selected) menu.addAction(action) else: - repre_contexts = pipeline.get_repres_contexts( + repre_contexts = get_repres_contexts( repre_context_by_id.keys(), self.dbcon) menu = lib.add_representation_loaders_to_menu( @@ -532,7 +542,7 @@ def on_context_menu(self, point): self.load_started.emit() - if api.SubsetLoader in inspect.getmro(loader): + if issubclass(loader, SubsetLoaderPlugin): subset_ids = [] subset_version_docs = {} for item in items: @@ -541,8 +551,7 @@ def on_context_menu(self, point): subset_version_docs[subset_id] = item["version_document"] # get contexts only for selected menu option - subset_contexts_by_id = pipeline.get_subset_contexts(subset_ids, - self.dbcon) + subset_contexts_by_id = get_subset_contexts(subset_ids, self.dbcon) subset_contexts = list(subset_contexts_by_id.values()) options = lib.get_options(action, loader, self, subset_contexts) @@ -575,8 +584,7 @@ def on_context_menu(self, point): repre_ids.append(representation["_id"]) # get contexts only for selected menu option - repre_contexts = pipeline.get_repres_contexts(repre_ids, - self.dbcon) + repre_contexts = get_repres_contexts(repre_ids, self.dbcon) options = lib.get_options(action, loader, self, list(repre_contexts.values())) @@ -1339,12 +1347,12 @@ def on_context_menu(self, point): selected_side = self._get_selected_side(point_index, rows) # Get all representation->loader combinations available for the # index under the cursor, so we can list the user the options. - available_loaders = api.discover(api.Loader) + available_loaders = discover_loader_plugins() filtered_loaders = [] for loader in available_loaders: # Skip subset loaders - if api.SubsetLoader in inspect.getmro(loader): + if issubclass(loader, SubsetLoaderPlugin): continue if ( @@ -1370,7 +1378,7 @@ def on_context_menu(self, point): for item in items: repre_context = repre_context_by_id[item["_id"]] - for loader in pipeline.loaders_from_repre_context( + for loader in loaders_from_repre_context( filtered_loaders, repre_context ): @@ -1426,7 +1434,7 @@ def on_context_menu(self, point): action = lib.get_no_loader_action(menu) menu.addAction(action) else: - repre_contexts = pipeline.get_repres_contexts( + repre_contexts = get_repres_contexts( repre_context_by_id.keys(), self.dbcon) menu = lib.add_representation_loaders_to_menu(loaders, menu, repre_contexts) @@ -1472,8 +1480,7 @@ def _process_action(self, items, menu, point): repre_ids.append(item.get("_id")) - repre_contexts = pipeline.get_repres_contexts(repre_ids, - self.dbcon) + repre_contexts = get_repres_contexts(repre_ids, self.dbcon) options = lib.get_options(action, loader, self, list(repre_contexts.values())) @@ -1540,7 +1547,7 @@ def _load_representations_by_loader(loader, repre_contexts, """Loops through list of repre_contexts and loads them with one loader Args: - loader (cls of api.Loader) - not initialized yet + loader (cls of LoaderPlugin) - not initialized yet repre_contexts (dicts) - full info about selected representations (containing repre_doc, version_doc, subset_doc, project info) options (dict) - qargparse arguments to fill OptionDialog @@ -1558,12 +1565,12 @@ def _load_representations_by_loader(loader, repre_contexts, _id = repre_context["representation"]["_id"] data = data_by_repre_id.get(_id) options.update(data) - pipeline.load_with_repre_context( + load_with_repre_context( loader, repre_context, options=options ) - except pipeline.IncompatibleLoaderError as exc: + except IncompatibleLoaderError as exc: print(exc) error_info.append(( "Incompatible Loader", @@ -1612,7 +1619,7 @@ def _load_subsets_by_loader(loader, subset_contexts, options, context["version"] = subset_version_docs[context["subset"]["_id"]] try: - pipeline.load_with_subset_contexts( + load_with_subset_contexts( loader, subset_contexts, options=options @@ -1638,7 +1645,7 @@ def _load_subsets_by_loader(loader, subset_contexts, options, version_doc = subset_version_docs[subset_context["subset"]["_id"]] subset_context["version"] = version_doc try: - pipeline.load_with_subset_context( + load_with_subset_context( loader, subset_context, options=options diff --git a/openpype/tools/mayalookassigner/commands.py b/openpype/tools/mayalookassigner/commands.py index 96fc28243b7..df72e41354e 100644 --- a/openpype/tools/mayalookassigner/commands.py +++ b/openpype/tools/mayalookassigner/commands.py @@ -4,10 +4,11 @@ import maya.cmds as cmds -from openpype.hosts.maya.api import lib - from avalon import io, api +from openpype.pipeline import remove_container +from openpype.hosts.maya.api import lib + from .vray_proxies import get_alembic_ids_cache log = logging.getLogger(__name__) @@ -206,6 +207,6 @@ def remove_unused_looks(): for container in unused: log.info("Removing unused look container: %s", container['objectName']) - api.remove(container) + remove_container(container) log.info("Finished removing unused looks. (see log for details)") diff --git a/openpype/tools/mayalookassigner/vray_proxies.py b/openpype/tools/mayalookassigner/vray_proxies.py index b22ec95a4d8..6a9347449a9 100644 --- a/openpype/tools/mayalookassigner/vray_proxies.py +++ b/openpype/tools/mayalookassigner/vray_proxies.py @@ -12,6 +12,12 @@ from avalon import io, api +from openpype.pipeline import ( + load_container, + loaders_from_representation, + discover_loader_plugins, + get_representation_path, +) from openpype.hosts.maya.api import lib @@ -155,7 +161,7 @@ def get_look_relationships(version_id): "name": "json"}) # Load relationships - shader_relation = api.get_representation_path(json_representation) + shader_relation = get_representation_path(json_representation) with open(shader_relation, "r") as f: relationships = json.load(f) @@ -193,8 +199,8 @@ def load_look(version_id): log.info("Using look for the first time ...") # Load file - loaders = api.loaders_from_representation(api.discover(api.Loader), - representation_id) + all_loaders = discover_loader_plugins() + loaders = loaders_from_representation(all_loaders, representation_id) loader = next( (i for i in loaders if i.__name__ == "LookLoader"), None) if loader is None: @@ -202,7 +208,7 @@ def load_look(version_id): # Reference the look file with lib.maintained_selection(): - container_node = api.load(loader, look_representation) + container_node = load_container(loader, look_representation) # Get container members shader_nodes = lib.get_container_members(container_node) diff --git a/openpype/tools/sceneinventory/model.py b/openpype/tools/sceneinventory/model.py index 6ec3601705d..7173ae751ef 100644 --- a/openpype/tools/sceneinventory/model.py +++ b/openpype/tools/sceneinventory/model.py @@ -7,9 +7,10 @@ import qtawesome from avalon import api, io, schema -from avalon.lib import HeroVersionType +from openpype.pipeline import HeroVersionType from openpype.style import get_default_entity_icon_color from openpype.tools.utils.models import TreeModel, Item +from openpype.modules import ModulesManager from .lib import ( get_site_icons, @@ -17,8 +18,6 @@ get_progress_for_repre ) -from openpype.modules import ModulesManager - class InventoryModel(TreeModel): """The model for the inventory""" diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index 93ea68beb4a..0e7b1b759ae 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -3,7 +3,12 @@ from Qt import QtWidgets, QtCore import qtawesome -from avalon import io, api, pipeline +from avalon import io, pipeline +from openpype.pipeline import ( + discover_loader_plugins, + switch_container, + get_repres_contexts, +) from .widgets import ( ButtonWithMenu, @@ -343,13 +348,13 @@ def _on_action_clicked(self, action): def _get_loaders(self, repre_ids): repre_contexts = None if repre_ids: - repre_contexts = pipeline.get_repres_contexts(repre_ids) + repre_contexts = get_repres_contexts(repre_ids) if not repre_contexts: return list() available_loaders = [] - for loader_plugin in api.discover(api.Loader): + for loader_plugin in discover_loader_plugins(): # Skip loaders without switch method if not hasattr(loader_plugin, "switch"): continue @@ -1352,7 +1357,7 @@ def _trigger_switch(self, loader=None): repre_doc = repres_by_name[container_repre_name] try: - api.switch(container, repre_doc, loader) + switch_container(container, repre_doc, loader) except Exception: msg = ( "Couldn't switch asset." diff --git a/openpype/tools/sceneinventory/view.py b/openpype/tools/sceneinventory/view.py index fb93faefd6e..c38390c6146 100644 --- a/openpype/tools/sceneinventory/view.py +++ b/openpype/tools/sceneinventory/view.py @@ -6,9 +6,13 @@ import qtawesome from avalon import io, api -from avalon.lib import HeroVersionType from openpype import style +from openpype.pipeline import ( + HeroVersionType, + update_container, + remove_container, +) from openpype.modules import ModulesManager from openpype.tools.utils.lib import ( get_progress_for_repre, @@ -196,7 +200,7 @@ def _on_switch_to_versioned(items): version_name = version_name_by_id.get(version_id) if version_name is not None: try: - api.update(item, version_name) + update_container(item, version_name) except AssertionError: self._show_version_error_dialog( version_name, [item] @@ -224,7 +228,7 @@ def _on_switch_to_versioned(items): def _on_update_to_latest(items): for item in items: try: - api.update(item, -1) + update_container(item, -1) except AssertionError: self._show_version_error_dialog(None, [item]) log.warning("Update failed", exc_info=True) @@ -249,7 +253,7 @@ def _on_update_to_latest(items): def _on_update_to_hero(items): for item in items: try: - api.update(item, HeroVersionType(-1)) + update_container(item, HeroVersionType(-1)) except AssertionError: self._show_version_error_dialog('hero', [item]) log.warning("Update failed", exc_info=True) @@ -728,7 +732,7 @@ def _show_version_dialog(self, items): version = versions_by_label[label] for item in items: try: - api.update(item, version) + update_container(item, version) except AssertionError: self._show_version_error_dialog(version, [item]) log.warning("Update failed", exc_info=True) @@ -759,7 +763,7 @@ def _show_remove_warning_dialog(self, items): return for item in items: - api.remove(item) + remove_container(item) self.data_changed.emit() def _show_version_error_dialog(self, version, items): @@ -829,7 +833,7 @@ def update_all(self): # Trigger update to latest for item in outdated_items: try: - api.update(item, -1) + update_container(item, -1) except AssertionError: self._show_version_error_dialog(None, [item]) log.warning("Update failed", exc_info=True) diff --git a/openpype/tools/utils/delegates.py b/openpype/tools/utils/delegates.py index 4ec6079bb7b..d3718b17343 100644 --- a/openpype/tools/utils/delegates.py +++ b/openpype/tools/utils/delegates.py @@ -6,7 +6,7 @@ import Qt from Qt import QtWidgets, QtGui, QtCore -from avalon.lib import HeroVersionType +from openpype.pipeline import HeroVersionType from .models import TreeModel from . import lib