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", diff --git a/client/ayon_core/pipeline/workfile/utils.py b/client/ayon_core/pipeline/workfile/utils.py index 77c1953e4d..6666853998 100644 --- a/client/ayon_core/pipeline/workfile/utils.py +++ b/client/ayon_core/pipeline/workfile/utils.py @@ -411,13 +411,14 @@ 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 version + 1 is used if is not passed in. - comment (optional[str]): Workfile comment. + comment (optional[str]): Workfile comment. Pass '""' to clear comment. + 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. @@ -427,6 +428,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"] @@ -480,10 +486,9 @@ def save_next_version( project_settings=project_settings, ) rootless_dir = workdir.rootless - if version is None: - workfile_extensions = host.get_workfile_extensions() - if not workfile_extensions: - raise ValueError("Host does not have defined file extensions") + last_workfile = None + current_workfile = None + if version is None or comment is None: workfiles = host.list_workfiles( project_name, folder_entity, task_entity, prepared_data=ListWorkfilesOptionalData( @@ -493,26 +498,58 @@ def save_next_version( template_key=template_key, ) ) - versions = { - workfile.version - for workfile in workfiles - if workfile.version is not None - } - version = None - if versions: - version = max(versions) + 1 + for workfile in workfiles: + if current_workfile is None and workfile.filepath == current_path: + current_workfile = 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" - ) + if workfile.version is None: + continue + + if ( + last_workfile is None + or last_workfile.version < workfile.version + ): + last_workfile = workfile + + 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" + ) + + # 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 - 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 + # 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: + if current_path: + ext = os.path.splitext(current_path)[1] + elif last_workfile is not None: + ext = os.path.splitext(last_workfile.filepath)[1] + else: + ext = next(iter(workfile_extensions)) + ext = ext.lstrip(".") + + if ext: + template_data["ext"] = ext filename = file_template.format_strict(template_data) workfile_path = os.path.join(workdir, filename) @@ -632,6 +669,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" ) 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..524381f656 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 @@ -27,16 +29,23 @@ 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) + if not isinstance(host, ILoadHost): + host_name = host.name + self.log.warning( + 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.") return - loaded_versions = [] - containers = list(host.ls()) repre_ids = { container["representation"] for container in containers @@ -61,6 +70,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) @@ -80,4 +90,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 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"]