From 9331187000e18c70d4a1d38f159f0ebc4c483f6b Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:09:29 +0200 Subject: [PATCH 01/14] ProcessContext also has information about preparation state --- client/ayon_core/addon/base.py | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 383703e2bc..41ba7d4a0e 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -116,6 +116,47 @@ def __init__( if kwargs: unknown_keys = ", ".join([f'"{key}"' for key in kwargs.keys()]) print(f"Unknown keys in ProcessContext: {unknown_keys}") + self._prepared: bool = False + self._exception: Optional[Exception] = None + + def is_prepared(self) -> bool: + """Preparation of process finished. + + Returns: + bool: Preparation is done. + """ + return self._prepared + + def set_prepared(self): + """Mark process as prepared.""" + self._prepared = True + + def preparation_failed(self) -> bool: + """Preparation failed. + + Returns: + bool: Preparation failed. + + """ + return self._exception is not None + + def get_exception(self) -> Optional[Exception]: + """Get exception that occurred during preparation. + + Returns: + Optional[Exception]: Exception that caused preparation fail. + + """ + return self._exception + + def set_exception(self, exception: Exception): + """Set exception that occurred during preparation. + + Args: + exception (Exception): Exception that caused preparation fail. + + """ + self._exception = exception # Inherit from `object` for Python 2 hosts From 501cacc4b8e5e081d7211ddae7a11ad492348e3c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:09:46 +0200 Subject: [PATCH 02/14] change state of context when is done --- client/ayon_core/addon/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index ac5ff25984..5f6922b924 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -134,6 +134,8 @@ def ensure_addons_are_process_context_ready( failed = True break + process_context.set_prepared() + process_context.set_exception(exception) output_str = output.getvalue() # Print stdout/stderr to console as it was redirected print(output_str) From 8e9c28a84a416d51169ccc160d269481b4a026b0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:10:02 +0200 Subject: [PATCH 03/14] 'ensure_addons_are_process_ready' returns ProcessContext --- client/ayon_core/addon/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 5f6922b924..b301c70564 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -161,7 +161,7 @@ def ensure_addons_are_process_ready( addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, **kwargs, -) -> Optional[Exception]: +) -> ProcessContext: """Ensure all enabled addons are ready to be used in the given context. Call this method only in AYON launcher process and as first thing @@ -181,6 +181,7 @@ def ensure_addons_are_process_ready( """ context: ProcessContext = ProcessContext(**kwargs) - return ensure_addons_are_process_context_ready( + ensure_addons_are_process_context_ready( context, addons_manager, exit_on_failure ) + return context From f3cccccab73bc58e0b8c9daa53ebd9b37b80e74c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:10:16 +0200 Subject: [PATCH 04/14] do not return exception on fail --- client/ayon_core/addon/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index b301c70564..0481ed4cad 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -72,7 +72,7 @@ def ensure_addons_are_process_context_ready( process_context: ProcessContext, addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, -) -> Optional[Exception]: +): """Ensure all enabled addons are ready to be used in the given context. Call this method only in AYON launcher process and as first thing @@ -152,9 +152,8 @@ def ensure_addons_are_process_context_ready( detail = output_str _handle_error(process_context, message, detail) - if not exit_on_failure: - return exception - sys.exit(1) + if exit_on_failure: + sys.exit(1) def ensure_addons_are_process_ready( From 2b46eee1dd2d074e979923ba313086cbbd90a271 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:19:52 +0200 Subject: [PATCH 05/14] added ProcessContext arguments to 'ensure_addons_are_process_ready' --- client/ayon_core/addon/base.py | 3 ++- client/ayon_core/addon/utils.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 41ba7d4a0e..e5b5087423 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -94,7 +94,8 @@ class ProcessContext: project_name (Optional[str]): Project name. Can be filled in case process is triggered for specific project. Some addons can have different behavior based on project. - headless (Optional[bool]): Is process running in headless mode. + headless (Optional[bool]): Is process running in headless mode. Value + is filled with value based on state set in AYON launcher. """ def __init__( diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 0481ed4cad..ad04586019 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -157,6 +157,10 @@ def ensure_addons_are_process_context_ready( def ensure_addons_are_process_ready( + addon_name: Optional[str] = None, + addon_version: Optional[str] = None, + project_name: Optional[str] = None, + headless: Optional[bool] = None, addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, **kwargs, @@ -168,6 +172,13 @@ def ensure_addons_are_process_ready( should not be created. Args: + addon_name (Optional[str]): Addon name which triggered process. + addon_version (Optional[str]): Addon version which triggered process. + project_name (Optional[str]): Project name. Can be filled in case + process is triggered for specific project. Some addons can have + different behavior based on project. + headless (Optional[bool]): Is process running in headless mode. Value + is filled with value based on state set in AYON launcher. addons_manager (Optional[AddonsManager]): The addons manager to use. If not provided, a new one will be created. exit_on_failure (bool, optional): If True, the process will exit @@ -179,7 +190,13 @@ def ensure_addons_are_process_ready( preparation, if any. """ - context: ProcessContext = ProcessContext(**kwargs) + context: ProcessContext = ProcessContext( + addon_name, + addon_version, + project_name, + headless, + **kwargs + ) ensure_addons_are_process_context_ready( context, addons_manager, exit_on_failure ) From d983879ccd7f4215c63d9baa52b4e0b16607c62e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:39:56 +0200 Subject: [PATCH 06/14] added comment to project name --- client/ayon_core/addon/base.py | 2 +- client/ayon_core/addon/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index e5b5087423..5662375c0a 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -93,7 +93,7 @@ class ProcessContext: addon_version (Optional[str]): Addon version which triggered process. project_name (Optional[str]): Project name. Can be filled in case process is triggered for specific project. Some addons can have - different behavior based on project. + different behavior based on project. Value is NOT autofilled. headless (Optional[bool]): Is process running in headless mode. Value is filled with value based on state set in AYON launcher. diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index ad04586019..43118bff7e 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -176,7 +176,7 @@ def ensure_addons_are_process_ready( addon_version (Optional[str]): Addon version which triggered process. project_name (Optional[str]): Project name. Can be filled in case process is triggered for specific project. Some addons can have - different behavior based on project. + different behavior based on project. Value is NOT autofilled. headless (Optional[bool]): Is process running in headless mode. Value is filled with value based on state set in AYON launcher. addons_manager (Optional[AddonsManager]): The addons From eb4407b9efb55bf76bdb5b8040422f943bc2410f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:57:56 +0200 Subject: [PATCH 07/14] fix returns in docstrings --- client/ayon_core/addon/utils.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 43118bff7e..f2441e37be 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -87,10 +87,6 @@ def ensure_addons_are_process_context_ready( exit_on_failure (bool, optional): If True, the process will exit if an error occurs. Defaults to True. - Returns: - Optional[Exception]: The exception that occurred during the - preparation, if any. - """ if addons_manager is None: addons_manager = AddonsManager() @@ -186,7 +182,7 @@ def ensure_addons_are_process_ready( kwargs: The keyword arguments to pass to the ProcessContext. Returns: - Optional[Exception]: The exception that occurred during the + ProcessContext: The exception that occurred during the preparation, if any. """ From 92ce331a302c26a6a9a9fd47361269225d07b098 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:45:54 +0200 Subject: [PATCH 08/14] added 'is_headless_mode_enabled' function --- client/ayon_core/addon/base.py | 4 ++-- client/ayon_core/lib/__init__.py | 2 ++ client/ayon_core/lib/ayon_info.py | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 5662375c0a..6343166ac8 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -20,6 +20,7 @@ Logger, is_dev_mode_enabled, get_launcher_storage_dir, + is_headless_mode_enabled, ) from ayon_core.settings import get_studio_settings @@ -107,8 +108,7 @@ def __init__( **kwargs, ): if headless is None: - # TODO use lib function to get headless mode - headless = os.getenv("AYON_HEADLESS_MODE") == "1" + headless = is_headless_mode_enabled() self.addon_name: Optional[str] = addon_name self.addon_version: Optional[str] = addon_version self.project_name: Optional[str] = project_name diff --git a/client/ayon_core/lib/__init__.py b/client/ayon_core/lib/__init__.py index d4b161031e..0074c4d2bd 100644 --- a/client/ayon_core/lib/__init__.py +++ b/client/ayon_core/lib/__init__.py @@ -132,6 +132,7 @@ is_in_ayon_launcher_process, is_running_from_build, is_using_ayon_console, + is_headless_mode_enabled, is_staging_enabled, is_dev_mode_enabled, is_in_tests, @@ -245,6 +246,7 @@ "is_in_ayon_launcher_process", "is_running_from_build", "is_using_ayon_console", + "is_headless_mode_enabled", "is_staging_enabled", "is_dev_mode_enabled", "is_in_tests", diff --git a/client/ayon_core/lib/ayon_info.py b/client/ayon_core/lib/ayon_info.py index c4333fab95..7e194a824e 100644 --- a/client/ayon_core/lib/ayon_info.py +++ b/client/ayon_core/lib/ayon_info.py @@ -78,6 +78,10 @@ def is_using_ayon_console(): return "ayon_console" in executable_filename +def is_headless_mode_enabled(): + return os.getenv("AYON_HEADLESS_MODE") == "1" + + def is_staging_enabled(): return os.getenv("AYON_USE_STAGING") == "1" From 3bc993399117f5690d6597a26947603fafa8d206 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:10:57 +0200 Subject: [PATCH 09/14] return bool all the time --- client/ayon_core/addon/utils.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index f2441e37be..31cb128e4b 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -72,7 +72,7 @@ def ensure_addons_are_process_context_ready( process_context: ProcessContext, addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, -): +) -> bool: """Ensure all enabled addons are ready to be used in the given context. Call this method only in AYON launcher process and as first thing @@ -87,6 +87,9 @@ def ensure_addons_are_process_context_ready( exit_on_failure (bool, optional): If True, the process will exit if an error occurs. Defaults to True. + Returns: + bool: True if all addons are ready, False otherwise. + """ if addons_manager is None: addons_manager = AddonsManager() @@ -138,7 +141,7 @@ def ensure_addons_are_process_context_ready( if not failed: if not process_context.headless: _start_tray() - return None + return True detail = None if use_detail: @@ -150,6 +153,7 @@ def ensure_addons_are_process_context_ready( _handle_error(process_context, message, detail) if exit_on_failure: sys.exit(1) + return False def ensure_addons_are_process_ready( @@ -160,7 +164,7 @@ def ensure_addons_are_process_ready( addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, **kwargs, -) -> ProcessContext: +) -> bool: """Ensure all enabled addons are ready to be used in the given context. Call this method only in AYON launcher process and as first thing @@ -182,8 +186,7 @@ def ensure_addons_are_process_ready( kwargs: The keyword arguments to pass to the ProcessContext. Returns: - ProcessContext: The exception that occurred during the - preparation, if any. + bool: True if all addons are ready, False otherwise. """ context: ProcessContext = ProcessContext( @@ -193,7 +196,6 @@ def ensure_addons_are_process_ready( headless, **kwargs ) - ensure_addons_are_process_context_ready( + return ensure_addons_are_process_context_ready( context, addons_manager, exit_on_failure ) - return context From 173b2f27272cb408e4ae496eb5fe40bf3eb4c266 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:14:22 +0200 Subject: [PATCH 10/14] remove ProcessContext methods --- client/ayon_core/addon/base.py | 41 --------------------------------- client/ayon_core/addon/utils.py | 7 +----- 2 files changed, 1 insertion(+), 47 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 6343166ac8..e627fb2b38 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -117,47 +117,6 @@ def __init__( if kwargs: unknown_keys = ", ".join([f'"{key}"' for key in kwargs.keys()]) print(f"Unknown keys in ProcessContext: {unknown_keys}") - self._prepared: bool = False - self._exception: Optional[Exception] = None - - def is_prepared(self) -> bool: - """Preparation of process finished. - - Returns: - bool: Preparation is done. - """ - return self._prepared - - def set_prepared(self): - """Mark process as prepared.""" - self._prepared = True - - def preparation_failed(self) -> bool: - """Preparation failed. - - Returns: - bool: Preparation failed. - - """ - return self._exception is not None - - def get_exception(self) -> Optional[Exception]: - """Get exception that occurred during preparation. - - Returns: - Optional[Exception]: Exception that caused preparation fail. - - """ - return self._exception - - def set_exception(self, exception: Exception): - """Set exception that occurred during preparation. - - Args: - exception (Exception): Exception that caused preparation fail. - - """ - self._exception = exception # Inherit from `object` for Python 2 hosts diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 31cb128e4b..32b42bf1e2 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -94,7 +94,6 @@ def ensure_addons_are_process_context_ready( if addons_manager is None: addons_manager = AddonsManager() - exception = None message = None failed = False use_detail = False @@ -111,13 +110,11 @@ def ensure_addons_are_process_context_ready( addon.ensure_is_process_ready(process_context) addon_failed = False except ProcessPreparationError as exc: - exception = exc message = str(exc) print(f"Addon preparation failed: '{addon.name}'") print(message) - except BaseException as exc: - exception = exc + except BaseException: use_detail = True message = "An unexpected error occurred." formatted_traceback = "".join(traceback.format_exception( @@ -133,8 +130,6 @@ def ensure_addons_are_process_context_ready( failed = True break - process_context.set_prepared() - process_context.set_exception(exception) output_str = output.getvalue() # Print stdout/stderr to console as it was redirected print(output_str) From 9260a80cb0becbf322a78ad431a7de45b8f29836 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:14:53 +0200 Subject: [PATCH 11/14] require addon name and version --- client/ayon_core/addon/base.py | 29 +++++++++++++++++------------ client/ayon_core/addon/utils.py | 8 ++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index e627fb2b38..494c0f3da7 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -81,17 +81,22 @@ class ProcessPreparationError(Exception): class ProcessContext: - """Context of child process. + """Hold context of process that is going to be started. - Notes: - This class is used to pass context to child process. It can be used - to use different behavior of addon based on information in - the context. - The context can be enhanced in future versions. + Right now the context is simple, having information about addon that wants + to trigger preparation and possibly project name for which it should + happen. + + Preparation for process can be required for ayon-core or any other addon. + It can be, change of environment variables, or request login to + a project management. + + At the moment of creation is 'ProcessContext' only data holder, but that + might change in future if there will be need. Args: - addon_name (Optional[str]): Addon name which triggered process. - addon_version (Optional[str]): Addon version which triggered process. + addon_name (str): Addon name which triggered process. + addon_version (str): Addon version which triggered process. project_name (Optional[str]): Project name. Can be filled in case process is triggered for specific project. Some addons can have different behavior based on project. Value is NOT autofilled. @@ -101,16 +106,16 @@ class ProcessContext: """ def __init__( self, - addon_name: Optional[str] = None, - addon_version: Optional[str] = None, + addon_name: str = None, + addon_version: str = None, project_name: Optional[str] = None, headless: Optional[bool] = None, **kwargs, ): if headless is None: headless = is_headless_mode_enabled() - self.addon_name: Optional[str] = addon_name - self.addon_version: Optional[str] = addon_version + self.addon_name: str = addon_name + self.addon_version: str = addon_version self.project_name: Optional[str] = project_name self.headless: bool = headless diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 32b42bf1e2..1dea4cc4fe 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -152,8 +152,8 @@ def ensure_addons_are_process_context_ready( def ensure_addons_are_process_ready( - addon_name: Optional[str] = None, - addon_version: Optional[str] = None, + addon_name: str, + addon_version: str, project_name: Optional[str] = None, headless: Optional[bool] = None, addons_manager: Optional[AddonsManager] = None, @@ -167,8 +167,8 @@ def ensure_addons_are_process_ready( should not be created. Args: - addon_name (Optional[str]): Addon name which triggered process. - addon_version (Optional[str]): Addon version which triggered process. + addon_name (str): Addon name which triggered process. + addon_version (str): Addon version which triggered process. project_name (Optional[str]): Project name. Can be filled in case process is triggered for specific project. Some addons can have different behavior based on project. Value is NOT autofilled. From e5eefc81fc10db24c232157eb0ab0b08b5ef5017 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:15:07 +0200 Subject: [PATCH 12/14] added todo --- client/ayon_core/addon/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 1dea4cc4fe..8e8c2bd8d7 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -79,6 +79,10 @@ def ensure_addons_are_process_context_ready( to avoid possible clashes with preparation. For example 'QApplication' should not be created. + Todos: + Run all preparations and allow to "ignore" failed preparations. + Right now single addon can block using certain actions. + Args: process_context (ProcessContext): The context in which the addons should be prepared. From e0339aeb104c13b8aada5a728d67104d3041dc3e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:25:45 +0200 Subject: [PATCH 13/14] require addons_manager and exit_on_failure as kwargs --- client/ayon_core/addon/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/addon/utils.py b/client/ayon_core/addon/utils.py index 8e8c2bd8d7..f983e37d3c 100644 --- a/client/ayon_core/addon/utils.py +++ b/client/ayon_core/addon/utils.py @@ -160,6 +160,7 @@ def ensure_addons_are_process_ready( addon_version: str, project_name: Optional[str] = None, headless: Optional[bool] = None, + *, addons_manager: Optional[AddonsManager] = None, exit_on_failure: bool = True, **kwargs, From 725584a8dbb9b29e7dc1f675cf2c174efc268d9d Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:29:56 +0200 Subject: [PATCH 14/14] require addon name/version Co-authored-by: Roy Nieterau --- client/ayon_core/addon/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 494c0f3da7..7f0636ccca 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -106,8 +106,8 @@ class ProcessContext: """ def __init__( self, - addon_name: str = None, - addon_version: str = None, + addon_name: str, + addon_version: str, project_name: Optional[str] = None, headless: Optional[bool] = None, **kwargs,