From f2a82d1afcf8e05b0be278d2364126d6469dcb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 31 Jul 2019 06:29:53 +0200 Subject: [PATCH 1/9] initial wip commit --- pype/plugin.py | 89 +++++++++++++++++++++++- pype/plugins/maya/create/create_model.py | 4 +- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/pype/plugin.py b/pype/plugin.py index c77b9927e1..026ea757c5 100644 --- a/pype/plugin.py +++ b/pype/plugin.py @@ -1,6 +1,11 @@ import tempfile import os import pyblish.api +import avalon.api +from pprint import pprint + +from pypeapp import config +import inspect ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05 ValidateContentsOrder = pyblish.api.ValidatorOrder + 0.1 @@ -8,7 +13,89 @@ ValidateSceneOrder = pyblish.api.ValidatorOrder + 0.2 ValidateMeshOrder = pyblish.api.ValidatorOrder + 0.3 -class Extractor(pyblish.api.InstancePlugin): +def imprint_attributes(plugin): + """ + Load presets by class and set them as attributes (if found) + + :param plugin: plugin instance + :type plugin: instance + """ + print("-" * 50) + print("imprinting") + file = inspect.getfile(plugin.__class__) + file = os.path.normpath(file) + plugin_kind = file.split(os.path.sep)[-2:-1][0] + plugin_host = file.split(os.path.sep)[-3:-2][0] + plugin_name = type(plugin).__name__ + print(file) + print(plugin_kind) + print(plugin_host) + print(plugin_name) + + pprint(config.get_presets()['plugins']) + try: + config_data = config.get_presets()['plugins'][plugin_host][plugin_kind][plugin_name] # noqa: E501 + except KeyError: + print("preset not found") + return + + for option, value in config_data.items(): + if option == "enabled" and value is False: + setattr(plugin, "active", False) + else: + setattr(plugin, option, value) + print("setting {}: {} on {}".format(option, value, plugin_name)) + print("-" * 50) + + +def add_init_presets(source_class): + orig_init = source_class.__init__ + + def __init__(self, *args, **kwargs): + imprint_attributes(self) + print("overriding init") + orig_init(self, *args, **kwargs) + + source_class.__init__ = __init__ + return source_class + + +def add_process_presets(source_class): + orig_process = source_class.__init__ + + def process(self, *args, **kwargs): + imprint_attributes(self) + orig_process(self, *args, **kwargs) + + source_class.__init__ = process + return source_class + + +@add_process_presets +class ContextPlugin(pyblish.api.ContextPlugin): + pass + + +@add_process_presets +class InstancePlugin(pyblish.api.InstancePlugin): + pass + + + +class PypeLoader(avalon.api.Loader): + pass + + +@add_init_presets +class PypeCreator(avalon.api.Creator): + pass + + +avalon.api.Creator = PypeCreator + + + +class Extractor(InstancePlugin): """Extractor base class. The extractor base class implements a "staging_dir" function used to diff --git a/pype/plugins/maya/create/create_model.py b/pype/plugins/maya/create/create_model.py index 241e2be7f9..6a1cc91c5f 100644 --- a/pype/plugins/maya/create/create_model.py +++ b/pype/plugins/maya/create/create_model.py @@ -1,7 +1,7 @@ -import avalon.maya +import pype.plugin -class CreateModel(avalon.maya.Creator): +class CreateModel(pype.plugin.PypeCreator): """Polygonal static geometry""" name = "modelMain" From d6211201b5729a2e75da462ee7b3710f6a9109ab Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 6 Sep 2019 09:53:44 +0200 Subject: [PATCH 2/9] fixed method name in close window connection --- pype/clockify/clockify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/clockify/clockify.py b/pype/clockify/clockify.py index ed6d996e2e..5e6cfec778 100644 --- a/pype/clockify/clockify.py +++ b/pype/clockify/clockify.py @@ -194,7 +194,7 @@ class ClockifyModule: self.message_widget = MessageWidget( self.main_parent, msg, "Clockify - Info Message" ) - self.message_widget.closed.connect(self.message_widget) + self.message_widget.closed.connect(self.on_message_widget_close) self.message_widget.show() return From 2bbe2f9372837ee03cc5100e6ef85fafe89012f2 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Sep 2019 14:28:41 +0200 Subject: [PATCH 3/9] added avalon loader/creator presets --- pype/__init__.py | 53 ++++++++++++++++++++++++ pype/tests/test_avalon_plugin_presets.py | 40 ++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 pype/tests/test_avalon_plugin_presets.py diff --git a/pype/__init__.py b/pype/__init__.py index a5858f49e7..bcbedc9a90 100644 --- a/pype/__init__.py +++ b/pype/__init__.py @@ -3,6 +3,8 @@ import os from pyblish import api as pyblish from avalon import api as avalon from .lib import filter_pyblish_plugins +from pypeapp import config + import logging log = logging.getLogger(__name__) @@ -16,6 +18,51 @@ PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins") PUBLISH_PATH = os.path.join(PLUGINS_DIR, "global", "publish") LOAD_PATH = os.path.join(PLUGINS_DIR, "global", "load") +# we are monkey patching `avalon.api.discover()` to allow us to load +# plugin presets on plugins being discovered by avalon. Little bit of +# hacking, but it allows us to add out own features without need +# to modify upstream code. + +_original_discover = avalon.discover + + +def patched_discover(superclass): + """ + Monkey patched version of :func:`avalon.api.discover()`. It allows + us to load presets on plugins being discovered. + """ + # run original discover and get plugins + plugins = _original_discover(superclass) + + # determine host application to use for finding presets + host = avalon.registered_host().__name__.split(".")[-1] + + # map plugin superclass to preset json. Currenly suppoted is load and + # create (avalon.api.Loader and avalon.api.Creator) + plugin_type = "undefined" + if superclass.__name__.split(".")[-1] == "Loader": + plugin_type = "load" + elif superclass.__name__.split(".")[-1] == "Creator": + plugin_type = "create" + + print(">>> trying to find presets for {}:{} ...".format(host, plugin_type)) + try: + config_data = config.get_presets()['plugins'][host][plugin_type] + except KeyError: + print("*** no presets found.") + else: + for plugin in plugins: + if plugin.__name__ in config_data: + print(">>> We have preset for {}".format(plugin.__name__)) + for option, value in config_data[plugin.__name__].items(): + if option == "enabled" and value is False: + setattr(plugin, "active", False) + print(" - is disabled by preset") + else: + setattr(plugin, option, value) + print(" - setting `{}`: `{}`".format(option, value)) + return plugins + def install(): log.info("Registering global plug-ins..") @@ -23,6 +70,9 @@ def install(): pyblish.register_discovery_filter(filter_pyblish_plugins) avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + # apply monkey patched discover to original one + avalon.discover = patched_discover + def uninstall(): log.info("Deregistering global plug-ins..") @@ -30,3 +80,6 @@ def uninstall(): pyblish.deregister_discovery_filter(filter_pyblish_plugins) avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) log.info("Global plug-ins unregistred") + + # restore original discover + avalon.discover = _original_discover diff --git a/pype/tests/test_avalon_plugin_presets.py b/pype/tests/test_avalon_plugin_presets.py new file mode 100644 index 0000000000..7f023ea358 --- /dev/null +++ b/pype/tests/test_avalon_plugin_presets.py @@ -0,0 +1,40 @@ +import avalon.api as api +import pype + + +class MyTestCreator(api.Creator): + + my_test_property = "A" + + def __init__(self, name, asset, options=None, data=None): + super(MyTestCreator, self).__init__(self, name, asset, + options=None, data=None) + + +# this is hack like no other - we need to inject our own avalon host +# and bypass all its validation. Avalon hosts are modules that needs +# `ls` callable as attribute. Voila: +class Test: + __name__ = "test" + ls = len + + def __call__(self): + pass + + +def test_avalon_plugin_presets(monkeypatch, printer): + + pype.install() + api.register_host(Test()) + api.register_plugin(api.Creator, MyTestCreator) + plugins = api.discover(api.Creator) + printer("Test if we got our test plugin") + assert MyTestCreator in plugins + for p in plugins: + if p.__name__ == "MyTestCreator": + printer("Test if we have overriden existing property") + assert p.my_test_property == "B" + printer("Test if we have overriden superclass property") + assert p.active is False + printer("Test if we have added new property") + assert p.new_property == "new" From dca53a183c5d70fdaa21048442c5dbebba46612d Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Sep 2019 15:41:00 +0200 Subject: [PATCH 4/9] added support for presets on global plugins --- pype/lib.py | 22 +++++++++++++++++----- pype/tests/test_pyblish_filter.py | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index c097ad1f10..acd8756aa7 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -5,6 +5,7 @@ import importlib import itertools import contextlib import subprocess +import inspect from .vendor import pather from .vendor.pather.error import ParseError @@ -467,9 +468,7 @@ def filter_pyblish_plugins(plugins): host = api.current_host() - presets = config.get_presets().get('plugins', {}).get(host, {}).get( - "publish", {} - ) + presets = config.get_presets().get('plugins', {}) # iterate over plugins for plugin in plugins[:]: @@ -477,10 +476,23 @@ def filter_pyblish_plugins(plugins): if not presets: continue + file = os.path.normpath(inspect.getfile(plugin.__class__)) + 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] + + print(host_from_file) + print(plugin_kind) + try: - config_data = presets[plugin.__name__] # noqa: E501 + config_data = presets[host]["publish"][plugin.__name__] except KeyError: - continue + 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: diff --git a/pype/tests/test_pyblish_filter.py b/pype/tests/test_pyblish_filter.py index 8d747e63df..cf3d5d6015 100644 --- a/pype/tests/test_pyblish_filter.py +++ b/pype/tests/test_pyblish_filter.py @@ -18,7 +18,7 @@ def test_pyblish_plugin_filter_modifier(printer, monkeypatch): assert len(plugins) == 0 paths = pyblish.api.registered_paths() printer("Test if we have no registered plugin paths") - print(paths) + assert len(paths) == 0 class MyTestPlugin(pyblish.api.InstancePlugin): my_test_property = 1 From 04919acaeb3fb5aa3faa54162f3450fa9fa8447e Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Sep 2019 15:59:35 +0200 Subject: [PATCH 5/9] fixed getting source path --- pype/lib.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index acd8756aa7..f357de2a85 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -476,16 +476,13 @@ def filter_pyblish_plugins(plugins): if not presets: continue - file = os.path.normpath(inspect.getfile(plugin.__class__)) + 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] - print(host_from_file) - print(plugin_kind) - try: config_data = presets[host]["publish"][plugin.__name__] except KeyError: From 495b747ace09d286787cb3a178121da0ac6342d9 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Sep 2019 18:39:31 +0200 Subject: [PATCH 6/9] fixed uncommited changes --- pype/plugin.py | 58 ++++++-------------------------------------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/pype/plugin.py b/pype/plugin.py index 026ea757c5..a3460e693e 100644 --- a/pype/plugin.py +++ b/pype/plugin.py @@ -1,8 +1,6 @@ import tempfile import os import pyblish.api -import avalon.api -from pprint import pprint from pypeapp import config import inspect @@ -20,19 +18,11 @@ def imprint_attributes(plugin): :param plugin: plugin instance :type plugin: instance """ - print("-" * 50) - print("imprinting") file = inspect.getfile(plugin.__class__) file = os.path.normpath(file) plugin_kind = file.split(os.path.sep)[-2:-1][0] plugin_host = file.split(os.path.sep)[-3:-2][0] plugin_name = type(plugin).__name__ - print(file) - print(plugin_kind) - print(plugin_host) - print(plugin_name) - - pprint(config.get_presets()['plugins']) try: config_data = config.get_presets()['plugins'][plugin_host][plugin_kind][plugin_name] # noqa: E501 except KeyError: @@ -45,54 +35,18 @@ def imprint_attributes(plugin): else: setattr(plugin, option, value) print("setting {}: {} on {}".format(option, value, plugin_name)) - print("-" * 50) -def add_init_presets(source_class): - orig_init = source_class.__init__ - - def __init__(self, *args, **kwargs): - imprint_attributes(self) - print("overriding init") - orig_init(self, *args, **kwargs) - - source_class.__init__ = __init__ - return source_class - - -def add_process_presets(source_class): - orig_process = source_class.__init__ - - def process(self, *args, **kwargs): - imprint_attributes(self) - orig_process(self, *args, **kwargs) - - source_class.__init__ = process - return source_class - - -@add_process_presets class ContextPlugin(pyblish.api.ContextPlugin): - pass + def process(cls, *args, **kwargs): + imprint_attributes(cls) + super(ContextPlugin, cls).process(cls, *args, **kwargs) -@add_process_presets class InstancePlugin(pyblish.api.InstancePlugin): - pass - - - -class PypeLoader(avalon.api.Loader): - pass - - -@add_init_presets -class PypeCreator(avalon.api.Creator): - pass - - -avalon.api.Creator = PypeCreator - + def process(cls, *args, **kwargs): + imprint_attributes(cls) + super(ContextPlugin, cls).process(cls, *args, **kwargs) class Extractor(InstancePlugin): From b1d459008175f74ed0ec8ffd2b4b4d6b8a5ff577 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Sep 2019 18:41:33 +0200 Subject: [PATCH 7/9] reverted changes in CreateModel --- pype/plugins/maya/create/create_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/plugins/maya/create/create_model.py b/pype/plugins/maya/create/create_model.py index 6a1cc91c5f..241e2be7f9 100644 --- a/pype/plugins/maya/create/create_model.py +++ b/pype/plugins/maya/create/create_model.py @@ -1,7 +1,7 @@ -import pype.plugin +import avalon.maya -class CreateModel(pype.plugin.PypeCreator): +class CreateModel(avalon.maya.Creator): """Polygonal static geometry""" name = "modelMain" From 8502cd48126b231b911874c6097b251554380f18 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 6 Sep 2019 18:44:22 +0200 Subject: [PATCH 8/9] add changelog --- changelog.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 159ff0baeb..02939896eb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,29 @@ # Pype changelog # Welcome to pype changelog -## 2.1 ## +## 2.2.0 ## + +**new**: +- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts +- _(nuke)_ option to choose deadline chunk size on write nodes +- _(nukestudio)_ added option to publish soft effects (subTrackItems) from NukeStudio as subsets including LUT files. these can then be loaded in nuke or NukeStudio +- _(nuke)_ option to build nuke script from previously published latest versions of plate and render subsets. +- _(nuke)_ nuke writes now have deadline tab. +- _(ftrack)_ Prepare Project action can now be used for creating the base folder structure on disk and in ftrack, setting up all the initial project attributes and it automatically prepares `pype_project_config` folder for the given project. +- _(clockify)_ Added support for time tracking in clockify. This currently in addition to ftrack time logs, but does not completely replace them. +- _(pype)_ any attributes in Creator and Loader plugins can now be customised using pype preset system + +**changed**: +- nukestudio now uses workio API for workfiles +- _(maya)_ `FIX FPS` prompt in maya now appears in the middle of the screen +- _(muster)_ can now be configured with custom templates + + +**fix**: +- wrong version retrieval from path in certain scenarios +- nuke reset resolution wasn't working in certain scenarios + +## 2.1.0 ## A large cleanup release. Most of the change are under the hood. From f2d1613bb004c88c2d6cb7a2b88ef790c538eabb Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 6 Sep 2019 18:55:01 +0200 Subject: [PATCH 9/9] add release dates to changelog --- changelog.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 02939896eb..46cceb9fdc 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ Welcome to pype changelog ## 2.2.0 ## +_release date: 8 Sept 2019_ **new**: - _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts @@ -15,8 +16,9 @@ Welcome to pype changelog **changed**: - nukestudio now uses workio API for workfiles -- _(maya)_ `FIX FPS` prompt in maya now appears in the middle of the screen +- _(maya)_ "FIX FPS" prompt in maya now appears in the middle of the screen - _(muster)_ can now be configured with custom templates +- _(pype)_ global publishing plugins can now be configured using presets as well as host specific ones **fix**: @@ -24,6 +26,7 @@ Welcome to pype changelog - nuke reset resolution wasn't working in certain scenarios ## 2.1.0 ## +_release date: 6 Aug 2019_ A large cleanup release. Most of the change are under the hood.