From 1ec9106f0124d6d69ed7a90429d791b5ad46267d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 4 Mar 2025 16:06:07 +0100 Subject: [PATCH 1/8] Support `list[str]` for leaf entries in `core/project_folder_structure` settings to define folder names instead of requiring dicts with empty values --- client/ayon_core/pipeline/project_folders.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index 902b969457..df4353c503 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -82,6 +82,14 @@ def create_project_folders(project_name, basic_paths=None): def _list_path_items(folder_structure): output = [] + + # Allow leaf folders of the `project_folder_structure` to use a list of + # strings instead of a dictionary of keys with empty values. + if isinstance(folder_structure, list): + assert all(isinstance(item, str) for item in folder_structure) + return [folder_structure] + + # Process key, value as key for folder names and value its subfolders for key, value in folder_structure.items(): if not value: output.append(key) From b9adc29be190e9c2ecada1f64278669c53cf38ed Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 4 Mar 2025 16:06:45 +0100 Subject: [PATCH 2/8] Add some type hints --- client/ayon_core/pipeline/project_folders.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index df4353c503..a6f903701f 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -1,6 +1,7 @@ import os import re import json +from typing import Dict, Any, List, Union from ayon_core.settings import get_project_settings from ayon_core.lib import Logger @@ -9,7 +10,7 @@ from .anatomy import Anatomy from .template_data import get_project_template_data -def concatenate_splitted_paths(split_paths, anatomy): +def concatenate_splitted_paths(split_paths, anatomy: Anatomy): log = Logger.get_logger("concatenate_splitted_paths") pattern_array = re.compile(r"\[.*\]") output = [] @@ -47,7 +48,7 @@ def concatenate_splitted_paths(split_paths, anatomy): return output -def fill_paths(path_list, anatomy): +def fill_paths(path_list: List[str], anatomy: Anatomy): format_data = get_project_template_data(project_name=anatomy.project_name) format_data["root"] = anatomy.roots filled_paths = [] @@ -59,7 +60,7 @@ def fill_paths(path_list, anatomy): return filled_paths -def create_project_folders(project_name, basic_paths=None): +def create_project_folders(project_name: str, basic_paths=None): log = Logger.get_logger("create_project_folders") anatomy = Anatomy(project_name) if basic_paths is None: @@ -80,7 +81,8 @@ def create_project_folders(project_name, basic_paths=None): os.makedirs(path) -def _list_path_items(folder_structure): +def _list_path_items( + folder_structure: Union[Dict[str, Any], List[str]]): output = [] # Allow leaf folders of the `project_folder_structure` to use a list of @@ -107,7 +109,7 @@ def _list_path_items(folder_structure): return output -def get_project_basic_paths(project_name): +def get_project_basic_paths(project_name: str): project_settings = get_project_settings(project_name) folder_structure = ( project_settings["core"]["project_folder_structure"] From 7baf208c61f992a30de62f29a3aef484207ac542 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Mar 2025 14:51:12 +0100 Subject: [PATCH 3/8] Fix `List[str]` entries --- client/ayon_core/pipeline/project_folders.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index a6f903701f..37197495f9 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -89,7 +89,7 @@ def _list_path_items( # strings instead of a dictionary of keys with empty values. if isinstance(folder_structure, list): assert all(isinstance(item, str) for item in folder_structure) - return [folder_structure] + return [[path] for path in folder_structure] # Process key, value as key for folder names and value its subfolders for key, value in folder_structure.items(): @@ -119,4 +119,6 @@ def get_project_basic_paths(project_name: str): if isinstance(folder_structure, str): folder_structure = json.loads(folder_structure) - return _list_path_items(folder_structure) + result = _list_path_items(folder_structure) + print(result) + return [] From 1b4f6bea20b2c6e7abac4eb5b57b9377ae78db90 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Mar 2025 15:05:50 +0100 Subject: [PATCH 4/8] Revert debug code --- client/ayon_core/pipeline/project_folders.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index 37197495f9..570442ff0c 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -119,6 +119,4 @@ def get_project_basic_paths(project_name: str): if isinstance(folder_structure, str): folder_structure = json.loads(folder_structure) - result = _list_path_items(folder_structure) - print(result) - return [] + return _list_path_items(folder_structure) From ab682da2b83b1e405ed776d6b18ca8234e83d302 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 11:51:29 +0100 Subject: [PATCH 5/8] Raise ValueError instead of using assertion --- client/ayon_core/pipeline/project_folders.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index 570442ff0c..7386382d56 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -88,7 +88,9 @@ def _list_path_items( # Allow leaf folders of the `project_folder_structure` to use a list of # strings instead of a dictionary of keys with empty values. if isinstance(folder_structure, list): - assert all(isinstance(item, str) for item in folder_structure) + if not all(isinstance(item, str) for item in folder_structure): + raise ValueError( + f"List items must all be strings. Got: {folder_structure}") return [[path] for path in folder_structure] # Process key, value as key for folder names and value its subfolders From eb17eebb99460963ef4888c039975ede350596b5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 12:28:49 +0100 Subject: [PATCH 6/8] Update client/ayon_core/pipeline/project_folders.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/pipeline/project_folders.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index 7386382d56..1e4d807c49 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -1,3 +1,4 @@ +from __future__ import annotations import os import re import json From 8008ab02b543b2d42a0dfbb91bd6afca315d28cf Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 12:29:45 +0100 Subject: [PATCH 7/8] Use future annotations style --- client/ayon_core/pipeline/project_folders.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/pipeline/project_folders.py b/client/ayon_core/pipeline/project_folders.py index 1e4d807c49..def2af9ba1 100644 --- a/client/ayon_core/pipeline/project_folders.py +++ b/client/ayon_core/pipeline/project_folders.py @@ -2,7 +2,7 @@ from __future__ import annotations import os import re import json -from typing import Dict, Any, List, Union +from typing import Any, Union from ayon_core.settings import get_project_settings from ayon_core.lib import Logger @@ -49,7 +49,7 @@ def concatenate_splitted_paths(split_paths, anatomy: Anatomy): return output -def fill_paths(path_list: List[str], anatomy: Anatomy): +def fill_paths(path_list: list[str], anatomy: Anatomy): format_data = get_project_template_data(project_name=anatomy.project_name) format_data["root"] = anatomy.roots filled_paths = [] @@ -83,7 +83,7 @@ def create_project_folders(project_name: str, basic_paths=None): def _list_path_items( - folder_structure: Union[Dict[str, Any], List[str]]): + folder_structure: Union[dict[str, Any], list[str]]): output = [] # Allow leaf folders of the `project_folder_structure` to use a list of From 9d68669b6a99b450ad7e7860f453e1b15f4e8cde Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 13 Mar 2025 12:40:36 +0100 Subject: [PATCH 8/8] do not trigger publish attributes collection after each add bulk, but when it finishes --- client/ayon_core/pipeline/create/context.py | 90 ++++++++++----------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/client/ayon_core/pipeline/create/context.py b/client/ayon_core/pipeline/create/context.py index 24557234f4..26b04ed3ed 100644 --- a/client/ayon_core/pipeline/create/context.py +++ b/client/ayon_core/pipeline/create/context.py @@ -839,7 +839,7 @@ class CreateContext: publish_attributes.update(output) for plugin in self.plugins_with_defs: - attr_defs = plugin.get_attr_defs_for_context (self) + attr_defs = plugin.get_attr_defs_for_context(self) if not attr_defs: continue self._publish_attributes.set_publish_plugin_attr_defs( @@ -1259,50 +1259,6 @@ class CreateContext: with self._bulk_context("add", sender) as bulk_info: yield bulk_info - # Set publish attributes before bulk context is exited - for instance in bulk_info.get_data(): - publish_attributes = instance.publish_attributes - # Prepare publish plugin attributes and set it on instance - for plugin in self.plugins_with_defs: - try: - if is_func_signature_supported( - plugin.convert_attribute_values, self, instance - ): - plugin.convert_attribute_values(self, instance) - - elif plugin.__instanceEnabled__: - output = plugin.convert_attribute_values( - publish_attributes - ) - if output: - publish_attributes.update(output) - - except Exception: - self.log.error( - "Failed to convert attribute values of" - f" plugin '{plugin.__name__}'", - exc_info=True - ) - - for plugin in self.plugins_with_defs: - attr_defs = None - try: - attr_defs = plugin.get_attr_defs_for_instance( - self, instance - ) - except Exception: - self.log.error( - "Failed to get attribute definitions" - f" from plugin '{plugin.__name__}'.", - exc_info=True - ) - - if not attr_defs: - continue - instance.set_publish_plugin_attr_defs( - plugin.__name__, attr_defs - ) - @contextmanager def bulk_instances_collection(self, sender=None): """DEPRECATED use 'bulk_add_instances' instead.""" @@ -2251,6 +2207,50 @@ class CreateContext: if not instances_to_validate: return + # Set publish attributes before bulk callbacks are triggered + for instance in instances_to_validate: + publish_attributes = instance.publish_attributes + # Prepare publish plugin attributes and set it on instance + for plugin in self.plugins_with_defs: + try: + if is_func_signature_supported( + plugin.convert_attribute_values, self, instance + ): + plugin.convert_attribute_values(self, instance) + + elif plugin.__instanceEnabled__: + output = plugin.convert_attribute_values( + publish_attributes + ) + if output: + publish_attributes.update(output) + + except Exception: + self.log.error( + "Failed to convert attribute values of" + f" plugin '{plugin.__name__}'", + exc_info=True + ) + + for plugin in self.plugins_with_defs: + attr_defs = None + try: + attr_defs = plugin.get_attr_defs_for_instance( + self, instance + ) + except Exception: + self.log.error( + "Failed to get attribute definitions" + f" from plugin '{plugin.__name__}'.", + exc_info=True + ) + + if not attr_defs: + continue + instance.set_publish_plugin_attr_defs( + plugin.__name__, attr_defs + ) + # Cache folder and task entities for all instances at once self.get_instances_context_info(instances_to_validate)