From 0d235ed8cacffb9196a54e1b3cf40fbcc36fd57e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 22 Oct 2025 18:58:20 +0200 Subject: [PATCH 01/33] Create destination task if no task selected --- .../tools/push_to_project/models/integrate.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index ef49838152..a7cb1de95a 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -762,8 +762,11 @@ class ProjectPushItemProcess: ) self._folder_entity = folder_entity if not dst_task_name: - self._task_info = {} - return + dst_task_name = self._make_sure_task_exists(folder_entity) + + if not dst_task_name: # really no task selected nor on source + self._task_info = {} + return folder_path = folder_entity["path"] folder_tasks = { @@ -962,6 +965,28 @@ class ProjectPushItemProcess: ) self._version_entity = version_entity + def _make_sure_task_exists(self, folder_entity: Dict[str, Any]) -> str: + """Creates destination task from source task information""" + project_name = self._item.dst_project_name + src_version_entity = self._src_version_entity + src_task = ayon_api.get_task_by_id( + self._item.src_project_name, src_version_entity["taskId"] + ) + if not src_task: + self._status.set_failed( + f"No task selected and couldn't find source task" + ) + raise PushToProjectError(self._status.fail_reason) + _task_id = ayon_api.create_task( + project_name, + src_task["name"], + folder_id=folder_entity["id"], + task_type=src_task["taskType"], + attrib=src_task["attrib"], + ) + + return src_task["name"] + def _integrate_representations(self): try: self._real_integrate_representations() From 0ebbd0a23224e4fd539f8b1a479892de38af96dc Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 10:55:37 +0200 Subject: [PATCH 02/33] Extracted logic to methods --- .../tools/push_to_project/models/integrate.py | 52 +++++++++++++------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index a7cb1de95a..9365379148 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -482,6 +482,8 @@ class ProjectPushItemProcess: self._log_info("Destination project was found") self._fill_or_create_destination_folder() self._log_info("Destination folder was determined") + self._fill_or_create_destination_task() + self._log_info("Destination task was determined") self._determine_product_type() self._determine_publish_template_name() self._determine_product_name() @@ -730,7 +732,6 @@ class ProjectPushItemProcess: def _fill_or_create_destination_folder(self): dst_project_name = self._item.dst_project_name dst_folder_id = self._item.dst_folder_id - dst_task_name = self._item.dst_task_name new_folder_name = self._item.new_folder_name if not dst_folder_id and not new_folder_name: self._status.set_failed( @@ -761,12 +762,11 @@ class ProjectPushItemProcess: new_folder_name ) self._folder_entity = folder_entity - if not dst_task_name: - dst_task_name = self._make_sure_task_exists(folder_entity) - if not dst_task_name: # really no task selected nor on source - self._task_info = {} - return + def _fill_or_create_destination_task(self): + folder_entity = self._folder_entity + dst_task_name = self._item.dst_task_name + dst_project_name = self._item.dst_project_name folder_path = folder_entity["path"] folder_tasks = { @@ -775,6 +775,21 @@ class ProjectPushItemProcess: dst_project_name, folder_ids=[folder_entity["id"]] ) } + + if not dst_task_name: + src_task_info = self._get_src_task_info() + if not src_task_info: # really no task selected nor on source + self._task_info = {} + return + + dst_task_name = src_task_info["name"].lower() + if dst_task_name not in folder_tasks: + self._make_sure_task_exists( + folder_entity, src_task_info + ) + task_info = copy.deepcopy(src_task_info) + folder_tasks[dst_task_name] = task_info + task_info = folder_tasks.get(dst_task_name.lower()) if not task_info: self._status.set_failed( @@ -965,9 +980,22 @@ class ProjectPushItemProcess: ) self._version_entity = version_entity - def _make_sure_task_exists(self, folder_entity: Dict[str, Any]) -> str: + def _make_sure_task_exists( + self, + folder_entity: Dict[str, Any], + task_info: Dict[str, Any], + ): """Creates destination task from source task information""" project_name = self._item.dst_project_name + _task_id = ayon_api.create_task( + project_name, + task_info["name"], + folder_id=folder_entity["id"], + task_type=task_info["taskType"], + attrib=task_info["attrib"], + ) + + def _get_src_task_info(self): src_version_entity = self._src_version_entity src_task = ayon_api.get_task_by_id( self._item.src_project_name, src_version_entity["taskId"] @@ -977,15 +1005,7 @@ class ProjectPushItemProcess: f"No task selected and couldn't find source task" ) raise PushToProjectError(self._status.fail_reason) - _task_id = ayon_api.create_task( - project_name, - src_task["name"], - folder_id=folder_entity["id"], - task_type=src_task["taskType"], - attrib=src_task["attrib"], - ) - - return src_task["name"] + return src_task def _integrate_representations(self): try: From d8dd2a23a895b06a45ec27a1c24842729aaa7189 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 10:55:48 +0200 Subject: [PATCH 03/33] Typing --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 9365379148..b2475ac7d1 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -5,7 +5,7 @@ import itertools import sys import traceback import uuid -from typing import Optional, Dict +from typing import Optional, Dict, Any import ayon_api from ayon_api.utils import create_entity_id From f0230e24a7bc3a2e321caeb14bf7e33acd523eab Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 11:20:03 +0200 Subject: [PATCH 04/33] Fix use operations instead of ayon_api Must be in same session as create folder if 'Create New Folder' --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index b2475ac7d1..027416922b 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -987,7 +987,7 @@ class ProjectPushItemProcess: ): """Creates destination task from source task information""" project_name = self._item.dst_project_name - _task_id = ayon_api.create_task( + _task_id = self._operations.create_task( project_name, task_info["name"], folder_id=folder_entity["id"], From 1ee701b52fdaafcabe9ce6a726f4d74e9a8a9da5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 11:32:30 +0200 Subject: [PATCH 05/33] Fix dict typing --- .../tools/push_to_project/models/integrate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 027416922b..1ecf8a8a59 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -5,7 +5,7 @@ import itertools import sys import traceback import uuid -from typing import Optional, Dict, Any +from typing import Optional, Any import ayon_api from ayon_api.utils import create_entity_id @@ -225,8 +225,8 @@ class ProjectPushRepreItem: but filenames are not template based. Args: - repre_entity (Dict[str, Ant]): Representation entity. - roots (Dict[str, str]): Project roots (based on project anatomy). + repre_entity (dict[str, Ant]): Representation entity. + roots (dict[str, str]): Project roots (based on project anatomy). """ def __init__(self, repre_entity, roots): @@ -982,8 +982,8 @@ class ProjectPushItemProcess: def _make_sure_task_exists( self, - folder_entity: Dict[str, Any], - task_info: Dict[str, Any], + folder_entity: dict[str, Any], + task_info: dict[str, Any], ): """Creates destination task from source task information""" project_name = self._item.dst_project_name @@ -1326,6 +1326,6 @@ class IntegrateModel: return item.integrate() - def get_items(self) -> Dict[str, ProjectPushItemProcess]: + def get_items(self) -> dict[str, ProjectPushItemProcess]: """Returns dict of all ProjectPushItemProcess items """ return self._process_items From 7b5ca16993bbc844d14ca27bc042e23ee58ce9bf Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 17:03:50 +0200 Subject: [PATCH 06/33] Use lower only for comparison Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/push_to_project/models/integrate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 1ecf8a8a59..1cd9e2deaf 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -782,8 +782,8 @@ class ProjectPushItemProcess: self._task_info = {} return - dst_task_name = src_task_info["name"].lower() - if dst_task_name not in folder_tasks: + dst_task_name = src_task_info["name"] + if dst_task_name.lower() not in folder_tasks: self._make_sure_task_exists( folder_entity, src_task_info ) From 67994bb5a3bc8dc527a4fd09f6110049c551238e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 17:04:07 +0200 Subject: [PATCH 07/33] Remove unnecessary variable Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 1cd9e2deaf..2030027bb0 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -987,7 +987,7 @@ class ProjectPushItemProcess: ): """Creates destination task from source task information""" project_name = self._item.dst_project_name - _task_id = self._operations.create_task( + self._operations.create_task( project_name, task_info["name"], folder_id=folder_entity["id"], From cea56fbe5322075dbdb0826e78d0b2a27069b5ac Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 17:04:32 +0200 Subject: [PATCH 08/33] Formatting change Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 2030027bb0..7e92d82f41 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1002,7 +1002,7 @@ class ProjectPushItemProcess: ) if not src_task: self._status.set_failed( - f"No task selected and couldn't find source task" + "No task selected and couldn't find source task" ) raise PushToProjectError(self._status.fail_reason) return src_task From 04322ef94d673cd3b4356afb6897ec7d30d8d8bb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 17:08:35 +0200 Subject: [PATCH 09/33] Removed hard fail, unnecessary --- client/ayon_core/tools/push_to_project/models/integrate.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 5127afd0ee..164b73e0ef 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1020,11 +1020,7 @@ class ProjectPushItemProcess: src_task = ayon_api.get_task_by_id( self._item.src_project_name, src_version_entity["taskId"] ) - if not src_task: - self._status.set_failed( - f"No task selected and couldn't find source task" - ) - raise PushToProjectError(self._status.fail_reason) + return src_task def _integrate_representations(self): From 42722c08960e528a9e9cfa735aedfd7023533bde Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Oct 2025 17:20:16 +0200 Subject: [PATCH 10/33] Added validation that task type is in destination project --- .../tools/push_to_project/models/integrate.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 164b73e0ef..e80a525204 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1007,11 +1007,26 @@ class ProjectPushItemProcess: ): """Creates destination task from source task information""" project_name = self._item.dst_project_name + found_task_type = False + src_task_type = task_info["taskType"] + for task_type in self._project_entity["taskTypes"]: + if task_type["name"].lower() == src_task_type.lower(): + found_task_type = True + break + + if not found_task_type: + self._status.set_failed( + f"'{src_task_type}' task type is not configured in " + "project Anatomy." + ) + + raise PushToProjectError(self._status.fail_reason) + _task_id = self._operations.create_task( project_name, task_info["name"], folder_id=folder_entity["id"], - task_type=task_info["taskType"], + task_type=src_task_type, attrib=task_info["attrib"], ) From 7e3e5855b86a31e1206c199478bddeb9829a6c80 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 11:01:24 +0200 Subject: [PATCH 11/33] Fix use of lower task name --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 5370a35c37..a98c045893 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -808,7 +808,7 @@ class ProjectPushItemProcess: folder_entity, src_task_info ) task_info = copy.deepcopy(src_task_info) - folder_tasks[dst_task_name] = task_info + folder_tasks[dst_task_name.lower()] = task_info task_info = folder_tasks.get(dst_task_name.lower()) if not task_info: From f33b13c19449aed3ab9b1aa9fb45716c6418d52e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 11:22:13 +0200 Subject: [PATCH 12/33] Fix if source version doesn't have task Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index a98c045893..a8cd3be2cc 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1032,6 +1032,8 @@ class ProjectPushItemProcess: def _get_src_task_info(self): src_version_entity = self._src_version_entity + if not src_version_entity["taskId"]: + return None src_task = ayon_api.get_task_by_id( self._item.src_project_name, src_version_entity["taskId"] ) From f6e4d50137f4dbcbc830639bc6e73efc054d27e1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 12:19:31 +0200 Subject: [PATCH 13/33] Fix overwriting real task name with name of task type --- client/ayon_core/tools/push_to_project/models/integrate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index a98c045893..5be7dbe2c1 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -828,7 +828,10 @@ class ProjectPushItemProcess: task_type["name"]: task_type for task_type in self._project_entity["taskTypes"] } - task_type_info = task_types_by_name.get(task_type_name, {}) + task_type_info = copy.deepcopy( + task_types_by_name.get(task_type_name, {}) + ) + task_type_info.pop("name") # do not overwrite real task name task_info.update(task_type_info) self._task_info = task_info From efec97fda3938f883b166fa4de26b127fc488920 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 12:20:14 +0200 Subject: [PATCH 14/33] Return task info from created object --- .../ayon_core/tools/push_to_project/models/integrate.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 5be7dbe2c1..2d02316db0 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -804,10 +804,9 @@ class ProjectPushItemProcess: dst_task_name = src_task_info["name"] if dst_task_name.lower() not in folder_tasks: - self._make_sure_task_exists( + task_info = self._make_sure_task_exists( folder_entity, src_task_info ) - task_info = copy.deepcopy(src_task_info) folder_tasks[dst_task_name.lower()] = task_info task_info = folder_tasks.get(dst_task_name.lower()) @@ -1007,7 +1006,7 @@ class ProjectPushItemProcess: self, folder_entity: dict[str, Any], task_info: dict[str, Any], - ): + ) -> dict[str, Any]: """Creates destination task from source task information""" project_name = self._item.dst_project_name found_task_type = False @@ -1025,13 +1024,15 @@ class ProjectPushItemProcess: raise PushToProjectError(self._status.fail_reason) - self._operations.create_task( + task_info = self._operations.create_task( project_name, task_info["name"], folder_id=folder_entity["id"], task_type=src_task_type, attrib=task_info["attrib"], ) + self._task_info = task_info.data + return self._task_info def _get_src_task_info(self): src_version_entity = self._src_version_entity From 636ef024b786dafe45233522aea2d92ecccd8440 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 12:20:34 +0200 Subject: [PATCH 15/33] Task is optional --- client/ayon_core/tools/push_to_project/models/integrate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 2d02316db0..fc61204bf3 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -965,8 +965,8 @@ class ProjectPushItemProcess: version = get_versioning_start( project_name, self.host_name, - task_name=self._task_info["name"], - task_type=self._task_info["taskType"], + task_name=self._task_info.get("name"), + task_type=self._task_info.get("taskType"), product_type=product_type, product_name=product_entity["name"], ) From 49162f228e9cb3bd8ceee2bad8ad54ca665b4c75 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 12:20:54 +0200 Subject: [PATCH 16/33] Fix pushed products not attaching to version --- client/ayon_core/tools/push_to_project/models/integrate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index fc61204bf3..45035671b2 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -994,6 +994,7 @@ class ProjectPushItemProcess: version_entity = new_version_entity( version, product_id, + task_id=self._task_info.get("id"), attribs=dst_attrib, thumbnail_id=thumbnail_id, ) From fcc82a8e463388e205aac4460a73fbff16552386 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 14:14:21 +0200 Subject: [PATCH 17/33] Transfer status and tags --- .../tools/push_to_project/models/integrate.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index f8360c520b..8c125dd3dc 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -990,10 +990,15 @@ class ProjectPushItemProcess: existing_version_entity["attrib"].update(dst_attrib) self._version_entity = existing_version_entity return + copied_tags = self._get_transferable_tags(src_version_entity) + copied_status = self._get_transferable_status(src_version_entity) version_entity = new_version_entity( version, product_id, + author=src_version_entity["author"], + status=copied_status, + tags=copied_tags, task_id=self._task_info.get("id"), attribs=dst_attrib, thumbnail_id=thumbnail_id, @@ -1291,6 +1296,30 @@ class ProjectPushItemProcess: repre_context.pop("task", None) return repre_context + def _get_transferable_tags(self, src_version_entity): + """Copy over only tags present in destination project""" + dst_project_tags = [ + tag["name"] for tag in self._project_entity["tags"] + ] + copied_tags = [] + for src_tag in src_version_entity["tags"]: + if src_tag in dst_project_tags: + copied_tags.append(src_tag) + return copied_tags + + def _get_transferable_status(self, src_version_entity): + """Copy over status, first status if not matching found""" + dst_project_statuses = { + status["name"]: status + for status in self._project_entity["statuses"] + } + copied_status = dst_project_statuses.get(src_version_entity["status"]) + if not copied_status: + copied_status = dst_project_statuses[ + dst_project_statuses.keys()[0] + ] + return copied_status["name"] + class IntegrateModel: def __init__(self, controller): From 3104e07c78dd62ff438b122c97dbe63cf1e3b665 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 15:30:52 +0200 Subject: [PATCH 18/33] Fix access to dict keys --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 8c125dd3dc..838bf079ec 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1316,7 +1316,7 @@ class ProjectPushItemProcess: copied_status = dst_project_statuses.get(src_version_entity["status"]) if not copied_status: copied_status = dst_project_statuses[ - dst_project_statuses.keys()[0] + next(iter(dst_project_statuses)) ] return copied_status["name"] From 542acd0896e1ad266f7764811817212dc4ab6d06 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 15:33:15 +0200 Subject: [PATCH 19/33] Fix access to dict keys --- client/ayon_core/tools/push_to_project/models/integrate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 838bf079ec..e23d2a8eb2 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1313,8 +1313,13 @@ class ProjectPushItemProcess: status["name"]: status for status in self._project_entity["statuses"] } - copied_status = dst_project_statuses.get(src_version_entity["status"]) + source_status = src_version_entity["status"] + copied_status = dst_project_statuses.get(source_status) if not copied_status: + self._log_warning( + f"'{source_status}' not found in destination project. " + "Used first configured status from there." + ) copied_status = dst_project_statuses[ next(iter(dst_project_statuses)) ] From fcebdaf13006aeeefd2979ceac24304dee9cd618 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Oct 2025 16:00:42 +0200 Subject: [PATCH 20/33] Do not send dummy status if not found --- .../tools/push_to_project/models/integrate.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index e23d2a8eb2..2adc708cf3 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -1284,10 +1284,12 @@ class ProjectPushItemProcess: if context_value and isinstance(context_value, dict): for context_sub_key in context_value.keys(): value_to_update = formatting_data.get(context_key, {}).get( - context_sub_key) + context_sub_key + ) if value_to_update: - repre_context[context_key][ - context_sub_key] = value_to_update + repre_context[context_key][context_sub_key] = ( + value_to_update + ) else: value_to_update = formatting_data.get(context_key) if value_to_update: @@ -1313,17 +1315,10 @@ class ProjectPushItemProcess: status["name"]: status for status in self._project_entity["statuses"] } - source_status = src_version_entity["status"] - copied_status = dst_project_statuses.get(source_status) - if not copied_status: - self._log_warning( - f"'{source_status}' not found in destination project. " - "Used first configured status from there." - ) - copied_status = dst_project_statuses[ - next(iter(dst_project_statuses)) - ] - return copied_status["name"] + copied_status = dst_project_statuses.get(src_version_entity["status"]) + if copied_status: + return copied_status["name"] + return None class IntegrateModel: From 3ee7c30cae8b75726875e58970f19fe08af14ee4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 24 Oct 2025 17:35:28 +0200 Subject: [PATCH 21/33] Handles missing media references in OTIO clips Adds a check for missing media references in OTIO clips during publishing. --- .../ayon_core/plugins/publish/collect_otio_frame_ranges.py | 6 ++++++ .../plugins/publish/collect_otio_subset_resources.py | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/client/ayon_core/plugins/publish/collect_otio_frame_ranges.py b/client/ayon_core/plugins/publish/collect_otio_frame_ranges.py index d68970d428..543277f37e 100644 --- a/client/ayon_core/plugins/publish/collect_otio_frame_ranges.py +++ b/client/ayon_core/plugins/publish/collect_otio_frame_ranges.py @@ -71,6 +71,12 @@ class CollectOtioRanges(pyblish.api.InstancePlugin): import opentimelineio as otio otio_clip = instance.data["otioClip"] + if isinstance( + otio_clip.media_reference, + otio.schema.MissingReference + ): + self.log.info("Clip has no media reference") + return # Collect timeline ranges if workfile start frame is available if "workfileFrameStart" in instance.data: diff --git a/client/ayon_core/plugins/publish/collect_otio_subset_resources.py b/client/ayon_core/plugins/publish/collect_otio_subset_resources.py index 275b8a7f55..4d3c1cfb13 100644 --- a/client/ayon_core/plugins/publish/collect_otio_subset_resources.py +++ b/client/ayon_core/plugins/publish/collect_otio_subset_resources.py @@ -60,6 +60,13 @@ class CollectOtioSubsetResources( # get basic variables otio_clip = instance.data["otioClip"] + if isinstance( + otio_clip.media_reference, + otio.schema.MissingReference + ): + self.log.info("Clip has no media reference") + return + otio_available_range = otio_clip.available_range() media_fps = otio_available_range.start_time.rate available_duration = otio_available_range.duration.value From 373683890c07ac137df771c5e5d58c82f00fe87d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 27 Oct 2025 10:05:30 +0100 Subject: [PATCH 22/33] Use correct publish template in `get_instance_expected_output_path` --- client/ayon_core/pipeline/publish/lib.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/publish/lib.py b/client/ayon_core/pipeline/publish/lib.py index fb84417730..f6198bd45e 100644 --- a/client/ayon_core/pipeline/publish/lib.py +++ b/client/ayon_core/pipeline/publish/lib.py @@ -955,7 +955,26 @@ def get_instance_expected_output_path( "version": version }) - path_template_obj = anatomy.get_template_item("publish", "default")["path"] + # Get instance publish template name + task_name = task_type = None + task_entity = instance.data.get("taskEntity") + if task_entity: + task_name = task_entity["name"] + task_type = task_entity["taskType"] + + template_name = get_publish_template_name( + project_name=instance.context.data["projectName"], + host_name=instance.context.data["hostName"], + product_type=instance.data["productType"], + task_name=task_name, + task_type=task_type, + project_settings=instance.context.data["project_settings"], + ) + + path_template_obj = anatomy.get_template_item( + "publish", + template_name + )["path"] template_filled = path_template_obj.format_strict(template_data) return os.path.normpath(template_filled) From a162d6bce1c4ec9fe20c918d50bc831ffeb54e2f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:50:13 +0100 Subject: [PATCH 23/33] fix mytasks filtering --- client/ayon_core/tools/workfiles/widgets/window.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/tools/workfiles/widgets/window.py b/client/ayon_core/tools/workfiles/widgets/window.py index 3f96f0bb15..c7ff98f25e 100644 --- a/client/ayon_core/tools/workfiles/widgets/window.py +++ b/client/ayon_core/tools/workfiles/widgets/window.py @@ -358,9 +358,8 @@ class WorkfilesToolWindow(QtWidgets.QWidget): if not self._host_is_valid: return - self._folders_widget.set_project_name( - self._controller.get_current_project_name() - ) + self._project_name = self._controller.get_current_project_name() + self._folders_widget.set_project_name(self._project_name) def _on_save_as_finished(self, event): if event["failed"]: @@ -412,6 +411,7 @@ class WorkfilesToolWindow(QtWidgets.QWidget): entity_ids = self._controller.get_my_tasks_entity_ids( self._project_name ) + print(entity_ids) folder_ids = entity_ids["folder_ids"] task_ids = entity_ids["task_ids"] self._folders_widget.set_folder_ids_filter(folder_ids) From c03fe908a74b0d5e815f94526363980097bbe676 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:57:12 +0100 Subject: [PATCH 24/33] lock pyobjc-core to 11.1 --- client/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/pyproject.toml b/client/pyproject.toml index 6416d9b8e1..c98591b707 100644 --- a/client/pyproject.toml +++ b/client/pyproject.toml @@ -19,3 +19,6 @@ OpenTimelineIO = "0.16.0" opencolorio = "^2.3.2,<2.4.0" Pillow = "9.5.0" websocket-client = ">=0.40.0,<2" + +[ayon.runtimeDependencies.darwin] +pyobjc-core = "^11.1" From 5d74d9dc514b5ca8b4b4298c1346222c18ac0ca4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:52:18 +0100 Subject: [PATCH 25/33] Remove dev print --- client/ayon_core/tools/workfiles/widgets/window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/tools/workfiles/widgets/window.py b/client/ayon_core/tools/workfiles/widgets/window.py index c7ff98f25e..00362ea866 100644 --- a/client/ayon_core/tools/workfiles/widgets/window.py +++ b/client/ayon_core/tools/workfiles/widgets/window.py @@ -411,7 +411,6 @@ class WorkfilesToolWindow(QtWidgets.QWidget): entity_ids = self._controller.get_my_tasks_entity_ids( self._project_name ) - print(entity_ids) folder_ids = entity_ids["folder_ids"] task_ids = entity_ids["task_ids"] self._folders_widget.set_folder_ids_filter(folder_ids) From 425dbc6db1addf6cb603d0774f5aa6abf4637a01 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 27 Oct 2025 18:07:49 +0100 Subject: [PATCH 26/33] Implemented copy of source folder thumbnail --- .../tools/push_to_project/models/integrate.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 2adc708cf3..8a6000122f 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -3,6 +3,7 @@ import re import copy import itertools import sys +import tempfile import traceback import uuid from typing import Optional, Any @@ -709,11 +710,14 @@ class ProjectPushItemProcess: project_entity, src_folder_type ) + new_thumbnail_id = self._get_new_folder_thumbnail_id( + project_entity, src_folder_entity) folder_entity = new_folder_entity( folder_name, dst_folder_type, parent_id=parent_id, - attribs=new_folder_attrib + attribs=new_folder_attrib, + thumbnail_id=new_thumbnail_id ) if folder_label: folder_entity["label"] = folder_label @@ -733,6 +737,36 @@ class ProjectPushItemProcess: folder_entity["path"] = "/".join([parent_path, folder_name]) return folder_entity + def _get_new_folder_thumbnail_id( + self, + project_entity: dict[str, Any], + src_folder_entity: dict[str, Any] + ) -> Optional[str]: + """Copy thumbnail possibly set on folder. + + Could be different from representation thumbnails, and it is only shown + when folder is selected. + """ + new_thumbnail_id = None + if src_folder_entity["thumbnailId"]: + thumbnail = ayon_api.get_thumbnail_by_id( + self._item.src_project_name, src_folder_entity["thumbnailId"] + ) + if not thumbnail.id: + return new_thumbnail_id + + try: + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + tmp_file.write(thumbnail.content) + temp_file_path = tmp_file.name + + new_thumbnail_id = ayon_api.create_thumbnail( + project_entity["name"], temp_file_path) + finally: + if temp_file_path and os.path.exists(temp_file_path): + os.remove(temp_file_path) + return new_thumbnail_id + def _get_dst_folder_type( self, project_entity: dict[str, Any], From e184c1b3dd5de7fbd95bcf7afe643c1738659e2c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:22:29 +0100 Subject: [PATCH 27/33] don't require 'AYON_STUDIO_BUNDLE_NAME' to be set --- client/ayon_core/addon/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 9207bb74c0..a04aedb8cc 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -141,6 +141,9 @@ def _get_ayon_bundle_data() -> tuple[ ]: studio_bundle_name = os.environ.get("AYON_STUDIO_BUNDLE_NAME") project_bundle_name = os.getenv("AYON_BUNDLE_NAME") + # If AYON launcher <1.4.0 was used + if not studio_bundle_name: + studio_bundle_name = project_bundle_name bundles = ayon_api.get_bundles()["bundles"] studio_bundle = next( ( From 9d3585a0c0d73aae50ab2dd444fa1e0aea3bec71 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Oct 2025 15:12:38 +0100 Subject: [PATCH 28/33] Renamed method Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 8a6000122f..0968b99eb5 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -737,7 +737,7 @@ class ProjectPushItemProcess: folder_entity["path"] = "/".join([parent_path, folder_name]) return folder_entity - def _get_new_folder_thumbnail_id( + def _create_new_folder_thumbnail( self, project_entity: dict[str, Any], src_folder_entity: dict[str, Any] From 6dc68606222c88ffaac871bc25f68e5fe0856a19 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Oct 2025 15:13:35 +0100 Subject: [PATCH 29/33] Reorganized flow Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../tools/push_to_project/models/integrate.py | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 0968b99eb5..33eac6c3d6 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -747,24 +747,28 @@ class ProjectPushItemProcess: Could be different from representation thumbnails, and it is only shown when folder is selected. """ + if not src_folder_entity["thumbnailId"]: + return None + + thumbnail = ayon_api.get_folder_thumbnail( + self._item.src_project_name, + src_folder_entity["id"], + src_folder_entity["thumbnailId"] + ) + if not thumbnail.id: + return None + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + tmp_file.write(thumbnail.content) + temp_file_path = tmp_file.name + new_thumbnail_id = None - if src_folder_entity["thumbnailId"]: - thumbnail = ayon_api.get_thumbnail_by_id( - self._item.src_project_name, src_folder_entity["thumbnailId"] - ) - if not thumbnail.id: - return new_thumbnail_id - - try: - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: - tmp_file.write(thumbnail.content) - temp_file_path = tmp_file.name - - new_thumbnail_id = ayon_api.create_thumbnail( - project_entity["name"], temp_file_path) - finally: - if temp_file_path and os.path.exists(temp_file_path): - os.remove(temp_file_path) + try: + new_thumbnail_id = ayon_api.create_thumbnail( + project_entity["name"], temp_file_path) + finally: + if os.path.exists(temp_file_path): + os.remove(temp_file_path) return new_thumbnail_id def _get_dst_folder_type( From 35926269a624b8bbde492defa6aaf756e10c8316 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Oct 2025 15:14:38 +0100 Subject: [PATCH 30/33] Used renamed method --- client/ayon_core/tools/push_to_project/models/integrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/push_to_project/models/integrate.py b/client/ayon_core/tools/push_to_project/models/integrate.py index 33eac6c3d6..cacce44942 100644 --- a/client/ayon_core/tools/push_to_project/models/integrate.py +++ b/client/ayon_core/tools/push_to_project/models/integrate.py @@ -710,7 +710,7 @@ class ProjectPushItemProcess: project_entity, src_folder_type ) - new_thumbnail_id = self._get_new_folder_thumbnail_id( + new_thumbnail_id = self._create_new_folder_thumbnail( project_entity, src_folder_entity) folder_entity = new_folder_entity( folder_name, From e5265ccdc01829ee817327368a164778a40ad155 Mon Sep 17 00:00:00 2001 From: Ynbot Date: Wed, 29 Oct 2025 15:31:57 +0000 Subject: [PATCH 31/33] [Automated] Add generated package files from main --- client/ayon_core/version.py | 2 +- package.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index 8e0834b8da..e40a2e3663 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'core' version.""" -__version__ = "1.6.6+dev" +__version__ = "1.6.7" diff --git a/package.py b/package.py index 5fa4d165d2..8cd5df8dfc 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "1.6.6+dev" +version = "1.6.7" client_dir = "ayon_core" diff --git a/pyproject.toml b/pyproject.toml index 73b9a4a916..11e7d4d3c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ [tool.poetry] name = "ayon-core" -version = "1.6.6+dev" +version = "1.6.7" description = "" authors = ["Ynput Team "] readme = "README.md" From 757d42148e7476f4065fb4418c2d129319236090 Mon Sep 17 00:00:00 2001 From: Ynbot Date: Wed, 29 Oct 2025 15:32:36 +0000 Subject: [PATCH 32/33] [Automated] Update version in package.py for develop --- client/ayon_core/version.py | 2 +- package.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index e40a2e3663..6aa30b935a 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'core' version.""" -__version__ = "1.6.7" +__version__ = "1.6.7+dev" diff --git a/package.py b/package.py index 8cd5df8dfc..ff3fad5b19 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "1.6.7" +version = "1.6.7+dev" client_dir = "ayon_core" diff --git a/pyproject.toml b/pyproject.toml index 11e7d4d3c2..6656f15249 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ [tool.poetry] name = "ayon-core" -version = "1.6.7" +version = "1.6.7+dev" description = "" authors = ["Ynput Team "] readme = "README.md" From 5cd46678b473505384fa8b0b1ba061adab671bd3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 29 Oct 2025 15:33:32 +0000 Subject: [PATCH 33/33] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 60693f088d..c79ca69fca 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to AYON Tray options: + - 1.6.7 - 1.6.6 - 1.6.5 - 1.6.4