From bc8d66fdc1a25be8cb2e1afcf6d122b263b90125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 28 Oct 2020 13:03:11 +0100 Subject: [PATCH 01/19] extracted few things from lib.py --- pype/lib.py | 109 ++------------------------------------- pype/lib/__init__.py | 11 ++++ pype/lib/hooks.py | 71 +++++++++++++++++++++++++ pype/lib/plugin_tools.py | 59 +++++++++++++++++++++ 4 files changed, 144 insertions(+), 106 deletions(-) create mode 100644 pype/lib/__init__.py create mode 100644 pype/lib/hooks.py create mode 100644 pype/lib/plugin_tools.py diff --git a/pype/lib.py b/pype/lib.py index afcfa98307..ef3c1c1ae5 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -1,6 +1,6 @@ import os import sys -import types + import re import uuid import json @@ -11,15 +11,14 @@ import copy import contextlib import subprocess import getpass -import inspect import acre import platform -from abc import ABCMeta, abstractmethod from avalon import io, pipeline -import six + import avalon.api from .api import config, Anatomy, Logger +from .lib import execute_hook log = logging.getLogger(__name__) @@ -551,53 +550,6 @@ def set_io_database(): io.install() -def filter_pyblish_plugins(plugins): - """ - This servers as plugin filter / modifier for pyblish. It will load plugin - definitions from presets and filter those needed to be excluded. - - :param plugins: Dictionary of plugins produced by :mod:`pyblish-base` - `discover()` method. - :type plugins: Dict - """ - from pyblish import api - - host = api.current_host() - - presets = config.get_presets().get('plugins', {}) - - # iterate over plugins - for plugin in plugins[:]: - # skip if there are no presets to process - if not presets: - continue - - file = os.path.normpath(inspect.getsourcefile(plugin)) - file = os.path.normpath(file) - - # host determined from path - host_from_file = file.split(os.path.sep)[-3:-2][0] - plugin_kind = file.split(os.path.sep)[-2:-1][0] - - try: - config_data = presets[host]["publish"][plugin.__name__] - except KeyError: - try: - config_data = presets[host_from_file][plugin_kind][plugin.__name__] # noqa: E501 - except KeyError: - continue - - for option, value in config_data.items(): - if option == "enabled" and value is False: - log.info('removing plugin {}'.format(plugin.__name__)) - plugins.remove(plugin) - else: - log.info('setting {}:{} on plugin {}'.format( - option, value, plugin.__name__)) - - setattr(plugin, option, value) - - def get_subsets(asset_name, regex_filter=None, version=None, @@ -715,61 +667,6 @@ class CustomNone: return "".format(str(self.identifier)) -def execute_hook(hook, *args, **kwargs): - """ - This will load hook file, instantiate class and call `execute` method - on it. Hook must be in a form: - - `$PYPE_SETUP_PATH/repos/pype/path/to/hook.py/HookClass` - - This will load `hook.py`, instantiate HookClass and then execute_hook - `execute(*args, **kwargs)` - - :param hook: path to hook class - :type hook: str - """ - - class_name = hook.split("/")[-1] - - abspath = os.path.join(os.getenv('PYPE_SETUP_PATH'), - 'repos', 'pype', *hook.split("/")[:-1]) - - mod_name, mod_ext = os.path.splitext(os.path.basename(abspath)) - - if not mod_ext == ".py": - return False - - module = types.ModuleType(mod_name) - module.__file__ = abspath - - try: - with open(abspath) as f: - six.exec_(f.read(), module.__dict__) - - sys.modules[abspath] = module - - except Exception as exp: - log.exception("loading hook failed: {}".format(exp), - exc_info=True) - return False - - obj = getattr(module, class_name) - hook_obj = obj() - ret_val = hook_obj.execute(*args, **kwargs) - return ret_val - - -@six.add_metaclass(ABCMeta) -class PypeHook: - - def __init__(self): - pass - - @abstractmethod - def execute(self, *args, **kwargs): - pass - - def get_linked_assets(asset_entity): """Return linked assets for `asset_entity`.""" inputs = asset_entity["data"].get("inputs", []) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py new file mode 100644 index 0000000000..51f305950c --- /dev/null +++ b/pype/lib/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +"""Pype lib module.""" +from .hooks import PypeHook, execute_hook +from .plugin_tools import filter_pyblish_plugins + +__all__ = [ + "PypeHook", + "execute_hook", + + "filter_pyblish_plugins" +] diff --git a/pype/lib/hooks.py b/pype/lib/hooks.py new file mode 100644 index 0000000000..425ad36342 --- /dev/null +++ b/pype/lib/hooks.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +"""Package containing code for handling hooks.""" +import os +import sys +import types +import logging +from abc import ABCMeta, abstractmethod + +import six + + +log = logging.getLogger(__name__) + + +@six.add_metaclass(ABCMeta) +class PypeHook: + """Abstract class from all hooks should inherit.""" + + def __init__(self): + """Constructor.""" + pass + + @abstractmethod + def execute(self, *args, **kwargs): + """Abstract execute method.""" + pass + + +def execute_hook(hook, *args, **kwargs): + """Execute hook with arguments. + + This will load hook file, instantiate class and call + :meth:`PypeHook.execute` method on it. Hook must be in a form:: + + $PYPE_SETUP_PATH/repos/pype/path/to/hook.py/HookClass + + This will load `hook.py`, instantiate HookClass and then execute_hook + `execute(*args, **kwargs)` + + Args: + hook (str): path to hook class. + + """ + class_name = hook.split("/")[-1] + + abspath = os.path.join(os.getenv('PYPE_SETUP_PATH'), + 'repos', 'pype', *hook.split("/")[:-1]) + + mod_name, mod_ext = os.path.splitext(os.path.basename(abspath)) + + if not mod_ext == ".py": + return False + + module = types.ModuleType(mod_name) + module.__file__ = abspath + + try: + with open(abspath) as f: + six.exec_(f.read(), module.__dict__) + + sys.modules[abspath] = module + + except Exception as exp: + log.exception("loading hook failed: {}".format(exp), + exc_info=True) + return False + + obj = getattr(module, class_name) + hook_obj = obj() + ret_val = hook_obj.execute(*args, **kwargs) + return ret_val diff --git a/pype/lib/plugin_tools.py b/pype/lib/plugin_tools.py new file mode 100644 index 0000000000..498da075c5 --- /dev/null +++ b/pype/lib/plugin_tools.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +"""Avalon/Pyblish plugin tools.""" +import os +import inspect +import logging + +from .api import config + + +log = logging.getLogger(__name__) + + +def filter_pyblish_plugins(plugins): + """Filter pyblish plugins by presets. + + This servers as plugin filter / modifier for pyblish. It will load plugin + definitions from presets and filter those needed to be excluded. + + Args: + plugins (dict): Dictionary of plugins produced by :mod:`pyblish-base` + `discover()` method. + + """ + from pyblish import api + + host = api.current_host() + + presets = config.get_presets().get('plugins', {}) + + # iterate over plugins + for plugin in plugins[:]: + # skip if there are no presets to process + if not presets: + continue + + file = os.path.normpath(inspect.getsourcefile(plugin)) + file = os.path.normpath(file) + + # host determined from path + host_from_file = file.split(os.path.sep)[-3:-2][0] + plugin_kind = file.split(os.path.sep)[-2:-1][0] + + try: + config_data = presets[host]["publish"][plugin.__name__] + except KeyError: + try: + config_data = presets[host_from_file][plugin_kind][plugin.__name__] # noqa: E501 + except KeyError: + continue + + for option, value in config_data.items(): + if option == "enabled" and value is False: + log.info('removing plugin {}'.format(plugin.__name__)) + plugins.remove(plugin) + else: + log.info('setting {}:{} on plugin {}'.format( + option, value, plugin.__name__)) + + setattr(plugin, option, value) From a2a10048b66e196922d5b3e823abc842edcccbb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 28 Oct 2020 15:11:39 +0100 Subject: [PATCH 02/19] create lib module --- pype/lib/__init__.py | 1 + pype/{lib.py => lib/lib_old.py} | 0 2 files changed, 1 insertion(+) create mode 100644 pype/lib/__init__.py rename pype/{lib.py => lib/lib_old.py} (100%) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py new file mode 100644 index 0000000000..ad42cd1dee --- /dev/null +++ b/pype/lib/__init__.py @@ -0,0 +1 @@ +from .lib_old import * diff --git a/pype/lib.py b/pype/lib/lib_old.py similarity index 100% rename from pype/lib.py rename to pype/lib/lib_old.py From eb9a67acf7a742000bec04a7b1303ca1e36fea25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 28 Oct 2020 15:16:13 +0100 Subject: [PATCH 03/19] few fixes --- pype/lib/lib_old.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index ef3c1c1ae5..eb22556e2c 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -1,6 +1,5 @@ import os import sys - import re import uuid import json @@ -13,12 +12,11 @@ import subprocess import getpass import acre import platform +from . import execute_hook from avalon import io, pipeline - import avalon.api from .api import config, Anatomy, Logger -from .lib import execute_hook log = logging.getLogger(__name__) From c13e48c0262cb965f85e1a606fb2b943b9a3a0d7 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 28 Oct 2020 16:02:07 +0100 Subject: [PATCH 04/19] lib changed to lib/old_lib to have a starting point --- pype/lib/__init__.py | 39 ++++++++++++++++++++++++++++++++++++++- pype/lib/lib_old.py | 2 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index ad42cd1dee..d8ce8badbc 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -1 +1,38 @@ -from .lib_old import * +# -*- coding: utf-8 -*- +"""Pype lib module.""" +from .lib_old import ( + _subprocess, + get_paths_from_environ, + get_ffmpeg_tool_path, + get_hierarchy, + add_tool_to_environment, + modified_environ, + pairwise, + grouper, + is_latest, + any_outdated, + _rreplace, + version_up, + switch_item, + _get_host_name, + get_asset, + get_project, + get_version_from_path, + get_last_version_from_path, + get_avalon_database, + set_io_database, + filter_pyblish_plugins, + get_subsets, + CustomNone, + execute_hook, + PypeHook, + get_linked_assets, + map_subsets_by_family, + BuildWorkfile, + ffprobe_streams, + source_hash, + get_latest_version, + ApplicationLaunchFailed, + launch_application, + ApplicationAction + ) diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index afcfa98307..e6de3882e9 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -19,7 +19,7 @@ from abc import ABCMeta, abstractmethod from avalon import io, pipeline import six import avalon.api -from .api import config, Anatomy, Logger +from ..api import config, Anatomy, Logger log = logging.getLogger(__name__) From d299c21a0abc73a961b5095cb5c9f7dcd43bc072 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 28 Oct 2020 16:03:52 +0100 Subject: [PATCH 05/19] remove functions from old-lib import --- pype/lib/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 6286d26078..12633959aa 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -21,11 +21,8 @@ from .lib_old import ( get_last_version_from_path, get_avalon_database, set_io_database, - filter_pyblish_plugins, get_subsets, CustomNone, - execute_hook, - PypeHook, get_linked_assets, map_subsets_by_family, BuildWorkfile, From d11ef77236bee628c5f0547c9f7e3ba04c34f0c3 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 28 Oct 2020 16:07:09 +0100 Subject: [PATCH 06/19] fix relative imports for 2.x compatibility --- pype/lib/lib_old.py | 2 +- pype/lib/plugin_tools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 224777b8ca..08146309cc 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -12,7 +12,7 @@ import subprocess import getpass import acre import platform -from . import execute_hook +from pype.lib.hooks import execute_hook from avalon import io, pipeline import avalon.api diff --git a/pype/lib/plugin_tools.py b/pype/lib/plugin_tools.py index 498da075c5..066f1ff20a 100644 --- a/pype/lib/plugin_tools.py +++ b/pype/lib/plugin_tools.py @@ -4,7 +4,7 @@ import os import inspect import logging -from .api import config +from ..api import config log = logging.getLogger(__name__) From 98012be8cc0cecd75473ae4798959f93e058f4c2 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 3 Nov 2020 09:51:30 +0100 Subject: [PATCH 07/19] add deprecated.py --- pype/lib/deprecated.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pype/lib/deprecated.py diff --git a/pype/lib/deprecated.py b/pype/lib/deprecated.py new file mode 100644 index 0000000000..e69de29bb2 From 15c03de4852ee337cc4f80a46543929bb9a559d2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 10:54:10 +0100 Subject: [PATCH 08/19] moved `get_avalon_database` and `set_io_database` to deprecated --- pype/lib/__init__.py | 10 ++++++++-- pype/lib/deprecated.py | 26 ++++++++++++++++++++++++++ pype/lib/lib_old.py | 10 +--------- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 12633959aa..4ca5fa999c 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -1,5 +1,10 @@ # -*- coding: utf-8 -*- """Pype lib module.""" + +from .deprecated import ( + get_avalon_database, + set_io_database +) from .lib_old import ( _subprocess, get_paths_from_environ, @@ -19,8 +24,6 @@ from .lib_old import ( get_project, get_version_from_path, get_last_version_from_path, - get_avalon_database, - set_io_database, get_subsets, CustomNone, get_linked_assets, @@ -38,6 +41,9 @@ from .hooks import PypeHook, execute_hook from .plugin_tools import filter_pyblish_plugins __all__ = [ + "get_avalon_database", + "set_io_database", + "PypeHook", "execute_hook", diff --git a/pype/lib/deprecated.py b/pype/lib/deprecated.py index e69de29bb2..e7296f67ef 100644 --- a/pype/lib/deprecated.py +++ b/pype/lib/deprecated.py @@ -0,0 +1,26 @@ +import os + +from avalon import io + + +def get_avalon_database(): + """Mongo database used in avalon's io. + + * Function is not used in pype 3.0 where was replaced with usage of + AvalonMongoDB. + """ + if io._database is None: + set_io_database() + return io._database + + +def set_io_database(): + """Set avalon's io context with environemnts. + + * Function is not used in pype 3.0 where was replaced with usage of + AvalonMongoDB. + """ + required_keys = ["AVALON_PROJECT", "AVALON_ASSET", "AVALON_SILO"] + for key in required_keys: + os.environ[key] = os.environ.get(key, "") + io.install() diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 08146309cc..7284a1026d 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -13,6 +13,7 @@ import getpass import acre import platform from pype.lib.hooks import execute_hook +from .deprecated import get_avalon_database from avalon import io, pipeline import avalon.api @@ -535,17 +536,8 @@ def get_last_version_from_path(path_dir, filter): return None -def get_avalon_database(): - if io._database is None: - set_io_database() - return io._database -def set_io_database(): - required_keys = ["AVALON_PROJECT", "AVALON_ASSET", "AVALON_SILO"] - for key in required_keys: - os.environ[key] = os.environ.get(key, "") - io.install() def get_subsets(asset_name, From 0096705347240e33fbf7473aacd8bc2745f9a51d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 10:54:28 +0100 Subject: [PATCH 09/19] removed unused `CustomNone` --- pype/lib/__init__.py | 1 - pype/lib/lib_old.py | 39 --------------------------------------- 2 files changed, 40 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 4ca5fa999c..bf3771c0e7 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -25,7 +25,6 @@ from .lib_old import ( get_version_from_path, get_last_version_from_path, get_subsets, - CustomNone, get_linked_assets, map_subsets_by_family, BuildWorkfile, diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 7284a1026d..6b142c8325 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -618,45 +618,6 @@ def get_subsets(asset_name, return output_dict -class CustomNone: - """Created object can be used as custom None (not equal to None). - - WARNING: Multiple created objects are not equal either. - Exmple: - >>> a = CustomNone() - >>> a == None - False - >>> b = CustomNone() - >>> a == b - False - >>> a == a - True - """ - - def __init__(self): - """Create uuid as identifier for custom None.""" - self.identifier = str(uuid.uuid4()) - - def __bool__(self): - """Return False (like default None).""" - return False - - def __eq__(self, other): - """Equality is compared by identifier value.""" - if type(other) == type(self): - if other.identifier == self.identifier: - return True - return False - - def __str__(self): - """Return value of identifier when converted to string.""" - return self.identifier - - def __repr__(self): - """Representation of custom None.""" - return "".format(str(self.identifier)) - - def get_linked_assets(asset_entity): """Return linked assets for `asset_entity`.""" inputs = asset_entity["data"].get("inputs", []) From dbfbe9983424db2af695badd2ec48201b435b1df Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 10:56:53 +0100 Subject: [PATCH 10/19] removed single line function `get_project` --- pype/hosts/hiero/lib.py | 4 +++- pype/hosts/maya/lib.py | 4 ++-- pype/hosts/nuke/lib.py | 2 +- pype/lib/__init__.py | 1 - pype/lib/lib_old.py | 5 ----- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/pype/hosts/hiero/lib.py b/pype/hosts/hiero/lib.py index db7199a190..a508343bfa 100644 --- a/pype/hosts/hiero/lib.py +++ b/pype/hosts/hiero/lib.py @@ -4,6 +4,7 @@ import sys import hiero import pyblish.api import avalon.api as avalon +import avalon.io from avalon.vendor.Qt import (QtWidgets, QtGui) import pype.api as pype from pype.api import Logger, Anatomy @@ -58,7 +59,8 @@ def sync_avalon_data_to_workfile(): project.setProjectRoot(active_project_root) # get project data from avalon db - project_data = pype.get_project()["data"] + project_doc = avalon.io.find_one({"type": "project"}) + project_data = project_doc["data"] log.debug("project_data: {}".format(project_data)) diff --git a/pype/hosts/maya/lib.py b/pype/hosts/maya/lib.py index 2dda198d45..e7ca5ec4dc 100644 --- a/pype/hosts/maya/lib.py +++ b/pype/hosts/maya/lib.py @@ -1857,8 +1857,8 @@ def set_context_settings(): """ # Todo (Wijnand): apply renderer and resolution of project - - project_data = lib.get_project()["data"] + project_doc = io.find_one({"type": "project"}) + project_data = project_doc["data"] asset_data = lib.get_asset()["data"] # Set project fps diff --git a/pype/hosts/nuke/lib.py b/pype/hosts/nuke/lib.py index 8fd84b8555..24cd4f9a97 100644 --- a/pype/hosts/nuke/lib.py +++ b/pype/hosts/nuke/lib.py @@ -195,7 +195,7 @@ def format_anatomy(data): if not version: file = script_name() data["version"] = pype.get_version_from_path(file) - project_document = pype.get_project() + project_document = io.find_one({"type": "project"}) data.update({ "subset": data["avalon"]["subset"], "asset": data["avalon"]["asset"], diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index bf3771c0e7..b2bbd9e60d 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -21,7 +21,6 @@ from .lib_old import ( switch_item, _get_host_name, get_asset, - get_project, get_version_from_path, get_last_version_from_path, get_subsets, diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 6b142c8325..747865f08d 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -472,11 +472,6 @@ def get_asset(asset_name=None): return asset_document -def get_project(): - io.install() - return io.find_one({"type": "project"}) - - def get_version_from_path(file): """ Finds version number in file path string From 83578a90b27f1f327b99c46e1306f7687d55c376 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:01:25 +0100 Subject: [PATCH 11/19] removed unused import --- pype/lib/lib_old.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 747865f08d..309ea4190f 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -1,7 +1,6 @@ import os import sys import re -import uuid import json import collections import logging From d46f6fba12a547daa5c7e4c49f915a5f05228979 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:11:02 +0100 Subject: [PATCH 12/19] moved independent imports as first in lib's __init__ --- pype/lib/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index b2bbd9e60d..a9cbc8c6ca 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -5,6 +5,9 @@ from .deprecated import ( get_avalon_database, set_io_database ) + +from .hooks import PypeHook, execute_hook +from .plugin_tools import filter_pyblish_plugins from .lib_old import ( _subprocess, get_paths_from_environ, @@ -35,8 +38,6 @@ from .lib_old import ( ApplicationAction ) -from .hooks import PypeHook, execute_hook -from .plugin_tools import filter_pyblish_plugins __all__ = [ "get_avalon_database", From 2ce0e7a46549659c198340dc8139fbaaa0960802 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:13:05 +0100 Subject: [PATCH 13/19] removed `get_project` import from pype.api --- pype/api.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pype/api.py b/pype/api.py index c1bf84b4ef..2c7dfa73f0 100644 --- a/pype/api.py +++ b/pype/api.py @@ -39,7 +39,6 @@ from .action import ( from .lib import ( version_up, get_asset, - get_project, get_hierarchy, get_subsets, get_version_from_path, @@ -88,7 +87,6 @@ __all__ = [ # get contextual data "version_up", - "get_project", "get_hierarchy", "get_asset", "get_subsets", From 9887dc40644207ac3f94af552535a7a81394bc9e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:13:35 +0100 Subject: [PATCH 14/19] moved applications import from lib_old --- pype/lib/__init__.py | 20 +- pype/lib/applications.py | 385 +++++++++++++++++++++++++++++++++++++++ pype/lib/lib_old.py | 376 -------------------------------------- 3 files changed, 399 insertions(+), 382 deletions(-) create mode 100644 pype/lib/applications.py diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index a9cbc8c6ca..6620bd5a12 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -7,7 +7,15 @@ from .deprecated import ( ) from .hooks import PypeHook, execute_hook + +from .applications import ( + ApplicationLaunchFailed, + launch_application, + ApplicationAction +) + from .plugin_tools import filter_pyblish_plugins + from .lib_old import ( _subprocess, get_paths_from_environ, @@ -32,12 +40,8 @@ from .lib_old import ( BuildWorkfile, ffprobe_streams, source_hash, - get_latest_version, - ApplicationLaunchFailed, - launch_application, - ApplicationAction - ) - + get_latest_version +) __all__ = [ "get_avalon_database", @@ -46,5 +50,9 @@ __all__ = [ "PypeHook", "execute_hook", + "ApplicationLaunchFailed", + "launch_application", + "ApplicationAction", + "filter_pyblish_plugins" ] diff --git a/pype/lib/applications.py b/pype/lib/applications.py new file mode 100644 index 0000000000..f4861ae866 --- /dev/null +++ b/pype/lib/applications.py @@ -0,0 +1,385 @@ +import os +import sys +import getpass +import copy +import platform +import logging + +import acre + +import avalon.lib + +from ..api import Anatomy, Logger, config +from .hooks import execute_hook +from .deprecated import get_avalon_database + +log = logging.getLogger(__name__) + + +class ApplicationLaunchFailed(Exception): + pass + + +def launch_application(project_name, asset_name, task_name, app_name): + database = get_avalon_database() + project_document = database[project_name].find_one({"type": "project"}) + asset_document = database[project_name].find_one({ + "type": "asset", + "name": asset_name + }) + + asset_doc_parents = asset_document["data"].get("parents") + hierarchy = "/".join(asset_doc_parents) + + app_def = avalon.lib.get_application(app_name) + app_label = app_def.get("ftrack_label", app_def.get("label", app_name)) + + host_name = app_def["application_dir"] + data = { + "project": { + "name": project_document["name"], + "code": project_document["data"].get("code") + }, + "task": task_name, + "asset": asset_name, + "app": host_name, + "hierarchy": hierarchy + } + + try: + anatomy = Anatomy(project_name) + anatomy_filled = anatomy.format(data) + workdir = os.path.normpath(anatomy_filled["work"]["folder"]) + + except Exception as exc: + raise ApplicationLaunchFailed( + "Error in anatomy.format: {}".format(str(exc)) + ) + + try: + os.makedirs(workdir) + except FileExistsError: + pass + + last_workfile_path = None + extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get(host_name) + if extensions: + # Find last workfile + file_template = anatomy.templates["work"]["file"] + data.update({ + "version": 1, + "user": os.environ.get("PYPE_USERNAME") or getpass.getuser(), + "ext": extensions[0] + }) + + last_workfile_path = avalon.api.last_workfile( + workdir, file_template, data, extensions, True + ) + + # set environments for Avalon + prep_env = copy.deepcopy(os.environ) + prep_env.update({ + "AVALON_PROJECT": project_name, + "AVALON_ASSET": asset_name, + "AVALON_TASK": task_name, + "AVALON_APP": host_name, + "AVALON_APP_NAME": app_name, + "AVALON_HIERARCHY": hierarchy, + "AVALON_WORKDIR": workdir + }) + + start_last_workfile = avalon.api.should_start_last_workfile( + project_name, host_name, task_name + ) + # Store boolean as "0"(False) or "1"(True) + prep_env["AVALON_OPEN_LAST_WORKFILE"] = ( + str(int(bool(start_last_workfile))) + ) + + if ( + start_last_workfile + and last_workfile_path + and os.path.exists(last_workfile_path) + ): + prep_env["AVALON_LAST_WORKFILE"] = last_workfile_path + + prep_env.update(anatomy.roots_obj.root_environments()) + + # collect all the 'environment' attributes from parents + tools_attr = [prep_env["AVALON_APP"], prep_env["AVALON_APP_NAME"]] + tools_env = asset_document["data"].get("tools_env") or [] + tools_attr.extend(tools_env) + + tools_env = acre.get_tools(tools_attr) + env = acre.compute(tools_env) + env = acre.merge(env, current_env=dict(prep_env)) + + # Get path to execute + st_temp_path = os.environ["PYPE_CONFIG"] + os_plat = platform.system().lower() + + # Path to folder with launchers + path = os.path.join(st_temp_path, "launchers", os_plat) + + # Full path to executable launcher + execfile = None + + launch_hook = app_def.get("launch_hook") + if launch_hook: + log.info("launching hook: {}".format(launch_hook)) + ret_val = execute_hook(launch_hook, env=env) + if not ret_val: + raise ApplicationLaunchFailed( + "Hook didn't finish successfully {}".format(app_label) + ) + + if sys.platform == "win32": + for ext in os.environ["PATHEXT"].split(os.pathsep): + fpath = os.path.join(path.strip('"'), app_def["executable"] + ext) + if os.path.isfile(fpath) and os.access(fpath, os.X_OK): + execfile = fpath + break + + # Run SW if was found executable + if execfile is None: + raise ApplicationLaunchFailed( + "We didn't find launcher for {}".format(app_label) + ) + + popen = avalon.lib.launch( + executable=execfile, args=[], environment=env + ) + + elif ( + sys.platform.startswith("linux") + or sys.platform.startswith("darwin") + ): + execfile = os.path.join(path.strip('"'), app_def["executable"]) + # Run SW if was found executable + if execfile is None: + raise ApplicationLaunchFailed( + "We didn't find launcher for {}".format(app_label) + ) + + if not os.path.isfile(execfile): + raise ApplicationLaunchFailed( + "Launcher doesn't exist - {}".format(execfile) + ) + + try: + fp = open(execfile) + except PermissionError as perm_exc: + raise ApplicationLaunchFailed( + "Access denied on launcher {} - {}".format(execfile, perm_exc) + ) + + fp.close() + # check executable permission + if not os.access(execfile, os.X_OK): + raise ApplicationLaunchFailed( + "No executable permission - {}".format(execfile) + ) + + popen = avalon.lib.launch( # noqa: F841 + "/usr/bin/env", args=["bash", execfile], environment=env + ) + return popen + + +class ApplicationAction(avalon.api.Action): + """Default application launcher + + This is a convenience application Action that when "config" refers to a + parsed application `.toml` this can launch the application. + + """ + _log = None + config = None + group = None + variant = None + required_session_keys = ( + "AVALON_PROJECT", + "AVALON_ASSET", + "AVALON_TASK" + ) + + @property + def log(self): + if self._log is None: + self._log = Logger().get_logger(self.__class__.__name__) + return self._log + + def is_compatible(self, session): + for key in self.required_session_keys: + if key not in session: + return False + return True + + def process(self, session, **kwargs): + """Process the full Application action""" + + project_name = session["AVALON_PROJECT"] + asset_name = session["AVALON_ASSET"] + task_name = session["AVALON_TASK"] + launch_application( + project_name, asset_name, task_name, self.name + ) + + self._ftrack_after_launch_procedure( + project_name, asset_name, task_name + ) + + def _ftrack_after_launch_procedure( + self, project_name, asset_name, task_name + ): + # TODO move to launch hook + required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") + for key in required_keys: + if not os.environ.get(key): + self.log.debug(( + "Missing required environment \"{}\"" + " for Ftrack after launch procedure." + ).format(key)) + return + + try: + import ftrack_api + session = ftrack_api.Session(auto_connect_event_hub=True) + self.log.debug("Ftrack session created") + except Exception: + self.log.warning("Couldn't create Ftrack session") + return + + try: + entity = self._find_ftrack_task_entity( + session, project_name, asset_name, task_name + ) + self._ftrack_status_change(session, entity, project_name) + self._start_timer(session, entity, ftrack_api) + except Exception: + self.log.warning( + "Couldn't finish Ftrack procedure.", exc_info=True + ) + return + + finally: + session.close() + + def _find_ftrack_task_entity( + self, session, project_name, asset_name, task_name + ): + project_entity = session.query( + "Project where full_name is \"{}\"".format(project_name) + ).first() + if not project_entity: + self.log.warning( + "Couldn't find project \"{}\" in Ftrack.".format(project_name) + ) + return + + potential_task_entities = session.query(( + "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" + ).format(asset_name, project_entity["id"])).all() + filtered_entities = [] + for _entity in potential_task_entities: + if ( + _entity.entity_type.lower() == "task" + and _entity["name"] == task_name + ): + filtered_entities.append(_entity) + + if not filtered_entities: + self.log.warning(( + "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + if len(filtered_entities) > 1: + self.log.warning(( + "Found more than one task \"{}\"" + " under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + return filtered_entities[0] + + def _ftrack_status_change(self, session, entity, project_name): + presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] + statuses = presets.get("status_update") + if not statuses: + return + + actual_status = entity["status"]["name"].lower() + already_tested = set() + ent_path = "/".join( + [ent["name"] for ent in entity["link"]] + ) + while True: + next_status_name = None + for key, value in statuses.items(): + if key in already_tested: + continue + if actual_status in value or "_any_" in value: + if key != "_ignore_": + next_status_name = key + already_tested.add(key) + break + already_tested.add(key) + + if next_status_name is None: + break + + try: + query = "Status where name is \"{}\"".format( + next_status_name + ) + status = session.query(query).one() + + entity["status"] = status + session.commit() + self.log.debug("Changing status to \"{}\" <{}>".format( + next_status_name, ent_path + )) + break + + except Exception: + session.rollback() + msg = ( + "Status \"{}\" in presets wasn't found" + " on Ftrack entity type \"{}\"" + ).format(next_status_name, entity.entity_type) + self.log.warning(msg) + + def _start_timer(self, session, entity, _ftrack_api): + self.log.debug("Triggering timer start.") + + user_entity = session.query("User where username is \"{}\"".format( + os.environ["FTRACK_API_USER"] + )).first() + if not user_entity: + self.log.warning( + "Couldn't find user with username \"{}\" in Ftrack".format( + os.environ["FTRACK_API_USER"] + ) + ) + return + + source = { + "user": { + "id": user_entity["id"], + "username": user_entity["username"] + } + } + event_data = { + "actionIdentifier": "start.timer", + "selection": [{"entityId": entity["id"], "entityType": "task"}] + } + session.event_hub.publish( + _ftrack_api.event.base.Event( + topic="ftrack.action.launch", + data=event_data, + source=source + ), + on_error="ignore" + ) + self.log.debug("Timer start triggered successfully.") diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 309ea4190f..30790651d4 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -1,18 +1,11 @@ import os -import sys import re import json import collections import logging import itertools -import copy import contextlib import subprocess -import getpass -import acre -import platform -from pype.lib.hooks import execute_hook -from .deprecated import get_avalon_database from avalon import io, pipeline import avalon.api @@ -1346,372 +1339,3 @@ def get_latest_version(asset_name, subset_name, dbcon=None, project_name=None): ) return None return version_doc - - -class ApplicationLaunchFailed(Exception): - pass - - -def launch_application(project_name, asset_name, task_name, app_name): - database = get_avalon_database() - project_document = database[project_name].find_one({"type": "project"}) - asset_document = database[project_name].find_one({ - "type": "asset", - "name": asset_name - }) - - asset_doc_parents = asset_document["data"].get("parents") - hierarchy = "/".join(asset_doc_parents) - - app_def = avalon.lib.get_application(app_name) - app_label = app_def.get("ftrack_label", app_def.get("label", app_name)) - - host_name = app_def["application_dir"] - data = { - "project": { - "name": project_document["name"], - "code": project_document["data"].get("code") - }, - "task": task_name, - "asset": asset_name, - "app": host_name, - "hierarchy": hierarchy - } - - try: - anatomy = Anatomy(project_name) - anatomy_filled = anatomy.format(data) - workdir = os.path.normpath(anatomy_filled["work"]["folder"]) - - except Exception as exc: - raise ApplicationLaunchFailed( - "Error in anatomy.format: {}".format(str(exc)) - ) - - try: - os.makedirs(workdir) - except FileExistsError: - pass - - last_workfile_path = None - extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get(host_name) - if extensions: - # Find last workfile - file_template = anatomy.templates["work"]["file"] - data.update({ - "version": 1, - "user": os.environ.get("PYPE_USERNAME") or getpass.getuser(), - "ext": extensions[0] - }) - - last_workfile_path = avalon.api.last_workfile( - workdir, file_template, data, extensions, True - ) - - # set environments for Avalon - prep_env = copy.deepcopy(os.environ) - prep_env.update({ - "AVALON_PROJECT": project_name, - "AVALON_ASSET": asset_name, - "AVALON_TASK": task_name, - "AVALON_APP": host_name, - "AVALON_APP_NAME": app_name, - "AVALON_HIERARCHY": hierarchy, - "AVALON_WORKDIR": workdir - }) - - start_last_workfile = avalon.api.should_start_last_workfile( - project_name, host_name, task_name - ) - # Store boolean as "0"(False) or "1"(True) - prep_env["AVALON_OPEN_LAST_WORKFILE"] = ( - str(int(bool(start_last_workfile))) - ) - - if ( - start_last_workfile - and last_workfile_path - and os.path.exists(last_workfile_path) - ): - prep_env["AVALON_LAST_WORKFILE"] = last_workfile_path - - prep_env.update(anatomy.roots_obj.root_environments()) - - # collect all the 'environment' attributes from parents - tools_attr = [prep_env["AVALON_APP"], prep_env["AVALON_APP_NAME"]] - tools_env = asset_document["data"].get("tools_env") or [] - tools_attr.extend(tools_env) - - tools_env = acre.get_tools(tools_attr) - env = acre.compute(tools_env) - env = acre.merge(env, current_env=dict(prep_env)) - - # Get path to execute - st_temp_path = os.environ["PYPE_CONFIG"] - os_plat = platform.system().lower() - - # Path to folder with launchers - path = os.path.join(st_temp_path, "launchers", os_plat) - - # Full path to executable launcher - execfile = None - - launch_hook = app_def.get("launch_hook") - if launch_hook: - log.info("launching hook: {}".format(launch_hook)) - ret_val = execute_hook(launch_hook, env=env) - if not ret_val: - raise ApplicationLaunchFailed( - "Hook didn't finish successfully {}".format(app_label) - ) - - if sys.platform == "win32": - for ext in os.environ["PATHEXT"].split(os.pathsep): - fpath = os.path.join(path.strip('"'), app_def["executable"] + ext) - if os.path.isfile(fpath) and os.access(fpath, os.X_OK): - execfile = fpath - break - - # Run SW if was found executable - if execfile is None: - raise ApplicationLaunchFailed( - "We didn't find launcher for {}".format(app_label) - ) - - popen = avalon.lib.launch( - executable=execfile, args=[], environment=env - ) - - elif ( - sys.platform.startswith("linux") - or sys.platform.startswith("darwin") - ): - execfile = os.path.join(path.strip('"'), app_def["executable"]) - # Run SW if was found executable - if execfile is None: - raise ApplicationLaunchFailed( - "We didn't find launcher for {}".format(app_label) - ) - - if not os.path.isfile(execfile): - raise ApplicationLaunchFailed( - "Launcher doesn't exist - {}".format(execfile) - ) - - try: - fp = open(execfile) - except PermissionError as perm_exc: - raise ApplicationLaunchFailed( - "Access denied on launcher {} - {}".format(execfile, perm_exc) - ) - - fp.close() - # check executable permission - if not os.access(execfile, os.X_OK): - raise ApplicationLaunchFailed( - "No executable permission - {}".format(execfile) - ) - - popen = avalon.lib.launch( # noqa: F841 - "/usr/bin/env", args=["bash", execfile], environment=env - ) - return popen - - -class ApplicationAction(avalon.api.Action): - """Default application launcher - - This is a convenience application Action that when "config" refers to a - parsed application `.toml` this can launch the application. - - """ - _log = None - config = None - group = None - variant = None - required_session_keys = ( - "AVALON_PROJECT", - "AVALON_ASSET", - "AVALON_TASK" - ) - - @property - def log(self): - if self._log is None: - self._log = Logger().get_logger(self.__class__.__name__) - return self._log - - def is_compatible(self, session): - for key in self.required_session_keys: - if key not in session: - return False - return True - - def process(self, session, **kwargs): - """Process the full Application action""" - - project_name = session["AVALON_PROJECT"] - asset_name = session["AVALON_ASSET"] - task_name = session["AVALON_TASK"] - launch_application( - project_name, asset_name, task_name, self.name - ) - - self._ftrack_after_launch_procedure( - project_name, asset_name, task_name - ) - - def _ftrack_after_launch_procedure( - self, project_name, asset_name, task_name - ): - # TODO move to launch hook - required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") - for key in required_keys: - if not os.environ.get(key): - self.log.debug(( - "Missing required environment \"{}\"" - " for Ftrack after launch procedure." - ).format(key)) - return - - try: - import ftrack_api - session = ftrack_api.Session(auto_connect_event_hub=True) - self.log.debug("Ftrack session created") - except Exception: - self.log.warning("Couldn't create Ftrack session") - return - - try: - entity = self._find_ftrack_task_entity( - session, project_name, asset_name, task_name - ) - self._ftrack_status_change(session, entity, project_name) - self._start_timer(session, entity, ftrack_api) - except Exception: - self.log.warning( - "Couldn't finish Ftrack procedure.", exc_info=True - ) - return - - finally: - session.close() - - def _find_ftrack_task_entity( - self, session, project_name, asset_name, task_name - ): - project_entity = session.query( - "Project where full_name is \"{}\"".format(project_name) - ).first() - if not project_entity: - self.log.warning( - "Couldn't find project \"{}\" in Ftrack.".format(project_name) - ) - return - - potential_task_entities = session.query(( - "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" - ).format(asset_name, project_entity["id"])).all() - filtered_entities = [] - for _entity in potential_task_entities: - if ( - _entity.entity_type.lower() == "task" - and _entity["name"] == task_name - ): - filtered_entities.append(_entity) - - if not filtered_entities: - self.log.warning(( - "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - if len(filtered_entities) > 1: - self.log.warning(( - "Found more than one task \"{}\"" - " under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - return filtered_entities[0] - - def _ftrack_status_change(self, session, entity, project_name): - presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] - statuses = presets.get("status_update") - if not statuses: - return - - actual_status = entity["status"]["name"].lower() - already_tested = set() - ent_path = "/".join( - [ent["name"] for ent in entity["link"]] - ) - while True: - next_status_name = None - for key, value in statuses.items(): - if key in already_tested: - continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": - next_status_name = key - already_tested.add(key) - break - already_tested.add(key) - - if next_status_name is None: - break - - try: - query = "Status where name is \"{}\"".format( - next_status_name - ) - status = session.query(query).one() - - entity["status"] = status - session.commit() - self.log.debug("Changing status to \"{}\" <{}>".format( - next_status_name, ent_path - )) - break - - except Exception: - session.rollback() - msg = ( - "Status \"{}\" in presets wasn't found" - " on Ftrack entity type \"{}\"" - ).format(next_status_name, entity.entity_type) - self.log.warning(msg) - - def _start_timer(self, session, entity, _ftrack_api): - self.log.debug("Triggering timer start.") - - user_entity = session.query("User where username is \"{}\"".format( - os.environ["FTRACK_API_USER"] - )).first() - if not user_entity: - self.log.warning( - "Couldn't find user with username \"{}\" in Ftrack".format( - os.environ["FTRACK_API_USER"] - ) - ) - return - - source = { - "user": { - "id": user_entity["id"], - "username": user_entity["username"] - } - } - event_data = { - "actionIdentifier": "start.timer", - "selection": [{"entityId": entity["id"], "entityType": "task"}] - } - session.event_hub.publish( - _ftrack_api.event.base.Event( - topic="ftrack.action.launch", - data=event_data, - source=source - ), - on_error="ignore" - ) - self.log.debug("Timer start triggered successfully.") From c9b0ab8bd9b0231fea4e5adc24bbcff2e1cccb9b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:21:59 +0100 Subject: [PATCH 15/19] added few comments --- pype/lib/applications.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index f4861ae866..fd3d0ef990 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -21,6 +21,11 @@ class ApplicationLaunchFailed(Exception): def launch_application(project_name, asset_name, task_name, app_name): + """Launch host application with filling required environments. + + TODO(iLLiCiT): This should be split into more parts. + """ + # `get_avalon_database` is in Pype 3 replaced with using `AvalonMongoDB` database = get_avalon_database() project_document = database[project_name].find_one({"type": "project"}) asset_document = database[project_name].find_one({ @@ -35,6 +40,7 @@ def launch_application(project_name, asset_name, task_name, app_name): app_label = app_def.get("ftrack_label", app_def.get("label", app_name)) host_name = app_def["application_dir"] + # Workfile data collection may be special function? data = { "project": { "name": project_document["name"], From b407291401897f47a7153822e6e3b0a2532b259b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:23:03 +0100 Subject: [PATCH 16/19] removed empoty lines --- pype/lib/lib_old.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 30790651d4..421e320415 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -523,10 +523,6 @@ def get_last_version_from_path(path_dir, filter): return None - - - - def get_subsets(asset_name, regex_filter=None, version=None, From 83c4696591918af18c25393c697c0fcb2ae69693 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 3 Nov 2020 11:55:25 +0100 Subject: [PATCH 17/19] moved `map_subsets_by_family` under `BuildWorkfile` class --- pype/lib/__init__.py | 1 - pype/lib/lib_old.py | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 6620bd5a12..a303bf038d 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -36,7 +36,6 @@ from .lib_old import ( get_last_version_from_path, get_subsets, get_linked_assets, - map_subsets_by_family, BuildWorkfile, ffprobe_streams, source_hash, diff --git a/pype/lib/lib_old.py b/pype/lib/lib_old.py index 421e320415..b384c3a06a 100644 --- a/pype/lib/lib_old.py +++ b/pype/lib/lib_old.py @@ -608,20 +608,6 @@ def get_linked_assets(asset_entity): return inputs -def map_subsets_by_family(subsets): - subsets_by_family = collections.defaultdict(list) - for subset in subsets: - family = subset["data"].get("family") - if not family: - families = subset["data"].get("families") - if not families: - continue - family = families[0] - - subsets_by_family[family].append(subset) - return subsets_by_family - - class BuildWorkfile: """Wrapper for build workfile process. @@ -629,6 +615,20 @@ class BuildWorkfile: are host related, since each host has it's loaders. """ + @staticmethod + def map_subsets_by_family(subsets): + subsets_by_family = collections.defaultdict(list) + for subset in subsets: + family = subset["data"].get("family") + if not family: + families = subset["data"].get("families") + if not families: + continue + family = families[0] + + subsets_by_family[family].append(subset) + return subsets_by_family + def process(self): """Main method of this wrapper. @@ -901,7 +901,7 @@ class BuildWorkfile: :rtype: dict """ # Prepare subsets - subsets_by_family = map_subsets_by_family(subsets) + subsets_by_family = self.map_subsets_by_family(subsets) profiles_per_subset_id = {} for family, subsets in subsets_by_family.items(): From 389d4756e94db84de83d21e08d391ccaf4ed8bd7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Nov 2020 16:19:11 +0100 Subject: [PATCH 18/19] Import tests for #669 --- pype/tests/README.md | 4 ++++ pype/tests/test_lib_restructuralization.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 pype/tests/README.md create mode 100644 pype/tests/test_lib_restructuralization.py diff --git a/pype/tests/README.md b/pype/tests/README.md new file mode 100644 index 0000000000..c05166767c --- /dev/null +++ b/pype/tests/README.md @@ -0,0 +1,4 @@ +Tests for Pype +-------------- +Trigger by: + `pype test --pype` \ No newline at end of file diff --git a/pype/tests/test_lib_restructuralization.py b/pype/tests/test_lib_restructuralization.py new file mode 100644 index 0000000000..e167c5f555 --- /dev/null +++ b/pype/tests/test_lib_restructuralization.py @@ -0,0 +1,13 @@ +# Test for backward compability of restructure of lib.py into lib library +# #664 +# Contains simple imports that should still work + + +def test_backward_compatibility(printer): + printer("Test if imports still work") + try: + from pype.lib import filter_pyblish_plugins + from pype.lib import execute_hook + from pype.lib import PypeHook + except ImportError as e: + raise \ No newline at end of file From 3ac01c55432d6e9d8d3b58810e0f64540399ba3f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Nov 2020 18:49:09 +0100 Subject: [PATCH 19/19] Import tests for #681 --- pype/tests/test_lib_restructuralization.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pype/tests/test_lib_restructuralization.py b/pype/tests/test_lib_restructuralization.py index e167c5f555..92197c8232 100644 --- a/pype/tests/test_lib_restructuralization.py +++ b/pype/tests/test_lib_restructuralization.py @@ -1,5 +1,4 @@ -# Test for backward compability of restructure of lib.py into lib library -# #664 +# Test for backward compatibility of restructure of lib.py into lib library # Contains simple imports that should still work @@ -9,5 +8,13 @@ def test_backward_compatibility(printer): from pype.lib import filter_pyblish_plugins from pype.lib import execute_hook from pype.lib import PypeHook + + from pype.lib import get_latest_version + from pype.lib import ApplicationLaunchFailed + from pype.lib import launch_application + from pype.lib import ApplicationAction + from pype.lib import get_avalon_database + from pype.lib import set_io_database + except ImportError as e: - raise \ No newline at end of file + raise