diff --git a/client/ayon_core/pipeline/farm/pyblish_functions.py b/client/ayon_core/pipeline/farm/pyblish_functions.py index 4652d34011..8d875ca56e 100644 --- a/client/ayon_core/pipeline/farm/pyblish_functions.py +++ b/client/ayon_core/pipeline/farm/pyblish_functions.py @@ -58,16 +58,16 @@ def remap_source(path, anatomy): return source -def extend_frames(asset, subset, start, end): +def extend_frames(folder_path, product_name, start, end): """Get latest version of asset nad update frame range. Based on minimum and maximum values. Arguments: - asset (str): asset name - subset (str): subset name - start (int): start frame - end (int): end frame + folder_path (str): Folder path. + product_name (str): Product name. + start (int): Start frame. + end (int): End frame. Returns: (int, int): update frame start/end @@ -80,8 +80,8 @@ def extend_frames(asset, subset, start, end): project_name = get_current_project_name() version = get_last_version_by_subset_name( project_name, - subset, - asset_name=asset + product_name, + asset_name=folder_path ) # Set prev start / end frames for comparison @@ -198,7 +198,7 @@ def create_skeleton_instance( if data.get("extendFrames", False): time_data.start, time_data.end = extend_frames( data["folderPath"], - data["subset"], + data["productName"], time_data.start, time_data.end, ) @@ -215,18 +215,18 @@ def create_skeleton_instance( log.warning(("Could not find root path for remapping \"{}\". " "This may cause issues.").format(source)) - family = ("render" + product_type = ("render" if "prerender.farm" not in instance.data["families"] else "prerender") - families = [family] + families = [product_type] # pass review to families if marked as review if data.get("review"): families.append("review") instance_skeleton_data = { - "family": family, - "subset": data["subset"], + "productType": product_type, + "productName": data["productName"], "families": families, "folderPath": data["folderPath"], "frameStart": time_data.start, @@ -472,8 +472,8 @@ def create_instances_for_aov(instance, skeleton, aov_filter, expected files. """ - # we cannot attach AOVs to other subsets as we consider every - # AOV subset of its own. + # we cannot attach AOVs to other products as we consider every + # AOV product of its own. log = Logger.get_logger("farm_publishing") additional_color_data = { @@ -493,7 +493,7 @@ def create_instances_for_aov(instance, skeleton, aov_filter, log.warning(e) additional_color_data["colorspaceTemplate"] = colorspace_template - # if there are subset to attach to and more than one AOV, + # if there are product to attach to and more than one AOV, # we cannot proceed. if ( len(instance.data.get("attachTo", [])) > 0 @@ -501,7 +501,7 @@ def create_instances_for_aov(instance, skeleton, aov_filter, ): raise KnownPublishError( "attaching multiple AOVs or renderable cameras to " - "subset is not supported yet.") + "product is not supported yet.") # create instances for every AOV we found in expected files. # NOTE: this is done for every AOV and every render camera (if @@ -544,7 +544,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, task = os.environ["AYON_TASK_NAME"] anatomy = instance.context.data["anatomy"] - subset = skeleton["subset"] + s_product_name = skeleton["productName"] cameras = instance.data.get("cameras", []) exp_files = instance.data["expectedFiles"] log = Logger.get_logger("farm_publishing") @@ -570,34 +570,33 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, ext = cols[0].tail.lstrip(".") col = list(cols[0]) - # create subset name `familyTaskSubset_AOV` + # create product name `` # TODO refactor/remove me - family = skeleton["family"] - if not subset.startswith(family): + product_type = skeleton["productType"] + if not s_product_name.startswith(product_type): group_name = '{}{}{}{}{}'.format( - family, + product_type, task[0].upper(), task[1:], - subset[0].upper(), subset[1:]) + s_product_name[0].upper(), s_product_name[1:]) else: - group_name = subset + group_name = s_product_name # if there are multiple cameras, we need to add camera name expected_filepath = col[0] if isinstance(col, (list, tuple)) else col cams = [cam for cam in cameras if cam in expected_filepath] if cams: for cam in cams: - if aov: - if not aov.startswith(cam): - subset_name = '{}_{}_{}'.format(group_name, cam, aov) - else: - subset_name = "{}_{}".format(group_name, aov) + if not aov: + product_name = '{}_{}'.format(group_name, cam) + elif not aov.startswith(cam): + product_name = '{}_{}_{}'.format(group_name, cam, aov) else: - subset_name = '{}_{}'.format(group_name, cam) + product_name = "{}_{}".format(group_name, aov) else: if aov: - subset_name = '{}_{}'.format(group_name, aov) + product_name = '{}_{}'.format(group_name, aov) else: - subset_name = '{}'.format(group_name) + product_name = '{}'.format(group_name) if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) @@ -609,7 +608,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, except ValueError as e: log.warning(e) - log.info("Creating data for: {}".format(subset_name)) + log.info("Creating data for: {}".format(product_name)) app = os.environ.get("AYON_HOST_NAME", "") @@ -626,7 +625,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, preview = True new_instance = deepcopy(skeleton) - new_instance["subset"] = subset_name + new_instance["productName"] = product_name new_instance["subsetGroup"] = group_name # explicitly disable review by user @@ -778,7 +777,7 @@ def create_skeleton_instance_cache(instance): if data.get("extendFrames", False): time_data.start, time_data.end = extend_frames( data["folderPath"], - data["subset"], + data["productName"], time_data.start, time_data.end, ) @@ -795,15 +794,15 @@ def create_skeleton_instance_cache(instance): log.warning(("Could not find root path for remapping \"{}\". " "This may cause issues.").format(source)) - family = instance.data["family"] + product_type = instance.data["productType"] # Make sure "render" is in the families to go through # validating expected and rendered files # during publishing job. - families = ["render", family] + families = ["render", product_type] instance_skeleton_data = { - "family": family, - "subset": data["subset"], + "productType": product_type, + "productName": data["productName"], "families": families, "folderPath": data["folderPath"], "frameStart": time_data.start, @@ -910,8 +909,8 @@ def create_instances_for_cache(instance, skeleton): """ anatomy = instance.context.data["anatomy"] - subset = skeleton["subset"] - family = skeleton["family"] + product_name = skeleton["productName"] + product_type = skeleton["productType"] exp_files = instance.data["expectedFiles"] log = Logger.get_logger("farm_publishing") @@ -948,9 +947,9 @@ def create_instances_for_cache(instance, skeleton): new_instance = deepcopy(skeleton) - new_instance["subset"] = subset - log.info("Creating data for: {}".format(subset)) - new_instance["family"] = family + new_instance["productName"] = product_name + log.info("Creating data for: {}".format(product_name)) + new_instance["productType"] = product_type new_instance["families"] = skeleton["families"] # create representation if isinstance(col, (list, tuple)): @@ -984,7 +983,7 @@ def create_instances_for_cache(instance, skeleton): def copy_extend_frames(instance, representation): """Copy existing frames from latest version. - This will copy all existing frames from subset's latest version back + This will copy all existing frames from product's latest version back to render directory and rename them to what renderer is expecting. Arguments: @@ -1005,20 +1004,20 @@ def copy_extend_frames(instance, representation): project_name = instance.context.data["project"] anatomy = instance.context.data["anatomy"] # type: Anatomy - # get latest version of subset - # this will stop if subset wasn't published yet + # get latest version of product + # this will stop if product wasn't published yet version = get_last_version_by_subset_name( project_name, - instance.data.get("subset"), + instance.data.get("productName"), asset_name=instance.data.get("folderPath") ) # get its files based on extension - subset_resources = get_resources( + product_resources = get_resources( project_name, version, representation.get("ext") ) - r_col, _ = clique.assemble(subset_resources) + r_col, _ = clique.assemble(product_resources) # if override remove all frames we are expecting to be rendered, # so we'll copy only those missing from current render @@ -1064,11 +1063,11 @@ def copy_extend_frames(instance, representation): log.info("Finished copying %i files" % len(resource_files)) -def attach_instances_to_subset(attach_to, instances): - """Attach instance to subset. +def attach_instances_to_product(attach_to, instances): + """Attach instance to product. - If we are attaching to other subsets, create copy of existing - instances, change data to match its subset and replace + If we are attaching to other products, create copy of existing + instances, change data to match its product and replace existing instances with modified data. Args: @@ -1084,8 +1083,8 @@ def attach_instances_to_subset(attach_to, instances): for i in instances: new_inst = copy.deepcopy(i) new_inst["version"] = attach_instance.get("version") - new_inst["subset"] = attach_instance.get("subset") - new_inst["family"] = attach_instance.get("family") + new_inst["productName"] = attach_instance.get("productName") + new_inst["productType"] = attach_instance.get("productType") new_inst["append"] = True # don't set subsetGroup if we are attaching new_inst.pop("subsetGroup") @@ -1108,7 +1107,7 @@ def create_metadata_path(instance, anatomy): # directory is not available log.warning("Path is unreachable: `{}`".format(output_dir)) - metadata_filename = "{}_metadata.json".format(ins_data["subset"]) + metadata_filename = "{}_metadata.json".format(ins_data["productName"]) metadata_path = os.path.join(output_dir, metadata_filename) diff --git a/client/ayon_core/pipeline/farm/pyblish_functions.pyi b/client/ayon_core/pipeline/farm/pyblish_functions.pyi index d9d46a63be..16c11aa480 100644 --- a/client/ayon_core/pipeline/farm/pyblish_functions.pyi +++ b/client/ayon_core/pipeline/farm/pyblish_functions.pyi @@ -16,9 +16,9 @@ class TimeData: ... def remap_source(source: str, anatomy: Anatomy): ... -def extend_frames(asset: str, subset: str, start: int, end: int) -> Tuple[int, int]: ... +def extend_frames(folder_path: str, product_name: str, start: int, end: int) -> Tuple[int, int]: ... def get_time_data_from_instance_or_context(instance: pyblish.api.Instance) -> TimeData: ... def get_transferable_representations(instance: pyblish.api.Instance) -> list: ... def create_skeleton_instance(instance: pyblish.api.Instance, families_transfer: list = ..., instance_transfer: dict = ...) -> dict: ... def create_instances_for_aov(instance: pyblish.api.Instance, skeleton: dict, aov_filter: dict) -> List[pyblish.api.Instance]: ... -def attach_instances_to_subset(attach_to: list, instances: list) -> list: ... +def attach_instances_to_product(attach_to: list, instances: list) -> list: ... diff --git a/client/ayon_core/pipeline/farm/tools.py b/client/ayon_core/pipeline/farm/tools.py index f3acac7a32..8ab3b87ff6 100644 --- a/client/ayon_core/pipeline/farm/tools.py +++ b/client/ayon_core/pipeline/farm/tools.py @@ -5,8 +5,9 @@ def get_published_workfile_instance(context): """Find workfile instance in context""" for i in context: is_workfile = ( - "workfile" in i.data.get("families", []) or - i.data["family"] == "workfile" + i.data["productType"] == "workfile" + or "workfile" in i.data.get("families", []) + ) if not is_workfile: continue diff --git a/client/ayon_core/pipeline/publish/abstract_collect_render.py b/client/ayon_core/pipeline/publish/abstract_collect_render.py index 6ca1d81bc7..4ec38bbdd5 100644 --- a/client/ayon_core/pipeline/publish/abstract_collect_render.py +++ b/client/ayon_core/pipeline/publish/abstract_collect_render.py @@ -28,10 +28,11 @@ class RenderInstance(object): time = attr.ib() # time of instance creation (get_formatted_current_time) source = attr.ib() # path to source scene file label = attr.ib() # label to show in GUI - subset = attr.ib() # subset name - task = attr.ib() # task name + productType = attr.ib() # product type + productName = attr.ib() # product name folderPath = attr.ib() # folder path - attachTo = attr.ib() # subset name to attach render to + task = attr.ib() # task name + attachTo = attr.ib() # product name to attach render to setMembers = attr.ib() # list of nodes/members producing render output publish = attr.ib() # bool, True to publish instance name = attr.ib() # instance name @@ -60,7 +61,7 @@ class RenderInstance(object): review = attr.ib(default=None) # False - explicitly skip review priority = attr.ib(default=50) # job priority on farm - family = attr.ib(default="renderlayer") + # family = attr.ib(default="renderlayer") families = attr.ib(default=["renderlayer"]) # list of families # True if should be rendered on farm, eg not integrate farm = attr.ib(default=False) @@ -153,13 +154,13 @@ class AbstractCollectRender(pyblish.api.ContextPlugin): exp_files = self.get_expected_files(render_instance) assert exp_files, "no file names were generated, this is bug" - # if we want to attach render to subset, check if we have AOV's + # if we want to attach render to product, check if we have AOV's # in expectedFiles. If so, raise error as we cannot attach AOV - # (considered to be subset on its own) to another subset + # (considered to be product on its own) to another product if render_instance.attachTo: assert isinstance(exp_files, list), ( "attaching multiple AOVs or renderable cameras to " - "subset is not supported" + "product is not supported" ) frame_start_render = int(render_instance.frameStart) diff --git a/client/ayon_core/pipeline/publish/lib.py b/client/ayon_core/pipeline/publish/lib.py index 7d980b4bbe..c61bac7f9a 100644 --- a/client/ayon_core/pipeline/publish/lib.py +++ b/client/ayon_core/pipeline/publish/lib.py @@ -105,7 +105,7 @@ def get_hero_template_name_profiles( def get_publish_template_name( project_name, host_name, - family, + product_type, task_name, task_type, project_settings=None, @@ -123,7 +123,7 @@ def get_publish_template_name( Args: project_name (str): Name of project where to look for settings. host_name (str): Name of host integration. - family (str): Family for which should be found template. + product_type (str): Product type for which should be found template. task_name (str): Task name on which is instance working. task_type (str): Task type on which is instance working. project_settings (Dict[str, Any]): Prepared project settings. @@ -138,7 +138,7 @@ def get_publish_template_name( template = None filter_criteria = { "hosts": host_name, - "product_types": family, + "product_types": product_type, "task_names": task_name, "task_types": task_type, } @@ -701,19 +701,26 @@ def get_publish_repre_path(instance, repre, only_published=False): return None -def get_custom_staging_dir_info(project_name, host_name, family, task_name, - task_type, subset_name, - project_settings=None, - anatomy=None, log=None): +def get_custom_staging_dir_info( + project_name, + host_name, + product_type, + task_name, + task_type, + product_name, + project_settings=None, + anatomy=None, + log=None +): """Checks profiles if context should use special custom dir as staging. Args: project_name (str) host_name (str) - family (str) + product_type (str) task_name (str) task_type (str) - subset_name (str) + product_name (str) project_settings(Dict[str, Any]): Prepared project settings. anatomy (Dict[str, Any]) log (Logger) (optional) @@ -736,10 +743,10 @@ def get_custom_staging_dir_info(project_name, host_name, family, task_name, filtering_criteria = { "hosts": host_name, - "families": family, + "families": product_type, "task_names": task_name, "task_types": task_type, - "subsets": subset_name + "subsets": product_name } profile = filter_profiles(custom_staging_dir_profiles, filtering_criteria, @@ -780,18 +787,18 @@ def _validate_transient_template(project_name, template_name, anatomy): def get_published_workfile_instance(context): """Find workfile instance in context""" for i in context: - is_workfile = ( - "workfile" in i.data.get("families", []) or - i.data["family"] == "workfile" - ) - if not is_workfile: - continue - # test if there is instance of workfile waiting # to be published. if not i.data.get("publish", True): continue + if not ( + i.data["productType"] == "workfile" + # QUESTION Is check in 'families' valid? + or "workfile" in i.data.get("families", []) + ): + continue + return i @@ -917,7 +924,7 @@ def get_publish_instance_label(instance): is used string conversion of instance object -> 'instance._name'. Todos: - Maybe 'subset' key could be used too. + Maybe 'productName' key could be used too. Args: instance (pyblish.api.Instance): Pyblish instance. @@ -936,8 +943,8 @@ def get_publish_instance_label(instance): def get_publish_instance_families(instance): """Get all families of the instance. - Look for families under 'family' and 'families' keys in instance data. - Value of 'family' is used as first family and then all other families + Look for families under 'productType' and 'families' keys in instance data. + Value of 'productType' is used as first family and then all other families in random order. Args: @@ -947,11 +954,11 @@ def get_publish_instance_families(instance): list[str]: List of families. """ - family = instance.data.get("family") + product_type = instance.data.get("productType") families = set(instance.data.get("families") or []) output = [] - if family: - output.append(family) - families.discard(family) + if product_type: + output.append(product_type) + families.discard(product_type) output.extend(families) return output diff --git a/client/ayon_core/pipeline/version_start.py b/client/ayon_core/pipeline/version_start.py index 4813910bf3..7ee20a5dd4 100644 --- a/client/ayon_core/pipeline/version_start.py +++ b/client/ayon_core/pipeline/version_start.py @@ -7,8 +7,8 @@ def get_versioning_start( host_name, task_name=None, task_type=None, - family=None, - subset=None, + product_type=None, + product_name=None, project_settings=None, ): """Get anatomy versioning start""" @@ -22,12 +22,14 @@ def get_versioning_start( if not profiles: return version_start + # TODO use 'product_types' and 'product_name' instead of + # 'families' and 'subsets' filtering_criteria = { "host_names": host_name, - "families": family, + "families": product_type, "task_names": task_name, "task_types": task_type, - "subsets": subset + "subsets": product_name } profile = filter_profiles(profiles, filtering_criteria) diff --git a/client/ayon_core/pipeline/workfile/build_workfile.py b/client/ayon_core/pipeline/workfile/build_workfile.py index 3a0d9ba95e..34d8ef0c8f 100644 --- a/client/ayon_core/pipeline/workfile/build_workfile.py +++ b/client/ayon_core/pipeline/workfile/build_workfile.py @@ -48,18 +48,18 @@ class BuildWorkfile: return self._log @staticmethod - def map_subsets_by_family(subsets): - subsets_by_family = collections.defaultdict(list) - for subset in subsets: - family = subset["data"].get("family") - if not family: - families = subset["data"].get("families") + def map_products_by_type(subset_docs): + products_by_type = collections.defaultdict(list) + for subset_doc in subset_docs: + product_type = subset_doc["data"].get("family") + if not product_type: + families = subset_doc["data"].get("families") if not families: continue - family = families[0] + product_type = families[0] - subsets_by_family[family].append(subset) - return subsets_by_family + products_by_type[product_type].append(subset_doc) + return products_by_type def process(self): """Main method of this wrapper. @@ -80,17 +80,17 @@ class BuildWorkfile: stored in Workfile profiles from presets. Profiles are set by host, filtered by current task name and used by families. - Each family can specify representation names and loaders for + 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. loaded_containers [{ - "asset_entity": , + "asset_doc": , "containers": [, , ...] }, { - "asset_entity": , + "asset_doc": , "containers": [, ...] }, { ... @@ -110,14 +110,14 @@ class BuildWorkfile: # Get current asset name and entity project_name = get_current_project_name() - current_asset_name = get_current_asset_name() - current_asset_entity = get_asset_by_name( - project_name, current_asset_name + current_folder_path = get_current_asset_name() + current_asset_doc = get_asset_by_name( + project_name, current_folder_path ) # Skip if asset was not found - if not current_asset_entity: - print("Asset entity with name `{}` was not found".format( - current_asset_name + if not current_asset_doc: + print("Folder entity `{}` was not found".format( + current_folder_path )) return loaded_containers @@ -143,7 +143,7 @@ class BuildWorkfile: # Load workfile presets for task self.build_presets = self.get_build_presets( - current_task_name, current_asset_entity + current_task_name, current_asset_doc ) # Skip if there are any presets for task @@ -155,9 +155,9 @@ class BuildWorkfile: ) return loaded_containers - # Get presets for loading current asset + # Get presets for loading current folder current_context_profiles = self.build_presets.get("current_context") - # Get presets for loading linked assets + # Get presets for loading linked folders link_context_profiles = self.build_presets.get("linked_assets") # Skip if both are missing if not current_context_profiles and not link_context_profiles: @@ -177,38 +177,38 @@ class BuildWorkfile: elif not link_context_profiles: self.log.warning(( "Current task `{}` doesn't have any" - "loading preset for it's linked assets." + "loading preset for it's linked folders." ).format(current_task_name)) # Prepare assets to process by workfile presets - assets = [] - current_asset_id = None + asset_docs = [] + current_folder_id = None if current_context_profiles: # Add current asset entity if preset has current context set - assets.append(current_asset_entity) - current_asset_id = current_asset_entity["_id"] + asset_docs.append(current_asset_doc) + current_folder_id = current_asset_doc["_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_entity) + link_assets = get_linked_assets(project_name, current_asset_doc) if link_assets: - assets.extend(link_assets) + asset_docs.extend(link_assets) # 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 assets: + if not asset_docs: self.log.warning( "Asset does not have linked assets. Nothing to process." ) return loaded_containers # Prepare entities from database for assets - prepared_entities = self._collect_last_version_repres(assets) + prepared_entities = self._collect_last_version_repres(asset_docs) # Load containers by prepared entities and presets # - Current asset containers - if current_asset_id and current_asset_id in prepared_entities: - current_context_data = prepared_entities.pop(current_asset_id) + 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 ) @@ -281,7 +281,7 @@ class BuildWorkfile: with valid values. - "loaders" expects list of strings representing possible loaders. - "families" expects list of strings for filtering - by main subset family. + by product type. - "repre_names" expects list of strings for filtering by representation name. @@ -349,33 +349,33 @@ class BuildWorkfile: return valid_profiles - def _prepare_profile_for_subsets(self, subsets, profiles): - """Select profile for each subset by it's data. + def _prepare_profile_for_products(self, subset_docs, profiles): + """Select profile for each product by it's data. - Profiles are filtered for each subset individually. - Profile is filtered by subset's family, optionally by name regex and + Profiles are filtered for each product individually. + Profile is filtered by product type, optionally by name regex and representation names set in profile. - It is possible to not find matching profile for subset, in that case - subset is skipped and it is possible that none of subsets have + It is possible to not find matching profile for product, in that case + product is skipped and it is possible that none of products have matching profile. Args: - subsets (List[Dict[str, Any]]): Subset documents. + subset_docs (List[Dict[str, Any]]): Subset documents. profiles (List[Dict[str, Any]]): Build profiles. Returns: - Dict[str, Any]: Profile by subset's id. + Dict[str, Any]: Profile by product id. """ - # Prepare subsets - subsets_by_family = self.map_subsets_by_family(subsets) + # Prepare products + products_by_type = self.map_products_by_type(subset_docs) - profiles_per_subset_id = {} - for family, subsets in subsets_by_family.items(): - family_low = family.lower() + profiles_by_product_id = {} + for product_type, subset_docs in products_by_type.items(): + product_type_low = product_type.lower() for profile in profiles: - # Skip profile if does not contain family - if family_low not in profile["product_types_lowered"]: + # Skip profile if does not contain product type + if product_type_low not in profile["product_types_lowered"]: continue # Precompile name filters as regexes @@ -387,31 +387,31 @@ class BuildWorkfile: profile_regexes = _profile_regexes # TODO prepare regex compilation - for subset in subsets: + for subset_doc in subset_docs: # Verify regex filtering (optional) if profile_regexes: valid = False for pattern in profile_regexes: - if re.match(pattern, subset["name"]): + if re.match(pattern, subset_doc["name"]): valid = True break if not valid: continue - profiles_per_subset_id[subset["_id"]] = profile + profiles_by_product_id[subset_doc["_id"]] = profile # break profiles loop on finding the first matching profile break - return profiles_per_subset_id + return profiles_by_product_id def load_containers_by_asset_data( - self, asset_entity_data, build_profiles, loaders_by_name + self, asset_doc_data, build_profiles, loaders_by_name ): """Load containers for entered asset entity by Build profiles. Args: - asset_entity_data (Dict[str, Any]): Prepared data with subsets, + asset_doc_data (Dict[str, Any]): Prepared data with products, last versions and representations for specific asset. build_profiles (Dict[str, Any]): Build profiles. loaders_by_name (Dict[str, LoaderPlugin]): Available loaders @@ -423,10 +423,10 @@ class BuildWorkfile: """ # Make sure all data are not empty - if not asset_entity_data or not build_profiles or not loaders_by_name: + if not asset_doc_data or not build_profiles or not loaders_by_name: return - asset_entity = asset_entity_data["asset_entity"] + asset_doc = asset_doc_data["asset_doc"] valid_profiles = self._filter_build_profiles( build_profiles, loaders_by_name @@ -439,53 +439,53 @@ class BuildWorkfile: self.log.debug("Valid Workfile profiles: {}".format(valid_profiles)) - subsets_by_id = {} - version_by_subset_id = {} + products_by_id = {} + version_by_product_id = {} repres_by_version_id = {} - for subset_id, in_data in asset_entity_data["subsets"].items(): - subset_entity = in_data["subset_entity"] - subsets_by_id[subset_entity["_id"]] = subset_entity + for product_id, in_data in asset_doc_data["subsets"].items(): + subset_doc = in_data["subset_doc"] + products_by_id[subset_doc["_id"]] = subset_doc version_data = in_data["version"] - version_entity = version_data["version_entity"] - version_by_subset_id[subset_id] = version_entity - repres_by_version_id[version_entity["_id"]] = ( + version_doc = version_data["version_doc"] + version_by_product_id[product_id] = version_doc + repres_by_version_id[version_doc["_id"]] = ( version_data["repres"] ) - if not subsets_by_id: - self.log.warning("There are not subsets for asset {0}".format( - asset_entity["name"] + if not products_by_id: + self.log.warning("There are not products for folder {0}".format( + asset_doc["name"] )) return - profiles_per_subset_id = self._prepare_profile_for_subsets( - subsets_by_id.values(), valid_profiles + profiles_by_product_id = self._prepare_profile_for_products( + products_by_id.values(), valid_profiles ) - if not profiles_per_subset_id: - self.log.warning("There are not valid subsets.") + if not profiles_by_product_id: + self.log.warning("There are not valid products.") return - valid_repres_by_subset_id = collections.defaultdict(list) - for subset_id, profile in profiles_per_subset_id.items(): + valid_repres_by_product_id = collections.defaultdict(list) + for product_id, profile in profiles_by_product_id.items(): profile_repre_names = profile["repre_names_lowered"] - version_entity = version_by_subset_id[subset_id] - version_id = version_entity["_id"] + version_doc = version_by_product_id[product_id] + version_id = version_doc["_id"] repres = repres_by_version_id[version_id] for repre in repres: repre_name_low = repre["name"].lower() if repre_name_low in profile_repre_names: - valid_repres_by_subset_id[subset_id].append(repre) + valid_repres_by_product_id[product_id].append(repre) # DEBUG message - msg = "Valid representations for Asset: `{}`".format( - asset_entity["name"] + msg = "Valid representations for Folder: `{}`".format( + asset_doc["name"] ) - for subset_id, repres in valid_repres_by_subset_id.items(): - subset = subsets_by_id[subset_id] - msg += "\n# Subset Name/ID: `{}`/{}".format( - subset["name"], subset_id + for product_id, repres in valid_repres_by_product_id.items(): + subset_doc = products_by_id[product_id] + msg += "\n# Product Name/ID: `{}`/{}".format( + subset_doc["name"], product_id ) for repre in repres: msg += "\n## Repre name: `{}`".format(repre["name"]) @@ -493,37 +493,37 @@ class BuildWorkfile: self.log.debug(msg) containers = self._load_containers( - valid_repres_by_subset_id, subsets_by_id, - profiles_per_subset_id, loaders_by_name + valid_repres_by_product_id, products_by_id, + profiles_by_product_id, loaders_by_name ) return { - "asset_entity": asset_entity, + "asset_doc": asset_doc, "containers": containers } def _load_containers( - self, repres_by_subset_id, subsets_by_id, - profiles_per_subset_id, loaders_by_name + self, repres_by_product_id, products_by_id, + profiles_by_product_id, loaders_by_name ): """Real load by collected data happens here. - Loading of representations per subset happens here. Each subset can + Loading of representations per product happens here. Each product can loads one representation. Loading is tried in specific order. Representations are tried to load by names defined in configuration. - If subset has representation matching representation name each loader + If product has representation matching representation name each loader is tried to load it until any is successful. If none of them was successful then next representation name is tried. Subset process loop ends when any representation is loaded or all matching representations were already tried. Args: - repres_by_subset_id (Dict[str, Dict[str, Any]]): Available - representations mapped by their parent (subset) id. - subsets_by_id (Dict[str, Dict[str, Any]]): Subset documents + repres_by_product_id (Dict[str, Dict[str, Any]]): Available + representations mapped by their parent (product) id. + products_by_id (Dict[str, Dict[str, Any]]): Subset documents mapped by their id. - profiles_per_subset_id (Dict[str, Dict[str, Any]]): Build profiles - mapped by subset id. + profiles_by_product_id (Dict[str, Dict[str, Any]]): Build profiles + mapped by product id. loaders_by_name (Dict[str, LoaderPlugin]): Available loaders per name. @@ -533,38 +533,40 @@ class BuildWorkfile: loaded_containers = [] - # Get subset id order from build presets. + # Get product id order from build presets. build_presets = self.build_presets.get("current_context", []) build_presets += self.build_presets.get("linked_assets", []) - subset_ids_ordered = [] + product_ids_ordered = [] for preset in build_presets: - for preset_family in preset["product_types"]: - for id, subset in subsets_by_id.items(): - if preset_family not in subset["data"].get("families", []): + for product_type in preset["product_types"]: + for product_id, subset_doc in products_by_id.items(): + # TODO 'families' is not available on product + families = subset_doc["data"].get("families") or [] + if product_type not in families: continue - subset_ids_ordered.append(id) + product_ids_ordered.append(product_id) - # Order representations from subsets. - print("repres_by_subset_id", repres_by_subset_id) + # Order representations from products. + print("repres_by_product_id", repres_by_product_id) representations_ordered = [] representations = [] - for id in subset_ids_ordered: - for subset_id, repres in repres_by_subset_id.items(): + for ordered_product_id in product_ids_ordered: + for product_id, repres in repres_by_product_id.items(): if repres in representations: continue - if id == subset_id: - representations_ordered.append((subset_id, repres)) + if ordered_product_id == product_id: + representations_ordered.append((product_id, repres)) representations.append(repres) print("representations", representations) # Load ordered representations. - for subset_id, repres in representations_ordered: - subset_name = subsets_by_id[subset_id]["name"] + for product_id, repres in representations_ordered: + product_name = products_by_id[product_id]["name"] - profile = profiles_per_subset_id[subset_id] + profile = profiles_by_product_id[product_id] loaders_last_idx = len(profile["loaders"]) - 1 repre_names_last_idx = len(profile["repre_names_lowered"]) - 1 @@ -595,7 +597,7 @@ class BuildWorkfile: container = load_container( loader, repre["_id"], - name=subset_name + name=product_name ) loaded_containers.append(container) is_loaded = True @@ -618,8 +620,8 @@ class BuildWorkfile: msg += " Trying next loader." elif repre_name_idx < repre_names_last_idx: msg += ( - " Loading of subset `{}` was not successful." - ).format(subset_name) + " Loading of product `{}` was not successful." + ).format(product_name) else: msg += " Trying next representation." self.log.info(msg) @@ -627,7 +629,7 @@ class BuildWorkfile: return loaded_containers def _collect_last_version_repres(self, asset_docs): - """Collect subsets, versions and representations for asset_entities. + """Collect products, versions and representations for asset_entities. Args: asset_docs (List[Dict[str, Any]]): Asset entities for which @@ -640,12 +642,12 @@ class BuildWorkfile: ``` { {Asset ID}: { - "asset_entity": , + "asset_doc": , "subsets": { {Subset ID}: { - "subset_entity": , + "subset_doc": , "version": { - "version_entity": , + "version_doc": , "repres": [ , , ... ] @@ -656,7 +658,7 @@ class BuildWorkfile: }, ... } - output[asset_id]["subsets"][subset_id]["version"]["repres"] + output[folder_id]["subsets"][product_id]["version"]["repres"] ``` """ @@ -666,20 +668,26 @@ class BuildWorkfile: if not asset_docs: return output - asset_docs_by_ids = {asset["_id"]: asset for asset in asset_docs} + asset_docs_by_ids = { + asset_doc["_id"]: asset_doc + for asset_doc in asset_docs + } project_name = get_current_project_name() - subsets = list(get_subsets( + subset_docs = list(get_subsets( project_name, asset_ids=asset_docs_by_ids.keys() )) - subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} + subset_docs_by_id = { + subset_doc["_id"]: subset_doc + for subset_doc in subset_docs + } - last_version_by_subset_id = get_last_versions( - project_name, subset_entity_by_ids.keys() + last_version_by_product_id = get_last_versions( + project_name, subset_docs_by_id.keys() ) last_version_docs_by_id = { version["_id"]: version - for version in last_version_by_subset_id.values() + for version in last_version_by_product_id.values() } repre_docs = get_representations( project_name, version_ids=last_version_docs_by_id.keys() @@ -689,28 +697,28 @@ class BuildWorkfile: version_id = repre_doc["parent"] version_doc = last_version_docs_by_id[version_id] - subset_id = version_doc["parent"] - subset_doc = subset_entity_by_ids[subset_id] + product_id = version_doc["parent"] + subset_doc = subset_docs_by_id[product_id] - asset_id = subset_doc["parent"] - asset_doc = asset_docs_by_ids[asset_id] + folder_id = subset_doc["parent"] + asset_doc = asset_docs_by_ids[folder_id] - if asset_id not in output: - output[asset_id] = { - "asset_entity": asset_doc, + if folder_id not in output: + output[folder_id] = { + "asset_doc": asset_doc, "subsets": {} } - if subset_id not in output[asset_id]["subsets"]: - output[asset_id]["subsets"][subset_id] = { - "subset_entity": subset_doc, + if product_id not in output[folder_id]["subsets"]: + output[folder_id]["subsets"][product_id] = { + "subset_doc": subset_doc, "version": { - "version_entity": version_doc, + "version_doc": version_doc, "repres": [] } } - output[asset_id]["subsets"][subset_id]["version"]["repres"].append( + output[folder_id]["subsets"][product_id]["version"]["repres"].append( repre_doc ) diff --git a/client/ayon_core/pipeline/workfile/path_resolving.py b/client/ayon_core/pipeline/workfile/path_resolving.py index 168e775475..7718e32317 100644 --- a/client/ayon_core/pipeline/workfile/path_resolving.py +++ b/client/ayon_core/pipeline/workfile/path_resolving.py @@ -321,7 +321,7 @@ def get_last_workfile( data["app"], task_name=data["task"]["name"], task_type=data["task"]["type"], - family="workfile" + product_type="workfile" ) data.pop("comment", None) if not data.get("ext"):