From 5372c016eadfe2dd09cfc1803a6984cfca24d61b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 25 Aug 2022 12:19:47 +0200 Subject: [PATCH 1/4] moved 'OpenPypeInterface' into interfaces.py --- openpype/modules/__init__.py | 2 -- openpype/modules/base.py | 42 +++++++--------------------------- openpype/modules/interfaces.py | 29 +++++++++++++++++++++-- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/openpype/modules/__init__.py b/openpype/modules/__init__.py index 68b5f6c247..02e7dc13ab 100644 --- a/openpype/modules/__init__.py +++ b/openpype/modules/__init__.py @@ -2,7 +2,6 @@ from .base import ( OpenPypeModule, OpenPypeAddOn, - OpenPypeInterface, load_modules, @@ -20,7 +19,6 @@ from .base import ( __all__ = ( "OpenPypeModule", "OpenPypeAddOn", - "OpenPypeInterface", "load_modules", diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 1316d7f734..1b8cf5d769 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -28,6 +28,14 @@ from openpype.settings.lib import ( ) from openpype.lib import PypeLogger +from .interfaces import ( + OpenPypeInterface, + IPluginPaths, + IHostModule, + ITrayModule, + ITrayService +) + # Files that will be always ignored on modules import IGNORED_FILENAMES = ( "__pycache__", @@ -391,29 +399,7 @@ def _load_modules(): log.error(msg, exc_info=True) -class _OpenPypeInterfaceMeta(ABCMeta): - """OpenPypeInterface meta class to print proper string.""" - def __str__(self): - return "<'OpenPypeInterface.{}'>".format(self.__name__) - - def __repr__(self): - return str(self) - - -@six.add_metaclass(_OpenPypeInterfaceMeta) -class OpenPypeInterface: - """Base class of Interface that can be used as Mixin with abstract parts. - - This is way how OpenPype module or addon can tell that has implementation - for specific part or for other module/addon. - - Child classes of OpenPypeInterface may be used as mixin in different - OpenPype modules which means they have to have implemented methods defined - in the interface. By default interface does not have any abstract parts. - """ - - pass @six.add_metaclass(ABCMeta) @@ -749,8 +735,6 @@ class ModulesManager: and "actions" each containing list of paths. """ # Output structure - from openpype_interfaces import IPluginPaths - output = { "publish": [], "create": [], @@ -807,8 +791,6 @@ class ModulesManager: list: List of creator plugin paths. """ # Output structure - from openpype_interfaces import IPluginPaths - output = [] for module in self.get_enabled_modules(): # Skip module that do not inherit from `IPluginPaths` @@ -897,8 +879,6 @@ class ModulesManager: host name set to passed 'host_name'. """ - from openpype_interfaces import IHostModule - for module in self.get_enabled_modules(): if ( isinstance(module, IHostModule) @@ -915,8 +895,6 @@ class ModulesManager: inheriting 'IHostModule'. """ - from openpype_interfaces import IHostModule - host_names = { module.host_name for module in self.get_enabled_modules() @@ -1098,8 +1076,6 @@ class TrayModulesManager(ModulesManager): self.tray_menu(tray_menu) def get_enabled_tray_modules(self): - from openpype_interfaces import ITrayModule - output = [] for module in self.modules: if module.enabled and isinstance(module, ITrayModule): @@ -1175,8 +1151,6 @@ class TrayModulesManager(ModulesManager): self._report["Tray menu"] = report def start_modules(self): - from openpype_interfaces import ITrayService - report = {} time_start = time.time() prev_start_time = time_start diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index 14f49204ee..8221db4d05 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -1,8 +1,33 @@ -from abc import abstractmethod, abstractproperty +from abc import ABCMeta, abstractmethod, abstractproperty + +import six from openpype import resources -from openpype.modules import OpenPypeInterface + +class _OpenPypeInterfaceMeta(ABCMeta): + """OpenPypeInterface meta class to print proper string.""" + + def __str__(self): + return "<'OpenPypeInterface.{}'>".format(self.__name__) + + def __repr__(self): + return str(self) + + +@six.add_metaclass(_OpenPypeInterfaceMeta) +class OpenPypeInterface: + """Base class of Interface that can be used as Mixin with abstract parts. + + This is way how OpenPype module or addon can tell OpenPype that contain + implementation for specific functionality. + + Child classes of OpenPypeInterface may be used as mixin in different + OpenPype modules which means they have to have implemented methods defined + in the interface. By default interface does not have any abstract parts. + """ + + pass class IPluginPaths(OpenPypeInterface): From 8cc6086e92a6c5135428898717e6d9057f567e8c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 25 Aug 2022 12:22:19 +0200 Subject: [PATCH 2/4] removed usage of 'ILaunchHookPaths' --- openpype/modules/ftrack/ftrack_module.py | 5 ++--- openpype/modules/shotgrid/shotgrid_module.py | 5 +---- openpype/modules/slack/slack_module.py | 10 ++++------ openpype/modules/timers_manager/timers_manager.py | 11 ++++------- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/openpype/modules/ftrack/ftrack_module.py b/openpype/modules/ftrack/ftrack_module.py index f99e189082..cb4f204523 100644 --- a/openpype/modules/ftrack/ftrack_module.py +++ b/openpype/modules/ftrack/ftrack_module.py @@ -9,7 +9,6 @@ from openpype.modules import OpenPypeModule from openpype_interfaces import ( ITrayModule, IPluginPaths, - ILaunchHookPaths, ISettingsChangeListener ) from openpype.settings import SaveWarningExc @@ -21,7 +20,6 @@ class FtrackModule( OpenPypeModule, ITrayModule, IPluginPaths, - ILaunchHookPaths, ISettingsChangeListener ): name = "ftrack" @@ -85,7 +83,8 @@ class FtrackModule( } def get_launch_hook_paths(self): - """Implementation of `ILaunchHookPaths`.""" + """Implementation for applications launch hooks.""" + return os.path.join(FTRACK_MODULE_DIR, "launch_hooks") def modify_application_launch_arguments(self, application, env): diff --git a/openpype/modules/shotgrid/shotgrid_module.py b/openpype/modules/shotgrid/shotgrid_module.py index 5644f0c35f..281c6fdcad 100644 --- a/openpype/modules/shotgrid/shotgrid_module.py +++ b/openpype/modules/shotgrid/shotgrid_module.py @@ -3,7 +3,6 @@ import os from openpype_interfaces import ( ITrayModule, IPluginPaths, - ILaunchHookPaths, ) from openpype.modules import OpenPypeModule @@ -11,9 +10,7 @@ from openpype.modules import OpenPypeModule SHOTGRID_MODULE_DIR = os.path.dirname(os.path.abspath(__file__)) -class ShotgridModule( - OpenPypeModule, ITrayModule, IPluginPaths, ILaunchHookPaths -): +class ShotgridModule(OpenPypeModule, ITrayModule, IPluginPaths): leecher_manager_url = None name = "shotgrid" enabled = False diff --git a/openpype/modules/slack/slack_module.py b/openpype/modules/slack/slack_module.py index 9b2976d766..499c1c19ce 100644 --- a/openpype/modules/slack/slack_module.py +++ b/openpype/modules/slack/slack_module.py @@ -1,14 +1,11 @@ import os from openpype.modules import OpenPypeModule -from openpype_interfaces import ( - IPluginPaths, - ILaunchHookPaths -) +from openpype.modules.interfaces import IPluginPaths SLACK_MODULE_DIR = os.path.dirname(os.path.abspath(__file__)) -class SlackIntegrationModule(OpenPypeModule, IPluginPaths, ILaunchHookPaths): +class SlackIntegrationModule(OpenPypeModule, IPluginPaths): """Allows sending notification to Slack channels during publishing.""" name = "slack" @@ -18,7 +15,8 @@ class SlackIntegrationModule(OpenPypeModule, IPluginPaths, ILaunchHookPaths): self.enabled = slack_settings["enabled"] def get_launch_hook_paths(self): - """Implementation of `ILaunchHookPaths`.""" + """Implementation for applications launch hooks.""" + return os.path.join(SLACK_MODULE_DIR, "launch_hooks") def get_plugin_paths(self): diff --git a/openpype/modules/timers_manager/timers_manager.py b/openpype/modules/timers_manager/timers_manager.py index 93332ace4f..c168e9534d 100644 --- a/openpype/modules/timers_manager/timers_manager.py +++ b/openpype/modules/timers_manager/timers_manager.py @@ -6,7 +6,6 @@ from openpype.client import get_asset_by_name from openpype.modules import OpenPypeModule from openpype_interfaces import ( ITrayService, - ILaunchHookPaths, IPluginPaths ) from openpype.lib.events import register_event_callback @@ -79,7 +78,6 @@ class ExampleTimersManagerConnector: class TimersManager( OpenPypeModule, ITrayService, - ILaunchHookPaths, IPluginPaths ): """ Handles about Timers. @@ -185,12 +183,11 @@ class TimersManager( ) def get_launch_hook_paths(self): - """Implementation of `ILaunchHookPaths`.""" + """Implementation for applications launch hooks.""" - return os.path.join( - TIMER_MODULE_DIR, - "launch_hooks" - ) + return [ + os.path.join(TIMER_MODULE_DIR, "launch_hooks") + ] def get_plugin_paths(self): """Implementation of `IPluginPaths`.""" From 8acb96c572a58c779b544dac8b79aab9d71b6663 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 25 Aug 2022 12:27:02 +0200 Subject: [PATCH 3/4] added deprecation warning to 'ILaunchHookPaths' --- openpype/modules/interfaces.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index 8221db4d05..13655773dd 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -81,6 +81,13 @@ class ILaunchHookPaths(OpenPypeInterface): Expected result is list of paths. ["path/to/launch_hooks_dir"] + + Deprecated: + This interface is not needed since OpenPype 3.14.*. Addon just have to + implement 'get_launch_hook_paths' which can expect Application object + or nothing as argument. + + Interface class will be removed after 3.16.*. """ @abstractmethod From 7356fc666d7aa4cca7251849f4eaf4d91dfc0e75 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 25 Aug 2022 12:31:47 +0200 Subject: [PATCH 4/4] moved collection of launch hooks from modules into applications logic --- openpype/lib/applications.py | 61 +++++++++++++++++++++++++++++++++-- openpype/modules/base.py | 62 ------------------------------------ 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 074e815160..b389bc2539 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -950,6 +950,63 @@ class ApplicationLaunchContext: ) self.kwargs["env"] = value + def _collect_addons_launch_hook_paths(self): + """Helper to collect application launch hooks from addons. + + Module have to have implemented 'get_launch_hook_paths' method which + can expect appliction as argument or nothing. + + Returns: + List[str]: Paths to launch hook directories. + """ + + expected_types = (list, tuple, set) + + output = [] + for module in self.modules_manager.get_enabled_modules(): + # Skip module if does not have implemented 'get_launch_hook_paths' + func = getattr(module, "get_launch_hook_paths", None) + if func is None: + continue + + func = module.get_launch_hook_paths + if hasattr(inspect, "signature"): + sig = inspect.signature(func) + expect_args = len(sig.parameters) > 0 + else: + expect_args = len(inspect.getargspec(func)[0]) > 0 + + # Pass application argument if method expect it. + try: + if expect_args: + hook_paths = func(self.application) + else: + hook_paths = func() + except Exception: + self.log.warning( + "Failed to call 'get_launch_hook_paths'", + exc_info=True + ) + continue + + if not hook_paths: + continue + + # Convert string to list + if isinstance(hook_paths, six.string_types): + hook_paths = [hook_paths] + + # Skip invalid types + if not isinstance(hook_paths, expected_types): + self.log.warning(( + "Result of `get_launch_hook_paths`" + " has invalid type {}. Expected {}" + ).format(type(hook_paths), expected_types)) + continue + + output.extend(hook_paths) + return output + def paths_to_launch_hooks(self): """Directory paths where to look for launch hooks.""" # This method has potential to be part of application manager (maybe). @@ -983,9 +1040,7 @@ class ApplicationLaunchContext: paths.append(path) # Load modules paths - paths.extend( - self.modules_manager.collect_launch_hook_paths(self.application) - ) + paths.extend(self._collect_addons_launch_hook_paths()) return paths diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 1b8cf5d769..25355cbd9c 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -805,68 +805,6 @@ class ModulesManager: output.extend(paths) return output - def collect_launch_hook_paths(self, app): - """Helper to collect application launch hooks. - - It used to be based on 'ILaunchHookPaths' which is not true anymore. - Module just have to have implemented 'get_launch_hook_paths' method. - - Args: - app (Application): Application object which can be used for - filtering of which launch hook paths are returned. - - Returns: - list: Paths to launch hook directories. - """ - - str_type = type("") - expected_types = (list, tuple, set) - - output = [] - for module in self.get_enabled_modules(): - # Skip module if does not have implemented 'get_launch_hook_paths' - func = getattr(module, "get_launch_hook_paths", None) - if func is None: - continue - - func = module.get_launch_hook_paths - if hasattr(inspect, "signature"): - sig = inspect.signature(func) - expect_args = len(sig.parameters) > 0 - else: - expect_args = len(inspect.getargspec(func)[0]) > 0 - - # Pass application argument if method expect it. - try: - if expect_args: - hook_paths = func(app) - else: - hook_paths = func() - except Exception: - self.log.warning( - "Failed to call 'get_launch_hook_paths'", - exc_info=True - ) - continue - - if not hook_paths: - continue - - # Convert string to list - if isinstance(hook_paths, str_type): - hook_paths = [hook_paths] - - # Skip invalid types - if not isinstance(hook_paths, expected_types): - self.log.warning(( - "Result of `get_launch_hook_paths`" - " has invalid type {}. Expected {}" - ).format(type(hook_paths), expected_types)) - continue - - output.extend(hook_paths) - return output - def get_host_module(self, host_name): """Find host module by host name.