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 diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 2f305e24e3..f624b96125 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("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 2cc0ed8448..27b2d1fe37 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("mongodb") 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 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) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index 77fb8b5ae5..2a406f83dd 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -25,8 +25,112 @@ except ImportError: import platform -import appdirs import six +import appdirs + +_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 + + 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) @@ -46,13 +150,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 = {} @@ -127,78 +224,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`. @@ -459,9 +484,10 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" + if not name: + 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/hooks/pre_with_windows_shell.py b/openpype/hooks/pre_with_windows_shell.py index 5f0f03f13e..0c10583b99 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 @@ -10,15 +11,32 @@ class LaunchWithWindowsShell(PreLaunchHook): instead. """ - order = 10 - app_groups = ["resolve", "nuke", "nukex", "hiero", "nukestudio"] + # Should be as last hook becuase must change launch arguments to string + order = 1000 + app_groups = ["nuke", "nukex", "hiero", "nukestudio"] 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 + # Change `creationflags` to CREATE_NEW_CONSOLE + self.launch_context.kwargs["creationflags"] = ( + subprocess.CREATE_NEW_CONSOLE + ) 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/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 + 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 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/lib/__init__.py b/openpype/lib/__init__.py index 554c0d8ec3..ce8f8ec2b6 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -104,7 +104,8 @@ from .plugin_tools import ( from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, - PypeSettingsRegistry, + OpenPypeSecureRegistry, + OpenPypeSettingsRegistry, get_local_site_id, change_openpype_mongo_url ) @@ -217,7 +218,8 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", - "PypeSettingsRegistry", + "OpenPypeSecureRegistry", + "OpenPypeSettingsRegistry", "get_local_site_id", "change_openpype_mongo_url", 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 diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 3302a88f97..51c646d494 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 ) @@ -165,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)) @@ -265,22 +278,31 @@ 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: - # TODO This should be replaced with `full_name` in future 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: + 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: @@ -336,16 +358,24 @@ 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"] 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 @@ -372,8 +402,10 @@ 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.variant_label = label + self.label = " ".join((group.label, label)) self.group = group self._environment = environment self.full_name = "/".join((group.name, name)) @@ -804,10 +836,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 @@ -853,7 +890,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: @@ -865,8 +905,6 @@ class ApplicationLaunchContext: new_args.append(arg) args = new_args - if all_cleared: - break return args diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 82507cb0c0..5d2955532a 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,115 @@ except ImportError: import platform -import appdirs import six +import appdirs from .import validate_mongo_connection +_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 + + 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 is not None: + 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 +153,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 +218,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 +227,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 +244,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 +378,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 +395,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 +413,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 +446,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: @@ -452,8 +478,8 @@ class JSONSettingRegistry(ASettingRegistry): json.dump(data, cfg, indent=4) -class PypeSettingsRegistry(JSONSettingRegistry): - """Class handling Pype general settings registry. +class OpenPypeSettingsRegistry(JSONSettingRegistry): + """Class handling OpenPype general settings registry. Attributes: vendor (str): Name used for path construction. @@ -461,11 +487,13 @@ class PypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" - self.product = "pype" + self.product = "openpype" + if not name: + name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) - super(PypeSettingsRegistry, self).__init__("pype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__(name, path) def _create_local_site_id(registry=None): @@ -473,7 +501,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 +517,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 +532,9 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = PypeSettingsRegistry() - registry.set_secure_item("pypeMongo", new_mongo_url) + key = "openPypeMongo" + registry = OpenPypeSecureRegistry("mongodb") + existing_value = registry.get_item(key, None) + if existing_value is not None: + registry.delete_item(key) + registry.set_item(key, new_mongo_url) 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 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: 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( 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() 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/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 diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 42e742d07c..8034bc6368 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" @@ -84,86 +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": { - "enabled": true, - "variant_label": "2020", - "executables": { - "windows": [ - "C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "MAYA_VERSION": "2020" - } - }, - "2019": { - "enabled": true, - "variant_label": "2019", - "executables": { - "windows": [ - "C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "MAYA_VERSION": "2019" - } - }, - "2018": { - "enabled": true, - "variant_label": "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", @@ -182,8 +96,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -201,8 +113,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -220,8 +130,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -239,8 +147,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -254,6 +160,11 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3" } } }, @@ -275,8 +186,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -300,8 +209,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -325,8 +232,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -350,8 +255,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -371,6 +274,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -392,8 +301,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -417,8 +324,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -442,8 +347,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -467,8 +370,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [], "darwin": [], @@ -486,6 +387,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -507,8 +414,6 @@ }, "variants": { "12-2": { - "enabled": true, - "variant_label": "12.2", "executables": { "windows": [ "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe" @@ -532,8 +437,6 @@ "environment": {} }, "12-0": { - "enabled": true, - "variant_label": "12.0", "executables": { "windows": [ "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" @@ -557,8 +460,6 @@ "environment": {} }, "11-3": { - "enabled": true, - "variant_label": "11.3", "executables": { "windows": [ "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" @@ -582,8 +483,6 @@ "environment": {} }, "11-2": { - "enabled": true, - "variant_label": "11.2", "executables": { "windows": [ "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" @@ -603,6 +502,12 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "12-2": "12.2", + "12-0": "12.0", + "11-3": "11.3", + "11-2": "11.2" } } }, @@ -752,8 +657,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 +672,6 @@ "environment": {} }, "18": { - "enabled": true, - "variant_label": "18", "executables": { "windows": [], "darwin": [], @@ -784,8 +685,6 @@ "environment": {} }, "17": { - "enabled": true, - "variant_label": "17", "executables": { "windows": [], "darwin": [], @@ -797,6 +696,11 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "18-5": "18.5", + "18": "18", + "17": "17" } } }, @@ -815,8 +719,6 @@ }, "variants": { "2-83": { - "enabled": true, - "variant_label": "2.83", "executables": { "windows": [ "C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe" @@ -838,8 +740,6 @@ "environment": {} }, "2-90": { - "enabled": true, - "variant_label": "2.90", "executables": { "windows": [ "C:\\Program Files\\Blender Foundation\\Blender 2.90\\blender.exe" @@ -859,6 +759,10 @@ ] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "2-83": "2.83", + "2-90": "2.90" } } }, @@ -916,8 +820,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 +835,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 +848,10 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "animation_11-64bits": "11 (64bits)", + "animation_11-32bits": "11 (32bits)" } } }, @@ -1085,8 +989,6 @@ }, "variants": { "4-24": { - "enabled": true, - "variant_label": "4.24", "executables": { "windows": [], "darwin": [], @@ -1106,8 +1008,6 @@ "environment": {}, "variants": { "python_3-7": { - "enabled": true, - "variant_label": "3.7", "executables": { "windows": [], "darwin": [], @@ -1121,8 +1021,6 @@ "environment": {} }, "python_2-7": { - "enabled": true, - "variant_label": "2.7", "executables": { "windows": [], "darwin": [], @@ -1136,8 +1034,6 @@ "environment": {} }, "terminal": { - "enabled": true, - "variant_label": "", "executables": { "windows": [], "darwin": [], @@ -1149,6 +1045,10 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "python_3-7": "Python 3.7", + "python_2-7": "Python 2.7" } } }, @@ -1160,8 +1060,6 @@ "environment": {}, "variants": { "1-1": { - "enabled": true, - "variant_label": "1.1", "executables": { "windows": [], "darwin": [], @@ -1173,6 +1071,9 @@ "linux": [] }, "environment": {} + }, + "__dynamic_keys_labels__": { + "1-1": "1.1" } } } diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index 00e98aa8de..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 }, @@ -165,8 +166,5 @@ }, "standalonepublish_tool": { "enabled": true - }, - "idle_manager": { - "enabled": true } } \ No newline at end of file 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 = ( 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: 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" + } + ] + } } ] } 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 deleted file mode 100644 index bdeca9089c..0000000000 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_mayabatch.json +++ /dev/null @@ -1,47 +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", - "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" - } - ] - } - ] - } - ] -} 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_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/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" + } + ] + } } ] } 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..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 @@ -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": "schema_template", + "name": "template_host_variant_items" } ] } 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" + } +] 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" + } + ] + } } ] } 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", diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index 8bfb0e90dc..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, @@ -176,20 +181,6 @@ "label": "Enabled" } ] - }, - { - "type": "dict", - "key": "idle_manager", - "label": "Idle Manager", - "collapsible": true, - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] } ] } diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 60a51c01a0..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 @@ -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() 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 diff --git a/openpype/tools/settings/settings/widgets/dict_mutable_widget.py b/openpype/tools/settings/settings/widgets/dict_mutable_widget.py index 30e12aa5ac..9bea89c0d6 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" 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") 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) 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): 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