From 4d142ab6289f7fafc3e6ca8d43110998eb00dab6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:48:49 +0200 Subject: [PATCH 01/15] fill extension in template data --- client/ayon_core/pipeline/workfile/utils.py | 51 ++++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index 77c1953e4d..d5c717bd6d 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -411,8 +411,8 @@ def save_next_version( ) -> None: """Save workfile using current context, version and comment. - Helper function to save workfile using current context. Last workfile - version + 1 is used if is not passed in. + Helper function to save a workfile using the current context. Last + workfile version + 1 is used if is not passed in. Args: version (Optional[int]): Workfile version that will be used. Last @@ -480,10 +480,8 @@ def save_next_version( project_settings=project_settings, ) rootless_dir = workdir.rootless + last_workfile = None if version is None: - workfile_extensions = host.get_workfile_extensions() - if not workfile_extensions: - raise ValueError("Host does not have defined file extensions") workfiles = host.list_workfiles( project_name, folder_entity, task_entity, prepared_data=ListWorkfilesOptionalData( @@ -493,14 +491,18 @@ def save_next_version( template_key=template_key, ) ) - versions = { - workfile.version - for workfile in workfiles - if workfile.version is not None - } + for workfile in workfiles: + if workfile.version is None: + continue + if ( + last_workfile is None + or last_workfile.version < workfile.version + ): + last_workfile = workfile + version = None - if versions: - version = max(versions) + 1 + if last_workfile is not None: + version = last_workfile.version + 1 if version is None: version = get_versioning_start( @@ -514,6 +516,26 @@ def save_next_version( template_data["version"] = version template_data["comment"] = comment + # Resolve extension + # - Don't fill any if the host does not have defined any -> e.g. if host + # uses directory instead of a file. + # 1. Use the current file extension. + # 2. Use the last known workfile extension. + # 3. Use the first extensions from 'get_workfile_extensions'. + ext = None + workfile_extensions = host.get_workfile_extensions() + if workfile_extensions: + current_path = host.get_current_workfile() + if current_path: + ext = os.path.splitext(current_path)[1].lstrip(".") + elif last_workfile is not None: + ext = os.path.splitext(last_workfile.filepath)[1].lstrip(".") + else: + ext = next(iter(workfile_extensions), None) + + if ext: + template_data["ext"] = ext + filename = file_template.format_strict(template_data) workfile_path = os.path.join(workdir, filename) rootless_path = f"{rootless_dir}/{filename}" @@ -632,6 +654,11 @@ def copy_workfile_to_context( if comment: template_data["comment"] = comment + workfile_extensions = host.get_workfile_extensions() + if workfile_extensions: + ext = os.path.splitext(src_workfile_path)[1].lstrip(".") + template_data["ext"] = ext + workfile_template = anatomy.get_template_item( "work", template_key, "path" ) From 94b96345552beaccf6a16530d7a8b89f9035235d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:25:55 +0200 Subject: [PATCH 02/15] Fix logged warnings --- .../plugins/publish/collect_scene_loaded_versions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index 1abb8e29d2..c8d9747091 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -27,12 +27,13 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): def process(self, context): host = registered_host() if host is None: - self.log.warn("No registered host.") + self.log.warning("No registered host.") return if not hasattr(host, "ls"): host_name = host.__name__ - self.log.warn("Host %r doesn't have ls() implemented." % host_name) + self.log.warning( + f"Host {host_name} doesn't have ls() implemented.") return loaded_versions = [] From f0ea841ebf339a14940792d268e46918c2c60a3c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:29:23 +0200 Subject: [PATCH 03/15] Use `ILoadHost.get_containers()` when available --- .../publish/collect_scene_loaded_versions.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index c8d9747091..34d3e5b136 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -1,7 +1,9 @@ import ayon_api import ayon_api.utils +from ayon_core.host import ILoadHost from ayon_core.pipeline import registered_host + import pyblish.api @@ -30,14 +32,19 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): self.log.warning("No registered host.") return - if not hasattr(host, "ls"): + if isinstance(host, ILoadHost): + containers = list(host.get_containers()) + elif hasattr(host, "ls"): + # Backwards compatibility for legacy host implementations + containers = list(host.ls()) + else: host_name = host.__name__ self.log.warning( - f"Host {host_name} doesn't have ls() implemented.") + f"Host {host_name} does not implement ILoadHost " + f"nor does it have ls() implemented. Skipping querying of " + f"loaded versions in scene.") return - loaded_versions = [] - containers = list(host.ls()) repre_ids = { container["representation"] for container in containers @@ -62,6 +69,7 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): # QUESTION should we add same representation id when loaded multiple # times? + loaded_versions = [] for con in containers: repre_id = con["representation"] repre_entity = repre_entities_by_id.get(repre_id) From 5a44efd2ad60cbd380c706217f896106958afb1c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:31:29 +0200 Subject: [PATCH 04/15] Opt-out early if there are no containers in the scene file --- .../plugins/publish/collect_scene_loaded_versions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index 34d3e5b136..e3e938b65b 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -45,6 +45,11 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): f"loaded versions in scene.") return + if not containers: + # Opt out early if there are no containers + self.log.debug("No loaded containers found in scene.") + return + repre_ids = { container["representation"] for container in containers From 8b8cff8ea5036e7a49e3b61e036f7beec35642fb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:32:48 +0200 Subject: [PATCH 05/15] Add debug log --- .../ayon_core/plugins/publish/collect_scene_loaded_versions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index e3e938b65b..ea949eb087 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -94,4 +94,5 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): } loaded_versions.append(version) + self.log.debug(f"Collected {len(loaded_versions)} loaded versions.") context.data["loadedVersions"] = loaded_versions From 6def9655f07f8c1dcb80d38a1cb52ff617f03e2e Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:39:08 +0200 Subject: [PATCH 06/15] Do not use deprecated `Logger.warn`, use `Logger.warning` instead --- client/ayon_core/plugins/publish/integrate_inputlinks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/integrate_inputlinks.py b/client/ayon_core/plugins/publish/integrate_inputlinks.py index a3b6a228d6..be399a95fc 100644 --- a/client/ayon_core/plugins/publish/integrate_inputlinks.py +++ b/client/ayon_core/plugins/publish/integrate_inputlinks.py @@ -105,7 +105,7 @@ class IntegrateInputLinksAYON(pyblish.api.ContextPlugin): created links by its type """ if workfile_instance is None: - self.log.warn("No workfile in this publish session.") + self.log.warning("No workfile in this publish session.") return workfile_version_id = workfile_instance.data["versionEntity"]["id"] From ecd3538dfd481d7fe3c4a4388d3affe7f7d4b615 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:46:52 +0200 Subject: [PATCH 07/15] Update client/ayon_core/plugins/publish/collect_scene_loaded_versions.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../ayon_core/plugins/publish/collect_scene_loaded_versions.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index ea949eb087..9574c8c211 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -34,9 +34,6 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): if isinstance(host, ILoadHost): containers = list(host.get_containers()) - elif hasattr(host, "ls"): - # Backwards compatibility for legacy host implementations - containers = list(host.ls()) else: host_name = host.__name__ self.log.warning( From 654833054901c0e53b9e2683328fad46610446cb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 11:47:38 +0200 Subject: [PATCH 08/15] Reformat code --- .../plugins/publish/collect_scene_loaded_versions.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index 9574c8c211..ee448e7911 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -32,16 +32,15 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): self.log.warning("No registered host.") return - if isinstance(host, ILoadHost): - containers = list(host.get_containers()) - else: + if not isinstance(host, ILoadHost): host_name = host.__name__ self.log.warning( - f"Host {host_name} does not implement ILoadHost " - f"nor does it have ls() implemented. Skipping querying of " - f"loaded versions in scene.") + f"Host {host_name} does not implement ILoadHost. " + "Skipping querying of loaded versions in scene." + ) return + containers = list(host.get_containers()) if not containers: # Opt out early if there are no containers self.log.debug("No loaded containers found in scene.") From 3941040d23e14aebfaa7b8c1d561ea011d8b34eb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 23 Jul 2025 12:22:28 +0200 Subject: [PATCH 09/15] Update client/ayon_core/plugins/publish/collect_scene_loaded_versions.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../ayon_core/plugins/publish/collect_scene_loaded_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py index ee448e7911..524381f656 100644 --- a/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py +++ b/client/ayon_core/plugins/publish/collect_scene_loaded_versions.py @@ -33,7 +33,7 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin): return if not isinstance(host, ILoadHost): - host_name = host.__name__ + host_name = host.name self.log.warning( f"Host {host_name} does not implement ILoadHost. " "Skipping querying of loaded versions in scene." From 50e6c541f982a52ede822f70eb72074888f038c6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 10:59:34 +0200 Subject: [PATCH 10/15] reuse comment from last workfile --- client/ayon_core/pipeline/workfile/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index d5c717bd6d..36e72bb55a 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -417,7 +417,9 @@ def save_next_version( Args: version (Optional[int]): Workfile version that will be used. Last version + 1 is used if is not passed in. - comment (optional[str]): Workfile comment. + comment (optional[str]): Workfile comment. Pass '""' to clear comment. + The last workfile comment is used if it is not passed in and + passed 'version' is 'None'. description (Optional[str]): Workfile description. prepared_data (Optional[SaveWorkfileOptionalData]): Prepared data for speed enhancements. @@ -513,6 +515,9 @@ def save_next_version( product_type="workfile" ) + if comment is None and last_workfile is not None: + comment = last_workfile.comment + template_data["version"] = version template_data["comment"] = comment From eea1f4cb6a9057a1cf5c4a00e5ba26ecd07985d8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:05:41 +0200 Subject: [PATCH 11/15] re-use comment from current file --- client/ayon_core/pipeline/workfile/utils.py | 24 +++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index 36e72bb55a..a6e4dad2b4 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -429,6 +429,11 @@ def save_next_version( from ayon_core.pipeline.context_tools import registered_host host = registered_host() + current_path = host.get_current_workfile() + if not current_path: + current_path = None + else: + current_path = os.path.normpath(current_path) context = host.get_current_context() project_name = context["project_name"] @@ -483,6 +488,7 @@ def save_next_version( ) rootless_dir = workdir.rootless last_workfile = None + current_workfile = None if version is None: workfiles = host.list_workfiles( project_name, folder_entity, task_entity, @@ -496,6 +502,10 @@ def save_next_version( for workfile in workfiles: if workfile.version is None: continue + + if current_workfile is None and workfile.filepath == current_path: + current_workfile = workfile + if ( last_workfile is None or last_workfile.version < workfile.version @@ -515,11 +525,18 @@ def save_next_version( product_type="workfile" ) - if comment is None and last_workfile is not None: - comment = last_workfile.comment + # Re-use comment if is not set + if comment is None: + if current_workfile is not None: + # Use 'comment' from the current workfile if is set + comment = current_workfile.comment + elif last_workfile is not None: + # Use 'comment' from the last workfile + comment = last_workfile.comment template_data["version"] = version - template_data["comment"] = comment + if comment: + template_data["comment"] = comment # Resolve extension # - Don't fill any if the host does not have defined any -> e.g. if host @@ -530,7 +547,6 @@ def save_next_version( ext = None workfile_extensions = host.get_workfile_extensions() if workfile_extensions: - current_path = host.get_current_workfile() if current_path: ext = os.path.splitext(current_path)[1].lstrip(".") elif last_workfile is not None: From 4b5431f26718169a93cda20706b37f343f441e8b Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:07:09 +0200 Subject: [PATCH 12/15] added helper functions to workfile __init__.py --- client/ayon_core/pipeline/workfile/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/__init__.py b/client/ayon_core/pipeline/workfile/__init__.py index c6a0e0d80b..7acaf69a7c 100644 --- a/client/ayon_core/pipeline/workfile/__init__.py +++ b/client/ayon_core/pipeline/workfile/__init__.py @@ -22,9 +22,11 @@ from .utils import ( should_open_workfiles_tool_on_launch, MissingWorkdirError, + save_workfile_info, save_current_workfile_to, save_workfile_with_current_context, - save_workfile_info, + save_next_version, + copy_workfile_to_context, find_workfile_rootless_path, ) @@ -63,9 +65,11 @@ __all__ = ( "should_open_workfiles_tool_on_launch", "MissingWorkdirError", + "save_workfile_info", "save_current_workfile_to", "save_workfile_with_current_context", - "save_workfile_info", + "save_next_version", + "copy_workfile_to_context", "BuildWorkfile", From 15854f07060838d9e3c5008feeb4551d5da898c5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:49:00 +0200 Subject: [PATCH 13/15] revert some of the logic --- client/ayon_core/pipeline/workfile/utils.py | 43 +++++++++------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index a6e4dad2b4..3812fb6471 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -418,8 +418,7 @@ def save_next_version( version (Optional[int]): Workfile version that will be used. Last version + 1 is used if is not passed in. comment (optional[str]): Workfile comment. Pass '""' to clear comment. - The last workfile comment is used if it is not passed in and - passed 'version' is 'None'. + The current workfile comment is used if it is not passed. description (Optional[str]): Workfile description. prepared_data (Optional[SaveWorkfileOptionalData]): Prepared data for speed enhancements. @@ -489,7 +488,7 @@ def save_next_version( rootless_dir = workdir.rootless last_workfile = None current_workfile = None - if version is None: + if version is None or comment is None: workfiles = host.list_workfiles( project_name, folder_entity, task_entity, prepared_data=ListWorkfilesOptionalData( @@ -500,39 +499,33 @@ def save_next_version( ) ) for workfile in workfiles: - if workfile.version is None: - continue - if current_workfile is None and workfile.filepath == current_path: current_workfile = workfile + if workfile.version is None: + continue + if ( last_workfile is None or last_workfile.version < workfile.version ): last_workfile = workfile - version = None - if last_workfile is not None: - version = last_workfile.version + 1 + if version is None and last_workfile is not None: + version = last_workfile.version + 1 - if version is None: - version = get_versioning_start( - project_name, - host.name, - task_name=task_entity["name"], - task_type=task_entity["taskType"], - product_type="workfile" - ) + if version is None: + version = get_versioning_start( + project_name, + host.name, + task_name=task_entity["name"], + task_type=task_entity["taskType"], + product_type="workfile" + ) - # Re-use comment if is not set - if comment is None: - if current_workfile is not None: - # Use 'comment' from the current workfile if is set - comment = current_workfile.comment - elif last_workfile is not None: - # Use 'comment' from the last workfile - comment = last_workfile.comment + # Re-use comment from the current workfile if is not passed in + if comment is None and current_workfile is not None: + comment = current_workfile.comment template_data["version"] = version if comment: From 583dae949dabe0abd75fb1bb311dbe6547a1730d Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:57:25 +0200 Subject: [PATCH 14/15] strip dot of extension --- client/ayon_core/pipeline/workfile/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index 3812fb6471..354449bd3e 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -541,11 +541,12 @@ def save_next_version( workfile_extensions = host.get_workfile_extensions() if workfile_extensions: if current_path: - ext = os.path.splitext(current_path)[1].lstrip(".") + ext = os.path.splitext(current_path)[1] elif last_workfile is not None: - ext = os.path.splitext(last_workfile.filepath)[1].lstrip(".") + ext = os.path.splitext(last_workfile.filepath)[1] else: ext = next(iter(workfile_extensions), None) + ext = ext.lstrip(".") if ext: template_data["ext"] = ext From a4ec6c4a774008dd66af401957f05d1e55569e8c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 24 Jul 2025 12:40:59 +0200 Subject: [PATCH 15/15] Remove redundant default value Co-authored-by: Roy Nieterau --- client/ayon_core/pipeline/workfile/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index 354449bd3e..6666853998 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -545,7 +545,7 @@ def save_next_version( elif last_workfile is not None: ext = os.path.splitext(last_workfile.filepath)[1] else: - ext = next(iter(workfile_extensions), None) + ext = next(iter(workfile_extensions)) ext = ext.lstrip(".") if ext: