From f66f67971078cb137484796d13692ff1ec064592 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:22:23 +0100 Subject: [PATCH 01/38] renamed 'root' to '_workfiles_root' --- openpype/tools/workfiles/app.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index f4a86050cb..e05a51a962 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -367,7 +367,7 @@ class FilesWidget(QtWidgets.QWidget): self.template_key = "work" # This is not root but workfile directory - self.root = None + self._workfiles_root = None self.host = api.registered_host() # Whether to automatically select the latest modified @@ -465,8 +465,8 @@ class FilesWidget(QtWidgets.QWidget): # This way we can browse it even before we enter it. if self._asset_id and self._task_name and self._task_type: session = self._get_session() - self.root = self.host.work_root(session) - self.files_model.set_root(self.root) + self._workfiles_root = self.host.work_root(session) + self.files_model.set_root(self._workfiles_root) else: self.files_model.set_root(None) @@ -590,7 +590,7 @@ class FilesWidget(QtWidgets.QWidget): window = NameWindow( parent=self, - root=self.root, + root=self._workfiles_root, anatomy=self.anatomy, template_key=self.template_key, session=session @@ -605,7 +605,7 @@ class FilesWidget(QtWidgets.QWidget): return src = self._get_selected_filepath() - dst = os.path.join(self.root, work_file) + dst = os.path.join(self._workfiles_root, work_file) shutil.copy(src, dst) self.workfile_created.emit(dst) @@ -638,9 +638,9 @@ class FilesWidget(QtWidgets.QWidget): "filter": ext_filter } if Qt.__binding__ in ("PySide", "PySide2"): - kwargs["dir"] = self.root + kwargs["dir"] = self._workfiles_root else: - kwargs["directory"] = self.root + kwargs["directory"] = self._workfiles_root work_file = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] if work_file: @@ -652,17 +652,21 @@ class FilesWidget(QtWidgets.QWidget): return # Initialize work directory if it has not been initialized before - if not os.path.exists(self.root): - log.debug("Initializing Work Directory: %s", self.root) + if not os.path.exists(self._workfiles_root): + log.debug("Initializing Work Directory: %s", self._workfiles_root) self.initialize_work_directory() - if not os.path.exists(self.root): + if not os.path.exists(self._workfiles_root): # Failed to initialize Work Directory log.error( - "Failed to initialize Work Directory: {}".format(self.root) + "Failed to initialize Work Directory: {}".format( + self._workfiles_root + ) ) return - file_path = os.path.join(os.path.normpath(self.root), work_file) + file_path = os.path.join( + os.path.normpath(self._workfiles_root), work_file + ) pipeline.emit("before.workfile.save", [file_path]) @@ -673,7 +677,7 @@ class FilesWidget(QtWidgets.QWidget): self._asset_id, self._task_name, self._task_type ) create_workdir_extra_folders( - self.root, + self._workfiles_root, api.Session["AVALON_APP"], self._task_type, self._task_name, From 82432e476434ac36724dee72bd830cfcd678c7c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:22:40 +0100 Subject: [PATCH 02/38] added variable '_workdir_path' which is used to create extra folders --- openpype/tools/workfiles/app.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index e05a51a962..04dc1ed40b 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -368,6 +368,7 @@ class FilesWidget(QtWidgets.QWidget): # This is not root but workfile directory self._workfiles_root = None + self._workdir_path = None self.host = api.registered_host() # Whether to automatically select the latest modified @@ -465,6 +466,7 @@ class FilesWidget(QtWidgets.QWidget): # This way we can browse it even before we enter it. if self._asset_id and self._task_name and self._task_type: session = self._get_session() + self._workdir_path = session["AVALON_WORKDIR"] self._workfiles_root = self.host.work_root(session) self.files_model.set_root(self._workfiles_root) @@ -677,6 +679,7 @@ class FilesWidget(QtWidgets.QWidget): self._asset_id, self._task_name, self._task_type ) create_workdir_extra_folders( + self._workdir_path, self._workfiles_root, api.Session["AVALON_APP"], self._task_type, From 7075183a47e0f6848d98db9b804a92f94bfec6e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:26:12 +0100 Subject: [PATCH 03/38] emit also workdir for 'before.workfile.save' --- openpype/hosts/maya/api/__init__.py | 9 +++------ openpype/tools/workfiles/app.py | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index b25fd44217..17ec7ac56d 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -218,12 +218,9 @@ def on_task_changed(*args): ) -def before_workfile_save(workfile_path): - if not workfile_path: - return - - workdir = os.path.dirname(workfile_path) - copy_workspace_mel(workdir) +def before_workfile_save(workfile_path, workdir_path): + if workdir_path: + copy_workspace_mel(workdir_path) class MayaDirmap(HostDirmap): diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index 04dc1ed40b..bd666d9d4f 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -670,7 +670,7 @@ class FilesWidget(QtWidgets.QWidget): os.path.normpath(self._workfiles_root), work_file ) - pipeline.emit("before.workfile.save", [file_path]) + pipeline.emit("before.workfile.save", [file_path, self._workdir_path]) self._enter_session() # Make sure we are in the right session self.host.save_file(file_path) From 7a1edd6b1eb50fe3c2c3fec50fa7f75689e7dda7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:39:14 +0100 Subject: [PATCH 04/38] added base of event objects --- openpype/pipeline/lib/__init__.py | 8 +++++++ openpype/pipeline/lib/events.py | 38 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 openpype/pipeline/lib/events.py diff --git a/openpype/pipeline/lib/__init__.py b/openpype/pipeline/lib/__init__.py index 1bb65be79b..e2c15cbd2d 100644 --- a/openpype/pipeline/lib/__init__.py +++ b/openpype/pipeline/lib/__init__.py @@ -1,3 +1,8 @@ +from .events import ( + BaseEvent, + BeforeWorkfileSave +) + from .attribute_definitions import ( AbtractAttrDef, UnknownDef, @@ -9,6 +14,9 @@ from .attribute_definitions import ( __all__ = ( + "BaseEvent", + "BeforeWorkfileSave", + "AbtractAttrDef", "UnknownDef", "NumberDef", diff --git a/openpype/pipeline/lib/events.py b/openpype/pipeline/lib/events.py new file mode 100644 index 0000000000..8e7dcbd70e --- /dev/null +++ b/openpype/pipeline/lib/events.py @@ -0,0 +1,38 @@ +"""Events holding data about specific event.""" + + +class BaseEvent: + """Base event object. + + Can be used to anything because data are not much specific. Only required + argument is topic which defines why event is happening and may be used for + filtering. + + Arg: + topic (str): Identifier of event. + data (Any): Data specific for event. Dictionary is recommended. + """ + _data = {} + + def __init__(self, topic, data=None): + self._topic = topic + if data is None: + data = {} + self._data = data + + @property + def data(self): + return self._data + + @property + def topic(self): + return self._topic + + +class BeforeWorkfileSave(BaseEvent): + """Before workfile changes event data.""" + def __init__(self, new_workfile, workdir): + super(BeforeWorkfileSave, self).__init__("before.workfile.save") + + self.workfile_path = new_workfile + self.workdir_path = workdir From 4aa096d5bc0d4d812abcabdf9cc2e154f0461ef5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:54:11 +0100 Subject: [PATCH 05/38] added emit function --- openpype/pipeline/lib/events.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/lib/events.py b/openpype/pipeline/lib/events.py index 8e7dcbd70e..9a6bd12f2d 100644 --- a/openpype/pipeline/lib/events.py +++ b/openpype/pipeline/lib/events.py @@ -1,7 +1,8 @@ """Events holding data about specific event.""" -class BaseEvent: +# Inherit from 'object' for Python 2 hosts +class BaseEvent(object): """Base event object. Can be used to anything because data are not much specific. Only required @@ -28,6 +29,13 @@ class BaseEvent: def topic(self): return self._topic + @classmethod + def emit(cls, *args, **kwargs): + from avalon import pipeline + + obj = cls(*args, **kwargs) + pipeline.emit(obj.topic, [obj]) + class BeforeWorkfileSave(BaseEvent): """Before workfile changes event data.""" From 4e904288ad707b764676607f9aa1bbc2abdf077e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 18:55:30 +0100 Subject: [PATCH 06/38] emit BeforeWorkfileSave event in workfiles tool --- openpype/hosts/maya/api/__init__.py | 3 ++- openpype/pipeline/lib/events.py | 6 ++++++ openpype/tools/workfiles/app.py | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index 17ec7ac56d..0ad1c8ba29 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -218,7 +218,8 @@ def on_task_changed(*args): ) -def before_workfile_save(workfile_path, workdir_path): +def before_workfile_save(event): + workdir_path = event.workdir_path if workdir_path: copy_workspace_mel(workdir_path) diff --git a/openpype/pipeline/lib/events.py b/openpype/pipeline/lib/events.py index 9a6bd12f2d..b9ad889383 100644 --- a/openpype/pipeline/lib/events.py +++ b/openpype/pipeline/lib/events.py @@ -31,10 +31,16 @@ class BaseEvent(object): @classmethod def emit(cls, *args, **kwargs): + """Create object of event and emit. + + Args: + Same args as '__init__' expects which may be class specific. + """ from avalon import pipeline obj = cls(*args, **kwargs) pipeline.emit(obj.topic, [obj]) + return obj class BeforeWorkfileSave(BaseEvent): diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index bd666d9d4f..763e0f796d 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -11,6 +11,7 @@ from Qt import QtWidgets, QtCore from avalon import io, api, pipeline from openpype import style +from openpype.pipeline.lib import BeforeWorkfileSave from openpype.tools.utils.lib import ( qt_app_context ) @@ -670,7 +671,7 @@ class FilesWidget(QtWidgets.QWidget): os.path.normpath(self._workfiles_root), work_file ) - pipeline.emit("before.workfile.save", [file_path, self._workdir_path]) + BeforeWorkfileSave.emit(file_path, self._workdir_path) self._enter_session() # Make sure we are in the right session self.host.save_file(file_path) From c94ce278f15428c4b717471378cb7f29c320988f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 19:04:46 +0100 Subject: [PATCH 07/38] added data to event --- openpype/pipeline/lib/events.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/lib/events.py b/openpype/pipeline/lib/events.py index b9ad889383..d9920b38e3 100644 --- a/openpype/pipeline/lib/events.py +++ b/openpype/pipeline/lib/events.py @@ -46,7 +46,11 @@ class BaseEvent(object): class BeforeWorkfileSave(BaseEvent): """Before workfile changes event data.""" def __init__(self, new_workfile, workdir): - super(BeforeWorkfileSave, self).__init__("before.workfile.save") + data = { + "workfile_path": new_workfile, + "workdir_path": workdir + } + super(BeforeWorkfileSave, self).__init__("before.workfile.save", data) self.workfile_path = new_workfile self.workdir_path = workdir From 34830ee8813a6256131dea57eb6ac312b8d465b4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 21:22:02 +0100 Subject: [PATCH 08/38] removed line --- openpype/tools/workfiles/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index 763e0f796d..703d077448 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -681,7 +681,6 @@ class FilesWidget(QtWidgets.QWidget): ) create_workdir_extra_folders( self._workdir_path, - self._workfiles_root, api.Session["AVALON_APP"], self._task_type, self._task_name, From 3d2a39b592ae11a96bbb1f293d632110629e034a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 22:45:42 +0100 Subject: [PATCH 09/38] trigger before save event as first thing --- openpype/pipeline/lib/events.py | 11 +++-------- openpype/tools/workfiles/app.py | 6 +++--- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/openpype/pipeline/lib/events.py b/openpype/pipeline/lib/events.py index d9920b38e3..05dea20e8c 100644 --- a/openpype/pipeline/lib/events.py +++ b/openpype/pipeline/lib/events.py @@ -45,12 +45,7 @@ class BaseEvent(object): class BeforeWorkfileSave(BaseEvent): """Before workfile changes event data.""" - def __init__(self, new_workfile, workdir): - data = { - "workfile_path": new_workfile, - "workdir_path": workdir - } - super(BeforeWorkfileSave, self).__init__("before.workfile.save", data) - - self.workfile_path = new_workfile + def __init__(self, filename, workdir): + super(BeforeWorkfileSave, self).__init__("before.workfile.save") + self.filename = filename self.workdir_path = workdir diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index 703d077448..92cb23b619 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -654,6 +654,9 @@ class FilesWidget(QtWidgets.QWidget): if not work_file: return + # Trigger before save event + BeforeWorkfileSave.emit(work_file, self._workdir_path) + # Initialize work directory if it has not been initialized before if not os.path.exists(self._workfiles_root): log.debug("Initializing Work Directory: %s", self._workfiles_root) @@ -670,9 +673,6 @@ class FilesWidget(QtWidgets.QWidget): file_path = os.path.join( os.path.normpath(self._workfiles_root), work_file ) - - BeforeWorkfileSave.emit(file_path, self._workdir_path) - self._enter_session() # Make sure we are in the right session self.host.save_file(file_path) From d3eac428adf7d34fbee2cb73763c32a743c64246 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Jan 2022 22:49:09 +0100 Subject: [PATCH 10/38] reorganized on save as method --- openpype/tools/workfiles/app.py | 91 +++++++++------------------------ 1 file changed, 24 insertions(+), 67 deletions(-) diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index 92cb23b619..b73f0e4930 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -650,35 +650,33 @@ class FilesWidget(QtWidgets.QWidget): self.open_file(work_file) def on_save_as_pressed(self): - work_file = self.get_filename() - if not work_file: + work_filename = self.get_filename() + if not work_filename: return # Trigger before save event - BeforeWorkfileSave.emit(work_file, self._workdir_path) - - # Initialize work directory if it has not been initialized before - if not os.path.exists(self._workfiles_root): - log.debug("Initializing Work Directory: %s", self._workfiles_root) - self.initialize_work_directory() - if not os.path.exists(self._workfiles_root): - # Failed to initialize Work Directory - log.error( - "Failed to initialize Work Directory: {}".format( - self._workfiles_root - ) - ) - return - - file_path = os.path.join( - os.path.normpath(self._workfiles_root), work_file - ) - self._enter_session() # Make sure we are in the right session - self.host.save_file(file_path) + BeforeWorkfileSave.emit(work_filename, self._workdir_path) + # Make sure workfiles root is updated + # - this triggers 'workio.work_root(...)' which may change value of + # '_workfiles_root' self.set_asset_task( self._asset_id, self._task_name, self._task_type ) + + # Create workfiles root folder + if not os.path.exists(self._workfiles_root): + log.debug("Initializing Work Directory: %s", self._workfiles_root) + os.makedirs(self._workfiles_root) + + # Update session if context has changed + self._enter_session() + # Prepare full path to workfile and save it + filepath = os.path.join( + os.path.normpath(self._workfiles_root), work_filename + ) + self.host.save_file(filepath) + # Create extra folders create_workdir_extra_folders( self._workdir_path, api.Session["AVALON_APP"], @@ -686,57 +684,16 @@ class FilesWidget(QtWidgets.QWidget): self._task_name, api.Session["AVALON_PROJECT"] ) - pipeline.emit("after.workfile.save", [file_path]) - - self.workfile_created.emit(file_path) + # Trigger after save events + pipeline.emit("after.workfile.save", [filepath]) + self.workfile_created.emit(filepath) + # Refresh files model self.refresh() def on_file_select(self): self.file_selected.emit(self._get_selected_filepath()) - def initialize_work_directory(self): - """Initialize Work Directory. - - This is used when the Work Directory does not exist yet. - - This finds the current AVALON_APP_NAME and tries to triggers its - `.toml` initialization step. Note that this will only be valid - whenever `AVALON_APP_NAME` is actually set in the current session. - - """ - - # Inputs (from the switched session and running app) - session = api.Session.copy() - changes = pipeline.compute_session_changes( - session, - asset=self._get_asset_doc(), - task=self._task_name, - template_key=self.template_key - ) - session.update(changes) - - # Prepare documents to get workdir data - project_doc = io.find_one({"type": "project"}) - asset_doc = io.find_one( - { - "type": "asset", - "name": session["AVALON_ASSET"] - } - ) - task_name = session["AVALON_TASK"] - host_name = session["AVALON_APP"] - - # Get workdir from collected documents - workdir = get_workdir(project_doc, asset_doc, task_name, host_name) - # Create workdir if does not exist yet - if not os.path.exists(workdir): - os.makedirs(workdir) - - # Force a full to the asset as opposed to just self.refresh() so - # that it will actually check again whether the Work directory exists - self.set_asset_task(self._asset_id, self._task_name, self._task_type) - def refresh(self): """Refresh listed files for current selection in the interface""" self.files_model.refresh() From 75d55b9ac5aee789ed6f6c1cb41677b67a34ad4e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 14 Jan 2022 18:09:41 +0100 Subject: [PATCH 11/38] OP-1117 - added context menu to Launcher actions to skip opening last workfile Choice is persistent in Local Setting (only in DB, not exposed to GUI yet.) --- openpype/hooks/pre_global_host_data.py | 1 + openpype/hooks/pre_non_python_host_launch.py | 2 +- openpype/lib/applications.py | 5 ++ openpype/tools/launcher/actions.py | 4 +- openpype/tools/launcher/constants.py | 1 + openpype/tools/launcher/delegates.py | 13 ++- openpype/tools/launcher/models.py | 86 +++++++++++++++++++- openpype/tools/launcher/widgets.py | 39 ++++++++- 8 files changed, 145 insertions(+), 6 deletions(-) diff --git a/openpype/hooks/pre_global_host_data.py b/openpype/hooks/pre_global_host_data.py index 6b08cdb444..bae967e25f 100644 --- a/openpype/hooks/pre_global_host_data.py +++ b/openpype/hooks/pre_global_host_data.py @@ -43,6 +43,7 @@ class GlobalHostDataHook(PreLaunchHook): "env": self.launch_context.env, + "start_last_workfile": self.data.get("start_last_workfile"), "last_workfile_path": self.data.get("last_workfile_path"), "log": self.log diff --git a/openpype/hooks/pre_non_python_host_launch.py b/openpype/hooks/pre_non_python_host_launch.py index 29e40d28c8..8aa61a9027 100644 --- a/openpype/hooks/pre_non_python_host_launch.py +++ b/openpype/hooks/pre_non_python_host_launch.py @@ -40,7 +40,7 @@ class NonPythonHostHook(PreLaunchHook): ) # Add workfile path if exists workfile_path = self.data["last_workfile_path"] - if os.path.exists(workfile_path): + if workfile_path and os.path.exists(workfile_path): new_launch_args.append(workfile_path) # Append as whole list as these areguments should not be separated diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index d0438e12a6..ab20d812e7 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1490,6 +1490,11 @@ def _prepare_last_workfile(data, workdir): import avalon.api log = data["log"] + + if not data.get("start_last_workfile", True): + log.info("Explicitly forbidden to open last workfile, skipping") + return + _workdir_data = data.get("workdir_data") if not _workdir_data: log.info( diff --git a/openpype/tools/launcher/actions.py b/openpype/tools/launcher/actions.py index 4d86970f9c..fbaef05261 100644 --- a/openpype/tools/launcher/actions.py +++ b/openpype/tools/launcher/actions.py @@ -62,6 +62,7 @@ class ApplicationAction(api.Action): icon = None color = None order = 0 + data = {} _log = None required_session_keys = ( @@ -103,7 +104,8 @@ class ApplicationAction(api.Action): self.application.launch( project_name=project_name, asset_name=asset_name, - task_name=task_name + task_name=task_name, + **self.data ) except ApplictionExecutableNotFound as exc: diff --git a/openpype/tools/launcher/constants.py b/openpype/tools/launcher/constants.py index 7f394cb5ac..3747b0f0a4 100644 --- a/openpype/tools/launcher/constants.py +++ b/openpype/tools/launcher/constants.py @@ -7,6 +7,7 @@ VARIANT_GROUP_ROLE = QtCore.Qt.UserRole + 2 ACTION_ID_ROLE = QtCore.Qt.UserRole + 3 ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4 ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5 +FORCE_NOT_OPEN_WORKFILE_ROLE = QtCore.Qt.UserRole + 6 # Animation length in seconds ANIMATION_LEN = 7 diff --git a/openpype/tools/launcher/delegates.py b/openpype/tools/launcher/delegates.py index cef0f5e1a2..7b53658727 100644 --- a/openpype/tools/launcher/delegates.py +++ b/openpype/tools/launcher/delegates.py @@ -2,7 +2,8 @@ import time from Qt import QtCore, QtWidgets, QtGui from .constants import ( ANIMATION_START_ROLE, - ANIMATION_STATE_ROLE + ANIMATION_STATE_ROLE, + FORCE_NOT_OPEN_WORKFILE_ROLE ) @@ -69,6 +70,16 @@ class ActionDelegate(QtWidgets.QStyledItemDelegate): self._draw_animation(painter, option, index) super(ActionDelegate, self).paint(painter, option, index) + + if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): + rect = QtCore.QRectF(option.rect.x(), option.rect.height(), + 5, 5) + painter.setPen(QtCore.Qt.transparent) + painter.setBrush(QtGui.QColor(200, 0, 0)) + painter.drawEllipse(rect) + + painter.setBrush(self.extender_bg_brush) + is_group = False for group_role in self.group_roles: is_group = index.data(group_role) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 427475cb4b..d3fd7ac3b9 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -8,7 +8,8 @@ from .constants import ( ACTION_ROLE, GROUP_ROLE, VARIANT_GROUP_ROLE, - ACTION_ID_ROLE + ACTION_ID_ROLE, + FORCE_NOT_OPEN_WORKFILE_ROLE ) from .actions import ApplicationAction from Qt import QtCore, QtGui @@ -16,6 +17,8 @@ from avalon.vendor import qtawesome from avalon import style, api from openpype.lib import ApplicationManager +from openpype.settings.lib import get_local_settings, save_local_settings + log = logging.getLogger(__name__) @@ -75,7 +78,8 @@ class ActionModel(QtGui.QStandardItemModel): "group": None, "icon": app.icon, "color": getattr(app, "color", None), - "order": getattr(app, "order", None) or 0 + "order": getattr(app, "order", None) or 0, + "data": {} } ) @@ -179,11 +183,20 @@ class ActionModel(QtGui.QStandardItemModel): self.beginResetModel() + local_settings = get_local_settings() items = [] for order in sorted(items_by_order.keys()): for item in items_by_order[order]: item_id = str(uuid.uuid4()) item.setData(item_id, ACTION_ID_ROLE) + + if self.is_force_not_open_workfile(item, + local_settings): + label = item.text() + label += " (Not opening last workfile)" + item.setData(label, QtCore.Qt.ToolTipRole) + item.setData(True, FORCE_NOT_OPEN_WORKFILE_ROLE) + self.items_by_id[item_id] = item items.append(item) @@ -222,6 +235,75 @@ class ActionModel(QtGui.QStandardItemModel): key=lambda action: (action.order, action.name) ) + def update_force_not_open_workfile_settings(self, is_checked, action): + """Store/remove config for forcing to skip opening last workfile. + + Args: + is_checked (bool): True to add, False to remove + action (ApplicationAction) + """ + local_settings = get_local_settings() + + actual_data = self._prepare_compare_data(action) + + force_not_open_workfile = local_settings.get("force_not_open_workfile", + []) + final_local_sett = local_settings + if is_checked: + if not force_not_open_workfile: + final_local_sett["force_not_open_workfile"] = [] + + final_local_sett["force_not_open_workfile"].append(actual_data) + else: + final_local_sett["force_not_open_workfile"] = [] + for config in force_not_open_workfile: + if config != actual_data: + final_local_sett["force_not_open_workfile"].append(config) + + if not final_local_sett["force_not_open_workfile"]: + final_local_sett.pop("force_not_open_workfile") + + save_local_settings(final_local_sett) + + def is_force_not_open_workfile(self, item, local_settings): + """Checks if application for task is marked to not open workfile + + There might be specific tasks where is unwanted to open workfile right + always (broken file, low performance). This allows artist to mark to + skip opening for combination (project, asset, task_name, app) + + Args: + item (QStandardItem) + local_settings (dict) + """ + action = item.data(ACTION_ROLE) + actual_data = self._prepare_compare_data(action) + for config in local_settings.get("force_not_open_workfile", []): + if config == actual_data: + return True + + return False + + def _prepare_compare_data(self, action): + if isinstance(action, list) and action: + action = action[0] + + _session = copy.deepcopy(self.dbcon.Session) + session = { + key: value + for key, value in _session.items() + if value + } + + actual_data = { + "app_label": action.label.lower(), + "project_name": session["AVALON_PROJECT"], + "asset": session["AVALON_ASSET"], + "task_name": session["AVALON_TASK"] + } + + return actual_data + class ProjectModel(QtGui.QStandardItemModel): """List of projects""" diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index edda8d08b5..0c21fcb33d 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -15,7 +15,8 @@ from .constants import ( ACTION_ID_ROLE, ANIMATION_START_ROLE, ANIMATION_STATE_ROLE, - ANIMATION_LEN + ANIMATION_LEN, + FORCE_NOT_OPEN_WORKFILE_ROLE ) @@ -96,6 +97,7 @@ class ActionBar(QtWidgets.QWidget): view.setViewMode(QtWidgets.QListView.IconMode) view.setResizeMode(QtWidgets.QListView.Adjust) view.setSelectionMode(QtWidgets.QListView.NoSelection) + view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) view.setEditTriggers(QtWidgets.QListView.NoEditTriggers) view.setWrapping(True) view.setGridSize(QtCore.QSize(70, 75)) @@ -135,6 +137,7 @@ class ActionBar(QtWidgets.QWidget): project_handler.projects_refreshed.connect(self._on_projects_refresh) view.clicked.connect(self.on_clicked) + view.customContextMenuRequested.connect(self.on_context_menu) def discover_actions(self): if self._animation_timer.isActive(): @@ -181,6 +184,38 @@ class ActionBar(QtWidgets.QWidget): self._animated_items.add(action_id) self._animation_timer.start() + def on_context_menu(self, point): + """Creates menu to force skip opening last workfile.""" + index = self.view.indexAt(point) + if not index.isValid(): + return + + action_item = index.data(ACTION_ROLE) + menu = QtWidgets.QMenu(self.view) + checkbox = QtWidgets.QCheckBox("Force not open last workfile", + menu) + if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): + checkbox.setChecked(True) + + checkbox.stateChanged.connect( + lambda: self.on_checkbox_changed(checkbox.isChecked(), + action_item)) + action = QtWidgets.QWidgetAction(menu) + action.setDefaultWidget(checkbox) + + menu.addAction(action) + + global_point = self.mapToGlobal(point) + action = menu.exec_(global_point) + if not action or not action.data(): + return + + return + + def on_checkbox_changed(self, is_checked, action): + self.model.update_force_not_open_workfile_settings(is_checked, action) + self.discover_actions() # repaint + def on_clicked(self, index): if not index or not index.isValid(): return @@ -189,6 +224,8 @@ class ActionBar(QtWidgets.QWidget): is_variant_group = index.data(VARIANT_GROUP_ROLE) if not is_group and not is_variant_group: action = index.data(ACTION_ROLE) + if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): + action.data["start_last_workfile"] = False self._start_animation(index) self.action_clicked.emit(action) return From c9b93837d6167c8c4111eb8a154b46c23049de0c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 12:17:36 +0100 Subject: [PATCH 12/38] OP-1117 - switched from local settings to JSONRegistry LS change in UI might be destructive, create json file in user dir instead --- openpype/tools/launcher/models.py | 45 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index d3fd7ac3b9..b872dda8c2 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -2,6 +2,7 @@ import uuid import copy import logging import collections +import appdirs from . import lib from .constants import ( @@ -15,9 +16,7 @@ from .actions import ApplicationAction from Qt import QtCore, QtGui from avalon.vendor import qtawesome from avalon import style, api -from openpype.lib import ApplicationManager - -from openpype.settings.lib import get_local_settings, save_local_settings +from openpype.lib import ApplicationManager, JSONSettingRegistry log = logging.getLogger(__name__) @@ -33,6 +32,13 @@ class ActionModel(QtGui.QStandardItemModel): # Cache of available actions self._registered_actions = list() self.items_by_id = {} + path = appdirs.user_data_dir("openpype", "pype_club") + self.launcher_registry = JSONSettingRegistry("launcher", path) + + try: + _ = self.launcher_registry.get_item("force_not_open_workfile") + except ValueError: + self.launcher_registry.set_item("force_not_open_workfile", []) def discover(self): """Set up Actions cache. Run this for each new project.""" @@ -183,7 +189,7 @@ class ActionModel(QtGui.QStandardItemModel): self.beginResetModel() - local_settings = get_local_settings() + stored = self.launcher_registry.get_item("force_not_open_workfile") items = [] for order in sorted(items_by_order.keys()): for item in items_by_order[order]: @@ -191,7 +197,7 @@ class ActionModel(QtGui.QStandardItemModel): item.setData(item_id, ACTION_ID_ROLE) if self.is_force_not_open_workfile(item, - local_settings): + stored): label = item.text() label += " (Not opening last workfile)" item.setData(label, QtCore.Qt.ToolTipRole) @@ -242,30 +248,21 @@ class ActionModel(QtGui.QStandardItemModel): is_checked (bool): True to add, False to remove action (ApplicationAction) """ - local_settings = get_local_settings() - actual_data = self._prepare_compare_data(action) - force_not_open_workfile = local_settings.get("force_not_open_workfile", - []) - final_local_sett = local_settings + stored = self.launcher_registry.get_item("force_not_open_workfile") if is_checked: - if not force_not_open_workfile: - final_local_sett["force_not_open_workfile"] = [] - - final_local_sett["force_not_open_workfile"].append(actual_data) + stored.append(actual_data) else: - final_local_sett["force_not_open_workfile"] = [] - for config in force_not_open_workfile: + final_values = [] + for config in stored: if config != actual_data: - final_local_sett["force_not_open_workfile"].append(config) + final_values.append(config) + stored = final_values - if not final_local_sett["force_not_open_workfile"]: - final_local_sett.pop("force_not_open_workfile") + self.launcher_registry.set_item("force_not_open_workfile", stored) - save_local_settings(final_local_sett) - - def is_force_not_open_workfile(self, item, local_settings): + def is_force_not_open_workfile(self, item, stored): """Checks if application for task is marked to not open workfile There might be specific tasks where is unwanted to open workfile right @@ -274,11 +271,11 @@ class ActionModel(QtGui.QStandardItemModel): Args: item (QStandardItem) - local_settings (dict) + stored (list) of dict """ action = item.data(ACTION_ROLE) actual_data = self._prepare_compare_data(action) - for config in local_settings.get("force_not_open_workfile", []): + for config in stored: if config == actual_data: return True From 14d05f5f077dc53f8c95fc5861c3122070d5eaf8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 13:14:35 +0100 Subject: [PATCH 13/38] OP-1117 - apply only on ApplicationAction --- openpype/tools/launcher/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index b872dda8c2..1df41fbc9d 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -274,6 +274,12 @@ class ActionModel(QtGui.QStandardItemModel): stored (list) of dict """ action = item.data(ACTION_ROLE) + if isinstance(action, list) and action: + action = action[0] + + if ApplicationAction not in action.__bases__: + return False + actual_data = self._prepare_compare_data(action) for config in stored: if config == actual_data: From 66e032dc6fb507b54ede43a1fb964307ad8f46a7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 13:44:33 +0100 Subject: [PATCH 14/38] Update openpype/tools/launcher/models.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/tools/launcher/models.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 1df41fbc9d..0d57114e46 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -291,22 +291,13 @@ class ActionModel(QtGui.QStandardItemModel): if isinstance(action, list) and action: action = action[0] - _session = copy.deepcopy(self.dbcon.Session) - session = { - key: value - for key, value in _session.items() - if value - } - - actual_data = { + return { "app_label": action.label.lower(), - "project_name": session["AVALON_PROJECT"], - "asset": session["AVALON_ASSET"], - "task_name": session["AVALON_TASK"] + "project_name": self.dbcon.Session["AVALON_PROJECT"], + "asset": self.dbcon.Session["AVALON_ASSET"], + "task_name": self.dbcon.Session["AVALON_TASK"] } - return actual_data - class ProjectModel(QtGui.QStandardItemModel): """List of projects""" From 69f97476f921ab86ca984cea934889ede207606a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 14:45:39 +0100 Subject: [PATCH 15/38] OP-1117 - add check for ApplicationAction on context menu --- openpype/tools/launcher/models.py | 17 +++++++++++++---- openpype/tools/launcher/widgets.py | 3 +++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 0d57114e46..86c3d816b2 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -261,6 +261,18 @@ class ActionModel(QtGui.QStandardItemModel): stored = final_values self.launcher_registry.set_item("force_not_open_workfile", stored) + self.launcher_registry._get_item.cache_clear() + + def is_application_action(self, action): + """Checks if item is of a ApplicationAction type + + Args: + action (action) + """ + if isinstance(action, list) and action: + action = action[0] + + return ApplicationAction in action.__bases__ def is_force_not_open_workfile(self, item, stored): """Checks if application for task is marked to not open workfile @@ -274,10 +286,7 @@ class ActionModel(QtGui.QStandardItemModel): stored (list) of dict """ action = item.data(ACTION_ROLE) - if isinstance(action, list) and action: - action = action[0] - - if ApplicationAction not in action.__bases__: + if not self.is_application_action(action): return False actual_data = self._prepare_compare_data(action) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 0c21fcb33d..907aff91d4 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -191,6 +191,9 @@ class ActionBar(QtWidgets.QWidget): return action_item = index.data(ACTION_ROLE) + if not self.model.is_application_action(action_item): + return + menu = QtWidgets.QMenu(self.view) checkbox = QtWidgets.QCheckBox("Force not open last workfile", menu) From 0bb4d317c45fc33072acf4333d670bda000b157a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 14:55:52 +0100 Subject: [PATCH 16/38] OP-1117 - remove unneeded code --- openpype/tools/launcher/widgets.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 907aff91d4..da9218e4ea 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -209,11 +209,7 @@ class ActionBar(QtWidgets.QWidget): menu.addAction(action) global_point = self.mapToGlobal(point) - action = menu.exec_(global_point) - if not action or not action.data(): - return - - return + _ = menu.exec_(global_point) def on_checkbox_changed(self, is_checked, action): self.model.update_force_not_open_workfile_settings(is_checked, action) From 276aff358b3c7da0ae9c7e4fa2920f1ee5064004 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 17:03:30 +0100 Subject: [PATCH 17/38] OP-1117 - better handling of setting of start_last_workfile --- openpype/lib/applications.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index ab20d812e7..772514823e 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1491,10 +1491,6 @@ def _prepare_last_workfile(data, workdir): log = data["log"] - if not data.get("start_last_workfile", True): - log.info("Explicitly forbidden to open last workfile, skipping") - return - _workdir_data = data.get("workdir_data") if not _workdir_data: log.info( @@ -1511,7 +1507,11 @@ def _prepare_last_workfile(data, workdir): start_last_workfile = should_start_last_workfile( project_name, app.host_name, task_name, task_type ) - data["start_last_workfile"] = start_last_workfile + if not data.get("start_last_workfile", True): + log.info("Explicitly forbidden to open last workfile") + start_last_workfile = False + else: + data["start_last_workfile"] = start_last_workfile workfile_startup = should_workfile_tool_start( project_name, app.host_name, task_name, task_type From 419555ec08b437761f7afc6ac2438f75f7169c7c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 17 Jan 2022 17:06:26 +0100 Subject: [PATCH 18/38] OP-1117 - handle empty action --- openpype/tools/launcher/models.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 86c3d816b2..305707319d 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -300,12 +300,15 @@ class ActionModel(QtGui.QStandardItemModel): if isinstance(action, list) and action: action = action[0] - return { - "app_label": action.label.lower(), - "project_name": self.dbcon.Session["AVALON_PROJECT"], - "asset": self.dbcon.Session["AVALON_ASSET"], - "task_name": self.dbcon.Session["AVALON_TASK"] - } + compare_data = {} + if action: + compare_data = { + "app_label": action.label.lower(), + "project_name": self.dbcon.Session["AVALON_PROJECT"], + "asset": self.dbcon.Session["AVALON_ASSET"], + "task_name": self.dbcon.Session["AVALON_TASK"] + } + return compare_data class ProjectModel(QtGui.QStandardItemModel): From 3e64f2d0ce224af2d3adabb518be4689c2e1e9c8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 18 Jan 2022 12:41:05 +0100 Subject: [PATCH 19/38] OP-1117 - fixed start_last_workfile logic It wasnt setting this property all the time. --- openpype/lib/applications.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 772514823e..152dc6af6b 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1504,14 +1504,16 @@ def _prepare_last_workfile(data, workdir): project_name = data["project_name"] task_name = data["task_name"] task_type = data["task_type"] - start_last_workfile = should_start_last_workfile( - project_name, app.host_name, task_name, task_type - ) - if not data.get("start_last_workfile", True): - log.info("Explicitly forbidden to open last workfile") - start_last_workfile = False + + start_last_workfile = data.get("start_last_workfile", True) + if start_last_workfile: + start_last_workfile = should_start_last_workfile( + project_name, app.host_name, task_name, task_type + ) else: - data["start_last_workfile"] = start_last_workfile + log.info("Explicitly forbidden to open last workfile") + + data["start_last_workfile"] = start_last_workfile workfile_startup = should_workfile_tool_start( project_name, app.host_name, task_name, task_type From 650294b65657d7bbfa5b28b3bbcd2265e44926ce Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Jan 2022 12:30:06 +0100 Subject: [PATCH 20/38] OP-1117 - fix for Adobe products --- openpype/hooks/pre_add_last_workfile_arg.py | 4 +++- openpype/hooks/pre_global_host_data.py | 2 +- openpype/hooks/pre_non_python_host_launch.py | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 5ca2a42510..4ff5e17edc 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -6,6 +6,8 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): """Add last workfile path to launch arguments. This is not possible to do for all applications the same way. + Checks 'start_last_workfile', if set to False, it will not open last + wokfile. This property is set explicitly in Launcher. """ # Execute after workfile template copy @@ -23,7 +25,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): ] def execute(self): - if not self.data.get("start_last_workfile"): + if not self.data.get("start_last_workfile", True): self.log.info("It is set to not start last workfile on start.") return diff --git a/openpype/hooks/pre_global_host_data.py b/openpype/hooks/pre_global_host_data.py index bae967e25f..3f56c47a42 100644 --- a/openpype/hooks/pre_global_host_data.py +++ b/openpype/hooks/pre_global_host_data.py @@ -43,7 +43,7 @@ class GlobalHostDataHook(PreLaunchHook): "env": self.launch_context.env, - "start_last_workfile": self.data.get("start_last_workfile"), + "start_last_workfile": self.data.get("start_last_workfile", True), "last_workfile_path": self.data.get("last_workfile_path"), "log": self.log diff --git a/openpype/hooks/pre_non_python_host_launch.py b/openpype/hooks/pre_non_python_host_launch.py index 8aa61a9027..5bbc0a4834 100644 --- a/openpype/hooks/pre_non_python_host_launch.py +++ b/openpype/hooks/pre_non_python_host_launch.py @@ -40,7 +40,10 @@ class NonPythonHostHook(PreLaunchHook): ) # Add workfile path if exists workfile_path = self.data["last_workfile_path"] - if workfile_path and os.path.exists(workfile_path): + if ( + self.data.get("start_last_workfile", True) + and workfile_path + and os.path.exists(workfile_path)): new_launch_args.append(workfile_path) # Append as whole list as these areguments should not be separated From f6ccc6aee10360a88ea0bba1b66ecce3b8958dd0 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Jan 2022 14:51:14 +0100 Subject: [PATCH 21/38] OP-1117 - updated setting of state on action item Updated handling of menu display and repaint --- openpype/tools/launcher/constants.py | 1 + openpype/tools/launcher/models.py | 26 +++++++++++++++++++------- openpype/tools/launcher/widgets.py | 26 +++++++++++++++++++++----- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/openpype/tools/launcher/constants.py b/openpype/tools/launcher/constants.py index 3747b0f0a4..61f631759b 100644 --- a/openpype/tools/launcher/constants.py +++ b/openpype/tools/launcher/constants.py @@ -8,6 +8,7 @@ ACTION_ID_ROLE = QtCore.Qt.UserRole + 3 ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4 ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5 FORCE_NOT_OPEN_WORKFILE_ROLE = QtCore.Qt.UserRole + 6 +ACTION_TOOLTIP_ROLE = QtCore.Qt.UserRole + 7 # Animation length in seconds ANIMATION_LEN = 7 diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 305707319d..10922e42cc 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -32,7 +32,7 @@ class ActionModel(QtGui.QStandardItemModel): # Cache of available actions self._registered_actions = list() self.items_by_id = {} - path = appdirs.user_data_dir("openpype", "pype_club") + path = appdirs.user_data_dir("openpype", "pypeclub") self.launcher_registry = JSONSettingRegistry("launcher", path) try: @@ -198,10 +198,7 @@ class ActionModel(QtGui.QStandardItemModel): if self.is_force_not_open_workfile(item, stored): - label = item.text() - label += " (Not opening last workfile)" - item.setData(label, QtCore.Qt.ToolTipRole) - item.setData(True, FORCE_NOT_OPEN_WORKFILE_ROLE) + self.change_action_item(item, True) self.items_by_id[item_id] = item items.append(item) @@ -241,13 +238,18 @@ class ActionModel(QtGui.QStandardItemModel): key=lambda action: (action.order, action.name) ) - def update_force_not_open_workfile_settings(self, is_checked, action): + def update_force_not_open_workfile_settings(self, is_checked, action_id): """Store/remove config for forcing to skip opening last workfile. Args: is_checked (bool): True to add, False to remove - action (ApplicationAction) + action_id (str) """ + action_item = self.items_by_id.get(action_id) + if not action_item: + return + + action = action_item.data(ACTION_ROLE) actual_data = self._prepare_compare_data(action) stored = self.launcher_registry.get_item("force_not_open_workfile") @@ -262,6 +264,16 @@ class ActionModel(QtGui.QStandardItemModel): self.launcher_registry.set_item("force_not_open_workfile", stored) self.launcher_registry._get_item.cache_clear() + self.change_action_item(action_item, is_checked) + + def change_action_item(self, item, checked): + """Modifies tooltip and sets if opening of last workfile forbidden""" + tooltip = item.data(QtCore.Qt.ToolTipRole) + if checked: + tooltip += " (Not opening last workfile)" + + item.setData(tooltip, QtCore.Qt.ToolTipRole) + item.setData(checked, FORCE_NOT_OPEN_WORKFILE_ROLE) def is_application_action(self, action): """Checks if item is of a ApplicationAction type diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index da9218e4ea..ae95e2e8d8 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -139,7 +139,14 @@ class ActionBar(QtWidgets.QWidget): view.clicked.connect(self.on_clicked) view.customContextMenuRequested.connect(self.on_context_menu) + self._context_menu = None + self._discover_on_menu = False + def discover_actions(self): + if self._context_menu is not None: + self._discover_on_menu = True + return + if self._animation_timer.isActive(): self._animation_timer.stop() self.model.discover() @@ -200,20 +207,29 @@ class ActionBar(QtWidgets.QWidget): if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): checkbox.setChecked(True) + action_id = index.data(ACTION_ID_ROLE) checkbox.stateChanged.connect( lambda: self.on_checkbox_changed(checkbox.isChecked(), - action_item)) + action_id)) action = QtWidgets.QWidgetAction(menu) action.setDefaultWidget(checkbox) menu.addAction(action) + self._context_menu = menu global_point = self.mapToGlobal(point) - _ = menu.exec_(global_point) + menu.exec_(global_point) + self._context_menu = None + if self._discover_on_menu: + self._discover_on_menu = False + self.discover_actions() - def on_checkbox_changed(self, is_checked, action): - self.model.update_force_not_open_workfile_settings(is_checked, action) - self.discover_actions() # repaint + def on_checkbox_changed(self, is_checked, action_id): + self.model.update_force_not_open_workfile_settings(is_checked, + action_id) + self.view.update() + if self._context_menu is not None: + self._context_menu.close() def on_clicked(self, index): if not index or not index.isValid(): From d6be6b0182f84fe746ae00d09e697db937ab6796 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 Jan 2022 15:14:21 +0100 Subject: [PATCH 22/38] Added CollectSceneVersion to Settings --- .../defaults/project_settings/global.json | 18 ++++++++++++++++ .../schemas/schema_global_publish.json | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index cff1259c98..3b5bb06267 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -3,6 +3,24 @@ "CollectAnatomyInstanceData": { "follow_workfile_version": false }, + "CollectSceneVersion": { + "hosts": [ + "aftereffects", + "blender", + "celaction", + "fusion", + "harmony", + "hiero", + "houdini", + "maya", + "nuke", + "photoshop", + "resolve", + "tvpaint" + ], + "skip_hosts_headless_publish": [ + ] + }, "ValidateEditorialAssetName": { "enabled": true, "optional": false diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index d146f3cf15..3f9776bcd6 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -18,6 +18,27 @@ } ] }, + { + "type": "dict", + "collapsible": true, + "key": "CollectSceneVersion", + "label": "Collect Version from Workfile", + "is_group": true, + "children": [ + { + "key": "hosts", + "label": "Host names", + "type": "hosts-enum", + "multiselection": true + }, + { + "key": "skip_hosts_headless_publish", + "label": "Skip for host if headless publish", + "type": "hosts-enum", + "multiselection": true + } + ] + }, { "type": "dict", "collapsible": true, From 676dce041abe1335bdbe2fdd94147c949e2f426a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 Jan 2022 15:15:57 +0100 Subject: [PATCH 23/38] Added possibility to skip version collecting Useful for headless publishing via webpublisher. Currently applicable only for Photoshop studio processing. --- openpype/plugins/publish/collect_scene_version.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openpype/plugins/publish/collect_scene_version.py b/openpype/plugins/publish/collect_scene_version.py index 8ed6e25e66..56a6e3fb46 100644 --- a/openpype/plugins/publish/collect_scene_version.py +++ b/openpype/plugins/publish/collect_scene_version.py @@ -11,6 +11,7 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder label = 'Collect Scene Version' + # configurable in Settings hosts = [ "aftereffects", "blender", @@ -26,7 +27,20 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): "tvpaint" ] + # in some cases of headless publishing (for example webpublisher using PS) + # you want to ignore version from name and let integrate use next version + skip_hosts_headless_publish = [ + + ] + def process(self, context): + # tests should be close to regular publish as possible + if (context.data["hostName"] in self.skip_hosts_headless_publish + and os.environ.get("HEADLESS_PUBLISH") + and not os.environ.get("IS_TEST")): + self.log.debug("Skipping for headless publishing") + return + assert context.data.get('currentFile'), "Cannot get current file" filename = os.path.basename(context.data.get('currentFile')) From 4c695d9ebc2ad26fde6257be7931f517cfb7d818 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 Jan 2022 15:24:52 +0100 Subject: [PATCH 24/38] Added mentioning HEADLESS_PUBLISH in readme for integration tests --- tests/integration/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/README.md b/tests/integration/README.md index 0b6a1804ae..eef8141127 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -5,6 +5,9 @@ Contains end-to-end tests for automatic testing of OP. Should run headless publish on all hosts to check basic publish use cases automatically to limit regression issues. +Uses env var `HEADLESS_PUBLISH` (set in test data zip files) to differentiate between regular publish +and "automated" one. + How to run ---------- - activate `{OPENPYPE_ROOT}/.venv` From c71e071a55cc04a065f5f6060eef6e676ff650cc Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 Jan 2022 15:33:55 +0100 Subject: [PATCH 25/38] Update openpype/tools/launcher/widgets.py Co-authored-by: Milan Kolar --- openpype/tools/launcher/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index ae95e2e8d8..beff2548f2 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -202,7 +202,7 @@ class ActionBar(QtWidgets.QWidget): return menu = QtWidgets.QMenu(self.view) - checkbox = QtWidgets.QCheckBox("Force not open last workfile", + checkbox = QtWidgets.QCheckBox("Skip opening last workfile.", menu) if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): checkbox.setChecked(True) From d07dc4ac999084b640cc2ec4834f2c17655cbccb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 Jan 2022 17:22:24 +0100 Subject: [PATCH 26/38] OP-1117 - fixed typos --- openpype/hooks/pre_add_last_workfile_arg.py | 2 +- openpype/lib/applications.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 4ff5e17edc..048545a150 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -7,7 +7,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): This is not possible to do for all applications the same way. Checks 'start_last_workfile', if set to False, it will not open last - wokfile. This property is set explicitly in Launcher. + workfile. This property is set explicitly in Launcher. """ # Execute after workfile template copy diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 152dc6af6b..1278ed396e 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1511,7 +1511,7 @@ def _prepare_last_workfile(data, workdir): project_name, app.host_name, task_name, task_type ) else: - log.info("Explicitly forbidden to open last workfile") + log.info("Opening of last workfile was disabled by user") data["start_last_workfile"] = start_last_workfile From e836416513477d9640c64e26c6066a6a8db3398e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 26 Jan 2022 17:56:19 +0100 Subject: [PATCH 27/38] OP-1117 - cleaned up use of default value --- openpype/hooks/pre_add_last_workfile_arg.py | 2 +- openpype/hooks/pre_global_host_data.py | 2 +- openpype/hooks/pre_non_python_host_launch.py | 2 +- openpype/lib/applications.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 048545a150..653f97b3dd 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -25,7 +25,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): ] def execute(self): - if not self.data.get("start_last_workfile", True): + if not self.data.get("start_last_workfile"): self.log.info("It is set to not start last workfile on start.") return diff --git a/openpype/hooks/pre_global_host_data.py b/openpype/hooks/pre_global_host_data.py index 3f56c47a42..bae967e25f 100644 --- a/openpype/hooks/pre_global_host_data.py +++ b/openpype/hooks/pre_global_host_data.py @@ -43,7 +43,7 @@ class GlobalHostDataHook(PreLaunchHook): "env": self.launch_context.env, - "start_last_workfile": self.data.get("start_last_workfile", True), + "start_last_workfile": self.data.get("start_last_workfile"), "last_workfile_path": self.data.get("last_workfile_path"), "log": self.log diff --git a/openpype/hooks/pre_non_python_host_launch.py b/openpype/hooks/pre_non_python_host_launch.py index 5bbc0a4834..dd193616e6 100644 --- a/openpype/hooks/pre_non_python_host_launch.py +++ b/openpype/hooks/pre_non_python_host_launch.py @@ -41,7 +41,7 @@ class NonPythonHostHook(PreLaunchHook): # Add workfile path if exists workfile_path = self.data["last_workfile_path"] if ( - self.data.get("start_last_workfile", True) + self.data.get("start_last_workfile") and workfile_path and os.path.exists(workfile_path)): new_launch_args.append(workfile_path) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 930b433ac0..a704c3ae68 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1505,8 +1505,8 @@ def _prepare_last_workfile(data, workdir): task_name = data["task_name"] task_type = data["task_type"] - start_last_workfile = data.get("start_last_workfile", True) - if start_last_workfile: + start_last_workfile = data.get("start_last_workfile") + if start_last_workfile is None: start_last_workfile = should_start_last_workfile( project_name, app.host_name, task_name, task_type ) From e68b9acb1ed018fb0d129d2c5a2453e58d309480 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 26 Jan 2022 18:04:16 +0100 Subject: [PATCH 28/38] Update openpype/tools/launcher/widgets.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/tools/launcher/widgets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index beff2548f2..ce3f128496 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -241,6 +241,8 @@ class ActionBar(QtWidgets.QWidget): action = index.data(ACTION_ROLE) if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE): action.data["start_last_workfile"] = False + else: + action.data.pop("start_last_workfile", None) self._start_animation(index) self.action_clicked.emit(action) return From af652e0d42ac7535518224dd20abd6e175f70604 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sun, 30 Jan 2022 21:32:44 +0100 Subject: [PATCH 29/38] Remove double 'project' in label --- openpype/tools/settings/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index e271585852..6a8d123617 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -168,7 +168,7 @@ class BaseWidget(QtWidgets.QWidget): with self.category_widget.working_state_context(): self.entity.add_to_project_override - action = QtWidgets.QAction("Add to project project override") + action = QtWidgets.QAction("Add to project override") actions_mapping[action] = add_to_project_override menu.addAction(action) From 20bc784698a9b148b9da4985c36f08ac4fb0b39b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sun, 30 Jan 2022 22:03:34 +0100 Subject: [PATCH 30/38] Fix typos/grammar mistakes. --- openpype/tools/assetcreator/app.py | 4 ++-- openpype/tools/assetcreator/widget.py | 6 +++--- openpype/tools/context_dialog/window.py | 2 +- openpype/tools/creator/window.py | 2 +- openpype/tools/experimental_tools/dialog.py | 2 +- openpype/tools/experimental_tools/tools_def.py | 2 +- openpype/tools/launcher/lib.py | 4 ++-- openpype/tools/launcher/models.py | 2 +- openpype/tools/launcher/widgets.py | 6 +++--- openpype/tools/loader/app.py | 4 ++-- openpype/tools/loader/lib.py | 2 +- openpype/tools/mayalookassigner/widgets.py | 4 ++-- .../project_manager/project_manager/model.py | 12 ++++++------ .../project_manager/multiselection_combobox.py | 2 +- openpype/tools/publisher/control.py | 4 ++-- .../publisher/widgets/border_label_widget.py | 6 +++--- .../tools/publisher/widgets/card_view_widgets.py | 2 +- .../tools/publisher/widgets/list_view_widgets.py | 6 +++--- .../publisher/widgets/validations_widget.py | 2 +- openpype/tools/publisher/widgets/widgets.py | 16 ++++++++-------- openpype/tools/pyblish_pype/control.py | 10 +++++----- openpype/tools/pyblish_pype/util.py | 2 +- openpype/tools/sceneinventory/window.py | 2 +- .../tools/settings/local_settings/constants.py | 2 +- openpype/tools/settings/local_settings/window.py | 2 +- openpype/tools/settings/settings/README.md | 4 ++-- openpype/tools/settings/settings/base.py | 2 +- openpype/tools/settings/settings/item_widgets.py | 6 +++--- openpype/tools/settings/settings/lib.py | 2 +- .../settings/settings/list_strict_widget.py | 2 +- .../settings/settings/multiselection_combobox.py | 2 +- openpype/tools/settings/settings/window.py | 2 +- openpype/tools/standalonepublish/app.py | 2 +- .../standalonepublish/widgets/model_asset.py | 2 +- .../standalonepublish/widgets/widget_asset.py | 6 +++--- .../widgets/widget_drop_frame.py | 2 +- .../standalonepublish/widgets/widget_family.py | 2 +- openpype/tools/tray/pype_info_widget.py | 2 +- openpype/tools/tray/pype_tray.py | 6 +++--- openpype/tools/tray_app/app.py | 2 +- openpype/tools/utils/host_tools.py | 6 +++--- openpype/tools/utils/lib.py | 6 +++--- openpype/tools/utils/widgets.py | 2 +- openpype/tools/workfiles/app.py | 10 +++++----- 44 files changed, 88 insertions(+), 88 deletions(-) diff --git a/openpype/tools/assetcreator/app.py b/openpype/tools/assetcreator/app.py index 58697e8aa3..1d332d647e 100644 --- a/openpype/tools/assetcreator/app.py +++ b/openpype/tools/assetcreator/app.py @@ -87,7 +87,7 @@ class Window(QtWidgets.QDialog): btn_layout = QtWidgets.QHBoxLayout(btns_widget) btn_create_asset = QtWidgets.QPushButton("Create asset") btn_create_asset.setToolTip( - "Creates all neccessary components for asset" + "Creates all necessary components for asset" ) checkbox_app = None if self.context is not None: @@ -231,7 +231,7 @@ class Window(QtWidgets.QDialog): test_name = name.replace(' ', '') error_message = None message = QtWidgets.QMessageBox(self) - message.setWindowTitle("Some errors has occured") + message.setWindowTitle("Some errors have occurred") message.setIcon(QtWidgets.QMessageBox.Critical) # TODO: show error messages on any error if self.valid_parent is not True and test_name == '': diff --git a/openpype/tools/assetcreator/widget.py b/openpype/tools/assetcreator/widget.py index 1e9e4ab624..fd0f438e68 100644 --- a/openpype/tools/assetcreator/widget.py +++ b/openpype/tools/assetcreator/widget.py @@ -44,7 +44,7 @@ def preserve_expanded_rows(tree_view, This function is created to maintain the expand vs collapse status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. Arguments: tree_view (QWidgets.QTreeView): the tree view which is @@ -94,7 +94,7 @@ def preserve_selection(tree_view, This function is created to maintain the selection status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. tree_view (QWidgets.QTreeView): the tree view nested in the application column (int): the column to retrieve the data from @@ -179,7 +179,7 @@ class AssetModel(TreeModel): """ if silos: # WARNING: Silo item "_id" is set to silo value - # mainly because GUI issue with perserve selection and expanded row + # mainly because GUI issue with preserve selection and expanded row # and because of easier hierarchy parenting (in "assets") for silo in silos: item = Item({ diff --git a/openpype/tools/context_dialog/window.py b/openpype/tools/context_dialog/window.py index 5d8a2ad62e..c8464faa3e 100644 --- a/openpype/tools/context_dialog/window.py +++ b/openpype/tools/context_dialog/window.py @@ -46,7 +46,7 @@ class ContextDialog(QtWidgets.QDialog): # UI initialization main_splitter = QtWidgets.QSplitter(self) - # Left side widget containt project combobox and asset widget + # Left side widget contains project combobox and asset widget left_side_widget = QtWidgets.QWidget(main_splitter) project_combobox = QtWidgets.QComboBox(left_side_widget) diff --git a/openpype/tools/creator/window.py b/openpype/tools/creator/window.py index 22a6d5ce9c..f1d0849dfe 100644 --- a/openpype/tools/creator/window.py +++ b/openpype/tools/creator/window.py @@ -354,7 +354,7 @@ class CreatorWindow(QtWidgets.QDialog): Override keyPressEvent to do nothing so that Maya's panels won't take focus when pressing "SHIFT" whilst mouse is over viewport or - outliner. This way users don't accidently perform Maya commands + outliner. This way users don't accidentally perform Maya commands whilst trying to name an instance. """ diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index ad65caa8e3..295afbe68d 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -107,7 +107,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): # Is dialog first shown self._first_show = True - # Trigger refresh when window get's activity + # Trigger refresh when window gets activity self._refresh_on_active = True # Is window active self._window_is_active = False diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 991eb5e4a3..316359c0f3 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -43,7 +43,7 @@ class ExperimentalTool: self._enabled = enabled def execute(self): - """Trigger registerd callback.""" + """Trigger registered callback.""" self.callback() diff --git a/openpype/tools/launcher/lib.py b/openpype/tools/launcher/lib.py index d6374f49d2..4d678b96ae 100644 --- a/openpype/tools/launcher/lib.py +++ b/openpype/tools/launcher/lib.py @@ -29,7 +29,7 @@ class ProjectHandler(QtCore.QObject): Helps to organize two separate widgets handling current project selection. It is easier to trigger project change callbacks from one place than from - multiple differect places without proper handling or sequence changes. + multiple different places without proper handling or sequence changes. Args: dbcon(AvalonMongoDB): Mongo connection with Session. @@ -42,7 +42,7 @@ class ProjectHandler(QtCore.QObject): # that may require reshing of projects refresh_interval = 10000 - # Signal emmited when project has changed + # Signal emitted when project has changed project_changed = QtCore.Signal(str) projects_refreshed = QtCore.Signal() timer_timeout = QtCore.Signal() diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 427475cb4b..42ad509854 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -102,7 +102,7 @@ class ActionModel(QtGui.QStandardItemModel): # Groups group_name = getattr(action, "group", None) - # Lable variants + # Label variants label = getattr(action, "label", None) label_variant = getattr(action, "label_variant", None) if label_variant and not label: diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index edda8d08b5..55232c4d1d 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -171,7 +171,7 @@ class ActionBar(QtWidgets.QWidget): self.update() def _start_animation(self, index): - # Offset refresh timout + # Offset refresh timeout self.project_handler.start_timer() action_id = index.data(ACTION_ID_ROLE) item = self.model.items_by_id.get(action_id) @@ -193,7 +193,7 @@ class ActionBar(QtWidgets.QWidget): self.action_clicked.emit(action) return - # Offset refresh timout + # Offset refresh timeout self.project_handler.start_timer() actions = index.data(ACTION_ROLE) @@ -212,7 +212,7 @@ class ActionBar(QtWidgets.QWidget): by_variant_label = collections.defaultdict(list) orders = [] for action in actions: - # Lable variants + # Label variants label = getattr(action, "label", None) label_variant = getattr(action, "label_variant", None) if label_variant and not label: diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 62bf5538de..1d5dee21f3 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -27,7 +27,7 @@ module.window = None # Register callback on task change # - callback can't be defined in Window as it is weak reference callback -# so `WeakSet` will remove it immidiatelly +# so `WeakSet` will remove it immediately def on_context_task_change(*args, **kwargs): if module.window: module.window.on_context_task_change(*args, **kwargs) @@ -455,7 +455,7 @@ class LoaderWindow(QtWidgets.QDialog): shift_pressed = QtCore.Qt.ShiftModifier & modifiers if shift_pressed: - print("Force quitted..") + print("Force quit..") self.setAttribute(QtCore.Qt.WA_DeleteOnClose) print("Good bye") diff --git a/openpype/tools/loader/lib.py b/openpype/tools/loader/lib.py index 14ebab6c85..8f18c01913 100644 --- a/openpype/tools/loader/lib.py +++ b/openpype/tools/loader/lib.py @@ -46,7 +46,7 @@ def get_options(action, loader, parent, repre_contexts): Args: action (OptionalAction) - action in menu - loader (cls of api.Loader) - not initilized yet + loader (cls of api.Loader) - not initialized yet parent (Qt element to parent dialog to) repre_contexts (list) of dict with full info about selected repres Returns: diff --git a/openpype/tools/mayalookassigner/widgets.py b/openpype/tools/mayalookassigner/widgets.py index fceaf27244..c78fcc460e 100644 --- a/openpype/tools/mayalookassigner/widgets.py +++ b/openpype/tools/mayalookassigner/widgets.py @@ -233,8 +233,8 @@ class LookOutliner(QtWidgets.QWidget): list: list of dictionaries """ - datas = [i.data(TreeModel.ItemRole) for i in self.view.get_indices()] - return [d for d in datas if d is not None] + items = [i.data(TreeModel.ItemRole) for i in self.view.get_indices()] + return [item for item in items if item is not None] def right_mouse_menu(self, pos): """Build RMB menu for look view""" diff --git a/openpype/tools/project_manager/project_manager/model.py b/openpype/tools/project_manager/project_manager/model.py index 0c02872b4c..1c3ec089f6 100644 --- a/openpype/tools/project_manager/project_manager/model.py +++ b/openpype/tools/project_manager/project_manager/model.py @@ -124,12 +124,12 @@ class HierarchyModel(QtCore.QAbstractItemModel): Main part of ProjectManager. Model should be able to load existing entities, create new, handle their - validations like name duplication and validate if is possible to save it's + validations like name duplication and validate if is possible to save its data. Args: dbcon (AvalonMongoDB): Connection to MongoDB with set AVALON_PROJECT in - it's Session to current project. + its Session to current project. """ # Definition of all possible columns with their labels in default order @@ -799,7 +799,7 @@ class HierarchyModel(QtCore.QAbstractItemModel): for row in range(parent_item.rowCount()): child_item = parent_item.child(row) child_id = child_item.id - # Not sure if this can happend + # Not sure if this can happen # TODO validate this line it seems dangerous as start/end # row is not changed if child_id not in children: @@ -1902,7 +1902,7 @@ class AssetItem(BaseItem): return self._data["name"] def child_parents(self): - """Chilren AssetItem can use this method to get it's parent names. + """Children AssetItem can use this method to get it's parent names. This is used for `data.parents` key on document. """ @@ -2006,7 +2006,7 @@ class AssetItem(BaseItem): @classmethod def data_from_doc(cls, asset_doc): """Convert asset document from Mongo to item data.""" - # Minimum required data for cases that it is new AssetItem withoud doc + # Minimum required data for cases that it is new AssetItem without doc data = { "name": None, "type": "asset" @@ -2253,7 +2253,7 @@ class TaskItem(BaseItem): """Item representing Task item on Asset document. Always should be AssetItem children and never should have any other - childrens. + children. It's name value should be validated with it's parent which only knows if has same name as other sibling under same parent. diff --git a/openpype/tools/project_manager/project_manager/multiselection_combobox.py b/openpype/tools/project_manager/project_manager/multiselection_combobox.py index b26976d3c6..890567de6d 100644 --- a/openpype/tools/project_manager/project_manager/multiselection_combobox.py +++ b/openpype/tools/project_manager/project_manager/multiselection_combobox.py @@ -110,7 +110,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): elif event.type() == QtCore.QEvent.KeyPress: # TODO: handle QtCore.Qt.Key_Enter, Key_Return? if event.key() == QtCore.Qt.Key_Space: - # toogle the current items check state + # toggle the current items check state if ( index_flags & QtCore.Qt.ItemIsUserCheckable and index_flags & QtCore.Qt.ItemIsTristate diff --git a/openpype/tools/publisher/control.py b/openpype/tools/publisher/control.py index 860c009f15..3dd1bd6dc9 100644 --- a/openpype/tools/publisher/control.py +++ b/openpype/tools/publisher/control.py @@ -555,7 +555,7 @@ class PublisherController: self.create_context.reset_avalon_context() self._reset_plugins() - # Publish part must be resetted after plugins + # Publish part must be reset after plugins self._reset_publish() self._reset_instances() @@ -690,7 +690,7 @@ class PublisherController: def remove_instances(self, instances): """""" - # QUESTION Expect that instaces are really removed? In that case save + # QUESTION Expect that instances are really removed? In that case save # reset is not required and save changes too. self.save_changes() diff --git a/openpype/tools/publisher/widgets/border_label_widget.py b/openpype/tools/publisher/widgets/border_label_widget.py index 3d49af410a..696a9050b8 100644 --- a/openpype/tools/publisher/widgets/border_label_widget.py +++ b/openpype/tools/publisher/widgets/border_label_widget.py @@ -51,7 +51,7 @@ class _HBottomLineWidget(QtWidgets.QWidget): Corners may have curve set by radius (`set_radius`). Radius should expect height of widget. - Bottom line is drawed at the bottom of widget. If radius is 0 then height + Bottom line is drawn at the bottom of widget. If radius is 0 then height of widget should be 1px. It is expected that parent widget will set height and radius. @@ -94,7 +94,7 @@ class _HTopCornerLineWidget(QtWidgets.QWidget): or ```┌───────``` - Horizontal line is drawed in the middle of widget. + Horizontal line is drawn in the middle of widget. Widget represents left or right corner. Corner may have curve set by radius (`set_radius`). Radius should expect height of widget (maximum half @@ -225,7 +225,7 @@ class BorderedLabelWidget(QtWidgets.QFrame): self._radius = radius side_width = 1 + radius - # Dont't use fixed width/height as that would set also set + # Don't use fixed width/height as that would set also set # the other size (When fixed width is set then is also set # fixed height). self._left_w.setMinimumWidth(side_width) diff --git a/openpype/tools/publisher/widgets/card_view_widgets.py b/openpype/tools/publisher/widgets/card_view_widgets.py index 271d06e94c..ff0dfc95ab 100644 --- a/openpype/tools/publisher/widgets/card_view_widgets.py +++ b/openpype/tools/publisher/widgets/card_view_widgets.py @@ -388,7 +388,7 @@ class InstanceCardView(AbstractInstanceView): def sizeHint(self): """Modify sizeHint based on visibility of scroll bars.""" - # Calculate width hint by content widget and verticall scroll bar + # Calculate width hint by content widget and vertical scroll bar scroll_bar = self._scroll_area.verticalScrollBar() width = ( self._content_widget.sizeHint().width() diff --git a/openpype/tools/publisher/widgets/list_view_widgets.py b/openpype/tools/publisher/widgets/list_view_widgets.py index 4b2082e523..23a86cd070 100644 --- a/openpype/tools/publisher/widgets/list_view_widgets.py +++ b/openpype/tools/publisher/widgets/list_view_widgets.py @@ -6,7 +6,7 @@ attribute on instance (Group defined by creator). Each item can be enabled/disabled with their checkbox, whole group can be enabled/disabled with checkbox on group or selection can be enabled disabled using checkbox or keyboard key presses: -- Space - change state of selection to oposite +- Space - change state of selection to opposite - Enter - enable selection - Backspace - disable selection @@ -589,7 +589,7 @@ class InstanceListView(AbstractInstanceView): # - create new instance, update existing and remove not existing for group_name, group_item in self._group_items.items(): # Instance items to remove - # - will contain all exising instance ids at the start + # - will contain all existing instance ids at the start # - instance ids may be removed when existing instances are checked to_remove = set() # Mapping of existing instances under group item @@ -659,7 +659,7 @@ class InstanceListView(AbstractInstanceView): for instance_id in to_remove: idx_to_remove.append(existing_mapping[instance_id]) - # Remove them in reverse order to prevend row index changes + # Remove them in reverse order to prevent row index changes for idx in reversed(sorted(idx_to_remove)): group_item.removeRows(idx, 1) diff --git a/openpype/tools/publisher/widgets/validations_widget.py b/openpype/tools/publisher/widgets/validations_widget.py index 09e56d64cc..28b3c3f95d 100644 --- a/openpype/tools/publisher/widgets/validations_widget.py +++ b/openpype/tools/publisher/widgets/validations_widget.py @@ -276,7 +276,7 @@ class VerticallScrollArea(QtWidgets.QScrollArea): The biggest difference is that the scroll area has scroll bar on left side and resize of content will also resize scrollarea itself. - Resize if deffered by 100ms because at the moment of resize are not yet + Resize if deferred by 100ms because at the moment of resize are not yet propagated sizes and visibility of scroll bars. """ def __init__(self, *args, **kwargs): diff --git a/openpype/tools/publisher/widgets/widgets.py b/openpype/tools/publisher/widgets/widgets.py index 2ebcf73d4e..a85fea9cbc 100644 --- a/openpype/tools/publisher/widgets/widgets.py +++ b/openpype/tools/publisher/widgets/widgets.py @@ -749,7 +749,7 @@ class TasksCombobox(QtWidgets.QComboBox): self.value_changed.emit() def set_text(self, text): - """Set context shown in combobox without chaning selected items.""" + """Set context shown in combobox without changing selected items.""" if text == self._text: return @@ -1000,7 +1000,7 @@ class VariantInputWidget(PlaceholderLineEdit): self.value_changed.emit() def reset_to_origin(self): - """Set origin value of selected instnaces.""" + """Set origin value of selected instances.""" self.set_value(self._origin_value) def get_value(self): @@ -1105,7 +1105,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget): Subset name is or may be affected on context. Gives abiity to modify context and subset name of instance. This change is not autopromoted but - must be submited. + must be submitted. Warning: Until artist hit `Submit` changes must not be propagated to instance data. @@ -1179,7 +1179,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget): self.cancel_btn = cancel_btn def _on_submit(self): - """Commit changes for selected instnaces.""" + """Commit changes for selected instances.""" variant_value = None asset_name = None task_name = None @@ -1363,7 +1363,7 @@ class CreatorAttrsWidget(QtWidgets.QWidget): self._attr_def_id_to_instances = {} self._attr_def_id_to_attr_def = {} - # To store content of scroll area to prevend garbage collection + # To store content of scroll area to prevent garbage collection self._content_widget = None def set_instances_valid(self, valid): @@ -1375,7 +1375,7 @@ class CreatorAttrsWidget(QtWidgets.QWidget): self._content_widget.setEnabled(valid) def set_current_instances(self, instances): - """Set current instances for which are attribute definitons shown.""" + """Set current instances for which are attribute definitions shown.""" prev_content_widget = self._scroll_area.widget() if prev_content_widget: self._scroll_area.takeWidget() @@ -1461,7 +1461,7 @@ class PublishPluginAttrsWidget(QtWidgets.QWidget): self._attr_def_id_to_attr_def = {} self._attr_def_id_to_plugin_name = {} - # Store content of scroll area to prevend garbage collection + # Store content of scroll area to prevent garbage collection self._content_widget = None def set_instances_valid(self, valid): @@ -1473,7 +1473,7 @@ class PublishPluginAttrsWidget(QtWidgets.QWidget): self._content_widget.setEnabled(valid) def set_current_instances(self, instances, context_selected): - """Set current instances for which are attribute definitons shown.""" + """Set current instances for which are attribute definitions shown.""" prev_content_widget = self._scroll_area.widget() if prev_content_widget: self._scroll_area.takeWidget() diff --git a/openpype/tools/pyblish_pype/control.py b/openpype/tools/pyblish_pype/control.py index d2b74e316a..64a7f193b4 100644 --- a/openpype/tools/pyblish_pype/control.py +++ b/openpype/tools/pyblish_pype/control.py @@ -106,14 +106,14 @@ class Controller(QtCore.QObject): # ??? Emitted for each process was_processed = QtCore.Signal(dict) - # Emmited when reset + # Emitted when reset # - all data are reset (plugins, processing, pari yielder, etc.) was_reset = QtCore.Signal() - # Emmited when previous group changed + # Emitted when previous group changed passed_group = QtCore.Signal(object) - # Emmited when want to change state of instances + # Emitted when want to change state of instances switch_toggleability = QtCore.Signal(bool) # On action finished @@ -322,7 +322,7 @@ class Controller(QtCore.QObject): try: result = pyblish.plugin.process(plugin, self.context, instance) # Make note of the order at which the - # potential error error occured. + # potential error error occurred. if result["error"] is not None: self.processing["ordersWithError"].add(plugin.order) @@ -564,7 +564,7 @@ class Controller(QtCore.QObject): case must be taken to ensure there are no memory leaks. Explicitly deleting objects shines a light on where objects may still be referenced in the form of an error. No errors - means this was uneccesary, but that's ok. + means this was unnecessary, but that's ok. """ for instance in self.context: diff --git a/openpype/tools/pyblish_pype/util.py b/openpype/tools/pyblish_pype/util.py index 0d581f17af..d3d76b187c 100644 --- a/openpype/tools/pyblish_pype/util.py +++ b/openpype/tools/pyblish_pype/util.py @@ -218,7 +218,7 @@ class OrderGroups: def sort_groups(_groups_dict): sorted_dict = collections.OrderedDict() - # make sure wont affect any dictionary as pointer + # make sure won't affect any dictionary as pointer groups_dict = copy.deepcopy(_groups_dict) last_order = None if None in groups_dict: diff --git a/openpype/tools/sceneinventory/window.py b/openpype/tools/sceneinventory/window.py index e71af6a93d..e363a99d07 100644 --- a/openpype/tools/sceneinventory/window.py +++ b/openpype/tools/sceneinventory/window.py @@ -125,7 +125,7 @@ class SceneInventoryWindow(QtWidgets.QDialog): Override keyPressEvent to do nothing so that Maya's panels won't take focus when pressing "SHIFT" whilst mouse is over viewport or - outliner. This way users don't accidently perform Maya commands + outliner. This way users don't accidentally perform Maya commands whilst trying to name an instance. """ diff --git a/openpype/tools/settings/local_settings/constants.py b/openpype/tools/settings/local_settings/constants.py index 7a8774467f..1836c579af 100644 --- a/openpype/tools/settings/local_settings/constants.py +++ b/openpype/tools/settings/local_settings/constants.py @@ -5,7 +5,7 @@ LABEL_REMOVE_PROJECT = "Remove from project" LABEL_ADD_PROJECT = "Add to project" LABEL_DISCARD_CHANGES = "Discard changes" -# Local setting contants +# Local setting constants # TODO move to settings constants LOCAL_GENERAL_KEY = "general" LOCAL_PROJECTS_KEY = "projects" diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py index a00bc232f4..3fbf841ce7 100644 --- a/openpype/tools/settings/local_settings/window.py +++ b/openpype/tools/settings/local_settings/window.py @@ -222,7 +222,7 @@ class LocalSettingsWindow(QtWidgets.QWidget): # Do not create local settings widget in init phase as it's using # settings objects that must be OK to be able create this widget # - we want to show dialog if anything goes wrong - # - without reseting nothing is shown + # - without resetting nothing is shown self._settings_widget = None self._scroll_widget = scroll_widget self.reset_btn = reset_btn diff --git a/openpype/tools/settings/settings/README.md b/openpype/tools/settings/settings/README.md index 31d8fc5b74..1c916ddff2 100644 --- a/openpype/tools/settings/settings/README.md +++ b/openpype/tools/settings/settings/README.md @@ -10,7 +10,7 @@ - `"is_file"` - this key is for storing openpype defaults in `openpype` repo - reasons of existence: developing new schemas does not require to create defaults manually - key is validated, must be once in hierarchy else it won't be possible to store openpype defaults - - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides + - `"is_group"` - define that all values under key in hierarchy will be overridden if any value is modified, this information is also stored to overrides - this keys is not allowed for all inputs as they may have not reason for that - key is validated, can be only once in hierarchy but is not required - currently there are `system configurations` and `project configurations` @@ -199,7 +199,7 @@ - number input, can be used for both integer and float - key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`) - key `"minimum"` as minimum allowed number to enter (Default: `-99999`) - - key `"maxium"` as maximum allowed number to enter (Default: `99999`) + - key `"maximum"` as maximum allowed number to enter (Default: `99999`) ``` { "type": "number", diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 6a8d123617..3a173e85de 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -289,7 +289,7 @@ class BaseWidget(QtWidgets.QWidget): action = QtWidgets.QAction("Paste", menu) output.append((action, paste_value)) - # Paste value to matchin entity + # Paste value to matching entity def paste_value_to_path(): with self.category_widget.working_state_context(): _set_entity_value(matching_entity, value) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index 22f672da2b..161b8ca67e 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -477,7 +477,7 @@ class OpenPypeVersionText(TextWidget): self.entity.set(value) self.update_style() else: - # Manually trigger hierachical style update + # Manually trigger hierarchical style update self.ignore_input_changes.set_ignore(True) self.ignore_input_changes.set_ignore(False) @@ -675,7 +675,7 @@ class RawJsonWidget(InputWidget): self.entity.set(self.input_field.json_value()) self.update_style() else: - # Manually trigger hierachical style update + # Manually trigger hierarchical style update self.ignore_input_changes.set_ignore(True) self.ignore_input_changes.set_ignore(False) @@ -792,7 +792,7 @@ class PathWidget(BaseWidget): self.input_field.hierarchical_style_update() def _on_entity_change(self): - # No need to do anything. Styles will be updated from top hierachy. + # No need to do anything. Styles will be updated from top hierarchy. pass def update_style(self): diff --git a/openpype/tools/settings/settings/lib.py b/openpype/tools/settings/settings/lib.py index d12a14259a..eef157812f 100644 --- a/openpype/tools/settings/settings/lib.py +++ b/openpype/tools/settings/settings/lib.py @@ -7,7 +7,7 @@ VALUE_CHANGE_OFFSET_MS = 300 def create_deffered_value_change_timer(callback): - """Deffer value change callback. + """Defer value change callback. UI won't trigger all callbacks on each value change but after predefined time. Timer is reset on each start so callback is triggered after user diff --git a/openpype/tools/settings/settings/list_strict_widget.py b/openpype/tools/settings/settings/list_strict_widget.py index 046b6992f6..f0a3022a50 100644 --- a/openpype/tools/settings/settings/list_strict_widget.py +++ b/openpype/tools/settings/settings/list_strict_widget.py @@ -28,7 +28,7 @@ class ListStrictWidget(BaseWidget): break self._any_children_has_label = any_children_has_label - # Change column stretch factor for verticall alignment + # Change column stretch factor for vertical alignment if not self.entity.is_horizontal: col_index = 2 if any_children_has_label else 1 content_layout.setColumnStretch(col_index, 1) diff --git a/openpype/tools/settings/settings/multiselection_combobox.py b/openpype/tools/settings/settings/multiselection_combobox.py index 176f4cab8c..c2cc2a8fee 100644 --- a/openpype/tools/settings/settings/multiselection_combobox.py +++ b/openpype/tools/settings/settings/multiselection_combobox.py @@ -131,7 +131,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): elif event.type() == QtCore.QEvent.KeyPress: # TODO: handle QtCore.Qt.Key_Enter, Key_Return? if event.key() == QtCore.Qt.Key_Space: - # toogle the current items check state + # toggle the current items check state if ( index_flags & QtCore.Qt.ItemIsUserCheckable and index_flags & QtCore.Qt.ItemIsTristate diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index c376e5e91e..411e7b5e7f 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -153,7 +153,7 @@ class MainWidget(QtWidgets.QWidget): def _on_restart_required(self): # Don't show dialog if there are not registered slots for # `trigger_restart` signal. - # - For example when settings are runnin as standalone tool + # - For example when settings are running as standalone tool # - PySide2 and PyQt5 compatible way how to find out method_index = self.metaObject().indexOfMethod("trigger_restart()") method = self.metaObject().method(method_index) diff --git a/openpype/tools/standalonepublish/app.py b/openpype/tools/standalonepublish/app.py index 2ce757f773..3630d92c83 100644 --- a/openpype/tools/standalonepublish/app.py +++ b/openpype/tools/standalonepublish/app.py @@ -99,7 +99,7 @@ class Window(QtWidgets.QDialog): return self._db def on_start(self): - ''' Things must be done when initilized. + ''' Things must be done when initialized. ''' # Refresh asset input in Family widget self.on_asset_changed() diff --git a/openpype/tools/standalonepublish/widgets/model_asset.py b/openpype/tools/standalonepublish/widgets/model_asset.py index 44649b3dc3..60afe8f96c 100644 --- a/openpype/tools/standalonepublish/widgets/model_asset.py +++ b/openpype/tools/standalonepublish/widgets/model_asset.py @@ -68,7 +68,7 @@ class AssetModel(TreeModel): """ if silos: # WARNING: Silo item "_id" is set to silo value - # mainly because GUI issue with perserve selection and expanded row + # mainly because GUI issue with preserve selection and expanded row # and because of easier hierarchy parenting (in "assets") for silo in silos: node = Node({ diff --git a/openpype/tools/standalonepublish/widgets/widget_asset.py b/openpype/tools/standalonepublish/widgets/widget_asset.py index f4a4dfe0c4..2886d600bf 100644 --- a/openpype/tools/standalonepublish/widgets/widget_asset.py +++ b/openpype/tools/standalonepublish/widgets/widget_asset.py @@ -18,7 +18,7 @@ def preserve_expanded_rows(tree_view, This function is created to maintain the expand vs collapse status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. Arguments: tree_view (QWidgets.QTreeView): the tree view which is @@ -68,7 +68,7 @@ def preserve_selection(tree_view, This function is created to maintain the selection status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. tree_view (QWidgets.QTreeView): the tree view nested in the application column (int): the column to retrieve the data from @@ -390,7 +390,7 @@ class AssetWidget(QtWidgets.QWidget): assets, (tuple, list) ), "Assets must be list or tuple" - # convert to list - tuple cant be modified + # convert to list - tuple can't be modified assets = list(assets) # Clear selection diff --git a/openpype/tools/standalonepublish/widgets/widget_drop_frame.py b/openpype/tools/standalonepublish/widgets/widget_drop_frame.py index 7fe43c4203..c1c59d65b6 100644 --- a/openpype/tools/standalonepublish/widgets/widget_drop_frame.py +++ b/openpype/tools/standalonepublish/widgets/widget_drop_frame.py @@ -101,7 +101,7 @@ class DropDataFrame(QtWidgets.QFrame): return paths def _add_item(self, data, actions=[]): - # Assign to self so garbage collector wont remove the component + # Assign to self so garbage collector won't remove the component # during initialization new_component = ComponentItem(self.components_list, self) new_component.set_context(data) diff --git a/openpype/tools/standalonepublish/widgets/widget_family.py b/openpype/tools/standalonepublish/widgets/widget_family.py index 1e20028392..ae44899a89 100644 --- a/openpype/tools/standalonepublish/widgets/widget_family.py +++ b/openpype/tools/standalonepublish/widgets/widget_family.py @@ -373,7 +373,7 @@ class FamilyWidget(QtWidgets.QWidget): Override keyPressEvent to do nothing so that Maya's panels won't take focus when pressing "SHIFT" whilst mouse is over viewport or - outliner. This way users don't accidently perform Maya commands + outliner. This way users don't accidentally perform Maya commands whilst trying to name an instance. """ diff --git a/openpype/tools/tray/pype_info_widget.py b/openpype/tools/tray/pype_info_widget.py index e68793b18c..8414cefec8 100644 --- a/openpype/tools/tray/pype_info_widget.py +++ b/openpype/tools/tray/pype_info_widget.py @@ -433,7 +433,7 @@ class PypeInfoSubWidget(QtWidgets.QWidget): pype_info.pop("version_type", self.not_applicable) ) pype_info["version_value"] = version_value - # Prepare lable mapping + # Prepare label mapping key_label_mapping = { "version_value": "Running version:", "build_verison": "Build version:", diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index 99d431172a..9d4d0aa31b 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -238,7 +238,7 @@ class TrayManager: @property def doubleclick_callback(self): - """Doubleclick callback for Tray icon.""" + """Double-click callback for Tray icon.""" callback_name = self.modules_manager.doubleclick_callback return self.modules_manager.doubleclick_callbacks.get(callback_name) @@ -398,7 +398,7 @@ class TrayManager: title = "Settings miss default values" msg = ( "Your OpenPype will not work as expected! \n" - "Some default values in settigs are missing. \n\n" + "Some default values in settings are missing. \n\n" "Please contact OpenPype team." ) msg_box = QtWidgets.QMessageBox( @@ -430,7 +430,7 @@ class TrayManager: message (str): Content of message. icon (QSystemTrayIcon.MessageIcon): Message's icon. Default is Information icon, may differ by Qt version. - msecs (int): Duration of message visibility in miliseconds. + msecs (int): Duration of message visibility in milliseconds. Default is 10000 msecs, may differ by Qt version. """ args = [title, message] diff --git a/openpype/tools/tray_app/app.py b/openpype/tools/tray_app/app.py index f1363d0cab..0005c6fb94 100644 --- a/openpype/tools/tray_app/app.py +++ b/openpype/tools/tray_app/app.py @@ -268,7 +268,7 @@ class ConsoleTrayApp: def _multiple_replace(text, adict): """Replace multiple tokens defined in dict. - Find and replace all occurances of strings defined in dict is + Find and replace all occurrences of strings defined in dict is supplied string. Args: diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index 60c9e79829..a7ad8fef3b 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -1,6 +1,6 @@ """Single access point to all tools usable in hosts. -It is possible to create `HostToolsHelper` in host implementaion or +It is possible to create `HostToolsHelper` in host implementation or use singleton approach with global functions (using helper anyway). """ @@ -223,7 +223,7 @@ class HostToolsHelper: """Dialog of experimental tools. For some hosts it is not easy to modify menu of tools. For - those cases was addded experimental tools dialog which is Qt based + those cases was added experimental tools dialog which is Qt based and can dynamically filled by experimental tools so host need only single "Experimental tools" button to see them. @@ -347,7 +347,7 @@ class _SingletonPoint: return cls.helper.get_tool_by_name(tool_name, parent, *args, **kwargs) -# Function callbacks using singleton acces point +# Function callbacks using singleton access point def get_tool_by_name(tool_name, parent=None, *args, **kwargs): return _SingletonPoint.get_tool_by_name(tool_name, parent, *args, **kwargs) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index caaad522ad..84156fce0d 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -132,7 +132,7 @@ def preserve_expanded_rows(tree_view, column=0, role=None): This function is created to maintain the expand vs collapse status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. Arguments: tree_view (QWidgets.QTreeView): the tree view which is @@ -176,7 +176,7 @@ def preserve_selection(tree_view, column=0, role=None, current_index=True): This function is created to maintain the selection status of the model items. When refresh is triggered the items which are expanded - will stay expanded and vise versa. + will stay expanded and vice versa. tree_view (QWidgets.QTreeView): the tree view nested in the application column (int): the column to retrieve the data from @@ -372,7 +372,7 @@ class GroupsConfig: group_configs = [] project_name = self.dbcon.Session.get("AVALON_PROJECT") if project_name: - # Get pre-defined group name and apperance from project config + # Get pre-defined group name and appearance from project config project_doc = self.dbcon.find_one( {"type": "project"}, projection={"config.groups": True} diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index c32eae043e..e82bced927 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -152,7 +152,7 @@ class OptionalMenu(QtWidgets.QMenu): """A subclass of `QtWidgets.QMenu` to work with `OptionalAction` This menu has reimplemented `mouseReleaseEvent`, `mouseMoveEvent` and - `leaveEvent` to provide better action hightlighting and triggering for + `leaveEvent` to provide better action highlighting and triggering for actions that were instances of `QtWidgets.QWidgetAction`. """ diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index f4a86050cb..3167a082de 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -162,7 +162,7 @@ class NameWindow(QtWidgets.QDialog): # Build inputs inputs_layout = QtWidgets.QFormLayout(inputs_widget) - # Add version only if template contain version key + # Add version only if template contains version key # - since the version can be padded with "{version:0>4}" we only search # for "{version". if "{version" in self.template: @@ -170,7 +170,7 @@ class NameWindow(QtWidgets.QDialog): else: version_widget.setVisible(False) - # Add subversion only if template containt `{comment}` + # Add subversion only if template contains `{comment}` if "{comment}" in self.template: inputs_layout.addRow("Subversion:", subversion_input) else: @@ -183,7 +183,7 @@ class NameWindow(QtWidgets.QDialog): main_layout.addWidget(inputs_widget) main_layout.addWidget(btns_widget) - # Singal callback registration + # Signal callback registration version_input.valueChanged.connect(self.on_version_spinbox_changed) last_version_check.stateChanged.connect( self.on_version_checkbox_changed @@ -833,7 +833,7 @@ class SidePanelWidget(QtWidgets.QWidget): self.note_input.setEnabled(enabled) self.btn_note_save.setEnabled(enabled) - # Make sure workfile doc is overriden + # Make sure workfile doc is overridden self._workfile_doc = workfile_doc # Disable inputs and remove texts if any required arguments are missing if not enabled: @@ -978,7 +978,7 @@ class Window(QtWidgets.QMainWindow): Override keyPressEvent to do nothing so that Maya's panels won't take focus when pressing "SHIFT" whilst mouse is over viewport or - outliner. This way users don't accidently perform Maya commands + outliner. This way users don't accidentally perform Maya commands whilst trying to name an instance. """ From dab508c7ca1ae425e13ab7543cd5028e836b2553 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sun, 30 Jan 2022 22:17:17 +0100 Subject: [PATCH 31/38] Fix type name for 'representation' --- openpype/tools/sceneinventory/switch_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index 75e2b6be40..4946c073d4 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -558,7 +558,7 @@ class SwitchAssetDialog(QtWidgets.QDialog): repre_docs = io.find( { - "type": "rerpesentation", + "type": "representation", "parent": subset_doc["_id"], "name": {"$in": list(repre_names)} }, From f9209be51939a47c19d62600f5604780047acdb2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sun, 30 Jan 2022 23:05:17 +0100 Subject: [PATCH 32/38] Refactor `overriden` -> `overridden` + `hightlight` -> `highlight` --- .../publish/extract_subset_resources.py | 2 +- .../ftrack/ftrack_server/lib.py | 2 +- .../sync_server/providers/dropbox.py | 2 +- .../sync_server/providers/gdrive.py | 6 ++--- .../sync_server/providers/sftp.py | 4 ++-- .../sync_server/sync_server_module.py | 2 +- openpype/modules/interfaces.py | 2 +- .../job_queue/job_server/workers_rpc_route.py | 2 +- openpype/pipeline/publish/lib.py | 2 +- openpype/scripts/otio_burnin.py | 4 ++-- openpype/settings/constants.py | 6 ++--- openpype/settings/entities/base_entity.py | 4 ++-- .../settings/entities/dict_conditional.py | 14 +++++------ .../entities/dict_immutable_keys_entity.py | 14 +++++------ .../entities/dict_mutable_keys_entity.py | 2 +- openpype/settings/entities/lib.py | 2 +- openpype/settings/entities/schemas/README.md | 4 ++-- .../schemas/system_schema/example_schema.json | 8 +++---- openpype/settings/handlers.py | 20 ++++++++-------- openpype/settings/lib.py | 14 +++++------ openpype/style/data.json | 2 +- openpype/style/style.css | 24 +++++++++---------- openpype/tests/test_avalon_plugin_presets.py | 4 ++-- .../local_settings/projects_widget.py | 4 ++-- openpype/tools/settings/settings/README.md | 2 +- openpype/tools/settings/settings/base.py | 2 +- .../settings/settings/dict_conditional.py | 2 +- .../settings/settings/dict_mutable_widget.py | 6 ++--- .../tools/settings/settings/item_widgets.py | 2 +- openpype/tools/utils/widgets.py | 2 +- openpype/tools/workfiles/app.py | 2 +- 31 files changed, 84 insertions(+), 84 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 291e440cbe..d1222f2492 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -71,7 +71,7 @@ class ExtractSubsetResources(openpype.api.Extractor): staging_dir = self.staging_dir(instance) # add default preset type for thumbnail and reviewable video - # update them with settings and overide in case the same + # update them with settings and override in case the same # are found in there export_presets = deepcopy(self.default_presets) export_presets.update(self.export_presets_mapping) diff --git a/openpype/modules/default_modules/ftrack/ftrack_server/lib.py b/openpype/modules/default_modules/ftrack/ftrack_server/lib.py index e80d6a3a6b..f8319b67d4 100644 --- a/openpype/modules/default_modules/ftrack/ftrack_server/lib.py +++ b/openpype/modules/default_modules/ftrack/ftrack_server/lib.py @@ -164,7 +164,7 @@ class ProcessEventHub(SocketBaseEventHub): sys.exit(0) def wait(self, duration=None): - """Overriden wait + """Overridden wait Event are loaded from Mongo DB when queue is empty. Handled event is set as processed in Mongo DB. """ diff --git a/openpype/modules/default_modules/sync_server/providers/dropbox.py b/openpype/modules/default_modules/sync_server/providers/dropbox.py index 90d7d44bb8..6200b12bb2 100644 --- a/openpype/modules/default_modules/sync_server/providers/dropbox.py +++ b/openpype/modules/default_modules/sync_server/providers/dropbox.py @@ -95,7 +95,7 @@ class DropboxHandler(AbstractProvider): "key": "acting_as_member", "label": "Acting As Member" }, - # roots could be overriden only on Project level, User cannot + # roots could be overridden only on Project level, User cannot { "key": "root", "label": "Roots", diff --git a/openpype/modules/default_modules/sync_server/providers/gdrive.py b/openpype/modules/default_modules/sync_server/providers/gdrive.py index d43e2b3d61..0b586613b5 100644 --- a/openpype/modules/default_modules/sync_server/providers/gdrive.py +++ b/openpype/modules/default_modules/sync_server/providers/gdrive.py @@ -119,7 +119,7 @@ class GDriveHandler(AbstractProvider): # {platform} tells that value is multiplatform and only specific OS # should be returned editable = [ - # credentials could be overriden on Project or User level + # credentials could be overridden on Project or User level { "type": "path", "key": "credentials_url", @@ -127,7 +127,7 @@ class GDriveHandler(AbstractProvider): "multiplatform": True, "placeholder": "Credentials url" }, - # roots could be overriden only on Project leve, User cannot + # roots could be overridden only on Project level, User cannot { "key": "root", "label": "Roots", @@ -414,7 +414,7 @@ class GDriveHandler(AbstractProvider): def delete_folder(self, path, force=False): """ Deletes folder on GDrive. Checks if folder contains any files or - subfolders. In that case raises error, could be overriden by + subfolders. In that case raises error, could be overridden by 'force' argument. In that case deletes folder on 'path' and all its children. diff --git a/openpype/modules/default_modules/sync_server/providers/sftp.py b/openpype/modules/default_modules/sync_server/providers/sftp.py index 1585b326bd..49b87b14ec 100644 --- a/openpype/modules/default_modules/sync_server/providers/sftp.py +++ b/openpype/modules/default_modules/sync_server/providers/sftp.py @@ -97,7 +97,7 @@ class SFTPHandler(AbstractProvider): # {platform} tells that value is multiplatform and only specific OS # should be returned editable = [ - # credentials could be overriden on Project or User level + # credentials could be overridden on Project or User level { 'key': "sftp_host", 'label': "SFTP host name", @@ -129,7 +129,7 @@ class SFTPHandler(AbstractProvider): 'label': "SFTP user ssh key password", 'type': 'text' }, - # roots could be overriden only on Project leve, User cannot + # roots could be overridden only on Project level, User cannot { "key": "root", "label": "Roots", diff --git a/openpype/modules/default_modules/sync_server/sync_server_module.py b/openpype/modules/default_modules/sync_server/sync_server_module.py index 500203f3fc..caf58503f1 100644 --- a/openpype/modules/default_modules/sync_server/sync_server_module.py +++ b/openpype/modules/default_modules/sync_server/sync_server_module.py @@ -1073,7 +1073,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): """ Returns settings for 'studio' and user's local site - Returns base values from setting, not overriden by Local Settings, + Returns base values from setting, not overridden by Local Settings, eg. value used to push TO LS not to get actual value for syncing. """ if not project_name: diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index e6e84a0d42..7c301c15b4 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -115,7 +115,7 @@ class ITrayAction(ITrayModule): Add action to tray menu which will trigger `on_action_trigger`. It is expected to be used for showing tools. - Methods `tray_start`, `tray_exit` and `connect_with_modules` are overriden + Methods `tray_start`, `tray_exit` and `connect_with_modules` are overridden as it's not expected that action will use them. But it is possible if necessary. """ diff --git a/openpype/modules/job_queue/job_server/workers_rpc_route.py b/openpype/modules/job_queue/job_server/workers_rpc_route.py index 0800ca0d4d..e3c67fb3c3 100644 --- a/openpype/modules/job_queue/job_server/workers_rpc_route.py +++ b/openpype/modules/job_queue/job_server/workers_rpc_route.py @@ -72,7 +72,7 @@ class WorkerRpc(JsonRpc): self._job_queue.remove_worker(worker) async def handle_websocket_request(self, http_request): - """Overide this method to catch CLOSING messages.""" + """Override this method to catch CLOSING messages.""" http_request.msg_id = 0 http_request.pending = {} diff --git a/openpype/pipeline/publish/lib.py b/openpype/pipeline/publish/lib.py index 0fa712a301..d3e4ec8a02 100644 --- a/openpype/pipeline/publish/lib.py +++ b/openpype/pipeline/publish/lib.py @@ -31,7 +31,7 @@ class DiscoverResult: def publish_plugins_discover(paths=None): """Find and return available pyblish plug-ins - Overriden function from `pyblish` module to be able collect crashed files + Overridden function from `pyblish` module to be able collect crashed files and reason of their crash. Arguments: diff --git a/openpype/scripts/otio_burnin.py b/openpype/scripts/otio_burnin.py index 639657d68f..abf69645b7 100644 --- a/openpype/scripts/otio_burnin.py +++ b/openpype/scripts/otio_burnin.py @@ -252,7 +252,7 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins): - required IF start frame is not set when using frames or timecode burnins On initializing class can be set General options through "options_init" arg. - General can be overriden when adding burnin + General can be overridden when adding burnin ''' TOP_CENTERED = ffmpeg_burnins.TOP_CENTERED @@ -549,7 +549,7 @@ def burnins_from_data( codec_data (list): All codec related arguments in list. options (dict): Options for burnins. burnin_values (dict): Contain positioned values. - overwrite (bool): Output will be overriden if already exists, + overwrite (bool): Output will be overwritten if already exists, True by default. Presets must be set separately. Should be dict with 2 keys: diff --git a/openpype/settings/constants.py b/openpype/settings/constants.py index 2ea19ead4b..9fd0d5b417 100644 --- a/openpype/settings/constants.py +++ b/openpype/settings/constants.py @@ -2,14 +2,14 @@ import re # Metadata keys for work with studio and project overrides -M_OVERRIDEN_KEY = "__overriden_keys__" +M_OVERRIDDEN_KEY = "__overridden_keys__" # Metadata key for storing information about environments M_ENVIRONMENT_KEY = "__environment_keys__" # Metadata key for storing dynamic created labels M_DYNAMIC_KEY_LABEL = "__dynamic_keys_labels__" METADATA_KEYS = ( - M_OVERRIDEN_KEY, + M_OVERRIDDEN_KEY, M_ENVIRONMENT_KEY, M_DYNAMIC_KEY_LABEL ) @@ -32,7 +32,7 @@ KEY_REGEX = re.compile(r"^[{}]+$".format(KEY_ALLOWED_SYMBOLS)) __all__ = ( - "M_OVERRIDEN_KEY", + "M_OVERRIDDEN_KEY", "M_ENVIRONMENT_KEY", "M_DYNAMIC_KEY_LABEL", diff --git a/openpype/settings/entities/base_entity.py b/openpype/settings/entities/base_entity.py index 582937481a..b5bc44640b 100644 --- a/openpype/settings/entities/base_entity.py +++ b/openpype/settings/entities/base_entity.py @@ -752,7 +752,7 @@ class BaseItemEntity(BaseEntity): @abstractmethod def _add_to_project_override(self, on_change_trigger): - """Item's implementation to set values as overriden for project. + """Item's implementation to set values as overridden for project. Mark item and all it's children to be stored as project overrides. """ @@ -794,7 +794,7 @@ class BaseItemEntity(BaseEntity): """Item's implementation to remove project overrides. Mark item as does not have project overrides. Must not change - `was_overriden` attribute value. + `was_overridden` attribute value. Args: on_change_trigger (list): Callbacks of `on_change` should be stored diff --git a/openpype/settings/entities/dict_conditional.py b/openpype/settings/entities/dict_conditional.py index 92512a6668..963fd406ed 100644 --- a/openpype/settings/entities/dict_conditional.py +++ b/openpype/settings/entities/dict_conditional.py @@ -6,7 +6,7 @@ from .lib import ( ) from openpype.settings.constants import ( METADATA_KEYS, - M_OVERRIDEN_KEY, + M_OVERRIDDEN_KEY, KEY_REGEX ) from . import ( @@ -119,7 +119,7 @@ class DictConditionalEntity(ItemEntity): # `current_metadata` are still when schema is loaded # - only metadata stored with dict item are gorup overrides in - # M_OVERRIDEN_KEY + # M_OVERRIDDEN_KEY self._current_metadata = {} self._metadata_are_modified = False @@ -377,9 +377,9 @@ class DictConditionalEntity(ItemEntity): ): continue - if M_OVERRIDEN_KEY not in current_metadata: - current_metadata[M_OVERRIDEN_KEY] = [] - current_metadata[M_OVERRIDEN_KEY].append(key) + if M_OVERRIDDEN_KEY not in current_metadata: + current_metadata[M_OVERRIDDEN_KEY] = [] + current_metadata[M_OVERRIDDEN_KEY].append(key) # Define if current metadata are avaialble for current override state metadata = NOT_SET @@ -535,7 +535,7 @@ class DictConditionalEntity(ItemEntity): enum_value = value.get(self.enum_key) - old_metadata = metadata.get(M_OVERRIDEN_KEY) + old_metadata = metadata.get(M_OVERRIDDEN_KEY) if old_metadata: old_metadata_set = set(old_metadata) new_metadata = [] @@ -547,7 +547,7 @@ class DictConditionalEntity(ItemEntity): for key in old_metadata_set: new_metadata.append(key) - metadata[M_OVERRIDEN_KEY] = new_metadata + metadata[M_OVERRIDDEN_KEY] = new_metadata return value, metadata diff --git a/openpype/settings/entities/dict_immutable_keys_entity.py b/openpype/settings/entities/dict_immutable_keys_entity.py index c477a0eb0f..060f8d522e 100644 --- a/openpype/settings/entities/dict_immutable_keys_entity.py +++ b/openpype/settings/entities/dict_immutable_keys_entity.py @@ -9,7 +9,7 @@ from .lib import ( ) from openpype.settings.constants import ( METADATA_KEYS, - M_OVERRIDEN_KEY, + M_OVERRIDDEN_KEY, KEY_REGEX ) from . import ( @@ -183,7 +183,7 @@ class DictImmutableKeysEntity(ItemEntity): # `current_metadata` are still when schema is loaded # - only metadata stored with dict item are gorup overrides in - # M_OVERRIDEN_KEY + # M_OVERRIDDEN_KEY self._current_metadata = {} self._metadata_are_modified = False @@ -257,9 +257,9 @@ class DictImmutableKeysEntity(ItemEntity): ): continue - if M_OVERRIDEN_KEY not in current_metadata: - current_metadata[M_OVERRIDEN_KEY] = [] - current_metadata[M_OVERRIDEN_KEY].append(key) + if M_OVERRIDDEN_KEY not in current_metadata: + current_metadata[M_OVERRIDDEN_KEY] = [] + current_metadata[M_OVERRIDDEN_KEY].append(key) # Define if current metadata are avaialble for current override state metadata = NOT_SET @@ -399,7 +399,7 @@ class DictImmutableKeysEntity(ItemEntity): if key in value: metadata[key] = value.pop(key) - old_metadata = metadata.get(M_OVERRIDEN_KEY) + old_metadata = metadata.get(M_OVERRIDDEN_KEY) if old_metadata: old_metadata_set = set(old_metadata) new_metadata = [] @@ -410,7 +410,7 @@ class DictImmutableKeysEntity(ItemEntity): for key in old_metadata_set: new_metadata.append(key) - metadata[M_OVERRIDEN_KEY] = new_metadata + metadata[M_OVERRIDDEN_KEY] = new_metadata return value, metadata diff --git a/openpype/settings/entities/dict_mutable_keys_entity.py b/openpype/settings/entities/dict_mutable_keys_entity.py index 08b0f75649..6b9c0bc7ed 100644 --- a/openpype/settings/entities/dict_mutable_keys_entity.py +++ b/openpype/settings/entities/dict_mutable_keys_entity.py @@ -222,7 +222,7 @@ class DictMutableKeysEntity(EndpointEntity): self.required_keys = self.schema_data.get("required_keys") or [] self.collapsible_key = self.schema_data.get("collapsible_key") or False # GUI attributes - self.hightlight_content = ( + self.highlight_content = ( self.schema_data.get("highlight_content") or False ) diff --git a/openpype/settings/entities/lib.py b/openpype/settings/entities/lib.py index bf3868c08d..1c7dc9bed0 100644 --- a/openpype/settings/entities/lib.py +++ b/openpype/settings/entities/lib.py @@ -101,7 +101,7 @@ class OverrideState: - DEFAULTS - Entity cares only about default values. It is not possible to set higher state if any entity does not have filled default value. - - STUDIO - First layer of overrides. Hold only studio overriden values + - STUDIO - First layer of overrides. Hold only studio overridden values that are applied on top of defaults. - PROJECT - Second layer of overrides. Hold only project overrides that are applied on top of defaults and studio overrides. diff --git a/openpype/settings/entities/schemas/README.md b/openpype/settings/entities/schemas/README.md index 4e8dcc36ce..dd7601c017 100644 --- a/openpype/settings/entities/schemas/README.md +++ b/openpype/settings/entities/schemas/README.md @@ -10,7 +10,7 @@ - `"is_file"` - this key is for storing openpype defaults in `openpype` repo - reasons of existence: developing new schemas does not require to create defaults manually - key is validated, must be once in hierarchy else it won't be possible to store openpype defaults - - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides + - `"is_group"` - define that all values under key in hierarchy will be overridden if any value is modified, this information is also stored to overrides - this keys is not allowed for all inputs as they may have not reason for that - key is validated, can be only once in hierarchy but is not required - currently there are `system settings` and `project settings` @@ -767,7 +767,7 @@ Anatomy represents data stored on project document. ### anatomy - entity works similarly to `dict` -- anatomy has always all keys overriden with overrides +- anatomy has always all keys overridden with overrides - overrides are not applied as all anatomy data must be available from project document - all children must be groups diff --git a/openpype/settings/entities/schemas/system_schema/example_schema.json b/openpype/settings/entities/schemas/system_schema/example_schema.json index c30e1f6848..6a86dae259 100644 --- a/openpype/settings/entities/schemas/system_schema/example_schema.json +++ b/openpype/settings/entities/schemas/system_schema/example_schema.json @@ -11,13 +11,13 @@ }, { "type": "dict-conditional", - "key": "overriden_value", - "label": "Overriden value", - "enum_key": "overriden", + "key": "overridden_value", + "label": "Overridden value", + "enum_key": "overridden", "enum_is_horizontal": true, "enum_children": [ { - "key": "overriden", + "key": "overridden", "label": "Override value", "children": [ { diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 51e390bb6d..af05bbf413 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -13,7 +13,7 @@ from .constants import ( PROJECT_SETTINGS_KEY, PROJECT_ANATOMY_KEY, LOCAL_SETTING_KEY, - M_OVERRIDEN_KEY + M_OVERRIDDEN_KEY ) from .lib import load_json_file @@ -254,12 +254,12 @@ class MongoSettingsHandler(SettingsHandler): continue # Pop key from values output[key] = general_data.pop(key) - # Pop key from overriden metadata + # Pop key from overridden metadata if ( - M_OVERRIDEN_KEY in general_data - and key in general_data[M_OVERRIDEN_KEY] + M_OVERRIDDEN_KEY in general_data + and key in general_data[M_OVERRIDDEN_KEY] ): - general_data[M_OVERRIDEN_KEY].remove(key) + general_data[M_OVERRIDDEN_KEY].remove(key) return output def _apply_global_settings( @@ -319,17 +319,17 @@ class MongoSettingsHandler(SettingsHandler): system_general = {} system_settings_data["general"] = system_general - overriden_keys = system_general.get(M_OVERRIDEN_KEY) or [] + overridden_keys = system_general.get(M_OVERRIDDEN_KEY) or [] for key in self.global_general_keys: if key not in globals_data: continue system_general[key] = globals_data[key] - if key not in overriden_keys: - overriden_keys.append(key) + if key not in overridden_keys: + overridden_keys.append(key) - if overriden_keys: - system_general[M_OVERRIDEN_KEY] = overriden_keys + if overridden_keys: + system_general[M_OVERRIDDEN_KEY] = overridden_keys return system_settings_document diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 43489aecfd..1b5682536a 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -8,7 +8,7 @@ from .exceptions import ( SaveWarningExc ) from .constants import ( - M_OVERRIDEN_KEY, + M_OVERRIDDEN_KEY, M_ENVIRONMENT_KEY, METADATA_KEYS, @@ -546,13 +546,13 @@ def subkey_merge(_dict, value, keys): def merge_overrides(source_dict, override_dict): """Merge data from override_dict to source_dict.""" - if M_OVERRIDEN_KEY in override_dict: - overriden_keys = set(override_dict.pop(M_OVERRIDEN_KEY)) + if M_OVERRIDDEN_KEY in override_dict: + overridden_keys = set(override_dict.pop(M_OVERRIDDEN_KEY)) else: - overriden_keys = set() + overridden_keys = set() for key, value in override_dict.items(): - if (key in overriden_keys or key not in source_dict): + if (key in overridden_keys or key not in source_dict): source_dict[key] = value elif isinstance(value, dict) and isinstance(source_dict[key], dict): @@ -574,7 +574,7 @@ def apply_local_settings_on_system_settings(system_settings, local_settings): """Apply local settings on studio system settings. ATM local settings can modify only application executables. Executable - values are not overriden but prepended. + values are not overridden but prepended. """ if not local_settings or "applications" not in local_settings: return @@ -914,7 +914,7 @@ def get_environments(): """Calculated environment based on defaults and system settings. Any default environment also found in the system settings will be fully - overriden by the one from the system settings. + overridden by the one from the system settings. Returns: dict: Output should be ready for `acre` module. diff --git a/openpype/style/data.json b/openpype/style/data.json index 1db0c732cf..e65690378d 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -112,7 +112,7 @@ "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", - "content-hightlighted": "rgba(19, 26, 32, 15)", + "content-highlighted": "rgba(19, 26, 32, 15)", "focus-border": "#839caf", "image-btn": "#bfccd6", "image-btn-hover": "#189aea", diff --git a/openpype/style/style.css b/openpype/style/style.css index d9b0ff7421..03b7b522f9 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1093,16 +1093,16 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #ExpandLabel[state="modified"]:hover, #SettingsLabel[state="modified"]:hover { color: {color:settings:modified-light}; } -#ExpandLabel[state="overriden-modified"], #SettingsLabel[state="overriden-modified"] { +#ExpandLabel[state="overridden-modified"], #SettingsLabel[state="overridden-modified"] { color: {color:settings:modified-mid}; } -#ExpandLabel[state="overriden-modified"]:hover, #SettingsLabel[state="overriden-modified"]:hover { +#ExpandLabel[state="overridden-modified"]:hover, #SettingsLabel[state="overridden-modified"]:hover { color: {color:settings:modified-light}; } -#ExpandLabel[state="overriden"], #SettingsLabel[state="overriden"] { +#ExpandLabel[state="overridden"], #SettingsLabel[state="overridden"] { color: {color:settings:project-mid}; } -#ExpandLabel[state="overriden"]:hover, #SettingsLabel[state="overriden"]:hover { +#ExpandLabel[state="overridden"]:hover, #SettingsLabel[state="overridden"]:hover { color: {color:settings:project-light}; } #ExpandLabel[state="invalid"], #SettingsLabel[state="invalid"] { @@ -1116,10 +1116,10 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsMainWidget QWidget[input-state="modified"] { border-color: {color:settings:modified-mid}; } -#SettingsMainWidget QWidget[input-state="overriden-modified"] { +#SettingsMainWidget QWidget[input-state="overridden-modified"] { border-color: {color:settings:modified-mid}; } -#SettingsMainWidget QWidget[input-state="overriden"] { +#SettingsMainWidget QWidget[input-state="overridden"] { border-color: {color:settings:project-mid}; } #SettingsMainWidget QWidget[input-state="invalid"] { @@ -1145,8 +1145,8 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #ContentWidget { background-color: transparent; } -#ContentWidget[content_state="hightlighted"] { - background-color: {color:settings:content-hightlighted}; +#ContentWidget[content_state="highlighted"] { + background-color: {color:settings:content-highlighted}; } #SideLineWidget { @@ -1172,11 +1172,11 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SideLineWidget[state="child-invalid"] {border-color: {color:settings:invalid-dark};} #SideLineWidget[state="child-invalid"]:hover {border-color: {color:settings:invalid-light};} -#SideLineWidget[state="child-overriden"] {border-color: {color:settings:project-dark};} -#SideLineWidget[state="child-overriden"]:hover {border-color: {color:settings:project-mid};} +#SideLineWidget[state="child-overridden"] {border-color: {color:settings:project-dark};} +#SideLineWidget[state="child-overridden"]:hover {border-color: {color:settings:project-mid};} -#SideLineWidget[state="child-overriden-modified"] {border-color: {color:settings:modified-dark};} -#SideLineWidget[state="child-overriden-modified"]:hover {border-color: {color:settings:modified-mid};} +#SideLineWidget[state="child-overridden-modified"] {border-color: {color:settings:modified-dark};} +#SideLineWidget[state="child-overridden-modified"]:hover {border-color: {color:settings:modified-mid};} #DictAsWidgetBody { background: transparent; diff --git a/openpype/tests/test_avalon_plugin_presets.py b/openpype/tests/test_avalon_plugin_presets.py index cc1858554c..ec21385d23 100644 --- a/openpype/tests/test_avalon_plugin_presets.py +++ b/openpype/tests/test_avalon_plugin_presets.py @@ -32,9 +32,9 @@ def test_avalon_plugin_presets(monkeypatch, printer): assert MyTestCreator in plugins for p in plugins: if p.__name__ == "MyTestCreator": - printer("Test if we have overriden existing property") + printer("Test if we have overridden existing property") assert p.my_test_property == "B" - printer("Test if we have overriden superclass property") + printer("Test if we have overridden superclass property") assert p.active is False printer("Test if we have added new property") assert p.new_property == "new" diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index da45467a4e..30a0d212f0 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -126,7 +126,7 @@ class DynamicInputItem(QtCore.QObject): return "studio" else: if current_value: - return "overriden" + return "overridden" if self.value_item.default_value: return "studio" @@ -512,7 +512,7 @@ class _SiteCombobox(QtWidgets.QWidget): return "studio" else: if current_value: - return "overriden" + return "overridden" studio_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY) if studio_value: diff --git a/openpype/tools/settings/settings/README.md b/openpype/tools/settings/settings/README.md index 31d8fc5b74..197f7a001a 100644 --- a/openpype/tools/settings/settings/README.md +++ b/openpype/tools/settings/settings/README.md @@ -10,7 +10,7 @@ - `"is_file"` - this key is for storing openpype defaults in `openpype` repo - reasons of existence: developing new schemas does not require to create defaults manually - key is validated, must be once in hierarchy else it won't be possible to store openpype defaults - - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides + - `"is_group"` - define that all values under key in hierarchy will be overridden if any value is modified, this information is also stored to overrides - this keys is not allowed for all inputs as they may have not reason for that - key is validated, can be only once in hierarchy but is not required - currently there are `system configurations` and `project configurations` diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index e271585852..c7b76add90 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -93,7 +93,7 @@ class BaseWidget(QtWidgets.QWidget): if is_modified: return "modified" if has_project_override: - return "overriden" + return "overridden" if has_studio_override: return "studio" return "" diff --git a/openpype/tools/settings/settings/dict_conditional.py b/openpype/tools/settings/settings/dict_conditional.py index 2e1617f505..b2a7bb52a2 100644 --- a/openpype/tools/settings/settings/dict_conditional.py +++ b/openpype/tools/settings/settings/dict_conditional.py @@ -183,7 +183,7 @@ class DictConditionalWidget(BaseWidget): content_widget.setObjectName("ContentWidget") if self.entity.highlight_content: - content_state = "hightlighted" + content_state = "highlighted" bottom_margin = 5 else: content_state = "" diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index 294711b38a..6489266131 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -354,7 +354,7 @@ class ModifiableDictItem(QtWidgets.QWidget): if self.entity.has_unsaved_changes: return "modified" if self.entity.has_project_override: - return "overriden" + return "overridden" if self.entity.has_studio_override: return "studio" return "" @@ -600,8 +600,8 @@ class DictMutableKeysWidget(BaseWidget): self.input_fields = [] self.required_inputs_by_key = {} - if self.entity.hightlight_content: - content_state = "hightlighted" + if self.entity.highlight_content: + content_state = "highlighted" bottom_margin = 5 else: content_state = "" diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index 22f672da2b..a8f5706d48 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -150,7 +150,7 @@ class DictImmutableKeysWidget(BaseWidget): content_widget.setObjectName("ContentWidget") if self.entity.highlight_content: - content_state = "hightlighted" + content_state = "highlighted" bottom_margin = 5 else: content_state = "" diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index c32eae043e..e82bced927 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -152,7 +152,7 @@ class OptionalMenu(QtWidgets.QMenu): """A subclass of `QtWidgets.QMenu` to work with `OptionalAction` This menu has reimplemented `mouseReleaseEvent`, `mouseMoveEvent` and - `leaveEvent` to provide better action hightlighting and triggering for + `leaveEvent` to provide better action highlighting and triggering for actions that were instances of `QtWidgets.QWidgetAction`. """ diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index f4a86050cb..e389ac620a 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -833,7 +833,7 @@ class SidePanelWidget(QtWidgets.QWidget): self.note_input.setEnabled(enabled) self.btn_note_save.setEnabled(enabled) - # Make sure workfile doc is overriden + # Make sure workfile doc is overridden self._workfile_doc = workfile_doc # Disable inputs and remove texts if any required arguments are missing if not enabled: From 69bfcd6a305f976b3f4ee5f3f36c9e1ed2acbadb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 31 Jan 2022 10:45:18 +0100 Subject: [PATCH 33/38] Update openpype/plugins/publish/collect_scene_version.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/collect_scene_version.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/publish/collect_scene_version.py b/openpype/plugins/publish/collect_scene_version.py index 56a6e3fb46..a81e85c1f5 100644 --- a/openpype/plugins/publish/collect_scene_version.py +++ b/openpype/plugins/publish/collect_scene_version.py @@ -35,9 +35,10 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): def process(self, context): # tests should be close to regular publish as possible - if (context.data["hostName"] in self.skip_hosts_headless_publish - and os.environ.get("HEADLESS_PUBLISH") - and not os.environ.get("IS_TEST")): + if ( + os.environ.get("HEADLESS_PUBLISH") + and not os.environ.get("IS_TEST") + and context.data["hostName"] in self.skip_hosts_headless_publish): self.log.debug("Skipping for headless publishing") return From 336585bbc92001ae3d942cfd3092839a095195c0 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 31 Jan 2022 10:48:11 +0100 Subject: [PATCH 34/38] Update openpype/plugins/publish/collect_scene_version.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/collect_scene_version.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/plugins/publish/collect_scene_version.py b/openpype/plugins/publish/collect_scene_version.py index a81e85c1f5..917647c61a 100644 --- a/openpype/plugins/publish/collect_scene_version.py +++ b/openpype/plugins/publish/collect_scene_version.py @@ -29,9 +29,7 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): # in some cases of headless publishing (for example webpublisher using PS) # you want to ignore version from name and let integrate use next version - skip_hosts_headless_publish = [ - - ] + skip_hosts_headless_publish = [] def process(self, context): # tests should be close to regular publish as possible From f97a9a9bb45c81d60d98f02446d3a9fecebb450b Mon Sep 17 00:00:00 2001 From: murphy Date: Mon, 31 Jan 2022 11:33:59 +0100 Subject: [PATCH 35/38] few typos fixed --- website/docs/artist_concepts.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index 6046ba6214..4d195e9220 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -26,7 +26,7 @@ Each published variant can come out of the software in multiple representations. ### Family -Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joins when it is published. +Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. [3b89d8e0]: #subset "subset" @@ -40,7 +40,7 @@ General term for Software or Application supported by OpenPype and Avalon. These ### Tool -Small piece of software usually dedicated to a particular purpose. Most of OpenPype and Avalon tools have GUI, but some are command line only +Small piece of software usually dedicated to a particular purpose. Most of OpenPype and Avalon tools have GUI, but some are command line only. ### Publish @@ -50,4 +50,4 @@ Process of exporting data from your work scene to versioned, immutable file that ### Load Process of importing previously published subsets into your current scene, using any of the OpenPype tools. -Loading asset using proper tools will ensure that all your scene content stays version controlled and updatable at a later point +Loading asset using proper tools will ensure that all your scene content stays version controlled and updatable at a later point. From bdfdc38b7284c56cbb5089f0b0f8c364b5a79daa Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 31 Jan 2022 14:28:27 +0100 Subject: [PATCH 36/38] Make sure current value in enum match with valid keys --- .../defaults/project_settings/photoshop.json | 2 +- openpype/settings/entities/enum_entity.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/photoshop.json b/openpype/settings/defaults/project_settings/photoshop.json index db9bf87268..31cd815dd8 100644 --- a/openpype/settings/defaults/project_settings/photoshop.json +++ b/openpype/settings/defaults/project_settings/photoshop.json @@ -12,7 +12,7 @@ { "color_code": [], "layer_name_regex": [], - "family": "", + "family": "image", "subset_template_name": "" } ] diff --git a/openpype/settings/entities/enum_entity.py b/openpype/settings/entities/enum_entity.py index fb6099e82a..0fcd8f3002 100644 --- a/openpype/settings/entities/enum_entity.py +++ b/openpype/settings/entities/enum_entity.py @@ -121,6 +121,20 @@ class EnumEntity(BaseEnumEntity): ) super(EnumEntity, self).schema_validations() + def set_override_state(self, *args, **kwargs): + super(EnumEntity, self).set_override_state(*args, **kwargs) + + # Make sure current value is valid + if self.multiselection: + new_value = [] + for key in self._current_value: + if key in self.valid_keys: + new_value.append(key) + self._current_value = new_value + + elif self._current_value not in self.valid_keys: + self._current_value = self.value_on_not_set + class HostsEnumEntity(BaseEnumEntity): """Enumeration of host names. From ec3b535f760c4e7bcae528776c449e8726327755 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 31 Jan 2022 23:08:41 +0100 Subject: [PATCH 37/38] Revert string value for M_OVERRIDDEN_KEY for backwards compatibility Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/settings/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/constants.py b/openpype/settings/constants.py index 9fd0d5b417..8cc991c999 100644 --- a/openpype/settings/constants.py +++ b/openpype/settings/constants.py @@ -2,7 +2,7 @@ import re # Metadata keys for work with studio and project overrides -M_OVERRIDDEN_KEY = "__overridden_keys__" +M_OVERRIDDEN_KEY = "__overriden_keys__" # Metadata key for storing information about environments M_ENVIRONMENT_KEY = "__environment_keys__" # Metadata key for storing dynamic created labels From 304d85510314636516b7a26e32e2ee4d2264cb19 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 1 Feb 2022 10:57:15 +0100 Subject: [PATCH 38/38] add extension on windows --- openpype/lib/vendor_bin_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/lib/vendor_bin_utils.py b/openpype/lib/vendor_bin_utils.py index a5d4153b2a..4c2cf93dfa 100644 --- a/openpype/lib/vendor_bin_utils.py +++ b/openpype/lib/vendor_bin_utils.py @@ -34,11 +34,17 @@ def get_vendor_bin_path(bin_app): def get_oiio_tools_path(tool="oiiotool"): """Path to vendorized OpenImageIO tool executables. + On Window it adds .exe extension if missing from tool argument. + Args: tool (string): Tool name (oiiotool, maketx, ...). Default is "oiiotool". """ oiio_dir = get_vendor_bin_path("oiio") + if platform.system().lower() == "windows" and not tool.lower().endswith( + ".exe" + ): + tool = "{}.exe".format(tool) return os.path.join(oiio_dir, tool)