From dcda171dbc410f196a8f21e8ae37ad210b3bf705 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Aug 2021 18:12:48 +0200 Subject: [PATCH] use custom publish plugins `discover` --- openpype/pipeline/create/context.py | 9 +- openpype/pipeline/publish/__init__.py | 9 +- openpype/pipeline/publish/lib.py | 126 ++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 openpype/pipeline/publish/lib.py diff --git a/openpype/pipeline/create/context.py b/openpype/pipeline/create/context.py index 960f5ab6df..1692c91d51 100644 --- a/openpype/pipeline/create/context.py +++ b/openpype/pipeline/create/context.py @@ -427,6 +427,7 @@ class CreateContext: self.instances = [] self.creators = {} + self.publish_discover_result = None self.publish_plugins = [] self.plugins_with_defs = [] self._attr_plugins_by_family = {} @@ -448,18 +449,22 @@ class CreateContext: def reset_plugins(self): import avalon.api - import pyblish.api + import pyblish.logic from openpype.pipeline import OpenPypePyblishPluginMixin + from openpype.pipeline.publish import publish_plugins_discover # Reset publish plugins self._attr_plugins_by_family = {} - publish_plugins = pyblish.api.discover() + discover_result = publish_plugins_discover() + publish_plugins = discover_result.plugins + targets = pyblish.logic.registered_targets() or ["default"] plugins_by_targets = pyblish.logic.plugins_by_targets( publish_plugins, targets ) + self.publish_discover_result = discover_result self.publish_plugins = plugins_by_targets # Collect plugins that can have attribute definitions diff --git a/openpype/pipeline/publish/__init__.py b/openpype/pipeline/publish/__init__.py index 4a18c1a110..7eed98e73a 100644 --- a/openpype/pipeline/publish/__init__.py +++ b/openpype/pipeline/publish/__init__.py @@ -4,8 +4,15 @@ from .publish_plugins import ( OpenPypePyblishPluginMixin ) +from .lib import ( + publish_plugins_discover +) + + __all__ = ( "PublishValidationError", "KnownPublishError", - "OpenPypePyblishPluginMixin" + "OpenPypePyblishPluginMixin", + + "publish_plugins_discover" ) diff --git a/openpype/pipeline/publish/lib.py b/openpype/pipeline/publish/lib.py new file mode 100644 index 0000000000..ba44066484 --- /dev/null +++ b/openpype/pipeline/publish/lib.py @@ -0,0 +1,126 @@ +import os +import sys +import types + +import six +import pyblish.logic + + +class DiscoverResult: + """Hold result of publish plugins discovery. + + Stores discovered plugins duplicated plugins and file paths which + crashed on execution of file. + """ + def __init__(self): + self.plugins = [] + self.crashed_file_paths = {} + self.duplicated_plugins = [] + + def __iter__(self): + for plugin in self.plugins: + yield plugin + + def __getitem__(self, item): + return self.plugins[item] + + def __setitem__(self, item, value): + self.plugins[item] = value + + +def publish_plugins_discover(paths=None): + """Find and return available pyblish plug-ins + + Overriden function from `pyblish` module to be able collect crashed files + and reason of their crash. + + Arguments: + paths (list, optional): Paths to discover plug-ins from. + If no paths are provided, all paths are searched. + + """ + + # The only difference with `pyblish.api.discover` + result = DiscoverResult() + + plugins = dict() + plugin_names = [] + + allow_duplicates = pyblish.logic.ALLOW_DUPLICATES + log = pyblish.logic.log + + # Include plug-ins from registered paths + if not paths: + paths = pyblish.logic.plugin_paths() + + for path in paths: + path = os.path.normpath(path) + if not os.path.isdir(path): + continue + + for fname in os.listdir(path): + if fname.startswith("_"): + continue + + abspath = os.path.join(path, fname) + + if not os.path.isfile(abspath): + continue + + mod_name, mod_ext = os.path.splitext(fname) + + if not mod_ext == ".py": + continue + + module = types.ModuleType(mod_name) + module.__file__ = abspath + + try: + with open(abspath, "rb") as f: + six.exec_(f.read(), module.__dict__) + + # Store reference to original module, to avoid + # garbage collection from collecting it's global + # imports, such as `import os`. + sys.modules[abspath] = module + + except Exception as err: + result.crashed_file_paths[abspath] = sys.exc_info() + + log.debug("Skipped: \"%s\" (%s)", mod_name, err) + continue + + for plugin in pyblish.logic.plugins_from_module(module): + if not allow_duplicates and plugin.__name__ in plugin_names: + result.duplicated_plugins.append(plugin) + log.debug("Duplicate plug-in found: %s", plugin) + continue + + plugin_names.append(plugin.__name__) + + plugin.__module__ = module.__file__ + key = "{0}.{1}".format(plugin.__module__, plugin.__name__) + plugins[key] = plugin + + # Include plug-ins from registration. + # Directly registered plug-ins take precedence. + for plugin in pyblish.logic.registered_plugins(): + if not allow_duplicates and plugin.__name__ in plugin_names: + result.duplicated_plugins.append(plugin) + log.debug("Duplicate plug-in found: %s", plugin) + continue + + plugin_names.append(plugin.__name__) + + plugins[plugin.__name__] = plugin + + plugins = list(plugins.values()) + pyblish.logic.sort(plugins) # In-place + + # In-place user-defined filter + for filter_ in pyblish.logic._registered_plugin_filters: + filter_(plugins) + + result.plugins = plugins + + return result