From e25856eb03582bc9a4286d0368a3d296135cfe3e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 4 Mar 2024 15:09:47 +0100 Subject: [PATCH] modified workfile utils to use folder and task entity --- .../pipeline/workfile/build_workfile.py | 193 ++++++++++-------- .../pipeline/workfile/path_resolving.py | 91 +++++---- .../workfile/workfile_template_builder.py | 163 ++++++++------- 3 files changed, 254 insertions(+), 193 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/build_workfile.py b/client/ayon_core/pipeline/workfile/build_workfile.py index 1f07493f9a..50273dce9e 100644 --- a/client/ayon_core/pipeline/workfile/build_workfile.py +++ b/client/ayon_core/pipeline/workfile/build_workfile.py @@ -13,12 +13,12 @@ import re import collections import json +import ayon_api + from ayon_core.client import ( - get_asset_by_name, get_subsets, get_last_versions, get_representations, - get_linked_assets, ) from ayon_core.settings import get_project_settings from ayon_core.lib import ( @@ -76,21 +76,21 @@ class BuildWorkfile: def build_workfile(self): """Prepares and load containers into workfile. - Loads latest versions of current and linked assets to workfile by logic - stored in Workfile profiles from presets. Profiles are set by host, - filtered by current task name and used by families. + Loads latest versions of current and linked folders to workfile by + logic stored in Workfile profiles from presets. Profiles are set + by host, filtered by current task name and used by families. Each product type can specify representation names and loaders for representations and first available and successful loaded representation is returned as container. - At the end you'll get list of loaded containers per each asset. + At the end you'll get list of loaded containers per each folder. loaded_containers [{ - "asset_doc": , + "folder_entity": , "containers": [, , ...] }, { - "asset_doc": , + "folder_entity": , "containers": [, ...] }, { ... @@ -100,22 +100,21 @@ class BuildWorkfile: List[Dict[str, Any]]: Loaded containers during build. """ - from ayon_core.pipeline.context_tools import ( - get_current_project_name, - get_current_folder_path, - get_current_task_name, - ) + from ayon_core.pipeline.context_tools import get_current_context loaded_containers = [] - # Get current asset name and entity - project_name = get_current_project_name() - current_folder_path = get_current_folder_path() - current_asset_doc = get_asset_by_name( + # Get current folder and task entities + context = get_current_context() + project_name = context["project_name"] + current_folder_path = context["folder_path"] + current_task_name = context["task_name"] + + current_folder_entity = ayon_api.get_folder_by_path( project_name, current_folder_path ) - # Skip if asset was not found - if not current_asset_doc: + # Skip if folder was not found + if not current_folder_entity: print("Folder entity `{}` was not found".format( current_folder_path )) @@ -138,12 +137,9 @@ class BuildWorkfile: self.log.warning("There are no registered loaders.") return loaded_containers - # Get current task name - current_task_name = get_current_task_name() - # Load workfile presets for task self.build_presets = self.get_build_presets( - current_task_name, current_asset_doc + current_task_name, current_folder_entity["id"] ) # Skip if there are any presets for task @@ -180,45 +176,53 @@ class BuildWorkfile: "loading preset for it's linked folders." ).format(current_task_name)) - # Prepare assets to process by workfile presets - asset_docs = [] + # Prepare folders to process by workfile presets + folder_entities = [] current_folder_id = None if current_context_profiles: - # Add current asset entity if preset has current context set - asset_docs.append(current_asset_doc) - current_folder_id = current_asset_doc["_id"] + # Add current folder entity if preset has current context set + folder_entities.append(current_folder_entity) + current_folder_id = current_folder_entity["_id"] if link_context_profiles: - # Find and append linked assets if preset has set linked mapping - link_assets = get_linked_assets(project_name, current_asset_doc) - if link_assets: - asset_docs.extend(link_assets) + # Find and append linked folders if preset has set linked mapping + linked_folder_entities = self._get_linked_folder_entities( + project_name, current_folder_entity["id"] + ) + if linked_folder_entities: + folder_entities.extend(linked_folder_entities) - # Skip if there are no assets. This can happen if only linked mapping - # is set and there are no links for his asset. - if not asset_docs: + # Skip if there are no folders. This can happen if only linked mapping + # is set and there are no links for his folder. + if not folder_entities: self.log.warning( - "Asset does not have linked assets. Nothing to process." + "Folder does not have linked folders. Nothing to process." ) return loaded_containers - # Prepare entities from database for assets - prepared_entities = self._collect_last_version_repres(asset_docs) + # Prepare entities from database for folders + prepared_entities = self._collect_last_version_repres( + folder_entities + ) # Load containers by prepared entities and presets - # - Current asset containers + # - Current folder containers if current_folder_id and current_folder_id in prepared_entities: current_context_data = prepared_entities.pop(current_folder_id) - loaded_data = self.load_containers_by_asset_data( - current_context_data, current_context_profiles, loaders_by_name + loaded_data = self.load_containers_by_folder_data( + current_context_data, + current_context_profiles, + loaders_by_name ) if loaded_data: loaded_containers.append(loaded_data) # - Linked assets container - for linked_asset_data in prepared_entities.values(): - loaded_data = self.load_containers_by_asset_data( - linked_asset_data, link_context_profiles, loaders_by_name + for linked_folder_data in prepared_entities.values(): + loaded_data = self.load_containers_by_folder_data( + linked_folder_data, + link_context_profiles, + loaders_by_name ) if loaded_data: loaded_containers.append(loaded_data) @@ -226,7 +230,7 @@ class BuildWorkfile: # Return list of loaded containers return loaded_containers - def get_build_presets(self, task_name, asset_doc): + def get_build_presets(self, task_name, folder_id): """ Returns presets to build workfile for task name. Presets are loaded for current project received by @@ -235,6 +239,7 @@ class BuildWorkfile: Args: task_name (str): Task name used for filtering build presets. + folder_id (str): Folder id. Returns: Dict[str, Any]: preset per entered task name @@ -245,10 +250,9 @@ class BuildWorkfile: get_current_project_name, ) + project_name = get_current_project_name() host_name = get_current_host_name() - project_settings = get_project_settings( - get_current_project_name() - ) + project_settings = get_project_settings(project_name) host_settings = project_settings.get(host_name) or {} # Get presets for host @@ -261,13 +265,15 @@ class BuildWorkfile: if not builder_profiles: return None - task_type = ( - asset_doc - .get("data", {}) - .get("tasks", {}) - .get(task_name, {}) - .get("type") + task_entity = ayon_api.get_task_by_name( + project_name, + folder_id, + task_name, ) + task_type = None + if task_entity: + task_type = task_entity["taskType"] + filter_data = { "task_types": task_type, "tasks": task_name @@ -349,6 +355,31 @@ class BuildWorkfile: return valid_profiles + def _get_linked_folder_entities(self, project_name, folder_id): + """Get linked folder entities for entered folder. + + Args: + project_name (str): Project name. + folder_id (str): Folder id. + + Returns: + list[dict[str, Any]]: Linked folder entities. + + """ + links = ayon_api.get_folder_links( + project_name, folder_id, link_direction="in" + ) + linked_folder_ids = { + link["entityId"] + for link in links + if link["entityType"] == "folder" + } + if not linked_folder_ids: + return [] + return list(ayon_api.get_folders( + project_name, folder_ids=linked_folder_ids + )) + def _prepare_profile_for_products(self, subset_docs, profiles): """Select profile for each product by it's data. @@ -405,28 +436,28 @@ class BuildWorkfile: break return profiles_by_product_id - def load_containers_by_asset_data( - self, asset_doc_data, build_profiles, loaders_by_name + def load_containers_by_folder_data( + self, linked_folder_data, build_profiles, loaders_by_name ): - """Load containers for entered asset entity by Build profiles. + """Load containers for entered folder entity by Build profiles. Args: - asset_doc_data (Dict[str, Any]): Prepared data with products, - last versions and representations for specific asset. + linked_folder_data (Dict[str, Any]): Prepared data with products, + last versions and representations for specific folder. build_profiles (Dict[str, Any]): Build profiles. loaders_by_name (Dict[str, LoaderPlugin]): Available loaders per name. Returns: - Dict[str, Any]: Output contains asset document + Dict[str, Any]: Output contains folder entity and loaded containers. """ # Make sure all data are not empty - if not asset_doc_data or not build_profiles or not loaders_by_name: + if not linked_folder_data or not build_profiles or not loaders_by_name: return - asset_doc = asset_doc_data["asset_doc"] + folder_entity = linked_folder_data["folder_entity"] valid_profiles = self._filter_build_profiles( build_profiles, loaders_by_name @@ -442,7 +473,7 @@ class BuildWorkfile: products_by_id = {} version_by_product_id = {} repres_by_version_id = {} - for product_id, in_data in asset_doc_data["subsets"].items(): + for product_id, in_data in linked_folder_data["subsets"].items(): subset_doc = in_data["subset_doc"] products_by_id[subset_doc["_id"]] = subset_doc @@ -454,8 +485,8 @@ class BuildWorkfile: ) if not products_by_id: - self.log.warning("There are not products for folder {0}".format( - asset_doc["name"] + self.log.warning("There are not products for folder {}".format( + folder_entity["path"] )) return @@ -480,7 +511,7 @@ class BuildWorkfile: # DEBUG message msg = "Valid representations for Folder: `{}`".format( - asset_doc["name"] + folder_entity["path"] ) for product_id, repres in valid_repres_by_product_id.items(): subset_doc = products_by_id[product_id] @@ -498,7 +529,7 @@ class BuildWorkfile: ) return { - "asset_doc": asset_doc, + "folder_entity": folder_entity, "containers": containers } @@ -628,11 +659,11 @@ class BuildWorkfile: return loaded_containers - def _collect_last_version_repres(self, asset_docs): - """Collect products, versions and representations for asset_entities. + def _collect_last_version_repres(self, folder_entities): + """Collect products, versions and representations for folder_entities. Args: - asset_docs (List[Dict[str, Any]]): Asset entities for which + folder_entities (List[Dict[str, Any]]): Folder entities for which want to find data. Returns: @@ -641,11 +672,11 @@ class BuildWorkfile: Example output: ``` { - {Asset ID}: { - "asset_doc": , + : { + "folder_entity": , "subsets": { - {Subset ID}: { - "subset_doc": , + : { + "subset_doc": , "version": { "version_doc": , "repres": [ @@ -665,17 +696,17 @@ class BuildWorkfile: from ayon_core.pipeline.context_tools import get_current_project_name output = {} - if not asset_docs: + if not folder_entities: return output - asset_docs_by_ids = { - asset_doc["_id"]: asset_doc - for asset_doc in asset_docs + folder_entities_by_id = { + folder_entity["id"]: folder_entity + for folder_entity in folder_entities } project_name = get_current_project_name() subset_docs = list(get_subsets( - project_name, asset_ids=asset_docs_by_ids.keys() + project_name, asset_ids=folder_entities_by_id.keys() )) subset_docs_by_id = { subset_doc["_id"]: subset_doc @@ -701,11 +732,11 @@ class BuildWorkfile: subset_doc = subset_docs_by_id[product_id] folder_id = subset_doc["parent"] - asset_doc = asset_docs_by_ids[folder_id] + folder_entity = folder_entities_by_id[folder_id] if folder_id not in output: output[folder_id] = { - "asset_doc": asset_doc, + "folder_entity": folder_entity, "subsets": {} } diff --git a/client/ayon_core/pipeline/workfile/path_resolving.py b/client/ayon_core/pipeline/workfile/path_resolving.py index fc0de60b36..5d36f432ad 100644 --- a/client/ayon_core/pipeline/workfile/path_resolving.py +++ b/client/ayon_core/pipeline/workfile/path_resolving.py @@ -5,7 +5,6 @@ import platform import ayon_api -from ayon_core.client import get_asset_by_name from ayon_core.settings import get_project_settings from ayon_core.lib import ( filter_profiles, @@ -17,7 +16,11 @@ from ayon_core.pipeline.template_data import get_template_data def get_workfile_template_key_from_context( - asset_name, task_name, host_name, project_name, project_settings=None + project_name, + folder_path, + task_name, + host_name, + project_settings=None ): """Helper function to get template key for workfile template. @@ -25,41 +28,39 @@ def get_workfile_template_key_from_context( context". Args: - asset_name(str): Name of asset document. - task_name(str): Task name for which is template key retrieved. - Must be available on asset document under `data.tasks`. - host_name(str): Name of host implementation for which is workfile - used. - project_name(str): Project name where asset and task is. - project_settings(Dict[str, Any]): Project settings for passed + project_name (str): Project name. + folder_path (str): Folder path. + task_name (str): Task name. + host_name (str): Host name. + project_settings (Dict[str, Any]): Project settings for passed 'project_name'. Not required at all but makes function faster. """ - asset_doc = get_asset_by_name( - project_name, asset_name, fields=["data.tasks"] + folder_entity = ayon_api.get_folder_by_path( + project_name, folder_path, fields={"id"} ) - asset_tasks = asset_doc.get("data", {}).get("tasks") or {} - task_info = asset_tasks.get(task_name) or {} - task_type = task_info.get("type") + task_entity = ayon_api.get_task_by_name( + project_name, folder_entity["id"], task_name + ) + task_type = task_entity.get("type") return get_workfile_template_key( - task_type, host_name, project_name, project_settings + project_name, task_type, host_name, project_settings ) def get_workfile_template_key( - task_type, host_name, project_name, project_settings=None + project_name, task_type, host_name, project_settings=None ): """Workfile template key which should be used to get workfile template. Function is using profiles from project settings to return right template - for passet task type and host name. + for passed task type and host name. Args: - task_type(str): Name of task type. - host_name(str): Name of host implementation (e.g. "maya", "nuke", ...) - project_name(str): Name of project in which context should look for - settings. + project_name(str): Project name. + task_type(str): Task type. + host_name(str): Host name (e.g. "maya", "nuke", ...) project_settings(Dict[str, Any]): Prepared project settings for project name. Optional to make processing faster. """ @@ -128,9 +129,9 @@ def get_workdir_with_workdir_data( if not template_key: template_key = get_workfile_template_key( + workdir_data["project"]["name"], workdir_data["task"]["type"], workdir_data["app"], - workdir_data["project"]["name"], project_settings ) @@ -144,8 +145,8 @@ def get_workdir_with_workdir_data( def get_workdir( project_entity, - asset_doc, - task_name, + folder_entity, + task_entity, host_name, anatomy=None, template_key=None, @@ -155,8 +156,8 @@ def get_workdir( Args: project_entity (Dict[str, Any]): Project entity. - asset_doc (Dict[str, Any]): Mongo document of asset from MongoDB. - task_name (str): Task name for which are workdir data preapred. + folder_entity (Dict[str, Any]): Folder entity. + task_entity (dict[str, Any]): Task entity. host_name (str): Host which is used to workdir. This is required because workdir template may contain `{app}` key. In `Session` is stored under `AYON_HOST_NAME` key. @@ -180,7 +181,10 @@ def get_workdir( ) workdir_data = get_template_data( - project_entity, asset_doc, task_name, host_name + project_entity, + folder_entity, + task_entity, + host_name, ) # Output is TemplateResult object which contain useful data return get_workdir_with_workdir_data( @@ -341,8 +345,8 @@ def get_last_workfile( def get_custom_workfile_template( project_entity, - asset_doc, - task_name, + folder_entity, + task_entity, host_name, anatomy=None, project_settings=None @@ -360,13 +364,13 @@ def get_custom_workfile_template( points to a file which is copied as first workfile - It is expected that passed argument are already queried documents of - project and asset as parents of processing task name. + It is expected that passed argument are already queried entities of + project and folder as parents of processing task name. Args: project_entity (Dict[str, Any]): Project entity. - asset_doc (Dict[str, Any]): Asset document from MongoDB. - task_name (str): Name of task for which templates are filtered. + folder_entity (Dict[str, Any]): Folder entity. + task_entity (Dict[str, Any]): Task entity. host_name (str): Name of host. anatomy (Anatomy): Optionally passed anatomy object for passed project name. @@ -415,9 +419,9 @@ def get_custom_workfile_template( if anatomy is None: anatomy = Anatomy(project_name) - # get project, asset, task anatomy context data + # get project, folder, task anatomy context data anatomy_context_data = get_template_data( - project_entity, asset_doc, task_name, host_name + project_entity, folder_entity, task_entity, host_name ) # add root dict anatomy_context_data["root"] = anatomy.roots @@ -448,7 +452,7 @@ def get_custom_workfile_template( def get_custom_workfile_template_by_string_context( project_name, - asset_name, + folder_path, task_name, host_name, anatomy=None, @@ -456,13 +460,13 @@ def get_custom_workfile_template_by_string_context( ): """Filter and fill workfile template profiles by passed context. - Passed context are string representations of project, asset and task. - Function will query documents of project and asset to be able use + Passed context are string representations of project, folder and task. + Function will query documents of project and folder to be able to use `get_custom_workfile_template` for rest of logic. Args: project_name (str): Project name. - asset_name (str): Asset name. + folder_path (str): Folder path. task_name (str): Task name. host_name (str): Name of host. anatomy (Anatomy): Optionally prepared anatomy object for passed @@ -476,12 +480,15 @@ def get_custom_workfile_template_by_string_context( """ project_entity = ayon_api.get_project(project_name) - asset_doc = get_asset_by_name(project_name, asset_name) + folder_entity = ayon_api.get_folder_by_path(project_name, folder_path) + task_entity = ayon_api.get_task_by_name( + project_name, folder_entity["id"], task_name + ) return get_custom_workfile_template( project_entity, - asset_doc, - task_name, + folder_entity, + task_entity, host_name, anatomy, project_settings diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 1b5a848ea2..a39c5dd31d 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -18,12 +18,17 @@ import copy from abc import ABCMeta, abstractmethod import six -from ayon_api import get_products, get_last_versions +from ayon_api import ( + get_folders, + get_folder_by_path, + get_folder_links, + get_task_by_name, + get_products, + get_last_versions, +) from ayon_api.graphql_queries import folders_graphql_query from ayon_core.client import ( - get_asset_by_name, - get_linked_assets, get_representations, get_ayon_server_api_connection, ) @@ -48,6 +53,8 @@ from ayon_core.pipeline.create import ( CreateContext, ) +_NOT_SET = object() + class TemplateNotFound(Exception): """Exception raised when template does not exist.""" @@ -117,9 +124,9 @@ class AbstractTemplateBuilder(object): self._project_settings = None - self._current_asset_doc = None - self._linked_asset_docs = None - self._task_type = None + self._current_folder_entity = _NOT_SET + self._current_task_entity = _NOT_SET + self._linked_folder_entities = _NOT_SET @property def project_name(self): @@ -155,33 +162,39 @@ class AbstractTemplateBuilder(object): return self._project_settings @property - def current_asset_doc(self): - if self._current_asset_doc is None: - self._current_asset_doc = get_asset_by_name( + def current_folder_entity(self): + if self._current_folder_entity is _NOT_SET: + self._current_folder_entity = get_folder_by_path( self.project_name, self.current_folder_path ) - return self._current_asset_doc + return self._current_folder_entity @property - def linked_asset_docs(self): - if self._linked_asset_docs is None: - self._linked_asset_docs = get_linked_assets( - self.project_name, self.current_asset_doc - ) - return self._linked_asset_docs + def linked_folder_entities(self): + if self._linked_folder_entities is _NOT_SET: + self._linked_folder_entities = self._get_linked_folder_entities() + return self._linked_folder_entities + + @property + def current_task_entity(self): + if self._current_task_entity is _NOT_SET: + task_entity = None + folder_entity = self.current_folder_entity + if folder_entity: + task_entity = get_task_by_name( + self.project_name, + folder_entity["id"], + self.current_task_name + ) + self._current_task_entity = task_entity + return self._current_task_entity @property def current_task_type(self): - asset_doc = self.current_asset_doc - if not asset_doc: - return None - return ( - asset_doc - .get("data", {}) - .get("tasks", {}) - .get(self.current_task_name, {}) - .get("type") - ) + task_entity = self.current_task_entity + if task_entity: + return task_entity["taskType"] + return None @property def create_context(self): @@ -242,9 +255,9 @@ class AbstractTemplateBuilder(object): self._loaders_by_name = None self._creators_by_name = None - self._current_asset_doc = None - self._linked_asset_docs = None - self._task_type = None + self._current_folder_entity = _NOT_SET + self._current_task_entity = _NOT_SET + self._linked_folder_entities = _NOT_SET self._project_settings = None @@ -256,6 +269,22 @@ class AbstractTemplateBuilder(object): self._loaders_by_name = get_loaders_by_name() return self._loaders_by_name + def _get_linked_folder_entities(self): + project_name = self.project_name + folder_entity = self.current_folder_entity + if not folder_entity: + return [] + links = get_folder_links( + project_name, folder_entity["id"], link_direction="in" + ) + linked_folder_ids = { + link["entityId"] + for link in links + if link["entityType"] == "folder" + } + + return list(get_folders(project_name, folder_ids=linked_folder_ids)) + def _collect_legacy_creators(self): creators_by_name = {} for creator in discover_legacy_creator_plugins(): @@ -305,8 +334,8 @@ class AbstractTemplateBuilder(object): different key or if the key is not already used for something else. Key should be self explanatory to content. - - wrong: 'asset' - - good: 'asset_name' + - wrong: 'folder' + - good: 'folder_name' Args: key (str): Key under which is key stored. @@ -351,8 +380,8 @@ class AbstractTemplateBuilder(object): different key or if the key is not already used for something else. Key should be self explanatory to content. - - wrong: 'asset' - - good: 'asset_name' + - wrong: 'folder' + - good: 'folder_path' Args: key (str): Key under which is key stored. @@ -371,8 +400,8 @@ class AbstractTemplateBuilder(object): different key or if the key is not already used for something else. Key should be self explanatory to content. - - wrong: 'asset' - - good: 'asset_name' + - wrong: 'folder' + - good: 'folder_path' Args: key (str): Key under which is key stored. @@ -1021,8 +1050,8 @@ class PlaceholderPlugin(object): Using shared data from builder but stored under plugin identifier. Key should be self explanatory to content. - - wrong: 'asset' - - good: 'asset_name' + - wrong: 'folder' + - good: 'folder_path' Args: key (str): Key under which is key stored. @@ -1061,8 +1090,8 @@ class PlaceholderPlugin(object): Using shared data from builder but stored under plugin identifier. Key should be self explanatory to content. - - wrong: 'asset' - - good: 'asset_name' + - wrong: 'folder' + - good: 'folder_path' Shared populate data are cleaned up during populate while loop. @@ -1323,7 +1352,7 @@ class PlaceholderLoadMixin(object): items=loader_items, tooltip=( "Loader" - "\nDefines what OpenPype loader will be used to" + "\nDefines what AYON loader will be used to" " load assets." "\nUseable loader depends on current host's loader list." "\nField is case sensitive." @@ -1480,7 +1509,7 @@ class PlaceholderLoadMixin(object): return [] project_name = self.builder.project_name - current_asset_doc = self.builder.current_asset_doc + current_folder_entity = self.builder.current_folder_entity folder_path_regex = placeholder.data["folder_path"] product_name_regex_value = placeholder.data["product_name"] @@ -1492,7 +1521,7 @@ class PlaceholderLoadMixin(object): builder_type = placeholder.data["builder_type"] folder_ids = [] if builder_type == "context_folder": - folder_ids = [current_asset_doc["_id"]] + folder_ids = [current_folder_entity["_id"]] elif builder_type == "all_folders": folder_ids = list(self._query_by_folder_regex( @@ -1547,17 +1576,18 @@ class PlaceholderLoadMixin(object): """Reduce representations to last verison.""" mapping = {} + # TODO use representation context with entities for repre_doc in representations: repre_context = repre_doc["context"] - asset_name = repre_context["asset"] + folder_name = repre_context["asset"] product_name = repre_context["subset"] version = repre_context.get("version", -1) - if asset_name not in mapping: - mapping[asset_name] = {} + if folder_name not in mapping: + mapping[folder_name] = {} - product_mapping = mapping[asset_name] + product_mapping = mapping[folder_name] if product_name not in product_mapping: product_mapping[product_name] = collections.defaultdict(list) @@ -1788,31 +1818,24 @@ class PlaceholderCreateMixin(object): # create product name context = self._builder.get_current_context() project_name = context["project_name"] - asset_name = context["folder_path"] + folder_path = context["folder_path"] task_name = context["task_name"] + host_name = self.builder.host_name - if legacy_create: - asset_doc = get_asset_by_name( - project_name, asset_name, fields=["_id"] - ) - assert asset_doc, "No current asset found in Session" - product_name = creator_plugin.get_product_name( - project_name, - asset_doc["_id"], - task_name, - create_variant, - ) + folder_entity = get_folder_by_path(project_name, folder_path) + if not folder_entity: + raise ValueError("Current context does not have set folder") + task_entity = get_task_by_name( + project_name, folder_entity["id"], task_name + ) - else: - asset_doc = get_asset_by_name(project_name, asset_name) - assert asset_doc, "No current asset found in Session" - product_name = creator_plugin.get_product_name( - project_name, - asset_doc, - task_name, - create_variant, - self.builder.host_name - ) + product_name = creator_plugin.get_product_name( + project_name, + folder_entity, + task_entity, + create_variant, + host_name + ) creator_data = { "creator_name": creator_name, @@ -1828,13 +1851,13 @@ class PlaceholderCreateMixin(object): if legacy_create: creator_instance = creator_plugin( product_name, - asset_name + folder_path ).process() else: creator_instance = self.builder.create_context.create( creator_plugin.identifier, create_variant, - asset_doc, + folder_entity, task_name=task_name, pre_create_data=pre_create_data )