AYON: Preparation for products (#5038)

* removed settings of IntegrateAssetNew

* added 'active' to 'ValidateEditorialAssetName' plugin settings

* removed unused 'families_to_review' setting from tvpain

* implemented product name -> subset and product type -> family conversion

* fixed most of conversion utils related to subsets

* removed unused constants

* anatomy templates are handling folder and product in templates

* handle all possible template changes of asset, subest and family in settings

* updated ayon api

* updated fixed ayon api

* added conversion functions for representations

* fixed 'get_thumbnail' compatibility

* use del to handle ayon mode in intput links

* changed labels in UI based on AYON mode

* updated ayon_api with 0.2.0 release code
This commit is contained in:
Jakub Trllo 2023-06-01 10:10:24 +02:00 committed by Jakub Trllo
parent eed665be31
commit b48e7ebfe4
31 changed files with 1194 additions and 929 deletions

View file

@ -1468,7 +1468,9 @@ def get_thumbnails(project_name, thumbnail_ids, fields=None):
return conn.find(query_filter, _prepare_fields(fields))
def get_thumbnail(project_name, thumbnail_id, fields=None):
def get_thumbnail(
project_name, thumbnail_id, entity_type, entity_id, fields=None
):
"""Receive thumbnail entity data.
Args:

View file

@ -1,13 +1,3 @@
# --- Project ---
DEFAULT_PROJECT_FIELDS = {
"active",
"name",
"code",
"config",
"data",
"createdAt",
}
# --- Folders ---
DEFAULT_FOLDER_FIELDS = {
"id",
@ -19,47 +9,6 @@ DEFAULT_FOLDER_FIELDS = {
"thumbnailId"
}
# --- Tasks ---
DEFAULT_TASK_FIELDS = {
"id",
"name",
"taskType",
"assignees",
}
# --- Subsets ---
DEFAULT_SUBSET_FIELDS = {
"id",
"name",
"active",
"family",
"folderId",
}
# --- Versions ---
DEFAULT_VERSION_FIELDS = {
"id",
"name",
"version",
"active",
"subsetId",
"taskId",
"author",
"thumbnailId",
"createdAt",
"updatedAt",
}
# --- Representations ---
DEFAULT_REPRESENTATION_FIELDS = {
"id",
"name",
"context",
"createdAt",
"active",
"versionId",
}
REPRESENTATION_FILES_FIELDS = {
"files.name",
"files.hash",
@ -67,17 +16,3 @@ REPRESENTATION_FILES_FIELDS = {
"files.path",
"files.size",
}
DEFAULT_WORKFILE_INFO_FIELDS = {
"active",
"createdAt",
"createdBy",
"id",
"name",
"path",
"projectName",
"taskId",
"thumbnailId",
"updatedAt",
"updatedBy",
}

View file

@ -56,7 +56,7 @@ SUBSET_FIELDS_MAPPING_V3_V4 = {
VERSION_FIELDS_MAPPING_V3_V4 = {
"_id": {"id"},
"name": {"version"},
"parent": {"subsetId"}
"parent": {"productId"}
}
# --- Representation entity ---
@ -130,10 +130,21 @@ def _get_default_template_name(templates):
return default_template
def _template_replacements_to_v3(template):
return (
template
.replace("{folder[name]}", "{asset}")
.replace("{product[name]}", "{subset}")
.replace("{product[type]}", "{family}")
)
def _convert_template_item(template):
template["folder"] = template.pop("directory")
folder = _template_replacements_to_v3(template.pop("directory"))
template["folder"] = folder
template["file"] = _template_replacements_to_v3(template["file"])
template["path"] = "/".join(
(template["folder"], template["file"])
(folder, template["file"])
)
@ -384,7 +395,7 @@ def subset_fields_v3_to_v4(fields, con):
if not fields:
return None
subset_attributes = con.get_attributes_for_type("subset")
product_attributes = con.get_attributes_for_type("product")
output = set()
for field in fields:
@ -395,11 +406,11 @@ def subset_fields_v3_to_v4(fields, con):
output |= SUBSET_FIELDS_MAPPING_V3_V4[field]
elif field == "data":
output.add("family")
output.add("productType")
output.add("active")
output |= {
"attrib.{}".format(attr)
for attr in subset_attributes
for attr in product_attributes
}
elif field.startswith("data"):
@ -407,9 +418,9 @@ def subset_fields_v3_to_v4(fields, con):
field_parts.pop(0)
data_key = ".".join(field_parts)
if data_key in ("family", "families"):
output.add("family")
output.add("productType")
elif data_key in subset_attributes:
elif data_key in product_attributes:
output.add("attrib.{}".format(data_key))
else:
@ -443,9 +454,11 @@ def convert_v4_subset_to_v3(subset):
if "attrib" in subset:
attrib = subset["attrib"]
if "productGroup" in attrib:
attrib["subsetGroup"] = attrib.pop("productGroup")
output_data.update(attrib)
family = subset.get("family")
family = subset.get("productType")
if family:
output_data["family"] = family
output_data["families"] = [family]
@ -537,8 +550,8 @@ def convert_v4_version_to_v3(version):
"type": "hero_version",
"schema": CURRENT_HERO_VERSION_SCHEMA,
}
if "subsetId" in version:
output["parent"] = version["subsetId"]
if "productId" in version:
output["parent"] = version["productId"]
if "data" in version:
output["data"] = version["data"]
@ -550,8 +563,8 @@ def convert_v4_version_to_v3(version):
"name": version_num,
"schema": CURRENT_VERSION_SCHEMA
}
if "subsetId" in version:
output["parent"] = version["subsetId"]
if "productId" in version:
output["parent"] = version["productId"]
output_data = version.get("data") or {}
if "attrib" in version:
@ -647,6 +660,16 @@ def convert_v4_representation_to_v3(representation):
context = representation["context"]
if isinstance(context, six.string_types):
context = json.loads(context)
if "folder" in context:
_c_folder = context.pop("folder")
context["asset"] = _c_folder["name"]
if "product" in context:
_c_product = context.pop("product")
context["family"] = _c_product["type"]
context["subset"] = _c_product["name"]
output["context"] = context
if "files" in representation:
@ -686,6 +709,14 @@ def convert_v4_representation_to_v3(representation):
if key in representation:
output_data[data_key] = representation[key]
if "template" in output_data:
output_data["template"] = (
output_data["template"]
.replace("{folder[name]}", "{asset}")
.replace("{product[name]}", "{subset}")
.replace("{product[type]}", "{family}")
)
output["data"] = output_data
return output
@ -714,7 +745,7 @@ def workfile_info_fields_v3_to_v4(fields):
def convert_v4_workfile_info_to_v3(workfile_info, task):
output = {
"type": "representation",
"type": "workfile",
"schema": CURRENT_WORKFILE_INFO_SCHEMA,
}
if "id" in workfile_info:
@ -790,44 +821,46 @@ def convert_create_task_to_v4(task, project, con):
def convert_create_subset_to_v4(subset, con):
subset_attributes = con.get_attributes_for_type("subset")
product_attributes = con.get_attributes_for_type("product")
subset_data = subset["data"]
family = subset_data.get("family")
if not family:
family = subset_data["families"][0]
product_type = subset_data.get("family")
if not product_type:
product_type = subset_data["families"][0]
converted_subset = {
converted_product = {
"name": subset["name"],
"family": family,
"productType": product_type,
"folderId": subset["parent"],
}
entity_id = subset.get("_id")
if entity_id:
converted_subset["id"] = entity_id
converted_product["id"] = entity_id
attribs = {}
data = {}
if "subsetGroup" in subset_data:
subset_data["productGroup"] = subset_data.pop("subsetGroup")
for key, value in subset_data.items():
if key not in subset_attributes:
if key not in product_attributes:
data[key] = value
elif value is not None:
attribs[key] = value
if attribs:
converted_subset["attrib"] = attribs
converted_product["attrib"] = attribs
if data:
converted_subset["data"] = data
converted_product["data"] = data
return converted_subset
return converted_product
def convert_create_version_to_v4(version, con):
version_attributes = con.get_attributes_for_type("version")
converted_version = {
"version": version["name"],
"subsetId": version["parent"],
"productId": version["parent"],
}
entity_id = version.get("_id")
if entity_id:
@ -870,7 +903,7 @@ def convert_create_hero_version_to_v4(hero_version, project_name, con):
version_attributes = con.get_attributes_for_type("version")
converted_version = {
"version": hero_version["version"],
"subsetId": hero_version["parent"],
"productId": hero_version["parent"],
}
entity_id = hero_version.get("_id")
if entity_id:
@ -923,12 +956,28 @@ def convert_create_representation_to_v4(representation, con):
new_files.append(new_file_item)
converted_representation["files"] = new_files
context = representation["context"]
context["folder"] = {
"name": context.pop("asset", None)
}
context["product"] = {
"type": context.pop("family", None),
"name": context.pop("subset", None),
}
attribs = {}
data = {
"context": representation["context"],
"context": context,
}
representation_data = representation["data"]
representation_data["template"] = (
representation_data["template"]
.replace("{asset}", "{folder[name]}")
.replace("{subset}", "{product[name]}")
.replace("{family}", "{product[type]}")
)
for key, value in representation_data.items():
if key not in representation_attributes:
@ -1073,7 +1122,7 @@ def convert_update_folder_to_v4(project_name, asset_id, update_data, con):
def convert_update_subset_to_v4(project_name, subset_id, update_data, con):
new_update_data = {}
subset_attributes = con.get_attributes_for_type("subset")
product_attributes = con.get_attributes_for_type("product")
full_update_data = _from_flat_dict(update_data)
data = full_update_data.get("data")
new_data = {}
@ -1081,15 +1130,17 @@ def convert_update_subset_to_v4(project_name, subset_id, update_data, con):
if data:
if "family" in data:
family = data.pop("family")
new_update_data["family"] = family
new_update_data["productType"] = family
if "families" in data:
families = data.pop("families")
if "family" not in new_update_data:
new_update_data["family"] = families[0]
if "productType" not in new_update_data:
new_update_data["productType"] = families[0]
if "subsetGroup" in data:
data["productGroup"] = data.pop("subsetGroup")
for key, value in data.items():
if key in subset_attributes:
if key in product_attributes:
if value is REMOVED_VALUE:
value = None
attribs[key] = value
@ -1159,7 +1210,7 @@ def convert_update_version_to_v4(project_name, version_id, update_data, con):
new_update_data["active"] = False
if "parent" in update_data:
new_update_data["subsetId"] = update_data["parent"]
new_update_data["productId"] = update_data["parent"]
flat_data = _to_flat_dict(new_update_data)
if new_data:
@ -1209,6 +1260,14 @@ def convert_update_representation_to_v4(
else:
new_data[key] = value
if "template" in attribs:
attribs["template"] = (
attribs["template"]
.replace("{asset}", "{folder[name]}")
.replace("{family}", "{product[type]}")
.replace("{subset}", "{product[name]}")
)
if "name" in update_data:
new_update_data["name"] = update_data["name"]
@ -1223,7 +1282,16 @@ def convert_update_representation_to_v4(
new_update_data["versionId"] = update_data["parent"]
if "context" in update_data:
new_data["context"] = update_data["context"]
context = update_data["context"]
if "asset" in context:
context["folder"] = {"name": context.pop("asset")}
if "family" in context or "subset" in context:
context["product"] = {
"name": context.pop("subset"),
"type": context.pop("family"),
}
new_data["context"] = context
if "files" in update_data:
new_files = update_data["files"]

View file

@ -79,7 +79,7 @@ def _get_subsets(
if archived:
active = False
for subset in con.get_subsets(
for subset in con.get_products(
project_name,
subset_ids,
subset_names,
@ -105,11 +105,11 @@ def _get_versions(
fields = version_fields_v3_to_v4(fields, con)
# Make sure 'subsetId' and 'version' are available when hero versions
# Make sure 'productId' and 'version' are available when hero versions
# are queried
if fields and hero:
fields = set(fields)
fields |= {"subsetId", "version"}
fields |= {"productId", "version"}
queried_versions = con.get_versions(
project_name,
@ -135,22 +135,22 @@ def _get_versions(
versions_nums = set()
for hero_version in hero_versions:
versions_nums.add(abs(hero_version["version"]))
subset_ids.add(hero_version["subsetId"])
subset_ids.add(hero_version["productId"])
hero_eq_versions = con.get_versions(
project_name,
subset_ids=subset_ids,
product_ids=subset_ids,
versions=versions_nums,
hero=False,
fields=["id", "version", "subsetId"]
fields=["id", "version", "productId"]
)
hero_eq_by_subset_id = collections.defaultdict(list)
for version in hero_eq_versions:
hero_eq_by_subset_id[version["subsetId"]].append(version)
hero_eq_by_subset_id[version["productId"]].append(version)
for hero_version in hero_versions:
abs_version = abs(hero_version["version"])
subset_id = hero_version["subsetId"]
subset_id = hero_version["productId"]
version_id = None
for version in hero_eq_by_subset_id.get(subset_id, []):
if version["version"] == abs_version:
@ -235,7 +235,7 @@ def get_archived_assets(
def get_asset_ids_with_subsets(project_name, asset_ids=None):
con = get_server_api_connection()
return con.get_asset_ids_with_subsets(project_name, asset_ids)
return con.get_folder_ids_with_products(project_name, asset_ids)
def get_subset_by_id(project_name, subset_id, fields=None):
@ -281,7 +281,7 @@ def get_subsets(
def get_subset_families(project_name, subset_ids=None):
con = get_server_api_connection()
return con.get_subset_families(project_name, subset_ids)
return con.get_product_type_names(project_name, subset_ids)
def get_version_by_id(project_name, version_id, fields=None):
@ -618,6 +618,14 @@ def get_thumbnail(
def get_thumbnails(project_name, thumbnail_contexts, fields=None):
"""Get thumbnail entities.
Warning:
This function is not OpenPype compatible. There is none usage of this
function in codebase so there is nothing to convert. The previous
implementation cannot be AYON compatible without entity types.
"""
thumbnail_items = set()
for thumbnail_context in thumbnail_contexts:
thumbnail_id, entity_type, entity_id = thumbnail_context

View file

@ -11,7 +11,7 @@ def folders_tasks_graphql_query(fields):
parent_folder_ids_var = query.add_variable("parentFolderIds", "[String!]")
folder_paths_var = query.add_variable("folderPaths", "[String!]")
folder_names_var = query.add_variable("folderNames", "[String!]")
has_subsets_var = query.add_variable("folderHasSubsets", "Boolean!")
has_products_var = query.add_variable("folderHasProducts", "Boolean!")
project_field = query.add_field("project")
project_field.set_filter("name", project_name_var)
@ -21,7 +21,7 @@ def folders_tasks_graphql_query(fields):
folders_field.set_filter("parentIds", parent_folder_ids_var)
folders_field.set_filter("names", folder_names_var)
folders_field.set_filter("paths", folder_paths_var)
folders_field.set_filter("hasSubsets", has_subsets_var)
folders_field.set_filter("hasProducts", has_products_var)
fields = set(fields)
fields.discard("tasks")

View file

@ -375,7 +375,18 @@ def prepare_representation_update_data(old_doc, new_doc, replace=True):
Dict[str, Any]: Changes between old and new document.
"""
return _prepare_update_data(old_doc, new_doc, replace)
changes = _prepare_update_data(old_doc, new_doc, replace)
context = changes.get("data", {}).get("context")
# Make sure that both 'family' and 'subset' are in changes if
# one of them changed (they'll both become 'product').
if (
context
and ("family" in context or "subset" in context)
):
context["family"] = new_doc["data"]["context"]["family"]
context["subset"] = new_doc["data"]["context"]["subset"]
return changes
def prepare_workfile_info_update_data(old_doc, new_doc, replace=True):
@ -445,6 +456,7 @@ class ServerCreateOperation(CreateOperation):
elif entity_type == "subset":
new_data = convert_create_subset_to_v4(data, self.con)
entity_type = "product"
elif entity_type == "version":
new_data = convert_create_version_to_v4(data, self.con)
@ -551,6 +563,7 @@ class ServerUpdateOperation(UpdateOperation):
new_update_data = convert_update_subset_to_v4(
project_name, entity_id, update_data, self.con
)
entity_type = "product"
elif entity_type == "version":
new_update_data = convert_update_version_to_v4(
@ -636,9 +649,12 @@ class ServerDeleteOperation(DeleteOperation):
if entity_type == "asset":
entity_type == "folder"
if entity_type == "hero_version":
elif entity_type == "hero_version":
entity_type = "version"
elif entity_type == "subset":
entity_type = "product"
super(ServerDeleteOperation, self).__init__(
project_name, entity_type, entity_id
)

View file

@ -36,10 +36,6 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin):
"""
if AYON_SERVER_ENABLED:
self.log.info("Skipping, in AYON mode")
return
workfile = None
publishing = []
@ -139,3 +135,7 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin):
{"_id": version_doc["_id"]},
{"$set": {"data.inputLinks": input_links}}
)
if AYON_SERVER_ENABLED:
del IntegrateInputLinks

View file

@ -32,10 +32,6 @@ class IntegrateInputLinksAYON(pyblish.api.ContextPlugin):
specific publish plugin.
"""
if not AYON_SERVER_ENABLED:
self.log.info("Skipping, not in AYON mode")
return
workfile_instance, other_instances = self.split_instances(context)
# Variable where links are stored in submethods
@ -158,3 +154,7 @@ class IntegrateInputLinksAYON(pyblish.api.ContextPlugin):
output_id,
"version"
)
if not AYON_SERVER_ENABLED:
del IntegrateInputLinksAYON

View file

@ -351,18 +351,25 @@ def _convert_flame_project_settings(ayon_settings, output):
ayon_flame = ayon_settings["flame"]
ayon_publish_flame = ayon_flame["publish"]
# Plugin 'ExtractSubsetResources' renamed to 'ExtractProductResources'
if "ExtractSubsetResources" in ayon_publish_flame:
ayon_product_resources = ayon_publish_flame["ExtractSubsetResources"]
else:
ayon_product_resources = (
ayon_publish_flame.pop("ExtractProductResources"))
ayon_publish_flame["ExtractSubsetResources"] = ayon_product_resources
# 'ExtractSubsetResources' changed model of 'export_presets_mapping'
# - some keys were moved under 'other_parameters'
ayon_subset_resources = ayon_publish_flame["ExtractSubsetResources"]
new_subset_resources = {}
for item in ayon_subset_resources.pop("export_presets_mapping"):
for item in ayon_product_resources.pop("export_presets_mapping"):
name = item.pop("name")
if "other_parameters" in item:
other_parameters = item.pop("other_parameters")
item.update(other_parameters)
new_subset_resources[name] = item
ayon_subset_resources["export_presets_mapping"] = new_subset_resources
ayon_product_resources["export_presets_mapping"] = new_subset_resources
# 'imageio' changed model
# - missing subkey 'project' which is in root of 'imageio' model
@ -375,6 +382,21 @@ def _convert_flame_project_settings(ayon_settings, output):
"profilesMapping": profile_mapping
}
ayon_load_flame = ayon_flame["load"]
for plugin_name in ("LoadClip", "LoadClipBatch"):
plugin_settings = ayon_load_flame[plugin_name]
plugin_settings["families"] = plugin_settings.pop("product_types")
plugin_settings["clip_name_template"] = (
plugin_settings["clip_name_template"]
.replace("{folder[name]}", "{asset}")
.replace("{product[name]}", "{subset}")
)
plugin_settings["layer_rename_template"] = (
plugin_settings["layer_rename_template"]
.replace("{folder[name]}", "{asset}")
.replace("{product[name]}", "{subset}")
)
output["flame"] = ayon_flame
@ -409,6 +431,15 @@ def _convert_fusion_project_settings(ayon_settings, output):
_convert_host_imageio(ayon_imageio_fusion)
ayon_create_saver = ayon_fusion["create"]["CreateSaver"]
ayon_create_saver["temp_rendering_path_template"] = (
ayon_create_saver["temp_rendering_path_template"]
.replace("{product[name]}", "{subset}")
.replace("{product[type]}", "{family}")
.replace("{folder[name]}", "{asset}")
.replace("{task[name]}", "{task}")
)
output["fusion"] = ayon_fusion
@ -477,6 +508,11 @@ def _convert_maya_project_settings(ayon_settings, output):
SUFFIX_NAMING_TABLE
)
validate_frame_range = ayon_publish["ValidateFrameRange"]
if "exclude_product_types" in validate_frame_range:
validate_frame_range["exclude_families"] = (
validate_frame_range.pop("exclude_product_types"))
# Extract playblast capture settings
validate_rendern_settings = ayon_publish["ValidateRenderSettings"]
for key in (
@ -537,12 +573,31 @@ def _convert_maya_project_settings(ayon_settings, output):
for item in renderer_settings["additional_options"]
]
# Workfile build
ayon_workfile_build = ayon_maya["workfile_build"]
for item in ayon_workfile_build["profiles"]:
for key in ("current_context", "linked_assets"):
for subitem in item[key]:
if "families" in subitem:
break
subitem["families"] = subitem.pop("product_types")
subitem["subset_name_filters"] = subitem.pop(
"product_name_filters")
_convert_host_imageio(ayon_maya)
load_colors = ayon_maya["load"]["colors"]
ayon_maya_load = ayon_maya["load"]
load_colors = ayon_maya_load["colors"]
for key, color in tuple(load_colors.items()):
load_colors[key] = _convert_color(color)
reference_loader = ayon_maya_load["reference_loader"]
reference_loader["namespace"] = (
reference_loader["namespace"]
.replace("{folder[name]}", "{asset_name}")
.replace("{product[name]}", "{subset}")
)
output["maya"] = ayon_maya
@ -630,13 +685,21 @@ def _convert_nuke_project_settings(ayon_settings, output):
"CreateWriteImage",
"CreateWriteRender",
):
create_plugin_settings = ayon_create[creator_name]
create_plugin_settings["temp_rendering_path_template"] = (
create_plugin_settings["temp_rendering_path_template"]
.replace("{product[name]}", "{subset}")
.replace("{product[type]}", "{family}")
.replace("{task[name]}", "{task}")
.replace("{folder[name]}", "{asset}")
)
new_prenodes = {}
for prenode in ayon_create[creator_name]["prenodes"]:
for prenode in create_plugin_settings["prenodes"]:
name = prenode.pop("name")
prenode["knobs"] = _convert_nuke_knobs(prenode["knobs"])
new_prenodes[name] = prenode
ayon_create[creator_name]["prenodes"] = new_prenodes
create_plugin_settings["prenodes"] = new_prenodes
# --- Publish ---
ayon_publish = ayon_nuke["publish"]
@ -651,6 +714,11 @@ def _convert_nuke_project_settings(ayon_settings, output):
new_review_data_outputs = {}
for item in ayon_publish["ExtractReviewDataMov"]["outputs"]:
item_filter = item["filter"]
if "product_names" in item_filter:
item_filter["subsets"] = item_filter.pop("product_names")
item_filter["families"] = item_filter.pop("product_types")
item["reformat_node_config"] = _convert_nuke_knobs(
item["reformat_node_config"])
@ -659,9 +727,14 @@ def _convert_nuke_project_settings(ayon_settings, output):
name = item.pop("name")
new_review_data_outputs[name] = item
ayon_publish["ExtractReviewDataMov"]["outputs"] = new_review_data_outputs
collect_instance_data = ayon_publish["CollectInstanceData"]
if "sync_workfile_version_on_product_types" in collect_instance_data:
collect_instance_data["sync_workfile_version_on_families"] = (
collect_instance_data.pop(
"sync_workfile_version_on_product_types"))
# TODO 'ExtractThumbnail' does not have ideal schema in v3
new_thumbnail_nodes = {}
for item in ayon_publish["ExtractThumbnail"]["nodes"]:
@ -707,6 +780,17 @@ def _convert_hiero_project_settings(ayon_settings, output):
new_gui_filters[key] = subvalue
ayon_hiero["filters"] = new_gui_filters
ayon_load_clip = ayon_hiero["load"]["LoadClip"]
if "product_types" in ayon_load_clip:
ayon_load_clip["families"] = ayon_load_clip.pop("product_types")
ayon_load_clip = ayon_hiero["load"]["LoadClip"]
ayon_load_clip["clip_name_template"] = (
ayon_load_clip["clip_name_template"]
.replace("{folder[name]}", "{asset}")
.replace("{product[name]}", "{subset}")
)
output["hiero"] = ayon_hiero
@ -717,7 +801,14 @@ def _convert_photoshop_project_settings(ayon_settings, output):
ayon_photoshop = ayon_settings["photoshop"]
_convert_host_imageio(ayon_photoshop)
collect_review = ayon_photoshop["publish"]["CollectReview"]
ayon_publish_photoshop = ayon_photoshop["publish"]
ayon_colorcoded = ayon_publish_photoshop["CollectColorCodedInstances"]
if "flatten_product_type_template" in ayon_colorcoded:
ayon_colorcoded["flatten_subset_template"] = (
ayon_colorcoded.pop("flatten_product_type_template"))
collect_review = ayon_publish_photoshop["CollectReview"]
if "active" in collect_review:
collect_review["publish"] = collect_review.pop("active")
@ -762,6 +853,14 @@ def _convert_tvpaint_project_settings(ayon_settings, output):
extract_sequence_setting["review_bg"]
)
# TODO remove when removed from OpenPype schema
# this is unused setting
ayon_tvpaint["publish"]["ExtractSequence"]["families_to_review"] = [
"review",
"renderlayer",
"renderscene"
]
output["tvpaint"] = ayon_tvpaint
@ -776,6 +875,13 @@ def _convert_traypublisher_project_settings(ayon_settings, output):
ayon_editorial_simple = (
ayon_traypublisher["editorial_creators"]["editorial_simple"]
)
# Subset -> Product type conversion
if "product_type_presets" in ayon_editorial_simple:
family_presets = ayon_editorial_simple.pop("product_type_presets")
for item in family_presets:
item["family"] = item.pop("product_type")
ayon_editorial_simple["family_presets"] = family_presets
if "shot_metadata_creator" in ayon_editorial_simple:
shot_metadata_creator = ayon_editorial_simple.pop(
"shot_metadata_creator"
@ -798,6 +904,13 @@ def _convert_traypublisher_project_settings(ayon_settings, output):
for item in ayon_editorial_simple["shot_hierarchy"]["parents"]:
item["type"] = item.pop("parent_type")
# Simple creators
ayon_simple_creators = ayon_traypublisher["simple_creators"]
for item in ayon_simple_creators:
if "product_type" not in item:
break
item["family"] = item.pop("product_type")
shot_add_tasks = ayon_editorial_simple["shot_add_tasks"]
if isinstance(shot_add_tasks, dict):
shot_add_tasks = []
@ -886,6 +999,13 @@ def _convert_kitsu_project_settings(ayon_settings, output):
ayon_kitsu_settings = ayon_settings["kitsu"]
ayon_kitsu_settings.pop("server")
integrate_note = ayon_kitsu_settings["publish"]["IntegrateKitsuNote"]
status_change_conditions = integrate_note["status_change_conditions"]
if "product_type_requirements" in status_change_conditions:
status_change_conditions["family_requirements"] = (
status_change_conditions.pop("product_type_requirements"))
output["kitsu"] = ayon_kitsu_settings
@ -946,12 +1066,25 @@ def _convert_global_project_settings(ayon_settings, output, default_settings):
# Publish conversion
ayon_publish = ayon_core["publish"]
ayon_collect_audio = ayon_publish["CollectAudio"]
if "audio_product_name" in ayon_collect_audio:
ayon_collect_audio["audio_subset_name"] = (
ayon_collect_audio.pop("audio_product_name"))
for profile in ayon_publish["ExtractReview"]["profiles"]:
if "product_types" in profile:
profile["families"] = profile.pop("product_types")
new_outputs = {}
for output_def in profile.pop("outputs"):
name = output_def.pop("name")
new_outputs[name] = output_def
output_def_filter = output_def["filter"]
if "product_names" in output_def_filter:
output_def_filter["subsets"] = (
output_def_filter.pop("product_names"))
for color_key in ("overscan_color", "bg_color"):
output_def[color_key] = _convert_color(output_def[color_key])
@ -967,6 +1100,7 @@ def _convert_global_project_settings(ayon_settings, output, default_settings):
profile["outputs"] = new_outputs
# Extract Burnin plugin
extract_burnin = ayon_publish["ExtractBurnin"]
extract_burnin_options = extract_burnin["options"]
for color_key in ("font_color", "bg_color"):
@ -976,16 +1110,56 @@ def _convert_global_project_settings(ayon_settings, output, default_settings):
for profile in extract_burnin["profiles"]:
extract_burnin_defs = profile["burnins"]
if "product_names" in profile:
profile["subsets"] = profile.pop("product_names")
profile["families"] = profile.pop("product_types")
for burnin_def in extract_burnin_defs:
for key in (
"TOP_LEFT",
"TOP_CENTERED",
"TOP_RIGHT",
"BOTTOM_LEFT",
"BOTTOM_CENTERED",
"BOTTOM_RIGHT",
):
burnin_def[key] = (
burnin_def[key]
.replace("{product[name]}", "{subset}")
.replace("{Product[name]}", "{Subset}")
.replace("{PRODUCT[NAME]}", "{SUBSET}")
.replace("{product[type]}", "{family}")
.replace("{Product[type]}", "{Family}")
.replace("{PRODUCT[TYPE]}", "{FAMILY}")
.replace("{folder[name]}", "{asset}")
.replace("{Folder[name]}", "{Asset}")
.replace("{FOLDER[NAME]}", "{ASSET}")
)
profile["burnins"] = {
extract_burnin_def.pop("name"): extract_burnin_def
for extract_burnin_def in extract_burnin_defs
}
ayon_integrate_hero = ayon_publish["IntegrateHeroVersion"]
for profile in ayon_integrate_hero["template_name_profiles"]:
if "product_types" not in profile:
break
profile["families"] = profile.pop("product_types")
if "IntegrateProductGroup" in ayon_publish:
subset_group = ayon_publish.pop("IntegrateProductGroup")
subset_group_profiles = subset_group.pop("product_grouping_profiles")
for profile in subset_group_profiles:
profile["families"] = profile.pop("product_types")
subset_group["subset_grouping_profiles"] = subset_group_profiles
ayon_publish["IntegrateSubsetGroup"] = subset_group
# Cleanup plugin
ayon_cleanup = ayon_publish["CleanUp"]
if "patterns" in ayon_cleanup:
ayon_cleanup["paterns"] = ayon_cleanup.pop("patterns")
# Project root settings
# Project root settings - json string to dict
ayon_core["project_environments"] = json.loads(
ayon_core["project_environments"]
)
@ -996,18 +1170,55 @@ def _convert_global_project_settings(ayon_settings, output, default_settings):
# Tools settings
ayon_tools = ayon_core["tools"]
ayon_create_tool = ayon_tools["creator"]
if "product_name_profiles" in ayon_create_tool:
product_name_profiles = ayon_create_tool.pop("product_name_profiles")
for profile in product_name_profiles:
profile["families"] = profile.pop("product_types")
ayon_create_tool["subset_name_profiles"] = product_name_profiles
for profile in ayon_create_tool["subset_name_profiles"]:
template = profile["template"]
profile["template"] = (
template
.replace("{task[name]}", "{task}")
.replace("{Task[name]}", "{Task}")
.replace("{TASK[NAME]}", "{TASK}")
.replace("{product[type]}", "{family}")
.replace("{Product[type]}", "{Family}")
.replace("{PRODUCT[TYPE]}", "{FAMILY}")
.replace("{folder[name]}", "{asset}")
.replace("{Folder[name]}", "{Asset}")
.replace("{FOLDER[NAME]}", "{ASSET}")
)
product_smart_select_key = "families_smart_select"
if "product_types_smart_select" in ayon_create_tool:
product_smart_select_key = "product_types_smart_select"
new_smart_select_families = {
item["name"]: item["task_names"]
for item in ayon_create_tool["families_smart_select"]
for item in ayon_create_tool.pop(product_smart_select_key)
}
ayon_create_tool["families_smart_select"] = new_smart_select_families
ayon_loader_tool = ayon_tools["loader"]
for profile in ayon_loader_tool["family_filter_profiles"]:
if "template_publish_families" in profile:
profile["filter_families"] = (
profile.pop("template_publish_families")
)
if "product_type_filter_profiles" in ayon_loader_tool:
product_type_filter_profiles = (
ayon_loader_tool.pop("product_type_filter_profiles"))
for profile in product_type_filter_profiles:
profile["filter_families"] = profile.pop("filter_product_types")
ayon_loader_tool["family_filter_profiles"] = (
product_type_filter_profiles)
ayon_publish_tool = ayon_tools["publish"]
for profile in ayon_publish_tool["hero_template_name_profiles"]:
if "product_types" in profile:
profile["families"] = profile.pop("product_types")
for profile in ayon_publish_tool["template_name_profiles"]:
if "product_types" in profile:
profile["families"] = profile.pop("product_types")
ayon_core["sync_server"] = (
default_settings["global"]["sync_server"]

View file

@ -53,7 +53,8 @@
},
"ValidateEditorialAssetName": {
"enabled": true,
"optional": false
"optional": false,
"active": true
},
"ValidateVersion": {
"enabled": true,
@ -300,71 +301,6 @@
}
]
},
"IntegrateAssetNew": {
"subset_grouping_profiles": [
{
"families": [],
"hosts": [],
"task_types": [],
"tasks": [],
"template": ""
}
],
"template_name_profiles": [
{
"families": [],
"hosts": [],
"task_types": [],
"tasks": [],
"template_name": "publish"
},
{
"families": [
"review",
"render",
"prerender"
],
"hosts": [],
"task_types": [],
"tasks": [],
"template_name": "render"
},
{
"families": [
"simpleUnrealTexture"
],
"hosts": [
"standalonepublisher"
],
"task_types": [],
"tasks": [],
"template_name": "simpleUnrealTexture"
},
{
"families": [
"staticMesh",
"skeletalMesh"
],
"hosts": [
"maya"
],
"task_types": [],
"tasks": [],
"template_name": "maya2unreal"
},
{
"families": [
"online"
],
"hosts": [
"traypublisher"
],
"task_types": [],
"tasks": [],
"template_name": "online"
}
]
},
"IntegrateHeroVersion": {
"enabled": true,
"optional": true,

View file

@ -60,11 +60,6 @@
255,
255,
255
],
"families_to_review": [
"review",
"renderlayer",
"renderscene"
]
},
"ValidateProjectSettings": {

View file

@ -273,18 +273,6 @@
"key": "review_bg",
"label": "Review BG color",
"use_alpha": false
},
{
"type": "enum",
"key": "families_to_review",
"label": "Families to review",
"multiselection": true,
"enum_items": [
{"review": "review"},
{"renderpass": "renderPass"},
{"renderlayer": "renderLayer"},
{"renderscene": "renderScene"}
]
}
]
},

View file

@ -118,6 +118,11 @@
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"type": "boolean",
"key": "active",
"label": "Active"
}
]
},
@ -888,111 +893,6 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"key": "IntegrateAssetNew",
"label": "IntegrateAsset (Legacy)",
"is_group": true,
"children": [
{
"type": "label",
"label": "<b>NOTE:</b> Subset grouping profiles settings were moved to <a href=\"settings://project_settings/global/publish/IntegrateSubsetGroup/subset_grouping_profiles\"><b>Integrate Subset Group</b></a>. Please move values there."
},
{
"type": "list",
"key": "subset_grouping_profiles",
"label": "Subset grouping profiles (DEPRECATED)",
"use_label_wrap": true,
"object_type": {
"type": "dict",
"children": [
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"multiselection": true
},
{
"key": "task_types",
"label": "Task types",
"type": "task-types-enum"
},
{
"key": "tasks",
"label": "Task names",
"type": "list",
"object_type": "text"
},
{
"type": "separator"
},
{
"type": "text",
"key": "template",
"label": "Template"
}
]
}
},
{
"type": "label",
"label": "<b>NOTE:</b> Publish template profiles settings were moved to <a href=\"settings://project_settings/global/tools/publish/template_name_profiles\"><b>Tools/Publish/Template name profiles</b></a>. Please move values there."
},
{
"type": "list",
"key": "template_name_profiles",
"label": "Template name profiles (DEPRECATED)",
"use_label_wrap": true,
"object_type": {
"type": "dict",
"children": [
{
"type": "label",
"label": ""
},
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"multiselection": true
},
{
"key": "task_types",
"label": "Task types",
"type": "task-types-enum"
},
{
"key": "tasks",
"label": "Task names",
"type": "list",
"object_type": "text"
},
{
"type": "separator"
},
{
"type": "text",
"key": "template_name",
"label": "Template name"
}
]
}
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -320,10 +320,6 @@
"key": "publish",
"label": "Publish",
"children": [
{
"type": "label",
"label": "<b>NOTE:</b> For backwards compatibility can be value empty and in that case are used values from <a href=\"settings://project_settings/global/publish/IntegrateAssetNew\"><b>IntegrateAssetNew</b></a>. This will change in future so please move all values here as soon as possible."
},
{
"type": "list",
"key": "template_name_profiles",

View file

@ -5,6 +5,7 @@ from qtpy import QtWidgets, QtCore, QtGui
import qtawesome
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline.create import SUBSET_NAME_ALLOWED_SYMBOLS
from openpype.tools.utils import ErrorMessageBox
@ -42,10 +43,13 @@ class CreateErrorMessageBox(ErrorMessageBox):
def _get_report_data(self):
report_message = (
"Failed to create Subset: \"{subset}\" Family: \"{family}\""
"Failed to create {subset_label}: \"{subset}\""
" {family_label}: \"{family}\""
" in Asset: \"{asset}\""
"\n\nError: {message}"
).format(
subset_label="Product" if AYON_SERVER_ENABLED else "Subset",
family_label="Type" if AYON_SERVER_ENABLED else "Family",
subset=self._subset_name,
family=self._family,
asset=self._asset_name,
@ -57,9 +61,13 @@ class CreateErrorMessageBox(ErrorMessageBox):
def _create_content(self, content_layout):
item_name_template = (
"<span style='font-weight:bold;'>Family:</span> {}<br>"
"<span style='font-weight:bold;'>Subset:</span> {}<br>"
"<span style='font-weight:bold;'>Asset:</span> {}<br>"
"<span style='font-weight:bold;'>{}:</span> {{}}<br>"
"<span style='font-weight:bold;'>{}:</span> {{}}<br>"
"<span style='font-weight:bold;'>{}:</span> {{}}<br>"
).format(
"Product type" if AYON_SERVER_ENABLED else "Family",
"Product name" if AYON_SERVER_ENABLED else "Subset",
"Folder" if AYON_SERVER_ENABLED else "Asset"
)
exc_msg_template = "<span style='font-weight:bold'>{}</span>"
@ -151,15 +159,21 @@ class VariantLineEdit(QtWidgets.QLineEdit):
def as_empty(self):
self._set_border("empty")
self.report.emit("Empty subset name ..")
self.report.emit("Empty {} name ..".format(
"product" if AYON_SERVER_ENABLED else "subset"
))
def as_exists(self):
self._set_border("exists")
self.report.emit("Existing subset, appending next version.")
self.report.emit("Existing {}, appending next version.".format(
"product" if AYON_SERVER_ENABLED else "subset"
))
def as_new(self):
self._set_border("new")
self.report.emit("New subset, creating first version.")
self.report.emit("New {}, creating first version.".format(
"product" if AYON_SERVER_ENABLED else "subset"
))
def _set_border(self, status):
qcolor, style = self.colors[status]

View file

@ -223,7 +223,7 @@ class LoaderWindow(QtWidgets.QDialog):
lib.schedule(self._refresh, 50, channel="mongo")
def on_assetschanged(self, *args):
self.echo("Fetching asset..")
self.echo("Fetching hierarchy..")
lib.schedule(self._assetschanged, 50, channel="mongo")
def on_subsetschanged(self, *args):

View file

@ -7,6 +7,7 @@ from uuid import uuid4
from qtpy import QtCore, QtGui
import qtawesome
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_assets,
get_subsets,
@ -143,9 +144,9 @@ class SubsetsModel(BaseRepresentationModel, TreeModel):
]
column_labels_mapping = {
"subset": "Subset",
"asset": "Asset",
"family": "Family",
"subset": "Product" if AYON_SERVER_ENABLED else "Subset",
"asset": "Folder" if AYON_SERVER_ENABLED else "Asset",
"family": "Product type" if AYON_SERVER_ENABLED else "Family",
"version": "Version",
"time": "Time",
"author": "Author",

View file

@ -2,6 +2,7 @@ import collections
from qtpy import QtWidgets, QtCore, QtGui
from openpype import AYON_SERVER_ENABLED
from openpype.tools.utils import (
PlaceholderLineEdit,
RecursiveSortFilterProxyModel,
@ -187,7 +188,8 @@ class AssetsDialog(QtWidgets.QDialog):
proxy_model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
filter_input = PlaceholderLineEdit(self)
filter_input.setPlaceholderText("Filter assets..")
filter_input.setPlaceholderText("Filter {}..".format(
"folders" if AYON_SERVER_ENABLED else "assets"))
asset_view = AssetDialogView(self)
asset_view.setModel(proxy_model)

View file

@ -2,6 +2,7 @@ import re
from qtpy import QtWidgets, QtCore, QtGui
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline.create import (
SUBSET_NAME_ALLOWED_SYMBOLS,
PRE_CREATE_THUMBNAIL_KEY,
@ -203,7 +204,9 @@ class CreateWidget(QtWidgets.QWidget):
variant_subset_layout.setHorizontalSpacing(INPUTS_LAYOUT_HSPACING)
variant_subset_layout.setVerticalSpacing(INPUTS_LAYOUT_VSPACING)
variant_subset_layout.addRow("Variant", variant_widget)
variant_subset_layout.addRow("Subset", subset_name_input)
variant_subset_layout.addRow(
"Product" if AYON_SERVER_ENABLED else "Subset",
subset_name_input)
creator_basics_layout = QtWidgets.QVBoxLayout(creator_basics_widget)
creator_basics_layout.setContentsMargins(0, 0, 0, 0)

View file

@ -9,6 +9,7 @@ import collections
from qtpy import QtWidgets, QtCore, QtGui
import qtawesome
from openpype import AYON_SERVER_ENABLED
from openpype.lib.attribute_definitions import UnknownDef
from openpype.tools.attribute_defs import create_widget_for_attr_def
from openpype.tools import resources
@ -1116,10 +1117,16 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
main_layout.setHorizontalSpacing(INPUTS_LAYOUT_HSPACING)
main_layout.setVerticalSpacing(INPUTS_LAYOUT_VSPACING)
main_layout.addRow("Variant", variant_input)
main_layout.addRow("Asset", asset_value_widget)
main_layout.addRow(
"Folder" if AYON_SERVER_ENABLED else "Asset",
asset_value_widget)
main_layout.addRow("Task", task_value_widget)
main_layout.addRow("Family", family_value_widget)
main_layout.addRow("Subset", subset_value_widget)
main_layout.addRow(
"Product type" if AYON_SERVER_ENABLED else "Family",
family_value_widget)
main_layout.addRow(
"Product name" if AYON_SERVER_ENABLED else "Subset",
subset_value_widget)
main_layout.addRow(btns_layout)
variant_input.value_changed.connect(self._on_variant_change)

View file

@ -2,6 +2,7 @@ import contextlib
from qtpy import QtWidgets, QtCore
import qtawesome
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_projects,
get_project,
@ -181,7 +182,8 @@ class AssetWidget(QtWidgets.QWidget):
filter = PlaceholderLineEdit()
filter.textChanged.connect(proxy.setFilterFixedString)
filter.setPlaceholderText("Filter assets..")
filter.setPlaceholderText("Filter {}..".format(
"folders" if AYON_SERVER_ENABLED else "assets"))
header.addWidget(filter)
header.addWidget(refresh)

View file

@ -5,6 +5,7 @@ import qtpy
from qtpy import QtWidgets, QtCore, QtGui
import qtawesome
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_project,
get_assets,
@ -607,7 +608,8 @@ class AssetsWidget(QtWidgets.QWidget):
refresh_btn.setToolTip("Refresh items")
filter_input = PlaceholderLineEdit(header_widget)
filter_input.setPlaceholderText("Filter assets..")
filter_input.setPlaceholderText("Filter {}..".format(
"folders" if AYON_SERVER_ENABLED else "assets"))
# Header
header_layout = QtWidgets.QHBoxLayout(header_widget)

View file

@ -99,22 +99,24 @@ from ._api import (
get_tasks,
get_folder_ids_with_subsets,
get_subset_by_id,
get_subset_by_name,
get_subsets,
get_subset_families,
get_folder_ids_with_products,
get_product_by_id,
get_product_by_name,
get_products,
get_product_types,
get_project_product_types,
get_product_type_names,
get_version_by_id,
get_version_by_name,
version_is_latest,
get_versions,
get_hero_version_by_subset_id,
get_hero_version_by_product_id,
get_hero_version_by_id,
get_hero_versions,
get_last_versions,
get_last_version_by_subset_id,
get_last_version_by_subset_name,
get_last_version_by_product_id,
get_last_version_by_product_name,
get_representation_by_id,
get_representation_by_name,
get_representations,
@ -122,6 +124,10 @@ from ._api import (
get_representation_parents,
get_repre_ids_by_context_filters,
get_workfiles_info,
get_workfile_info,
get_workfile_info_by_id,
get_thumbnail,
get_folder_thumbnail,
get_version_thumbnail,
@ -143,8 +149,8 @@ from ._api import (
get_folders_links,
get_task_links,
get_tasks_links,
get_subset_links,
get_subsets_links,
get_product_links,
get_products_links,
get_version_links,
get_versions_links,
get_representations_links,
@ -251,22 +257,24 @@ __all__ = (
"get_tasks",
"get_folder_ids_with_subsets",
"get_subset_by_id",
"get_subset_by_name",
"get_subsets",
"get_subset_families",
"get_folder_ids_with_products",
"get_product_by_id",
"get_product_by_name",
"get_products",
"get_product_types",
"get_project_product_types",
"get_product_type_names",
"get_version_by_id",
"get_version_by_name",
"version_is_latest",
"get_versions",
"get_hero_version_by_subset_id",
"get_hero_version_by_product_id",
"get_hero_version_by_id",
"get_hero_versions",
"get_last_versions",
"get_last_version_by_subset_id",
"get_last_version_by_subset_name",
"get_last_version_by_product_id",
"get_last_version_by_product_name",
"get_representation_by_id",
"get_representation_by_name",
"get_representations",
@ -274,6 +282,10 @@ __all__ = (
"get_representation_parents",
"get_repre_ids_by_context_filters",
"get_workfiles_info",
"get_workfile_info",
"get_workfile_info_by_id",
"get_thumbnail",
"get_folder_thumbnail",
"get_version_thumbnail",
@ -295,8 +307,8 @@ __all__ = (
"get_folders_links",
"get_task_links",
"get_tasks_links",
"get_subset_links",
"get_subsets_links",
"get_product_links",
"get_products_links",
"get_version_links",
"get_versions_links",
"get_representations_links",

View file

@ -656,29 +656,39 @@ def get_folder_by_name(*args, **kwargs):
return con.get_folder_by_name(*args, **kwargs)
def get_folder_ids_with_subsets(*args, **kwargs):
def get_folder_ids_with_products(*args, **kwargs):
con = get_server_api_connection()
return con.get_folder_ids_with_subsets(*args, **kwargs)
return con.get_folder_ids_with_products(*args, **kwargs)
def get_subsets(*args, **kwargs):
def get_product_types(*args, **kwargs):
con = get_server_api_connection()
return con.get_subsets(*args, **kwargs)
return con.get_product_types(*args, **kwargs)
def get_subset_by_id(*args, **kwargs):
def get_project_product_types(*args, **kwargs):
con = get_server_api_connection()
return con.get_subset_by_id(*args, **kwargs)
return con.get_project_product_types(*args, **kwargs)
def get_subset_by_name(*args, **kwargs):
def get_product_type_names(*args, **kwargs):
con = get_server_api_connection()
return con.get_subset_by_name(*args, **kwargs)
return con.get_product_type_names(*args, **kwargs)
def get_subset_families(*args, **kwargs):
def get_products(*args, **kwargs):
con = get_server_api_connection()
return con.get_subset_families(*args, **kwargs)
return con.get_products(*args, **kwargs)
def get_product_by_id(*args, **kwargs):
con = get_server_api_connection()
return con.get_product_by_id(*args, **kwargs)
def get_product_by_name(*args, **kwargs):
con = get_server_api_connection()
return con.get_product_by_name(*args, **kwargs)
def get_versions(*args, **kwargs):
@ -701,9 +711,9 @@ def get_hero_version_by_id(*args, **kwargs):
return con.get_hero_version_by_id(*args, **kwargs)
def get_hero_version_by_subset_id(*args, **kwargs):
def get_hero_version_by_product_id(*args, **kwargs):
con = get_server_api_connection()
return con.get_hero_version_by_subset_id(*args, **kwargs)
return con.get_hero_version_by_product_id(*args, **kwargs)
def get_hero_versions(*args, **kwargs):
@ -716,14 +726,14 @@ def get_last_versions(*args, **kwargs):
return con.get_last_versions(*args, **kwargs)
def get_last_version_by_subset_id(*args, **kwargs):
def get_last_version_by_product_id(*args, **kwargs):
con = get_server_api_connection()
return con.get_last_version_by_subset_id(*args, **kwargs)
return con.get_last_version_by_product_id(*args, **kwargs)
def get_last_version_by_subset_name(*args, **kwargs):
def get_last_version_by_product_name(*args, **kwargs):
con = get_server_api_connection()
return con.get_last_version_by_subset_name(*args, **kwargs)
return con.get_last_version_by_product_name(*args, **kwargs)
def version_is_latest(*args, **kwargs):
@ -761,6 +771,21 @@ def get_repre_ids_by_context_filters(*args, **kwargs):
return con.get_repre_ids_by_context_filters(*args, **kwargs)
def get_workfiles_info(*args, **kwargs):
con = get_server_api_connection()
return con.get_workfiles_info(*args, **kwargs)
def get_workfile_info(*args, **kwargs):
con = get_server_api_connection()
return con.get_workfile_info(*args, **kwargs)
def get_workfile_info_by_id(*args, **kwargs):
con = get_server_api_connection()
return con.get_workfile_info_by_id(*args, **kwargs)
def create_project(
project_name,
project_code,
@ -954,31 +979,31 @@ def get_task_links(
)
def get_subsets_links(
def get_products_links(
project_name,
subset_ids=None,
product_ids=None,
link_types=None,
link_direction=None
):
con = get_server_api_connection()
return con.get_subsets_links(
return con.get_products_links(
project_name,
subset_ids,
product_ids,
link_types,
link_direction
)
def get_subset_links(
def get_product_links(
project_name,
subset_id,
product_id,
link_types=None,
link_direction=None
):
con = get_server_api_connection()
return con.get_subset_links(
return con.get_product_links(
project_name,
subset_id,
product_id,
link_types,
link_direction
)

View file

@ -4,6 +4,13 @@ SERVER_API_ENV_KEY = "AYON_API_KEY"
# Backwards compatibility
SERVER_TOKEN_ENV_KEY = SERVER_API_ENV_KEY
# --- Product types ---
DEFAULT_PRODUCT_TYPE_FIELDS = {
"name",
"icon",
"color",
}
# --- Project ---
DEFAULT_PROJECT_FIELDS = {
"active",
@ -36,13 +43,13 @@ DEFAULT_TASK_FIELDS = {
"assignees",
}
# --- Subsets ---
DEFAULT_SUBSET_FIELDS = {
# --- Products ---
DEFAULT_PRODUCT_FIELDS = {
"id",
"name",
"folderId",
"active",
"family",
"productType",
}
# --- Versions ---
@ -50,7 +57,7 @@ DEFAULT_VERSION_FIELDS = {
"id",
"name",
"version",
"subsetId",
"productId",
"taskId",
"active",
"author",

View file

@ -558,7 +558,7 @@ class EntityHub(object):
folder_fields = set(
self._connection.get_default_fields_for_type("folder")
)
folder_fields.add("hasSubsets")
folder_fields.add("hasProducts")
if self._allow_data_changes:
folder_fields.add("data")
return folder_fields
@ -602,7 +602,7 @@ class EntityHub(object):
for folder in folders_by_parent_id[parent_id]:
folder_entity = self.add_folder(folder)
children_ids.add(folder_entity.id)
folder_entity.has_published_content = folder["hasSubsets"]
folder_entity.has_published_content = folder["hasProducts"]
hierarchy_queue.append((folder_entity.id, folder_entity))
for task in tasks_by_parent_id[parent_id]:
@ -1564,7 +1564,7 @@ class FolderEntity(BaseEntity):
self._orig_folder_type = folder_type
self._orig_label = label
# Know if folder has any subsets
# Know if folder has any products
# - is used to know if folder allows hierarchy changes
self._has_published_content = False
self._path = path

View file

@ -123,6 +123,51 @@ def projects_graphql_query(fields):
return query
def product_types_query(fields):
query = GraphQlQuery("ProductTypes")
product_types_field = query.add_field("productTypes")
nested_fields = fields_to_dict(fields)
query_queue = collections.deque()
for key, value in nested_fields.items():
query_queue.append((key, value, product_types_field))
while query_queue:
item = query_queue.popleft()
key, value, parent = item
field = parent.add_field(key)
if value is FIELD_VALUE:
continue
for k, v in value.items():
query_queue.append((k, v, field))
return query
def project_product_types_query(fields):
query = GraphQlQuery("ProjectProductTypes")
project_query = query.add_field("project")
project_name_var = query.add_variable("projectName", "String!")
project_query.set_filter("name", project_name_var)
product_types_field = project_query.add_field("productTypes")
nested_fields = fields_to_dict(fields)
query_queue = collections.deque()
for key, value in nested_fields.items():
query_queue.append((key, value, product_types_field))
while query_queue:
item = query_queue.popleft()
key, value, parent = item
field = parent.add_field(key)
if value is FIELD_VALUE:
continue
for k, v in value.items():
query_queue.append((k, v, field))
return query
def folders_graphql_query(fields):
query = GraphQlQuery("FoldersQuery")
project_name_var = query.add_variable("projectName", "String!")
@ -130,7 +175,7 @@ def folders_graphql_query(fields):
parent_folder_ids_var = query.add_variable("parentFolderIds", "[String!]")
folder_paths_var = query.add_variable("folderPaths", "[String!]")
folder_names_var = query.add_variable("folderNames", "[String!]")
has_subsets_var = query.add_variable("folderHasSubsets", "Boolean!")
has_products_var = query.add_variable("folderHasProducts", "Boolean!")
project_field = query.add_field("project")
project_field.set_filter("name", project_name_var)
@ -140,7 +185,7 @@ def folders_graphql_query(fields):
folders_field.set_filter("parentIds", parent_folder_ids_var)
folders_field.set_filter("names", folder_names_var)
folders_field.set_filter("paths", folder_paths_var)
folders_field.set_filter("hasSubsets", has_subsets_var)
folders_field.set_filter("hasProducts", has_products_var)
nested_fields = fields_to_dict(fields)
add_links_fields(folders_field, nested_fields)
@ -198,28 +243,28 @@ def tasks_graphql_query(fields):
return query
def subsets_graphql_query(fields):
query = GraphQlQuery("SubsetsQuery")
def products_graphql_query(fields):
query = GraphQlQuery("ProductsQuery")
project_name_var = query.add_variable("projectName", "String!")
folder_ids_var = query.add_variable("folderIds", "[String!]")
subset_ids_var = query.add_variable("subsetIds", "[String!]")
subset_names_var = query.add_variable("subsetNames", "[String!]")
product_ids_var = query.add_variable("productIds", "[String!]")
product_names_var = query.add_variable("productNames", "[String!]")
project_field = query.add_field("project")
project_field.set_filter("name", project_name_var)
subsets_field = project_field.add_field_with_edges("subsets")
subsets_field.set_filter("ids", subset_ids_var)
subsets_field.set_filter("names", subset_names_var)
subsets_field.set_filter("folderIds", folder_ids_var)
products_field = project_field.add_field_with_edges("products")
products_field.set_filter("ids", product_ids_var)
products_field.set_filter("names", product_names_var)
products_field.set_filter("folderIds", folder_ids_var)
nested_fields = fields_to_dict(set(fields))
add_links_fields(subsets_field, nested_fields)
add_links_fields(products_field, nested_fields)
query_queue = collections.deque()
for key, value in nested_fields.items():
query_queue.append((key, value, subsets_field))
query_queue.append((key, value, products_field))
while query_queue:
item = query_queue.popleft()
@ -237,7 +282,7 @@ def versions_graphql_query(fields):
query = GraphQlQuery("VersionsQuery")
project_name_var = query.add_variable("projectName", "String!")
subset_ids_var = query.add_variable("subsetIds", "[String!]")
product_ids_var = query.add_variable("productIds", "[String!]")
version_ids_var = query.add_variable("versionIds", "[String!]")
versions_var = query.add_variable("versions", "[Int!]")
hero_only_var = query.add_variable("heroOnly", "Boolean")
@ -249,20 +294,20 @@ def versions_graphql_query(fields):
project_field = query.add_field("project")
project_field.set_filter("name", project_name_var)
subsets_field = project_field.add_field_with_edges("versions")
subsets_field.set_filter("ids", version_ids_var)
subsets_field.set_filter("subsetIds", subset_ids_var)
subsets_field.set_filter("versions", versions_var)
subsets_field.set_filter("heroOnly", hero_only_var)
subsets_field.set_filter("latestOnly", latest_only_var)
subsets_field.set_filter("heroOrLatestOnly", hero_or_latest_only_var)
products_field = project_field.add_field_with_edges("versions")
products_field.set_filter("ids", version_ids_var)
products_field.set_filter("productIds", product_ids_var)
products_field.set_filter("versions", versions_var)
products_field.set_filter("heroOnly", hero_only_var)
products_field.set_filter("latestOnly", latest_only_var)
products_field.set_filter("heroOrLatestOnly", hero_or_latest_only_var)
nested_fields = fields_to_dict(set(fields))
add_links_fields(subsets_field, nested_fields)
add_links_fields(products_field, nested_fields)
query_queue = collections.deque()
for key, value in nested_fields.items():
query_queue.append((key, value, subsets_field))
query_queue.append((key, value, products_field))
while query_queue:
item = query_queue.popleft()
@ -312,7 +357,7 @@ def representations_graphql_query(fields):
def representations_parents_qraphql_query(
version_fields, subset_fields, folder_fields
version_fields, product_fields, folder_fields
):
query = GraphQlQuery("RepresentationsParentsQuery")
@ -331,11 +376,11 @@ def representations_parents_qraphql_query(
for key, value in fields_to_dict(version_fields).items():
fields_queue.append((key, value, version_field))
subset_field = version_field.add_field("subset")
for key, value in fields_to_dict(subset_fields).items():
fields_queue.append((key, value, subset_field))
product_field = version_field.add_field("product")
for key, value in fields_to_dict(product_fields).items():
fields_queue.append((key, value, product_field))
folder_field = subset_field.add_field("folder")
folder_field = product_field.add_field("folder")
for key, value in fields_to_dict(folder_fields).items():
fields_queue.append((key, value, folder_field))

View file

@ -31,12 +31,14 @@ def new_folder_entity(
Args:
name (str): Is considered as unique identifier of folder in project.
parent_id (str): Id of parent folder.
attribs (Dict[str, Any]): Explicitly set attributes of folder.
data (Dict[str, Any]): Custom folder data. Empty dictionary is used
if not passed.
thumbnail_id (str): Id of thumbnail related to folder.
entity_id (str): Predefined id of entity. New id is
folder_type (str): Type of folder.
parent_id (Optional[str]]): Id of parent folder.
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
of folder.
data (Optional[Dict[str, Any]]): Custom folder data. Empty dictionary
is used if not passed.
thumbnail_id (Optional[str]): Id of thumbnail related to folder.
entity_id (Optional[str]): Predefined id of entity. New id is
created if not passed.
Returns:
@ -64,23 +66,32 @@ def new_folder_entity(
}
def new_subset_entity(
name, family, folder_id, attribs=None, data=None, entity_id=None
def new_product_entity(
name,
product_type,
folder_id,
status=None,
attribs=None,
data=None,
entity_id=None
):
"""Create skeleton data of subset entity.
"""Create skeleton data of product entity.
Args:
name (str): Is considered as unique identifier of subset under folder.
family (str): Subset's family.
name (str): Is considered as unique identifier of
product under folder.
product_type (str): Product type.
folder_id (str): Id of parent folder.
attribs (Dict[str, Any]): Explicitly set attributes of subset.
data (Dict[str, Any]): Subset entity data. Empty dictionary is used
if not passed. Value of 'family' is used to fill 'family'.
entity_id (str): Predefined id of entity. New id is
status (Optional[str]): Product status.
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
of product.
data (Optional[Dict[str, Any]]): product entity data. Empty dictionary
is used if not passed.
entity_id (Optional[str]): Predefined id of entity. New id is
created if not passed.
Returns:
Dict[str, Any]: Skeleton of subset entity.
Dict[str, Any]: Skeleton of product entity.
"""
if attribs is None:
@ -89,19 +100,22 @@ def new_subset_entity(
if data is None:
data = {}
return {
output = {
"id": _create_or_convert_to_id(entity_id),
"name": name,
"family": family,
"productType": product_type,
"attrib": attribs,
"data": data,
"folderId": _create_or_convert_to_id(folder_id)
"folderId": _create_or_convert_to_id(folder_id),
}
if status:
output["status"] = status
return output
def new_version_entity(
version,
subset_id,
product_id,
task_id=None,
thumbnail_id=None,
author=None,
@ -113,14 +127,15 @@ def new_version_entity(
Args:
version (int): Is considered as unique identifier of version
under subset.
subset_id (str): Id of parent subset.
task_id (str): Id of task under which subset was created.
thumbnail_id (str): Thumbnail related to version.
author (str): Name of version author.
attribs (Dict[str, Any]): Explicitly set attributes of version.
data (Dict[str, Any]): Version entity custom data.
entity_id (str): Predefined id of entity. New id is
under product.
product_id (str): Id of parent product.
task_id (Optional[str]]): Id of task under which product was created.
thumbnail_id (Optional[str]]): Thumbnail related to version.
author (Optional[str]]): Name of version author.
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
of version.
data (Optional[Dict[str, Any]]): Version entity custom data.
entity_id (Optional[str]): Predefined id of entity. New id is
created if not passed.
Returns:
@ -139,7 +154,7 @@ def new_version_entity(
output = {
"id": _create_or_convert_to_id(entity_id),
"version": int(version),
"subsetId": _create_or_convert_to_id(subset_id),
"productId": _create_or_convert_to_id(product_id),
"attrib": attribs,
"data": data
}
@ -154,7 +169,7 @@ def new_version_entity(
def new_hero_version_entity(
version,
subset_id,
product_id,
task_id=None,
thumbnail_id=None,
author=None,
@ -166,14 +181,15 @@ def new_hero_version_entity(
Args:
version (int): Is considered as unique identifier of version
under subset. Should be same as standard version if there is any.
subset_id (str): Id of parent subset.
task_id (str): Id of task under which subset was created.
thumbnail_id (str): Thumbnail related to version.
author (str): Name of version author.
attribs (Dict[str, Any]): Explicitly set attributes of version.
data (Dict[str, Any]): Version entity data.
entity_id (str): Predefined id of entity. New id is
under product. Should be same as standard version if there is any.
product_id (str): Id of parent product.
task_id (Optional[str]): Id of task under which product was created.
thumbnail_id (Optional[str]): Thumbnail related to version.
author (Optional[str]): Name of version author.
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
of version.
data (Optional[Dict[str, Any]]): Version entity data.
entity_id (Optional[str]): Predefined id of entity. New id is
created if not passed.
Returns:
@ -189,7 +205,7 @@ def new_hero_version_entity(
output = {
"id": _create_or_convert_to_id(entity_id),
"version": -abs(int(version)),
"subsetId": subset_id,
"productId": product_id,
"attrib": attribs,
"data": data
}
@ -211,9 +227,10 @@ def new_representation_entity(
name (str): Representation name considered as unique identifier
of representation under version.
version_id (str): Id of parent version.
attribs (Dict[str, Any]): Explicitly set attributes of representation.
data (Dict[str, Any]): Representation entity data.
entity_id (str): Predefined id of entity. New id is created
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
of representation.
data (Optional[Dict[str, Any]]): Representation entity data.
entity_id (Optional[str]): Predefined id of entity. New id is created
if not passed.
Returns:
@ -247,8 +264,8 @@ def new_workfile_info_doc(
folder_id (str): Id of folder under which workfile live.
task_name (str): Task under which was workfile created.
files (List[str]): List of rootless filepaths related to workfile.
data (Dict[str, Any]): Additional metadata.
entity_id (str): Predefined id of entity. New id is created
data (Optional[Dict[str, Any]]): Additional metadata.
entity_id (Optional[str]): Predefined id of entity. New id is created
if not passed.
Returns:

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@ SLUGIFY_SEP_WHITELIST = " ,./\\;:!|*^#@~+-_="
RepresentationParents = collections.namedtuple(
"RepresentationParents",
("version", "subset", "folder", "project")
("version", "product", "folder", "project")
)

View file

@ -1,2 +1,2 @@
"""Package declaring Python API for Ayon server."""
__version__ = "0.1.18"
__version__ = "0.2.0"