From 4ae8b75371b119822eede77635dcf10f4dbaf602 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Apr 2021 16:07:53 +0200 Subject: [PATCH 01/54] updated custom session with new timeout attribute --- pype/modules/ftrack/ftrack_server/lib.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py index 0b92f6486a..497d32a235 100644 --- a/pype/modules/ftrack/ftrack_server/lib.py +++ b/pype/modules/ftrack/ftrack_server/lib.py @@ -252,7 +252,7 @@ class CustomEventHubSession(ftrack_api.session.Session): self, server_url=None, api_key=None, api_user=None, auto_populate=True, plugin_paths=None, cache=None, cache_key_maker=None, auto_connect_event_hub=False, schema_cache_path=None, - plugin_arguments=None, **kwargs + plugin_arguments=None, timeout=60, **kwargs ): self.kwargs = kwargs @@ -331,6 +331,7 @@ class CustomEventHubSession(ftrack_api.session.Session): self._request.auth = ftrack_api.session.SessionAuthentication( self._api_key, self._api_user ) + self.request_timeout = timeout self.auto_populate = auto_populate @@ -368,8 +369,9 @@ class CustomEventHubSession(ftrack_api.session.Session): # rebuilding types)? if schema_cache_path is not False: if schema_cache_path is None: + schema_cache_path = appdirs.user_cache_dir() schema_cache_path = os.environ.get( - 'FTRACK_API_SCHEMA_CACHE_PATH', tempfile.gettempdir() + 'FTRACK_API_SCHEMA_CACHE_PATH', schema_cache_path ) schema_cache_path = os.path.join( From 07a704cc27d5e153dc4ddd4710a245aeada20703 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Apr 2021 16:08:18 +0200 Subject: [PATCH 02/54] ftrack server waits until event hub is connected --- pype/modules/ftrack/ftrack_server/ftrack_server.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pype/modules/ftrack/ftrack_server/ftrack_server.py b/pype/modules/ftrack/ftrack_server/ftrack_server.py index 1612a2f474..a52faa176e 100644 --- a/pype/modules/ftrack/ftrack_server/ftrack_server.py +++ b/pype/modules/ftrack/ftrack_server/ftrack_server.py @@ -1,4 +1,5 @@ import os +import time import types import logging import traceback @@ -10,7 +11,6 @@ from pype.lib import ( modules_from_path ) - log = PypeLogger.get_logger(__name__) """ @@ -120,6 +120,18 @@ class FtrackServer: if not session: session = ftrack_api.Session(auto_connect_event_hub=True) + # Wait until session has connected event hub + if session._auto_connect_event_hub_thread: + # Use timeout from session (since ftrack-api 2.1.0) + timeout = getattr(session, "request_timeout", 60) + started = time.time() + while not session.event_hub.connected: + if (time.time() - started) > timeout: + raise RuntimeError(( + "Connection to Ftrack was not created in {} seconds" + ).format(timeout)) + time.sleep(0.1) + self.session = session if load_files: if not self.handler_paths: From 81b6452903b32e1970c7262a435ecd5f40cc8474 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Apr 2021 16:13:37 +0200 Subject: [PATCH 03/54] forgotten module import --- pype/modules/ftrack/ftrack_server/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py index 497d32a235..ad0fc34b01 100644 --- a/pype/modules/ftrack/ftrack_server/lib.py +++ b/pype/modules/ftrack/ftrack_server/lib.py @@ -3,11 +3,11 @@ import sys import logging import getpass import atexit -import tempfile import threading import datetime import time import queue +import appdirs import pymongo import requests From fb4786e8aa8b557b8d4897f5edd4af21114a3d44 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 6 Apr 2021 10:10:39 +0200 Subject: [PATCH 04/54] launch arguments may be a string --- openpype/lib/applications.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index e043c9d05c..e5bfe679d1 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -804,10 +804,15 @@ class ApplicationLaunchContext: self.log.debug("All prelaunch hook executed. Starting new process.") # Prepare subprocess args - args = self.clear_launch_args(self.launch_args) - self.log.debug( - "Launching \"{}\" with args ({}): {}".format( - self.app_name, len(args), args + args_len_str = "" + if isinstance(self.launch_args, str): + args = self.launch_args + else: + args = self.clear_launch_args(self.launch_args) + args_len_str = " ({})".format(len(args)) + self.log.info( + "Launching \"{}\" with args{}: {}".format( + self.app_name, args_len_str, args ) ) # Run process From bb2a82d8e322c78eab8adccdd4687339f27f239c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 6 Apr 2021 10:12:11 +0200 Subject: [PATCH 05/54] arguments are not stored as list but as string as it is required for subprocess.Popen --- openpype/hooks/pre_with_windows_shell.py | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/openpype/hooks/pre_with_windows_shell.py b/openpype/hooks/pre_with_windows_shell.py index 5f0f03f13e..fbc9cafae0 100644 --- a/openpype/hooks/pre_with_windows_shell.py +++ b/openpype/hooks/pre_with_windows_shell.py @@ -1,4 +1,5 @@ import os +import subprocess from openpype.lib import PreLaunchHook @@ -15,10 +16,22 @@ class LaunchWithWindowsShell(PreLaunchHook): platforms = ["windows"] def execute(self): - # Get comspec which is cmd.exe in most cases. - comspec = os.environ.get("COMSPEC", "cmd.exe") - # Add comspec to arguments list and add "/k" - new_args = [comspec, "/c"] - new_args.extend(self.launch_context.launch_args) + new_args = [ + # Get comspec which is cmd.exe in most cases. + os.environ.get("COMSPEC", "cmd.exe"), + # NOTE change to "/k" if want to keep console opened + "/c", + # Convert arguments to command line arguments (as string) + "\"{}\"".format( + subprocess.list2cmdline(self.launch_context.launch_args) + ) + ] + # Convert list to string + # WARNING this only works if is used as string + args_string = " ".join(new_args) + self.log.info(( + "Modified launch arguments to be launched with shell \"{}\"." + ).format(args_string)) + # Replace launch args with new one - self.launch_context.launch_args = new_args + self.launch_context.launch_args = args_string From 59a512db43f7ed45242b12764353acc7fb87fb22 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 6 Apr 2021 10:12:22 +0200 Subject: [PATCH 06/54] change creationflags --- openpype/hooks/pre_with_windows_shell.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hooks/pre_with_windows_shell.py b/openpype/hooks/pre_with_windows_shell.py index fbc9cafae0..a06191ad04 100644 --- a/openpype/hooks/pre_with_windows_shell.py +++ b/openpype/hooks/pre_with_windows_shell.py @@ -35,3 +35,7 @@ class LaunchWithWindowsShell(PreLaunchHook): # Replace launch args with new one self.launch_context.launch_args = args_string + # Change `creationflags` to CREATE_NEW_CONSOLE + self.launch_context.kwargs["creationflags"] = ( + subprocess.CREATE_NEW_CONSOLE + ) From 83f24e491ceeac94ce850f696eeda7dcbf28b233 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 6 Apr 2021 10:12:30 +0200 Subject: [PATCH 07/54] changed order of shell prelaunch hook --- openpype/hooks/pre_with_windows_shell.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hooks/pre_with_windows_shell.py b/openpype/hooks/pre_with_windows_shell.py index a06191ad04..e26c31532b 100644 --- a/openpype/hooks/pre_with_windows_shell.py +++ b/openpype/hooks/pre_with_windows_shell.py @@ -11,7 +11,8 @@ class LaunchWithWindowsShell(PreLaunchHook): instead. """ - order = 10 + # Should be as last hook becuase must change launch arguments to string + order = 1000 app_groups = ["resolve", "nuke", "nukex", "hiero", "nukestudio"] platforms = ["windows"] From 37db18a6300b4014c300dc378e2422106e006fb5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 6 Apr 2021 10:13:57 +0200 Subject: [PATCH 08/54] better while loop logic --- openpype/lib/applications.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index e5bfe679d1..6ce2ec297d 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -858,7 +858,10 @@ class ApplicationLaunchContext: Return: list: Unpacked arguments. """ - while True: + if isinstance(args, str): + return args + all_cleared = False + while not all_cleared: all_cleared = True new_args = [] for arg in args: @@ -870,8 +873,6 @@ class ApplicationLaunchContext: new_args.append(arg) args = new_args - if all_cleared: - break return args From fb16f1e7e1843eb0d0bbf93ecaf3602dffdbe246 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 7 Apr 2021 13:44:33 +0200 Subject: [PATCH 09/54] Fix clean up of composition must propagate to instance --- .../aftereffects/plugins/publish/remove_publish_highlight.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/aftereffects/plugins/publish/remove_publish_highlight.py b/openpype/hosts/aftereffects/plugins/publish/remove_publish_highlight.py index 291f22e3b8..d2b3fd1b12 100644 --- a/openpype/hosts/aftereffects/plugins/publish/remove_publish_highlight.py +++ b/openpype/hosts/aftereffects/plugins/publish/remove_publish_highlight.py @@ -21,3 +21,4 @@ class RemovePublishHighlight(openpype.api.Extractor): item = instance.data comp_name = item["comp_name"].replace(stub.PUBLISH_ICON, '') stub.rename_item(item["comp_id"], comp_name) + instance.data["comp_name"] = comp_name From 95a3f2f5a263f1965a56ab5acd1f25738e44934e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 14:10:44 +0200 Subject: [PATCH 10/54] defined template for application variant --- .../template_host_variant_items.json | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant_items.json diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant_items.json b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant_items.json new file mode 100644 index 0000000000..bba4634c46 --- /dev/null +++ b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant_items.json @@ -0,0 +1,43 @@ +[ + { + "type": "path", + "key": "executables", + "label": "Executables", + "multiplatform": true, + "multipath": true + }, + { + "type":"separator" + }, + { + "type": "dict", + "key": "arguments", + "label": "Arguments", + "use_label_wrap": false, + "children": [ + { + "key": "windows", + "label": "Windows", + "type": "list", + "object_type": "text" + }, + { + "key": "darwin", + "label": "MacOS", + "type": "list", + "object_type": "text" + }, + { + "key": "linux", + "label": "Linux", + "type": "list", + "object_type": "text" + } + ] + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json" + } +] From 3ac2a0c7c72644d8a61c1b69dd7712e1b2fc5be6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 14:11:45 +0200 Subject: [PATCH 11/54] modified template_host_variant to use template_host_variant_items --- .../host_settings/template_host_variant.json | 43 ++----------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json index 63d3d9413d..82da407942 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json @@ -15,48 +15,11 @@ "type": "text", "key": "variant_label", "label": "Variant label", - "placeholder": "Only \"Label\" is used if not filled." + "placeholder": "< {app_variant} >" }, { - "type": "path", - "key": "executables", - "label": "Executables", - "multiplatform": true, - "multipath": true - }, - { - "type":"separator" - }, - { - "type": "dict", - "key": "arguments", - "label": "Arguments", - "use_label_wrap": false, - "children": [ - { - "key": "windows", - "label": "Windows", - "type": "list", - "object_type": "text" - }, - { - "key": "darwin", - "label": "MacOS", - "type": "list", - "object_type": "text" - }, - { - "key": "linux", - "label": "Linux", - "type": "list", - "object_type": "text" - } - ] - }, - { - "key": "environment", - "label": "Environment", - "type": "raw-json" + "type": "template", + "name": "template_host_variant_items" } ] } From 03bd7bff9b6b1aaf39b8a1a6d59092680520125a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 14:35:38 +0200 Subject: [PATCH 12/54] fix invalid key style in mutable dict --- .../tools/settings/settings/widgets/dict_mutable_widget.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/widgets/dict_mutable_widget.py b/openpype/tools/settings/settings/widgets/dict_mutable_widget.py index 3b5f15f519..f849a9a2a9 100644 --- a/openpype/tools/settings/settings/widgets/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/widgets/dict_mutable_widget.py @@ -103,7 +103,10 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget): self.key_is_valid = KEY_REGEX.match(key) self.is_duplicated = self.entity_widget.is_key_duplicated(key) key_input_state = "" - if self.is_duplicated or not self.key_is_valid: + # Collapsible key and empty key are not invalid + if self.collapsible_key and self.key_input.text() == "": + pass + elif self.is_duplicated or not self.key_is_valid: key_input_state = "invalid" elif key != "": key_input_state = "modified" From 32c7382b764919ef6fd48c4eef74e0b591b1777d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 14:52:49 +0200 Subject: [PATCH 13/54] allow to have not set label on modifiable dict with enabled collapsible_key --- openpype/settings/entities/dict_mutable_keys_entity.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/settings/entities/dict_mutable_keys_entity.py b/openpype/settings/entities/dict_mutable_keys_entity.py index cbc80b6409..7ba44ed0df 100644 --- a/openpype/settings/entities/dict_mutable_keys_entity.py +++ b/openpype/settings/entities/dict_mutable_keys_entity.py @@ -226,7 +226,16 @@ class DictMutableKeysEntity(EndpointEntity): self.is_group = True def schema_validations(self): + # Allow to have not set label if keys are collapsible + # - this it to bypass label validation + used_temp_label = False + if self.is_group and not self.label and self.collapsible_key: + used_temp_label = True + self.label = "LABEL" + super(DictMutableKeysEntity, self).schema_validations() + if used_temp_label: + self.label = None if not self.schema_data.get("object_type"): reason = ( From 9f528e68b2e34562b4113b42c2a0395e9a5eea60 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 14:55:14 +0200 Subject: [PATCH 14/54] fix template type --- .../system_schema/host_settings/template_host_variant.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json index 82da407942..33cde3d216 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/template_host_variant.json @@ -18,7 +18,7 @@ "placeholder": "< {app_variant} >" }, { - "type": "template", + "type": "schema_template", "name": "template_host_variant_items" } ] From d7840ce760e1a2386359463e18041c42997fe693 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 15:02:47 +0200 Subject: [PATCH 15/54] added dynamic variants for blender --- .../host_settings/schema_blender.json | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json index 98d0f99843..e6e7381e9f 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json @@ -20,24 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant_label": "2.83", - "app_variant": "2-83" - }, - { - "app_variant_label": "2.90", - "app_variant": "2-90" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } From 1f62875f9d610e86a7ff8097133c91e59f16a598 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 15:03:18 +0200 Subject: [PATCH 16/54] added dynamic variants for other applications that may benefit from it --- .../host_settings/schema_djv.json | 24 ++++++----- .../host_settings/schema_houdini.json | 36 +++++++---------- .../host_settings/schema_maya.json | 36 +++++++---------- .../host_settings/schema_mayabatch.json | 36 +++++++---------- .../host_settings/schema_tvpaint.json | 32 +++++++-------- .../host_settings/template_nuke.json | 40 +++++++------------ 6 files changed, 89 insertions(+), 115 deletions(-) diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json index 9698266bca..a95cedf7c3 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json @@ -20,18 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": { - "app_variant_label": "1.1", - "app_variant": "1-1" + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" } - } - ] + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json index a6d2103dbe..22a5b2e737 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json @@ -20,28 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant_label": "18.5", - "app_variant": "18-5" - }, - { - "app_variant_label": "18", - "app_variant": "18" - }, - { - "app_variant_label": "17", - "app_variant": "17" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json index 007ebb4d62..7c33671fa7 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json @@ -20,28 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant_label": "2020", - "app_variant": "2020" - }, - { - "app_variant_label": "2019", - "app_variant": "2019" - }, - { - "app_variant_label": "2018", - "app_variant": "2018" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json index bdeca9089c..93e3adbd8e 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json @@ -20,28 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant_label": "2020", - "app_variant": "2020" - }, - { - "app_variant_label": "2019", - "app_variant": "2019" - }, - { - "app_variant_label": "2018", - "app_variant": "2018" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json index 8f8c2c5ac5..eac09be113 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json @@ -20,24 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant_label": "Animation 11 (64bits)", - "app_variant": "animation_11-64bits" - }, - { - "app_variant_label": "Animation 11 (32bits)", - "app_variant": "animation_11-32bits" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json b/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json index 737a695e1b..3f25c7d72f 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json @@ -21,32 +21,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant": "12-2", - "app_variant_label": "12.2" - }, - { - "app_variant": "12-0", - "app_variant_label": "12.0" - }, - { - "app_variant": "11-3", - "app_variant_label": "11.3" - }, - { - "app_variant": "11-2", - "app_variant_label": "11.2" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } From 1b7e7054191232701d929dc4af6b3a402bb7d6b4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 15:39:21 +0200 Subject: [PATCH 17/54] fix apps enum to have correct labels --- openpype/settings/entities/enum_entity.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openpype/settings/entities/enum_entity.py b/openpype/settings/entities/enum_entity.py index 919fd3178e..693305cb1e 100644 --- a/openpype/settings/entities/enum_entity.py +++ b/openpype/settings/entities/enum_entity.py @@ -128,13 +128,21 @@ class AppsEnumEntity(BaseEnumEntity): continue group_label = app_group["label"].value - - for variant_name, variant_entity in app_group["variants"].items(): + variants_entity = app_group["variants"] + for variant_name, variant_entity in variants_entity.items(): enabled_entity = variant_entity.get("enabled") if enabled_entity and not enabled_entity.value: continue - variant_label = variant_entity["variant_label"].value + variant_label = None + if "variant_label" in variant_entity: + variant_label = variant_entity["variant_label"].value + elif hasattr(variants_entity, "get_key_label"): + variant_label = variants_entity.get_key_label(variant_name) + + if not variant_label: + variant_label = variant_name + if group_label: full_label = "{} {}".format(group_label, variant_label) else: From 811d55971660350322a172ebda69bf38e2878e24 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 7 Apr 2021 16:01:15 +0200 Subject: [PATCH 18/54] AE remove orphaned instance from workfile Orphaned instance points to composition that doesn't exist anymore. Delete that instance, log warning --- .../hosts/aftereffects/plugins/publish/collect_render.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_render.py b/openpype/hosts/aftereffects/plugins/publish/collect_render.py index 4a124991fd..ba64551283 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_render.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_render.py @@ -46,6 +46,12 @@ class CollectAERender(abstract_collect_render.AbstractCollectRender): "Please recreate instance.") item_id = inst["members"][0] work_area_info = self.stub.get_work_area(int(item_id)) + + if not work_area_info: + self.log.warning("Orphaned instance, deleting metadata") + self.stub.remove_instance(int(item_id)) + continue + frameStart = work_area_info.workAreaStart frameEnd = round(work_area_info.workAreaStart + From f5830d9b1544d7c333b017f7190e442a5225f26f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:26:04 +0200 Subject: [PATCH 19/54] it is possible to retrieve settings with metadata and with or without local settings --- openpype/settings/lib.py | 74 +++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 60a51c01a0..895fc1e133 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -645,13 +645,22 @@ def apply_local_settings_on_project_settings( sync_server_config["remote_site"] = remote_site -def get_system_settings(clear_metadata=True): +def get_system_settings(clear_metadata=True, exclude_locals=None): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] studio_values = get_studio_system_settings_overrides() result = apply_overrides(default_values, studio_values) + + # Clear overrides metadata from settings if clear_metadata: clear_metadata_from_settings(result) + + # Apply local settings + # Default behavior is based on `clear_metadata` value + if exclude_locals is None: + exclude_locals = not clear_metadata + + if not exclude_locals: # TODO local settings may be required to apply for environments local_settings = get_local_settings() apply_local_settings_on_system_settings(result, local_settings) @@ -659,40 +668,52 @@ def get_system_settings(clear_metadata=True): return result -def get_default_project_settings(clear_metadata=True, exclude_locals=False): +def get_default_project_settings(clear_metadata=True, exclude_locals=None): """Project settings with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_SETTINGS_KEY] studio_values = get_studio_project_settings_overrides() result = apply_overrides(default_values, studio_values) + # Clear overrides metadata from settings if clear_metadata: clear_metadata_from_settings(result) - if not exclude_locals: - local_settings = get_local_settings() - apply_local_settings_on_project_settings( - result, local_settings, None - ) + + # Apply local settings + if exclude_locals is None: + exclude_locals = not clear_metadata + + if not exclude_locals: + local_settings = get_local_settings() + apply_local_settings_on_project_settings( + result, local_settings, None + ) return result -def get_default_anatomy_settings(clear_metadata=True, exclude_locals=False): +def get_default_anatomy_settings(clear_metadata=True, exclude_locals=None): """Project anatomy data with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_ANATOMY_KEY] studio_values = get_studio_project_anatomy_overrides() - # TODO uncomment and remove hotfix result when overrides of anatomy - # are stored correctly. result = apply_overrides(default_values, studio_values) + # Clear overrides metadata from settings if clear_metadata: clear_metadata_from_settings(result) - if not exclude_locals: - local_settings = get_local_settings() - apply_local_settings_on_anatomy_settings( - result, local_settings, None - ) + + # Apply local settings + if exclude_locals is None: + exclude_locals = not clear_metadata + + if not exclude_locals: + local_settings = get_local_settings() + apply_local_settings_on_anatomy_settings( + result, local_settings, None + ) return result -def get_anatomy_settings(project_name, site_name=None, exclude_locals=False): +def get_anatomy_settings( + project_name, site_name=None, clear_metadata=True, exclude_locals=None +): """Project anatomy data with applied studio and project overrides.""" if not project_name: raise ValueError( @@ -709,7 +730,13 @@ def get_anatomy_settings(project_name, site_name=None, exclude_locals=False): for key, value in project_overrides.items(): result[key] = value - clear_metadata_from_settings(result) + # Clear overrides metadata from settings + if clear_metadata: + clear_metadata_from_settings(result) + + # Apply local settings + if exclude_locals is None: + exclude_locals = not clear_metadata if not exclude_locals: local_settings = get_local_settings() @@ -719,7 +746,9 @@ def get_anatomy_settings(project_name, site_name=None, exclude_locals=False): return result -def get_project_settings(project_name, exclude_locals=False): +def get_project_settings( + project_name, clear_metadata=True, exclude_locals=None +): """Project settings with applied studio and project overrides.""" if not project_name: raise ValueError( @@ -733,7 +762,14 @@ def get_project_settings(project_name, exclude_locals=False): ) result = apply_overrides(studio_overrides, project_overrides) - clear_metadata_from_settings(result) + + # Clear overrides metadata from settings + if clear_metadata: + clear_metadata_from_settings(result) + + # Apply local settings + if exclude_locals is None: + exclude_locals = not clear_metadata if not exclude_locals: local_settings = get_local_settings() From 8ba5fd54dbeba18b1b127226f51631016ddf9d84 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:26:36 +0200 Subject: [PATCH 20/54] saved defaults of applications --- .../system_settings/applications.json | 99 ++++++++----------- 1 file changed, 39 insertions(+), 60 deletions(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 42e742d07c..38320b8981 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -20,8 +20,6 @@ }, "variants": { "2020": { - "enabled": true, - "variant_label": "2020", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2020\\bin\\maya.exe" @@ -41,8 +39,6 @@ } }, "2019": { - "enabled": true, - "variant_label": "2019", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2019\\bin\\maya.exe" @@ -62,8 +58,6 @@ } }, "2018": { - "enabled": true, - "variant_label": "2018", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2018\\bin\\maya.exe" @@ -106,8 +100,6 @@ }, "variants": { "2020": { - "enabled": true, - "variant_label": "2020", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe" @@ -125,8 +117,6 @@ } }, "2019": { - "enabled": true, - "variant_label": "2019", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe" @@ -144,8 +134,6 @@ } }, "2018": { - "enabled": true, - "variant_label": "2018", "executables": { "windows": [ "C:\\Program Files\\Autodesk\\Maya2018\\bin\\mayabatch.exe" @@ -182,8 +170,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -201,8 +187,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -220,8 +204,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -239,8 +221,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -254,6 +234,11 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3" } } }, @@ -275,8 +260,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -300,8 +283,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -325,8 +306,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -350,8 +329,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -371,6 +348,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -392,8 +375,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -417,8 +398,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -442,8 +421,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -467,8 +444,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [], "darwin": [], @@ -486,6 +461,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -507,8 +488,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -532,8 +511,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -557,8 +534,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -582,8 +557,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -603,6 +576,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -752,8 +731,6 @@ }, "variants": { "18-5": { - "enabled": true, - "variant_label": "18.5", "executables": { "windows": [ "C:\\Program Files\\Side Effects Software\\Houdini 18.5.499\\bin\\houdini.exe" @@ -769,8 +746,6 @@ "environment": {} }, "18": { - "enabled": true, - "variant_label": "18", "executables": { "windows": [], "darwin": [], @@ -784,8 +759,6 @@ "environment": {} }, "17": { - "enabled": true, - "variant_label": "17", "executables": { "windows": [], "darwin": [], @@ -797,6 +770,11 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "18-5": "18.5", + "18": "18", + "17": "17" } } }, @@ -815,8 +793,6 @@ }, "variants": { "2-83": { - "enabled": true, - "variant_label": "2.83", "executables": { "windows": [ "C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe" @@ -838,8 +814,6 @@ "environment": {} }, "2-90": { - "enabled": true, - "variant_label": "2.90", "executables": { "windows": [ "C:\\Program Files\\Blender Foundation\\Blender 2.90\\blender.exe" @@ -859,6 +833,10 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "2-83": "2.83", + "2-90": "2.90" } } }, @@ -916,8 +894,6 @@ }, "variants": { "animation_11-64bits": { - "enabled": true, - "variant_label": "11 (64bits)", "executables": { "windows": [ "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe" @@ -933,8 +909,6 @@ "environment": {} }, "animation_11-32bits": { - "enabled": true, - "variant_label": "11 (32bits)", "executables": { "windows": [ "C:\\Program Files (x86)\\TVPaint Developpement\\TVPaint Animation 11 (32bits)\\TVPaint Animation 11 (32bits).exe" @@ -948,6 +922,10 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "animation_11-64bits": "11 (64bits)", + "animation_11-32bits": "11 (32bits)" } } }, @@ -1160,8 +1138,6 @@ "environment": {}, "variants": { "1-1": { - "enabled": true, - "variant_label": "1.1", "executables": { "windows": [], "darwin": [], @@ -1173,6 +1149,9 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "1-1": "1.1" } } } From db4836e66217cdee37247857ac3657f703f54c3f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:36:39 +0200 Subject: [PATCH 21/54] fill variant label with label from metadata --- openpype/lib/applications.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 3302a88f97..a3c5b00a0b 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -17,6 +17,10 @@ from openpype.settings import ( get_project_settings, get_environments ) +from openpype.settings.constants import ( + METADATA_KEYS, + M_DYNAMIC_KEY_LABEL +) from . import ( PypeLogger, Anatomy @@ -123,7 +127,16 @@ class ApplicationGroup: self.host_name = host_name variants = data.get("variants") or {} + key_label_mapping = variants.pop(M_DYNAMIC_KEY_LABEL, {}) for variant_name, variant_data in variants.items(): + if variant_name in METADATA_KEYS: + continue + + if "variant_label" not in variant_data: + variant_label = key_label_mapping.get(variant_name) + if variant_label: + variant_data["variant_label"] = variant_label + variants[variant_name] = Application( variant_name, variant_data, self ) @@ -265,10 +278,15 @@ class ApplicationManager: self.tool_groups.clear() self.tools.clear() - settings = get_system_settings() + settings = get_system_settings( + clear_metadata=False, exclude_locals=False + ) app_defs = settings["applications"] for group_name, variant_defs in app_defs.items(): + if group_name in METADATA_KEYS: + continue + group = ApplicationGroup(group_name, variant_defs, self) self.app_groups[group_name] = group for app in group: @@ -277,7 +295,7 @@ class ApplicationManager: tools_definitions = settings["tools"]["tool_groups"] for tool_group_name, tool_group_data in tools_definitions.items(): - if not tool_group_name: + if not tool_group_name or tool_group_name in METADATA_KEYS: continue group = EnvironmentToolGroup( tool_group_name, tool_group_data, self From 633f99f13ea85bdf666e99726add89a25b600b3a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:37:00 +0200 Subject: [PATCH 22/54] count with metadata keys in tools too and add variant label too --- openpype/lib/applications.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index a3c5b00a0b..d48a8ea619 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -361,9 +361,16 @@ class EnvironmentToolGroup: self._environment = data["environment"] variants = data.get("variants") or {} + label_by_key = variants.pop(M_DYNAMIC_KEY_LABEL, {}) variants_by_name = {} for variant_name, variant_env in variants.items(): - tool = EnvironmentTool(variant_name, variant_env, self) + if variant_name in METADATA_KEYS: + continue + + variant_label = label_by_key.get(variant_name) or variant_name + tool = EnvironmentTool( + variant_name, variant_label, variant_env, self + ) variants_by_name[variant_name] = tool self.variants = variants_by_name @@ -390,8 +397,9 @@ class EnvironmentTool: group (str): Name of group which wraps tool. """ - def __init__(self, name, environment, group): + def __init__(self, name, label, environment, group): self.name = name + self.label = label self.group = group self._environment = environment self.full_name = "/".join((group.name, name)) From b86c56015a3e6def5fcadebba9301ee30f327f91 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:37:10 +0200 Subject: [PATCH 23/54] removed TODO which is already done --- openpype/lib/applications.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index d48a8ea619..660f7598e2 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -290,7 +290,6 @@ class ApplicationManager: group = ApplicationGroup(group_name, variant_defs, self) self.app_groups[group_name] = group for app in group: - # TODO This should be replaced with `full_name` in future self.applications[app.full_name] = app tools_definitions = settings["tools"]["tool_groups"] From 3c4f48e3ab0ad83157b189aa9c176dac75991512 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:49:38 +0200 Subject: [PATCH 24/54] fix applications in local settings --- .../settings/local_settings/apps_widget.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/openpype/tools/settings/local_settings/apps_widget.py b/openpype/tools/settings/local_settings/apps_widget.py index bc27a3c1c4..2e12c010d1 100644 --- a/openpype/tools/settings/local_settings/apps_widget.py +++ b/openpype/tools/settings/local_settings/apps_widget.py @@ -10,12 +10,20 @@ from .constants import CHILD_OFFSET class AppVariantWidget(QtWidgets.QWidget): exec_placeholder = "< Specific path for this machine >" - def __init__(self, group_label, variant_entity, parent): + def __init__(self, group_label, variant_name, variant_entity, parent): super(AppVariantWidget, self).__init__(parent) self.executable_input_widget = None + variant_label = variant_entity.label + if variant_label is None: + parent_entity = variant_entity.parent + if hasattr(parent_entity, "get_key_label"): + variant_label = parent_entity.get_key_label(variant_name) - label = " ".join([group_label, variant_entity.label]) + if not variant_label: + variant_label = variant_name + + label = " ".join([group_label, variant_label]) expading_widget = ExpandingWidget(label, self) content_widget = QtWidgets.QWidget(expading_widget) @@ -102,7 +110,7 @@ class AppGroupWidget(QtWidgets.QWidget): valid_variants = {} for key, entity in group_entity["variants"].items(): - if entity["enabled"].value: + if "enabled" not in entity or entity["enabled"].value: valid_variants[key] = entity group_label = group_entity.label @@ -114,7 +122,7 @@ class AppGroupWidget(QtWidgets.QWidget): widgets_by_variant_name = {} for variant_name, variant_entity in valid_variants.items(): variant_widget = AppVariantWidget( - group_label, variant_entity, content_widget + group_label, variant_name, variant_entity, content_widget ) widgets_by_variant_name[variant_name] = variant_widget content_layout.addWidget(variant_widget) @@ -173,7 +181,10 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): # Check if has enabled any variant enabled_variant = False for variant_entity in entity["variants"].values(): - if variant_entity["enabled"].value: + if ( + "enabled" not in variant_entity + or variant_entity["enabled"].value + ): enabled_variant = True break From e59e959a95050abf9bbbcfcfc5e8889778a3c792 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 16:51:05 +0200 Subject: [PATCH 25/54] fix enabled attribute in Application class --- openpype/lib/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 660f7598e2..dd6d0b93f4 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -178,7 +178,7 @@ class Application: enabled = False if group.enabled: enabled = data.get("enabled", True) - self.enabled = enabled + self.enabled = enabled self.label = data.get("variant_label") or name self.full_name = "/".join((group.name, name)) From da32cbe8b0376d186f6fc817c9d2685521e05d06 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 17:17:04 +0200 Subject: [PATCH 26/54] fix tool labels --- openpype/lib/applications.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index dd6d0b93f4..a6c110aa87 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -293,11 +293,16 @@ class ApplicationManager: self.applications[app.full_name] = app tools_definitions = settings["tools"]["tool_groups"] + tool_label_mapping = tools_definitions.pop(M_DYNAMIC_KEY_LABEL, {}) for tool_group_name, tool_group_data in tools_definitions.items(): if not tool_group_name or tool_group_name in METADATA_KEYS: continue + + tool_group_label = ( + tool_label_mapping.get(tool_group_name) or tool_group_name + ) group = EnvironmentToolGroup( - tool_group_name, tool_group_data, self + tool_group_name, tool_group_label, tool_group_data, self ) self.tool_groups[tool_group_name] = group for tool in group: @@ -353,8 +358,9 @@ class EnvironmentToolGroup: manager (ApplicationManager): Manager that creates the group. """ - def __init__(self, name, data, manager): + def __init__(self, name, label, data, manager): self.name = name + self.label = label self._data = data self.manager = manager self._environment = data["environment"] @@ -398,7 +404,8 @@ class EnvironmentTool: def __init__(self, name, label, environment, group): self.name = name - self.label = label + self.variant_label = label + self.label = " ".join((group.label, label)) self.group = group self._environment = environment self.full_name = "/".join((group.name, name)) From 19a9a54754e12aa3ce37fa0d73aee691b6db39ab Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 17:17:19 +0200 Subject: [PATCH 27/54] ftrack custom attributes have right tool label --- .../ftrack/event_handlers_user/action_create_cust_attrs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_create_cust_attrs.py b/openpype/modules/ftrack/event_handlers_user/action_create_cust_attrs.py index 0ebd221e9f..63025d35b3 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_create_cust_attrs.py +++ b/openpype/modules/ftrack/event_handlers_user/action_create_cust_attrs.py @@ -400,9 +400,9 @@ class CustomAttributes(BaseAction): def tools_attribute(self, event): tools_data = [] - for tool_name in self.app_manager.tools.keys(): + for tool_name, tool in self.app_manager.tools.items(): tools_data.append({ - tool_name: tool_name + tool_name: tool.label }) # Make sure there is at least one item From dd8240125985fd597b6329f4ff3ce1e23429e5d5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 7 Apr 2021 17:33:41 +0200 Subject: [PATCH 28/54] fix `root_value_for_template` method in Anatomy --- openpype/lib/anatomy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/anatomy.py b/openpype/lib/anatomy.py index ff15aec41a..c16c6e2e99 100644 --- a/openpype/lib/anatomy.py +++ b/openpype/lib/anatomy.py @@ -216,7 +216,7 @@ class Anatomy: """Returns value of root key from template.""" root_templates = [] for group in re.findall(self.root_key_regex, template): - root_templates.append(group) + root_templates.append("{" + group + "}") if not root_templates: return None From 0d71f7c216e2336967408c932c9b6e17a8791cfb Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 8 Apr 2021 09:50:20 +0200 Subject: [PATCH 29/54] remove mayabatch from applications --- .../host_settings/schema_mayabatch.json | 41 ------------------- .../system_schema/schema_applications.json | 4 -- 2 files changed, 45 deletions(-) delete mode 100644 openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json deleted file mode 100644 index 93e3adbd8e..0000000000 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "dict", - "key": "mayabatch", - "label": "Autodesk Maya Batch", - "collapsible": true, - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "schema_template", - "name": "template_host_unchangables" - }, - { - "key": "environment", - "label": "Environment", - "type": "raw-json" - }, - { - "type": "dict-modifiable", - "key": "variants", - "collapsible_key": true, - "dynamic_label": false, - "use_label_wrap": false, - "object_type": { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant_items" - } - ] - } - } - ] -} diff --git a/openpype/settings/entities/schemas/system_schema/schema_applications.json b/openpype/settings/entities/schemas/system_schema/schema_applications.json index 61d47df8b6..efdd021ede 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_applications.json +++ b/openpype/settings/entities/schemas/system_schema/schema_applications.json @@ -9,10 +9,6 @@ "type": "schema", "name": "schema_maya" }, - { - "type": "schema", - "name": "schema_mayabatch" - }, { "type": "schema_template", "name": "template_nuke", From 42fd33ef819981d831bda430ae1175539341593e Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 8 Apr 2021 09:53:16 +0200 Subject: [PATCH 30/54] add unreal and terminal to modifiable applications --- .../system_settings/applications.json | 86 +------------------ .../host_settings/schema_shell.json | 36 ++++---- .../host_settings/schema_unreal.json | 28 +++--- 3 files changed, 34 insertions(+), 116 deletions(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 38320b8981..8034bc6368 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -78,80 +78,6 @@ } } }, - "mayabatch": { - "enabled": true, - "label": "MayaBatch", - "icon": "{}/app_icons/maya.png", - "host_name": "maya", - "environment": { - "PYTHONPATH": [ - "{OPENPYPE_ROOT}/avalon-core/setup/maya", - "{OPENPYPE_ROOT}/maya-look-assigner", - "{PYTHON_ENV}/python2/Lib/site-packages", - "{PYTHONPATH}" - ], - "MAYA_DISABLE_CLIC_IPM": "Yes", - "MAYA_DISABLE_CIP": "Yes", - "MAYA_DISABLE_CER": "Yes", - "PYMEL_SKIP_MEL_INIT": "Yes", - "LC_ALL": "C", - "OPENPYPE_LOG_NO_COLORS": "Yes", - "MAYA_TEST": "{MAYA_VERSION}" - }, - "variants": { - "2020": { - "executables": { - "windows": [ - "C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "MAYA_VERSION": "2020" - } - }, - "2019": { - "executables": { - "windows": [ - "C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "MAYA_VERSION": "2019" - } - }, - "2018": { - "executables": { - "windows": [ - "C:\\Program Files\\Autodesk\\Maya2018\\bin\\mayabatch.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "MAYA_VERSION": "2018" - } - } - } - }, "nuke": { "enabled": true, "label": "Nuke", @@ -1063,8 +989,6 @@ }, "variants": { "4-24": { - "enabled": true, - "variant_label": "4.24", "executables": { "windows": [], "darwin": [], @@ -1084,8 +1008,6 @@ "environment": {}, "variants": { "python_3-7": { - "enabled": true, - "variant_label": "3.7", "executables": { "windows": [], "darwin": [], @@ -1099,8 +1021,6 @@ "environment": {} }, "python_2-7": { - "enabled": true, - "variant_label": "2.7", "executables": { "windows": [], "darwin": [], @@ -1114,8 +1034,6 @@ "environment": {} }, "terminal": { - "enabled": true, - "variant_label": "", "executables": { "windows": [], "darwin": [], @@ -1127,6 +1045,10 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "python_3-7": "Python 3.7", + "python_2-7": "Python 2.7" } } }, diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json index 1e356154fd..e344f98594 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json @@ -16,28 +16,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant": "python_3-7", - "app_variant_label": "Python 3.7" - }, - { - "app_variant": "python_2-7", - "app_variant_label": "Python 2.7" - }, - { - "app_variant": "terminal", - "app_variant_label": "Terminal" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json index 3cf3005e70..c5096197d6 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json @@ -20,20 +20,22 @@ "type": "raw-json" }, { - "type": "dict", + "type": "dict-modifiable", "key": "variants", - "children": [ - { - "type": "schema_template", - "name": "template_host_variant", - "template_data": [ - { - "app_variant": "4-24", - "app_variant_label": "4.24" - } - ] - } - ] + "collapsible_key": true, + "dynamic_label": false, + "use_label_wrap": false, + "object_type": { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "schema_template", + "name": "template_host_variant_items" + } + ] + } } ] } From 38926fe85e96bebde76a0dcf926e3d776c57b3a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 10:10:20 +0200 Subject: [PATCH 31/54] updated custom session with new timeout attribute --- openpype/modules/ftrack/ftrack_server/lib.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/modules/ftrack/ftrack_server/lib.py b/openpype/modules/ftrack/ftrack_server/lib.py index 91f3712136..88f849e765 100644 --- a/openpype/modules/ftrack/ftrack_server/lib.py +++ b/openpype/modules/ftrack/ftrack_server/lib.py @@ -3,11 +3,11 @@ import sys import logging import getpass import atexit -import tempfile import threading import datetime import time import queue +import appdirs import pymongo import requests @@ -165,7 +165,6 @@ class ProcessEventHub(SocketBaseEventHub): def wait(self, duration=None): """Overriden wait - Event are loaded from Mongo DB when queue is empty. Handled event is set as processed in Mongo DB. """ @@ -252,7 +251,7 @@ class CustomEventHubSession(ftrack_api.session.Session): self, server_url=None, api_key=None, api_user=None, auto_populate=True, plugin_paths=None, cache=None, cache_key_maker=None, auto_connect_event_hub=False, schema_cache_path=None, - plugin_arguments=None, **kwargs + plugin_arguments=None, timeout=60, **kwargs ): self.kwargs = kwargs @@ -331,6 +330,7 @@ class CustomEventHubSession(ftrack_api.session.Session): self._request.auth = ftrack_api.session.SessionAuthentication( self._api_key, self._api_user ) + self.request_timeout = timeout self.auto_populate = auto_populate @@ -368,8 +368,9 @@ class CustomEventHubSession(ftrack_api.session.Session): # rebuilding types)? if schema_cache_path is not False: if schema_cache_path is None: + schema_cache_path = appdirs.user_cache_dir() schema_cache_path = os.environ.get( - 'FTRACK_API_SCHEMA_CACHE_PATH', tempfile.gettempdir() + 'FTRACK_API_SCHEMA_CACHE_PATH', schema_cache_path ) schema_cache_path = os.path.join( From ae5d05a813cae233c0d1e002b3e7072c8e0db9fb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 10:10:44 +0200 Subject: [PATCH 32/54] ftrack server waits until event hub is connected --- .../modules/ftrack/ftrack_server/ftrack_server.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/ftrack_server/ftrack_server.py b/openpype/modules/ftrack/ftrack_server/ftrack_server.py index 285ca29dc5..bd67fba3d6 100644 --- a/openpype/modules/ftrack/ftrack_server/ftrack_server.py +++ b/openpype/modules/ftrack/ftrack_server/ftrack_server.py @@ -1,4 +1,5 @@ import os +import time import types import logging import traceback @@ -10,7 +11,6 @@ from openpype.lib import ( modules_from_path ) - log = PypeLogger.get_logger(__name__) """ @@ -120,6 +120,18 @@ class FtrackServer: if not session: session = ftrack_api.Session(auto_connect_event_hub=True) + # Wait until session has connected event hub + if session._auto_connect_event_hub_thread: + # Use timeout from session (since ftrack-api 2.1.0) + timeout = getattr(session, "request_timeout", 60) + started = time.time() + while not session.event_hub.connected: + if (time.time() - started) > timeout: + raise RuntimeError(( + "Connection to Ftrack was not created in {} seconds" + ).format(timeout)) + time.sleep(0.1) + self.session = session if load_files: if not self.handler_paths: From 4377dbb02681ccb42628366c16e6c3429d2430f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 10:46:01 +0200 Subject: [PATCH 33/54] removed resolve from shell prelaunch hook --- openpype/hooks/pre_with_windows_shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hooks/pre_with_windows_shell.py b/openpype/hooks/pre_with_windows_shell.py index e26c31532b..0c10583b99 100644 --- a/openpype/hooks/pre_with_windows_shell.py +++ b/openpype/hooks/pre_with_windows_shell.py @@ -13,7 +13,7 @@ class LaunchWithWindowsShell(PreLaunchHook): # Should be as last hook becuase must change launch arguments to string order = 1000 - app_groups = ["resolve", "nuke", "nukex", "hiero", "nukestudio"] + app_groups = ["nuke", "nukex", "hiero", "nukestudio"] platforms = ["windows"] def execute(self): From 5d64ed22a24a6d263cf92c709a79d5f01498fb5d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 8 Apr 2021 11:01:54 +0200 Subject: [PATCH 34/54] remains of unrenamed pype. namespace --- openpype/hosts/aftereffects/api/__init__.py | 2 +- openpype/hosts/fusion/api/pipeline.py | 2 +- .../hosts/fusion/plugins/publish/collect_render_target.py | 4 ++-- openpype/hosts/fusion/scripts/set_rendermode.py | 4 ++-- openpype/hosts/hiero/startup/Python/Startup/Startup.py | 2 +- openpype/hosts/photoshop/api/__init__.py | 2 +- openpype/hosts/resolve/api/pipeline.py | 2 +- openpype/hosts/resolve/hooks/pre_resolve_setup.py | 2 +- openpype/scripts/export_maya_ass_job.py | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/aftereffects/api/__init__.py b/openpype/hosts/aftereffects/api/__init__.py index ee73a0f52b..9a80801652 100644 --- a/openpype/hosts/aftereffects/api/__init__.py +++ b/openpype/hosts/aftereffects/api/__init__.py @@ -10,7 +10,7 @@ import pyblish.api as pyblish import openpype.hosts.aftereffects -log = logging.getLogger("pype.hosts.aftereffects") +log = logging.getLogger("openpype.hosts.aftereffects") HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.aftereffects.__file__)) diff --git a/openpype/hosts/fusion/api/pipeline.py b/openpype/hosts/fusion/api/pipeline.py index 4fec548993..0095530087 100644 --- a/openpype/hosts/fusion/api/pipeline.py +++ b/openpype/hosts/fusion/api/pipeline.py @@ -39,7 +39,7 @@ def install(): avalon.data["familiesStateDefault"] = False avalon.data["familiesStateToggled"] = family_states - log.info("pype.hosts.fusion installed") + log.info("openpype.hosts.fusion installed") pyblish.register_host("fusion") pyblish.register_plugin_path(PUBLISH_PATH) diff --git a/openpype/hosts/fusion/plugins/publish/collect_render_target.py b/openpype/hosts/fusion/plugins/publish/collect_render_target.py index 50cc4fd3e9..39017f32e0 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_render_target.py +++ b/openpype/hosts/fusion/plugins/publish/collect_render_target.py @@ -13,7 +13,7 @@ class CollectFusionRenderMode(pyblish.api.InstancePlugin): available tool does not visualize which render mode is set for the current comp, please run the following line in the console (Py2) - comp.GetData("pype.rendermode") + comp.GetData("openpype.rendermode") This will return the name of the current render mode as seen above under Options. @@ -34,7 +34,7 @@ class CollectFusionRenderMode(pyblish.api.InstancePlugin): raise RuntimeError("No comp previously collected, unable to " "retrieve Fusion version.") - rendermode = comp.GetData("pype.rendermode") or "local" + rendermode = comp.GetData("openpype.rendermode") or "local" assert rendermode in options, "Must be supported render mode" self.log.info("Render mode: {0}".format(rendermode)) diff --git a/openpype/hosts/fusion/scripts/set_rendermode.py b/openpype/hosts/fusion/scripts/set_rendermode.py index cb0b9da513..cb104445a8 100644 --- a/openpype/hosts/fusion/scripts/set_rendermode.py +++ b/openpype/hosts/fusion/scripts/set_rendermode.py @@ -96,11 +96,11 @@ class SetRenderMode(QtWidgets.QWidget): return self._comp.GetAttrs("COMPS_Name") def _get_comp_rendermode(self): - return self._comp.GetData("pype.rendermode") or "local" + return self._comp.GetData("openpype.rendermode") or "local" def _set_comp_rendermode(self): rendermode = self.mode_options.currentText() - self._comp.SetData("pype.rendermode", rendermode) + self._comp.SetData("openpype.rendermode", rendermode) self._comp.Print("Updated render mode to '%s'\n" % rendermode) self.hide() diff --git a/openpype/hosts/hiero/startup/Python/Startup/Startup.py b/openpype/hosts/hiero/startup/Python/Startup/Startup.py index 8de2dc2d11..21c21cd7c3 100644 --- a/openpype/hosts/hiero/startup/Python/Startup/Startup.py +++ b/openpype/hosts/hiero/startup/Python/Startup/Startup.py @@ -6,7 +6,7 @@ import openpype.hosts.hiero.api as phiero avalon.api.install(phiero) try: - __import__("pype.hosts.hiero.api") + __import__("openpype.hosts.hiero.api") __import__("pyblish") except ImportError as e: diff --git a/openpype/hosts/photoshop/api/__init__.py b/openpype/hosts/photoshop/api/__init__.py index 7304574ffd..81942c3b2a 100644 --- a/openpype/hosts/photoshop/api/__init__.py +++ b/openpype/hosts/photoshop/api/__init__.py @@ -9,7 +9,7 @@ from openpype import lib from pyblish import api as pyblish import openpype.hosts.photoshop -log = logging.getLogger("pype.hosts.photoshop") +log = logging.getLogger("openpype.hosts.photoshop") HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.photoshop.__file__)) PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") diff --git a/openpype/hosts/resolve/api/pipeline.py b/openpype/hosts/resolve/api/pipeline.py index d4d928a7d9..e3a832459b 100644 --- a/openpype/hosts/resolve/api/pipeline.py +++ b/openpype/hosts/resolve/api/pipeline.py @@ -47,7 +47,7 @@ def install(): avalon.data["familiesStateDefault"] = False avalon.data["familiesStateToggled"] = family_states - log.info("pype.hosts.resolve installed") + log.info("openpype.hosts.resolve installed") pyblish.register_host("resolve") pyblish.register_plugin_path(PUBLISH_PATH) diff --git a/openpype/hosts/resolve/hooks/pre_resolve_setup.py b/openpype/hosts/resolve/hooks/pre_resolve_setup.py index 0ee55d3790..bcb27e24fc 100644 --- a/openpype/hosts/resolve/hooks/pre_resolve_setup.py +++ b/openpype/hosts/resolve/hooks/pre_resolve_setup.py @@ -44,7 +44,7 @@ class ResolvePrelaunch(PreLaunchHook): self.launch_context.env["PRE_PYTHON_SCRIPT"] = pre_py_sc self.log.debug(f"-- pre_py_sc: `{pre_py_sc}`...") try: - __import__("pype.hosts.resolve") + __import__("openpype.hosts.resolve") __import__("pyblish") except ImportError: diff --git a/openpype/scripts/export_maya_ass_job.py b/openpype/scripts/export_maya_ass_job.py index 6e5eff6663..16e841ce96 100644 --- a/openpype/scripts/export_maya_ass_job.py +++ b/openpype/scripts/export_maya_ass_job.py @@ -54,11 +54,11 @@ def __main__(): print("Got Pype location from environment: {}".format( os.environ.get('OPENPYPE_SETUP_PATH'))) - pype_command = "pype.ps1" + pype_command = "openpype.ps1" if platform.system().lower() == "linux": pype_command = "pype" elif platform.system().lower() == "windows": - pype_command = "pype.bat" + pype_command = "openpype.bat" if kwargs.pype: pype_root = kwargs.pype From cf2dc1f70e5507f466998e610e0faf76f5882916 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:31:04 +0200 Subject: [PATCH 35/54] renamed PypeSettingsRegistry to OpenPypeSettingsRegistry --- openpype/lib/__init__.py | 4 ++-- openpype/lib/local_settings.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 554c0d8ec3..7b2f533921 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -104,7 +104,7 @@ from .plugin_tools import ( from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, - PypeSettingsRegistry, + OpenPypeSettingsRegistry, get_local_site_id, change_openpype_mongo_url ) @@ -217,7 +217,7 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", - "PypeSettingsRegistry", + "OpenPypeSettingsRegistry", "get_local_site_id", "change_openpype_mongo_url", diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 82507cb0c0..2095f1253e 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -452,7 +452,7 @@ class JSONSettingRegistry(ASettingRegistry): json.dump(data, cfg, indent=4) -class PypeSettingsRegistry(JSONSettingRegistry): +class OpenPypeSettingsRegistry(JSONSettingRegistry): """Class handling Pype general settings registry. Attributes: @@ -463,9 +463,9 @@ class PypeSettingsRegistry(JSONSettingRegistry): def __init__(self): self.vendor = "pypeclub" - self.product = "pype" + self.product = "openpype" path = appdirs.user_data_dir(self.product, self.vendor) - super(PypeSettingsRegistry, self).__init__("pype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__("openpype_settings", path) def _create_local_site_id(registry=None): @@ -473,7 +473,7 @@ def _create_local_site_id(registry=None): from uuid import uuid4 if registry is None: - registry = PypeSettingsRegistry() + registry = OpenPypeSettingsRegistry() new_id = str(uuid4()) @@ -489,7 +489,7 @@ def get_local_site_id(): Identifier is created if does not exists yet. """ - registry = PypeSettingsRegistry() + registry = OpenPypeSettingsRegistry() try: return registry.get_item("localId") except ValueError: @@ -504,5 +504,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = PypeSettingsRegistry() - registry.set_secure_item("pypeMongo", new_mongo_url) + registry = OpenPypeSettingsRegistry() + registry.set_secure_item("openPypeMongo", new_mongo_url) From a6ac99c7558273f093a7c41a95fc68b37778beeb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:31:41 +0200 Subject: [PATCH 36/54] added ability to define name of registry --- igniter/user_settings.py | 7 ++++--- openpype/lib/local_settings.py | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index 77fb8b5ae5..f9bbad4e5e 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -459,9 +459,10 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" + if name is None: + name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) - super(OpenPypeSettingsRegistry, self).__init__( - "openpype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__(name, path) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 2095f1253e..6386a69026 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -461,11 +461,13 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" + if name is None: + name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) - super(OpenPypeSettingsRegistry, self).__init__("openpype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__(name, path) def _create_local_site_id(registry=None): From 11fe828809c7399f2aeba8a97a68736db2b41ae5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:52:59 +0200 Subject: [PATCH 37/54] fix tests --- tests/igniter/test_bootstrap_repos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index 75996b4026..6c70380ab6 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -11,7 +11,7 @@ import pytest from igniter.bootstrap_repos import BootstrapRepos from igniter.bootstrap_repos import PypeVersion -from pype.lib import PypeSettingsRegistry +from pype.lib import OpenPypeSettingsRegistry @pytest.fixture @@ -348,7 +348,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): return d_path.as_posix() monkeypatch.setattr(appdirs, "user_data_dir", mock_user_data_dir) - fix_bootstrap.registry = PypeSettingsRegistry() + fix_bootstrap.registry = OpenPypeSettingsRegistry() fix_bootstrap.registry.set_item("pypePath", d_path.as_posix()) result = fix_bootstrap.find_pype(include_zips=True) From d7bca3f53c85de0f2d64c17aa3ae14fb196c519e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 12:11:16 +0200 Subject: [PATCH 38/54] fix executables from local settings --- openpype/settings/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 895fc1e133..3bf2141808 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -489,7 +489,7 @@ def apply_local_settings_on_system_settings(system_settings, local_settings): # TODO This is temporary fix until launch arguments will be stored # per platform and not per executable. # - local settings store only executable - new_executables = [[executable, ""]] + new_executables = [executable] new_executables.extend(platform_executables) variants[app_name]["executables"] = new_executables From d6fb7b47639933f034e4d8cdc41f156e3b3aae85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:28:54 +0200 Subject: [PATCH 39/54] updated linux build environment --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index aae79f2358..73620d7885 100644 --- a/README.md +++ b/README.md @@ -166,14 +166,23 @@ sudo yum install qt5-qtbase-devel
Use pyenv to install Python version for OpenPype build -You will need **bzip2**, **readline** and **sqlite3** libraries. +You will need **bzip2**, **readline**, **sqlite3** and other libraries. -**Ubuntu:** +For more details about Python build environments see: + +https://github.com/pyenv/pyenv/wiki#suggested-build-environment + +**For Ubuntu:** ```sh -sudo apt install libbz2-dev libreadline-dev libsqlite3-dev +sudo apt-get update; sudo apt-get install --no-install-recommends make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev ``` -1) install **pyenv** +**For Centos:** +```sh +yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel +``` + +**install pyenv** ```sh curl https://pyenv.run | bash From e2f8a5836d8be3c81de6c0e24d8366536459c229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Thu, 8 Apr 2021 13:24:17 +0200 Subject: [PATCH 40/54] updated web documentation --- website/docs/dev_build.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/website/docs/dev_build.md b/website/docs/dev_build.md index 01e53918d2..9523035705 100644 --- a/website/docs/dev_build.md +++ b/website/docs/dev_build.md @@ -65,23 +65,20 @@ To build pype on linux you wil need: - **[curl](https://curl.se)** on systems that doesn't have one preinstalled. - Python header files installed (**python3-dev** on Ubuntu for example). -- **[CMake](https://cmake.org/)**: to build some external openPype dependencies. -- **bzip2**, **readline** and **sqlite3** libraries. +- **bzip2**, **readline**, **sqlite3** and other libraries. Because some Linux distros come with newer Python version pre-installed, you might need to install **3.7** version and make use of it explicitly. Your best bet is probably using [pyenv](https://github.com/pyenv/pyenv). -You can use your package manager to install **git** and **cmake**. +You can use your package manager to install **git** and other packages to your build +environment. Use curl for pyenv installation :::note Install build requirements for **Ubuntu** - ```sh -sudo apt install build-essential checkinstall -sudo apt install git cmake curl -sudo apt install libbz2-dev libreadline-dev libsqlite3-dev +sudo apt-get update; sudo apt-get install --no-install-recommends make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev git ``` In case you run in error about `xcb` when running Pype, @@ -95,8 +92,7 @@ sudo apt install qt5-default :::note Install build requirements for **Centos** ```sh -sudo yum install git cmake python3-devel python3-pip -sudo yum install bzip2-devel readline-devel sqlite-devel +yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel git ``` In case you run in error about `xcb` when running Pype, @@ -108,6 +104,8 @@ sudo yum install qt5-qtbase-devel ::: +For more information about setting your build environmet please refer to [pyenv suggested build environment](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) + #### Common steps for all Distros Use pyenv to prepare Python version for Pype build From 68fe4c8a934ffac8df4307d2cbd3768bb3feb6ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:32:32 +0200 Subject: [PATCH 41/54] implemented OpenPypeSecureRegistry handling keyring information --- igniter/user_settings.py | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index f9bbad4e5e..1d4fcd04eb 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -28,6 +28,99 @@ import platform import appdirs import six +_PLACEHOLDER = object() + + +class OpenPypeSecureRegistry: + def __init__(self, name): + try: + import keyring + + except Exception: + raise NotImplementedError( + "Python module `keyring` is not available." + ) + + # hack for cx_freeze and Windows keyring backend + if platform.system().lower() == "windows": + from keyring.backends import Windows + + keyring.set_keyring(Windows.WinVaultKeyring()) + + # Force "OpenPype" prefix + self._name = "/".join(("OpenPype", name)) + + def set_item(self, name, value): + # type: (str, str) -> None + """Set sensitive item into system's keyring. + + This uses `Keyring module`_ to save sensitive stuff into system's + keyring. + + Args: + name (str): Name of the item. + value (str): Value of the item. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + keyring.set_password(self._name, name, value) + + @lru_cache(maxsize=32) + def get_item(self, name, default=_PLACEHOLDER): + """Get value of sensitive item from system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item. + default (Any): Default value if item is not available. + + Returns: + value (str): Value of the item. + + Raises: + ValueError: If item doesn't exist and default is not defined. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + value = keyring.get_password(self._name, name) + if value: + return value + + if default is not _PLACEHOLDER: + return default + + # NOTE Should raise `KeyError` + raise ValueError( + "Item {}:{} does not exist in keyring.".format(self._name, name) + ) + + def delete_item(self, name): + # type: (str) -> None + """Delete value stored in system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item to be deleted. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + self.get_item.cache_clear() + keyring.delete_password(self._name, name) + @six.add_metaclass(ABCMeta) class ASettingRegistry(): From d08fde832a2b4c7d5fccee8772c3646cbc3be47a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:34:30 +0200 Subject: [PATCH 42/54] bootstrap repos also has secure_registry which is used for mongo url storage --- igniter/bootstrap_repos.py | 6 +++++- igniter/install_thread.py | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 2f305e24e3..51dec7f51e 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -14,7 +14,10 @@ from zipfile import ZipFile, BadZipFile from appdirs import user_data_dir from speedcopy import copyfile -from .user_settings import OpenPypeSettingsRegistry +from .user_settings import ( + OpenPypeSecureRegistry, + OpenPypeSettingsRegistry +) from .tools import get_openpype_path_from_db @@ -239,6 +242,7 @@ class BootstrapRepos: self._app = "openpype" self._log = log.getLogger(str(__class__)) self.data_dir = Path(user_data_dir(self._app, self._vendor)) + self.secure_registry = OpenPypeSecureRegistry("Settings") self.registry = OpenPypeSettingsRegistry() self.zip_filter = [".pyc", "__pycache__"] self.openpype_filter = [ diff --git a/igniter/install_thread.py b/igniter/install_thread.py index bf5d541056..df8b830209 100644 --- a/igniter/install_thread.py +++ b/igniter/install_thread.py @@ -71,7 +71,7 @@ class InstallThread(QThread): if not os.getenv("OPENPYPE_MONGO"): # try to get it from settings registry try: - self._mongo = bs.registry.get_secure_item( + self._mongo = bs.secure_registry.get_item( "openPypeMongo") except ValueError: self.message.emit( @@ -82,7 +82,7 @@ class InstallThread(QThread): self._mongo = os.getenv("OPENPYPE_MONGO") else: self.message.emit("Saving mongo connection string ...", False) - bs.registry.set_secure_item("openPypeMongo", self._mongo) + bs.secure_registry.set_item("openPypeMongo", self._mongo) os.environ["OPENPYPE_MONGO"] = self._mongo @@ -169,7 +169,7 @@ class InstallThread(QThread): f"!!! invalid mongo url {self._mongo}", True) self.finished.emit(InstallResult(-1)) return - bs.registry.set_secure_item("openPypeMongo", self._mongo) + bs.secure_registry.set_item("openPypeMongo", self._mongo) os.environ["OPENPYPE_MONGO"] = self._mongo self.message.emit(f"processing {self._path}", True) From 41beb27a693e7d808da72595c83c7ca003d98309 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:35:15 +0200 Subject: [PATCH 43/54] secure registry is also used in install dialog --- igniter/install_dialog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/igniter/install_dialog.py b/igniter/install_dialog.py index 2cc0ed8448..dab00079a5 100644 --- a/igniter/install_dialog.py +++ b/igniter/install_dialog.py @@ -13,7 +13,7 @@ from .tools import ( validate_mongo_connection, get_openpype_path_from_db ) -from .user_settings import OpenPypeSettingsRegistry +from .user_settings import OpenPypeSecureRegistry from .version import __version__ @@ -42,13 +42,13 @@ class InstallDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(InstallDialog, self).__init__(parent) - self.registry = OpenPypeSettingsRegistry() + self.secure_registry = OpenPypeSecureRegistry("Settings") self.mongo_url = "" try: self.mongo_url = ( os.getenv("OPENPYPE_MONGO", "") - or self.registry.get_secure_item("openPypeMongo") + or self.secure_registry.get_item("openPypeMongo") ) except ValueError: pass From 3cc8599684a7374c98a9cd375fce588e382d91aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:36:22 +0200 Subject: [PATCH 44/54] removed secure getter and setters from ASettingRegistry --- igniter/user_settings.py | 83 +--------------------------------------- 1 file changed, 2 insertions(+), 81 deletions(-) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index 1d4fcd04eb..bb5336a9ab 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -25,8 +25,8 @@ except ImportError: import platform -import appdirs import six +import appdirs _PLACEHOLDER = object() @@ -139,13 +139,6 @@ class ASettingRegistry(): # type: (str) -> ASettingRegistry super(ASettingRegistry, self).__init__() - if six.PY3: - import keyring - # hack for cx_freeze and Windows keyring backend - if platform.system() == "Windows": - from keyring.backends import Windows - keyring.set_keyring(Windows.WinVaultKeyring()) - self._name = name self._items = {} @@ -220,78 +213,6 @@ class ASettingRegistry(): del self._items[name] self._delete_item(name) - def set_secure_item(self, name, value): - # type: (str, str) -> None - """Set sensitive item into system's keyring. - - This uses `Keyring module`_ to save sensitive stuff into system's - keyring. - - Args: - name (str): Name of the item. - value (str): Value of the item. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - keyring.set_password(self._name, name, value) - - @lru_cache(maxsize=32) - def get_secure_item(self, name): - # type: (str) -> str - """Get value of sensitive item from system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item. - - Returns: - value (str): Value of the item. - - Raises: - ValueError: If item doesn't exist. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - value = keyring.get_password(self._name, name) - if not value: - raise ValueError( - "Item {}:{} does not exist in keyring.".format( - self._name, name)) - return value - - def delete_secure_item(self, name): - # type: (str) -> None - """Delete value stored in system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item to be deleted. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - self.get_secure_item.cache_clear() - keyring.delete_password(self._name, name) - class IniSettingRegistry(ASettingRegistry): """Class using :mod:`configparser`. @@ -555,7 +476,7 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" - if name is None: + if not name: name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) super(OpenPypeSettingsRegistry, self).__init__(name, path) From 454bd9d1b51b4b4782bff4e2afbaba2d7102aad4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:40:21 +0200 Subject: [PATCH 45/54] copy pasted secure registry logic from igniter to pype lib --- openpype/lib/local_settings.py | 195 ++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 90 deletions(-) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 6386a69026..ec76b57cfd 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -5,6 +5,7 @@ from datetime import datetime from abc import ABCMeta, abstractmethod import json +# TODO Use pype igniter logic instead of using duplicated code # disable lru cache in Python 2 try: from functools import lru_cache @@ -25,11 +26,104 @@ except ImportError: import platform -import appdirs import six +import appdirs from .import validate_mongo_connection +_PLACEHOLDER = object() + + +class OpenPypeSecureRegistry: + def __init__(self, name): + try: + import keyring + + except Exception: + raise NotImplementedError( + "Python module `keyring` is not available." + ) + + # hack for cx_freeze and Windows keyring backend + if platform.system().lower() == "windows": + from keyring.backends import Windows + + keyring.set_keyring(Windows.WinVaultKeyring()) + + # Force "OpenPype" prefix + self._name = "/".join(("OpenPype", name)) + + def set_item(self, name, value): + # type: (str, str) -> None + """Set sensitive item into system's keyring. + + This uses `Keyring module`_ to save sensitive stuff into system's + keyring. + + Args: + name (str): Name of the item. + value (str): Value of the item. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + keyring.set_password(self._name, name, value) + + @lru_cache(maxsize=32) + def get_item(self, name, default=_PLACEHOLDER): + """Get value of sensitive item from system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item. + default (Any): Default value if item is not available. + + Returns: + value (str): Value of the item. + + Raises: + ValueError: If item doesn't exist and default is not defined. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + value = keyring.get_password(self._name, name) + if value: + return value + + if default is not _PLACEHOLDER: + return default + + # NOTE Should raise `KeyError` + raise ValueError( + "Item {}:{} does not exist in keyring.".format(self._name, name) + ) + + def delete_item(self, name): + # type: (str) -> None + """Delete value stored in system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item to be deleted. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + self.get_item.cache_clear() + keyring.delete_password(self._name, name) + @six.add_metaclass(ABCMeta) class ASettingRegistry(): @@ -48,13 +142,6 @@ class ASettingRegistry(): # type: (str) -> ASettingRegistry super(ASettingRegistry, self).__init__() - if six.PY3: - import keyring - # hack for cx_freeze and Windows keyring backend - if platform.system() == "Windows": - from keyring.backends import Windows - keyring.set_keyring(Windows.WinVaultKeyring()) - self._name = name self._items = {} @@ -120,7 +207,7 @@ class ASettingRegistry(): """Delete item from settings. Note: - see :meth:`pype.lib.local_settings.ARegistrySettings.delete_item` + see :meth:`openpype.lib.user_settings.ARegistrySettings.delete_item` """ pass @@ -129,78 +216,6 @@ class ASettingRegistry(): del self._items[name] self._delete_item(name) - def set_secure_item(self, name, value): - # type: (str, str) -> None - """Set sensitive item into system's keyring. - - This uses `Keyring module`_ to save sensitive stuff into system's - keyring. - - Args: - name (str): Name of the item. - value (str): Value of the item. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - keyring.set_password(self._name, name, value) - - @lru_cache(maxsize=32) - def get_secure_item(self, name): - # type: (str) -> str - """Get value of sensitive item from system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item. - - Returns: - value (str): Value of the item. - - Raises: - ValueError: If item doesn't exist. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - value = keyring.get_password(self._name, name) - if not value: - raise ValueError( - "Item {}:{} does not exist in keyring.".format( - self._name, name)) - return value - - def delete_secure_item(self, name): - # type: (str) -> None - """Delete value stored in system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item to be deleted. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - self.get_secure_item.cache_clear() - keyring.delete_password(self._name, name) - class IniSettingRegistry(ASettingRegistry): """Class using :mod:`configparser`. @@ -218,7 +233,7 @@ class IniSettingRegistry(ASettingRegistry): if not os.path.exists(self._registry_file): with open(self._registry_file, mode="w") as cfg: print("# Settings registry", cfg) - print("# Generated by Pype {}".format(version), cfg) + print("# Generated by OpenPype {}".format(version), cfg) now = datetime.now().strftime("%d/%m/%Y %H:%M:%S") print("# {}".format(now), cfg) @@ -352,7 +367,7 @@ class IniSettingRegistry(ASettingRegistry): """Delete item from default section. Note: - See :meth:`~pype.lib.IniSettingsRegistry.delete_item_from_section` + See :meth:`~openpype.lib.IniSettingsRegistry.delete_item_from_section` """ self.delete_item_from_section("MAIN", name) @@ -369,7 +384,7 @@ class JSONSettingRegistry(ASettingRegistry): now = datetime.now().strftime("%d/%m/%Y %H:%M:%S") header = { "__metadata__": { - "pype-version": os.getenv("OPENPYPE_VERSION", "N/A"), + "openpype-version": os.getenv("OPENPYPE_VERSION", "N/A"), "generated": now }, "registry": {} @@ -387,7 +402,7 @@ class JSONSettingRegistry(ASettingRegistry): """Get item value from registry json. Note: - See :meth:`pype.lib.JSONSettingRegistry.get_item` + See :meth:`openpype.lib.JSONSettingRegistry.get_item` """ with open(self._registry_file, mode="r") as cfg: @@ -420,7 +435,7 @@ class JSONSettingRegistry(ASettingRegistry): """Set item value to registry json. Note: - See :meth:`pype.lib.JSONSettingRegistry.set_item` + See :meth:`openpype.lib.JSONSettingRegistry.set_item` """ with open(self._registry_file, "r+") as cfg: @@ -453,7 +468,7 @@ class JSONSettingRegistry(ASettingRegistry): class OpenPypeSettingsRegistry(JSONSettingRegistry): - """Class handling Pype general settings registry. + """Class handling OpenPype general settings registry. Attributes: vendor (str): Name used for path construction. @@ -464,7 +479,7 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" - if name is None: + if not name: name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) super(OpenPypeSettingsRegistry, self).__init__(name, path) @@ -506,5 +521,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = OpenPypeSettingsRegistry() - registry.set_secure_item("openPypeMongo", new_mongo_url) + registry = OpenPypeSecureRegistry("Settings") + registry.set_item("openPypeMongo", new_mongo_url) From 3785e9b53c5fc90bcfb32ea6dc39afb965b9e130 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:03 +0200 Subject: [PATCH 46/54] fix tests --- tests/pype/lib/test_user_settings.py | 32 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/pype/lib/test_user_settings.py b/tests/pype/lib/test_user_settings.py index 7f0f400f59..02342abbc9 100644 --- a/tests/pype/lib/test_user_settings.py +++ b/tests/pype/lib/test_user_settings.py @@ -1,10 +1,20 @@ import pytest -from pype.lib import IniSettingRegistry -from pype.lib import JSONSettingRegistry +from pype.lib import ( + IniSettingRegistry, + JSONSettingRegistry, + OpenPypeSecureRegistry +) from uuid import uuid4 import configparser +@pytest.fixture +def secure_registry(tmpdir): + name = "pypetest_{}".format(str(uuid4())) + r = OpenPypeSecureRegistry(name, tmpdir) + yield r + + @pytest.fixture def json_registry(tmpdir): name = "pypetest_{}".format(str(uuid4())) @@ -19,21 +29,21 @@ def ini_registry(tmpdir): yield r -def test_keyring(json_registry): - json_registry.set_secure_item("item1", "foo") - json_registry.set_secure_item("item2", "bar") - result1 = json_registry.get_secure_item("item1") - result2 = json_registry.get_secure_item("item2") +def test_keyring(secure_registry): + secure_registry.set_item("item1", "foo") + secure_registry.set_item("item2", "bar") + result1 = secure_registry.get_item("item1") + result2 = secure_registry.get_item("item2") assert result1 == "foo" assert result2 == "bar" - json_registry.delete_secure_item("item1") - json_registry.delete_secure_item("item2") + secure_registry.delete_item("item1") + secure_registry.delete_item("item2") with pytest.raises(ValueError): - json_registry.get_secure_item("item1") - json_registry.get_secure_item("item2") + secure_registry.get_item("item1") + secure_registry.get_item("item2") def test_ini_registry(ini_registry): From ee93c229fef4ed0b3cde55b6384bd8b704b7deac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:32 +0200 Subject: [PATCH 47/54] added some docstring to OpenPypeSecureRegistry --- igniter/user_settings.py | 11 +++++++++++ openpype/lib/local_settings.py | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index bb5336a9ab..2a406f83dd 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -32,6 +32,17 @@ _PLACEHOLDER = object() class OpenPypeSecureRegistry: + """Store information using keyring. + + Registry should be used for private data that should be available only for + user. + + All passed registry names will have added prefix `OpenPype/` to easier + identify which data were created by OpenPype. + + Args: + name(str): Name of registry used as identifier for data. + """ def __init__(self, name): try: import keyring diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index ec76b57cfd..1bd8540acb 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -35,6 +35,17 @@ _PLACEHOLDER = object() class OpenPypeSecureRegistry: + """Store information using keyring. + + Registry should be used for private data that should be available only for + user. + + All passed registry names will have added prefix `OpenPype/` to easier + identify which data were created by OpenPype. + + Args: + name(str): Name of registry used as identifier for data. + """ def __init__(self, name): try: import keyring From e81c9dd5b5ad7020d1da8ebfe39ab86854e2aafb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:55 +0200 Subject: [PATCH 48/54] fix bootstrap attribute access --- start.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start.py b/start.py index 1f946a705c..36e4c36d21 100644 --- a/start.py +++ b/start.py @@ -296,7 +296,7 @@ def _determine_mongodb() -> str: if not openpype_mongo: # try system keyring try: - openpype_mongo = bootstrap.registry.get_secure_item( + openpype_mongo = bootstrap.secure_registry.get_item( "openPypeMongo") except ValueError: print("*** No DB connection string specified.") @@ -305,7 +305,7 @@ def _determine_mongodb() -> str: igniter.open_dialog() try: - openpype_mongo = bootstrap.registry.get_secure_item( + openpype_mongo = bootstrap.secure_registry.get_item( "openPypeMongo") except ValueError: raise RuntimeError("missing mongodb url") From 787d037ca02a1a7e295a446bd459b7c7b6ec8e5b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 17:08:04 +0200 Subject: [PATCH 49/54] imported OpenPypeSecureRegistry in pype.lib.__init__ --- openpype/lib/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 7b2f533921..ce8f8ec2b6 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -104,6 +104,7 @@ from .plugin_tools import ( from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, + OpenPypeSecureRegistry, OpenPypeSettingsRegistry, get_local_site_id, change_openpype_mongo_url @@ -217,6 +218,7 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", + "OpenPypeSecureRegistry", "OpenPypeSettingsRegistry", "get_local_site_id", "change_openpype_mongo_url", From 261e1db2c0751b29df870c190e9ce75cda9eeadf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 17:15:26 +0200 Subject: [PATCH 50/54] changed keyring key of mongodb data to OpenPype/mongodb --- igniter/bootstrap_repos.py | 2 +- igniter/install_dialog.py | 2 +- openpype/lib/local_settings.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 51dec7f51e..f624b96125 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -242,7 +242,7 @@ class BootstrapRepos: self._app = "openpype" self._log = log.getLogger(str(__class__)) self.data_dir = Path(user_data_dir(self._app, self._vendor)) - self.secure_registry = OpenPypeSecureRegistry("Settings") + self.secure_registry = OpenPypeSecureRegistry("mongodb") self.registry = OpenPypeSettingsRegistry() self.zip_filter = [".pyc", "__pycache__"] self.openpype_filter = [ diff --git a/igniter/install_dialog.py b/igniter/install_dialog.py index dab00079a5..27b2d1fe37 100644 --- a/igniter/install_dialog.py +++ b/igniter/install_dialog.py @@ -42,7 +42,7 @@ class InstallDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(InstallDialog, self).__init__(parent) - self.secure_registry = OpenPypeSecureRegistry("Settings") + self.secure_registry = OpenPypeSecureRegistry("mongodb") self.mongo_url = "" try: diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 1bd8540acb..c043a2f837 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -532,5 +532,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = OpenPypeSecureRegistry("Settings") + registry = OpenPypeSecureRegistry("mongodb") registry.set_item("openPypeMongo", new_mongo_url) From cbd40cd73b1dfc86f3d35a9920ba4c715b60dc41 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 19:20:56 +0200 Subject: [PATCH 51/54] old mongo value is removed before change --- openpype/lib/local_settings.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index c043a2f837..5d2955532a 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -106,7 +106,7 @@ class OpenPypeSecureRegistry: import keyring value = keyring.get_password(self._name, name) - if value: + if value is not None: return value if default is not _PLACEHOLDER: @@ -532,5 +532,9 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) + key = "openPypeMongo" registry = OpenPypeSecureRegistry("mongodb") - registry.set_item("openPypeMongo", new_mongo_url) + existing_value = registry.get_item(key, None) + if existing_value is not None: + registry.delete_item(key) + registry.set_item(key, new_mongo_url) From 864e8b882cf881b9675bba439fc3f3b67d5796a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 19:42:31 +0200 Subject: [PATCH 52/54] idle manager is always enabled and starts thread only if has registered callbacks --- openpype/modules/idle_manager/idle_module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/modules/idle_manager/idle_module.py b/openpype/modules/idle_manager/idle_module.py index ddccf07f6a..c06dbed78c 100644 --- a/openpype/modules/idle_manager/idle_module.py +++ b/openpype/modules/idle_manager/idle_module.py @@ -40,8 +40,7 @@ class IdleManager(PypeModule, ITrayService): name = "idle_manager" def initialize(self, module_settings): - idle_man_settings = module_settings[self.name] - self.enabled = idle_man_settings["enabled"] + self.enabled = True self.time_callbacks = collections.defaultdict(list) self.idle_thread = None @@ -50,7 +49,8 @@ class IdleManager(PypeModule, ITrayService): return def tray_start(self): - self.start_thread() + if self.time_callbacks: + self.start_thread() def tray_exit(self): self.stop_thread() From f0b47e1c7ac493ae2f958a70685e21c1dc1589d7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 19:42:52 +0200 Subject: [PATCH 53/54] removed idle manager from settings schema --- .../settings/defaults/system_settings/modules.json | 3 --- .../schemas/system_schema/schema_modules.json | 14 -------------- 2 files changed, 17 deletions(-) diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index 00e98aa8de..3453bf72ec 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -165,8 +165,5 @@ }, "standalonepublish_tool": { "enabled": true - }, - "idle_manager": { - "enabled": true } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index 8bfb0e90dc..ad58411c9e 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_modules.json +++ b/openpype/settings/entities/schemas/system_schema/schema_modules.json @@ -176,20 +176,6 @@ "label": "Enabled" } ] - }, - { - "type": "dict", - "key": "idle_manager", - "label": "Idle Manager", - "collapsible": true, - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] } ] } From 84fb977558f66ac1ef80145d3ad0b05d513baa55 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 19:45:59 +0200 Subject: [PATCH 54/54] added auto stop attribute to timers manager --- openpype/modules/timers_manager/timers_manager.py | 5 +++++ openpype/settings/defaults/system_settings/modules.json | 1 + .../entities/schemas/system_schema/schema_modules.json | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/openpype/modules/timers_manager/timers_manager.py b/openpype/modules/timers_manager/timers_manager.py index a8ea5799e6..92edd5aeaa 100644 --- a/openpype/modules/timers_manager/timers_manager.py +++ b/openpype/modules/timers_manager/timers_manager.py @@ -45,11 +45,13 @@ class TimersManager(PypeModule, ITrayService, IIdleManager, IWebServerRoutes): timers_settings = modules_settings[self.name] self.enabled = timers_settings["enabled"] + auto_stop = timers_settings["auto_stop"] # When timer will stop if idle manager is running (minutes) full_time = int(timers_settings["full_time"] * 60) # How many minutes before the timer is stopped will popup the message message_time = int(timers_settings["message_time"] * 60) + self.auto_stop = auto_stop self.time_show_message = full_time - message_time self.time_stop_timer = full_time @@ -160,6 +162,9 @@ class TimersManager(PypeModule, ITrayService, IIdleManager, IWebServerRoutes): def callbacks_by_idle_time(self): """Implementation of IIdleManager interface.""" # Time when message is shown + if not self.auto_stop: + return {} + callbacks = collections.defaultdict(list) callbacks[self.time_show_message].append(lambda: self.time_callback(0)) diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index 3453bf72ec..b3065058a1 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -126,6 +126,7 @@ }, "timers_manager": { "enabled": true, + "auto_stop": true, "full_time": 15.0, "message_time": 0.5 }, diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index ad58411c9e..8512514ff3 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_modules.json +++ b/openpype/settings/entities/schemas/system_schema/schema_modules.json @@ -42,6 +42,11 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "boolean", + "key": "auto_stop", + "label": "Auto stop timer" + }, { "type": "number", "decimal": 2,