Merge pull request #5817 from ynput/feature/OP-7176_Use-folder-path-as-unique-identifier

AYON: Use folder path as unique identifier
This commit is contained in:
Jakub Trllo 2023-11-21 18:30:14 +01:00 committed by GitHub
commit 572122777f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 1055 additions and 392 deletions

View file

@ -44,6 +44,8 @@ from .entities import (
get_thumbnail_id_from_source,
get_workfile_info,
get_asset_name_identifier,
)
from .entity_links import (
@ -108,4 +110,6 @@ __all__ = (
"get_linked_representation_id",
"create_project",
"get_asset_name_identifier",
)

View file

@ -4,3 +4,22 @@ if not AYON_SERVER_ENABLED:
from .mongo.entities import *
else:
from .server.entities import *
def get_asset_name_identifier(asset_doc):
"""Get asset name identifier by asset document.
This function is added because of AYON implementation where name
identifier is not just a name but full path.
Asset document must have "name" key, and "data.parents" when in AYON mode.
Args:
asset_doc (dict[str, Any]): Asset document.
"""
if not AYON_SERVER_ENABLED:
return asset_doc["name"]
parents = list(asset_doc["data"]["parents"])
parents.append(asset_doc["name"])
return "/" + "/".join(parents)

View file

@ -182,6 +182,19 @@ def get_asset_by_name(project_name, asset_name, fields=None):
return None
def _folders_query(project_name, con, fields, **kwargs):
if fields is None or "tasks" in fields:
folders = get_folders_with_tasks(
con, project_name, fields=fields, **kwargs
)
else:
folders = con.get_folders(project_name, fields=fields, **kwargs)
for folder in folders:
yield folder
def get_assets(
project_name,
asset_ids=None,
@ -201,20 +214,39 @@ def get_assets(
fields = folder_fields_v3_to_v4(fields, con)
kwargs = dict(
folder_ids=asset_ids,
folder_names=asset_names,
parent_ids=parent_ids,
active=active,
fields=fields
)
if not asset_names:
for folder in _folders_query(project_name, con, fields, **kwargs):
yield convert_v4_folder_to_v3(folder, project_name)
return
if fields is None or "tasks" in fields:
folders = get_folders_with_tasks(con, project_name, **kwargs)
new_asset_names = set()
folder_paths = set()
for name in asset_names:
if "/" in name:
folder_paths.add(name)
else:
new_asset_names.add(name)
else:
folders = con.get_folders(project_name, **kwargs)
yielded_ids = set()
if folder_paths:
for folder in _folders_query(
project_name, con, fields, folder_paths=folder_paths, **kwargs
):
yielded_ids.add(folder["id"])
yield convert_v4_folder_to_v3(folder, project_name)
for folder in folders:
yield convert_v4_folder_to_v3(folder, project_name)
if not new_asset_names:
return
for folder in _folders_query(
project_name, con, fields, folder_names=new_asset_names, **kwargs
):
if folder["id"] not in yielded_ids:
yielded_ids.add(folder["id"])
yield convert_v4_folder_to_v3(folder, project_name)
def get_archived_assets(

View file

@ -170,7 +170,7 @@ class HostBase(object):
if project_name:
items.append(project_name)
if asset_name:
items.append(asset_name)
items.append(asset_name.lstrip("/"))
if task_name:
items.append(task_name)
if items:

View file

@ -1,3 +1,4 @@
from openpype import AYON_SERVER_ENABLED
import openpype.hosts.aftereffects.api as api
from openpype.client import get_asset_by_name
from openpype.pipeline import (
@ -43,6 +44,14 @@ class AEWorkfileCreator(AutoCreator):
task_name = context.get_current_task_name()
host_name = context.host_name
existing_asset_name = None
if existing_instance is not None:
if AYON_SERVER_ENABLED:
existing_asset_name = existing_instance.get("folderPath")
if existing_asset_name is None:
existing_asset_name = existing_instance["asset"]
if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
@ -50,10 +59,13 @@ class AEWorkfileCreator(AutoCreator):
project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(self.get_dynamic_data(
self.default_variant, task_name, asset_doc,
project_name, host_name, None
@ -68,7 +80,7 @@ class AEWorkfileCreator(AutoCreator):
new_instance.data_to_store())
elif (
existing_instance["asset"] != asset_name
existing_asset_name != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -76,6 +88,10 @@ class AEWorkfileCreator(AutoCreator):
self.default_variant, task_name, asset_doc,
project_name, host_name
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,6 +1,8 @@
import os
import pyblish.api
from openpype.client import get_asset_name_identifier
from openpype.pipeline.create import get_subset_name
@ -48,9 +50,11 @@ class CollectWorkfile(pyblish.api.ContextPlugin):
asset_entity = context.data["assetEntity"]
project_entity = context.data["projectEntity"]
asset_name = get_asset_name_identifier(asset_entity)
instance_data = {
"active": True,
"asset": asset_entity["name"],
"asset": asset_name,
"task": task,
"frameStart": context.data['frameStart'],
"frameEnd": context.data['frameEnd'],

View file

@ -6,11 +6,11 @@ from typing import Dict, List, Optional
import bpy
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import (
Creator,
CreatedInstance,
LoaderPlugin,
get_current_task_name,
)
from openpype.lib import BoolDef
@ -225,7 +225,12 @@ class BaseCreator(Creator):
bpy.context.scene.collection.children.link(instances)
# Create asset group
name = prepare_scene_name(instance_data["asset"], subset_name)
if AYON_SERVER_ENABLED:
asset_name = instance_data["folderPath"]
else:
asset_name = instance_data["asset"]
name = prepare_scene_name(asset_name, subset_name)
if self.create_as_asset_group:
# Create instance as empty
instance_node = bpy.data.objects.new(name=name, object_data=None)
@ -281,7 +286,14 @@ class BaseCreator(Creator):
Args:
update_list(List[UpdateData]): Changed instances
and their changes, as a list of tuples."""
and their changes, as a list of tuples.
"""
if AYON_SERVER_ENABLED:
asset_name_key = "folderPath"
else:
asset_name_key = "asset"
for created_instance, changes in update_list:
data = created_instance.data_to_store()
node = created_instance.transient_data["instance_node"]
@ -295,11 +307,12 @@ class BaseCreator(Creator):
# Rename the instance node in the scene if subset or asset changed
if (
"subset" in changes.changed_keys
or "asset" in changes.changed_keys
"subset" in changes.changed_keys
or asset_name_key in changes.changed_keys
):
asset_name = data[asset_name_key]
name = prepare_scene_name(
asset=data["asset"], subset=data["subset"]
asset=asset_name, subset=data["subset"]
)
node.name = name

View file

@ -1,5 +1,6 @@
import bpy
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import CreatedInstance, AutoCreator
from openpype.client import get_asset_by_name
from openpype.hosts.blender.api.plugin import BaseCreator
@ -24,7 +25,7 @@ class CreateWorkfile(BaseCreator, AutoCreator):
def create(self):
"""Create workfile instances."""
current_instance = next(
existing_instance = next(
(
instance for instance in self.create_context.instances
if instance.creator_identifier == self.identifier
@ -37,16 +38,27 @@ class CreateWorkfile(BaseCreator, AutoCreator):
task_name = self.create_context.get_current_task_name()
host_name = self.create_context.host_name
if not current_instance:
existing_asset_name = None
if existing_instance is not None:
if AYON_SERVER_ENABLED:
existing_asset_name = existing_instance.get("folderPath")
if existing_asset_name is None:
existing_asset_name = existing_instance["asset"]
if not existing_instance:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
task_name, task_name, asset_doc, project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": task_name,
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(
self.get_dynamic_data(
task_name,
@ -54,7 +66,7 @@ class CreateWorkfile(BaseCreator, AutoCreator):
asset_doc,
project_name,
host_name,
current_instance,
existing_instance,
)
)
self.log.info("Auto-creating workfile instance...")
@ -65,17 +77,21 @@ class CreateWorkfile(BaseCreator, AutoCreator):
current_instance.transient_data["instance_node"] = instance_node
self._add_instance_to_context(current_instance)
elif (
current_instance["asset"] != asset_name
or current_instance["task"] != task_name
existing_asset_name != asset_name
or existing_instance["task"] != task_name
):
# Update instance context if it's different
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
task_name, task_name, asset_doc, project_name, host_name
)
current_instance["asset"] = asset_name
current_instance["task"] = task_name
current_instance["subset"] = subset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name
def collect_instances(self):

View file

@ -19,7 +19,10 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.abc"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.abc"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -23,7 +23,11 @@ class ExtractAnimationABC(
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.abc"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.abc"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -20,7 +20,10 @@ class ExtractBlend(publish.Extractor, publish.OptionalPyblishPluginMixin):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.blend"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.blend"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -23,7 +23,10 @@ class ExtractBlendAnimation(
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.blend"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.blend"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -21,7 +21,10 @@ class ExtractCameraABC(publish.Extractor, publish.OptionalPyblishPluginMixin):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.abc"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.abc"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -20,7 +20,10 @@ class ExtractCamera(publish.Extractor, publish.OptionalPyblishPluginMixin):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.fbx"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.fbx"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -21,7 +21,10 @@ class ExtractFBX(publish.Extractor, publish.OptionalPyblishPluginMixin):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.fbx"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
filename = f"{instance_name}.fbx"
filepath = os.path.join(stagingdir, filename)
# Perform extraction

View file

@ -145,7 +145,10 @@ class ExtractAnimationFBX(
root.select_set(True)
armature.select_set(True)
fbx_filename = f"{instance.name}_{armature.name}.fbx"
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
fbx_filename = f"{instance_name}_{armature.name}.fbx"
filepath = os.path.join(stagingdir, fbx_filename)
override = plugin.create_blender_context(
@ -178,7 +181,7 @@ class ExtractAnimationFBX(
pair[1].user_clear()
bpy.data.actions.remove(pair[1])
json_filename = f"{instance.name}.json"
json_filename = f"{instance_name}.json"
json_path = os.path.join(stagingdir, json_filename)
json_dict = {

View file

@ -224,7 +224,11 @@ class ExtractLayout(publish.Extractor, publish.OptionalPyblishPluginMixin):
json_data.append(json_element)
json_filename = "{}.json".format(instance.name)
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
instance_name = f"{asset_name}_{subset}"
json_filename = f"{instance_name}.json"
json_path = os.path.join(stagingdir, json_filename)
with open(json_path, "w+") as file:

View file

@ -51,7 +51,10 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin):
# get output path
stagingdir = self.staging_dir(instance)
filename = instance.name
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
filename = f"{asset_name}_{subset}"
path = os.path.join(stagingdir, filename)
self.log.debug(f"Outputting images to {path}")

View file

@ -27,7 +27,10 @@ class ExtractThumbnail(publish.Extractor):
self.log.debug("Extracting capture..")
stagingdir = self.staging_dir(instance)
filename = instance.name
asset_name = instance.data["assetEntity"]["name"]
subset = instance.data["subset"]
filename = f"{asset_name}_{subset}"
path = os.path.join(stagingdir, filename)
self.log.debug(f"Outputting images to {path}")

View file

@ -1,6 +1,8 @@
import os
import pyblish.api
from openpype.client import get_asset_name_identifier
class CollectCelactionInstances(pyblish.api.ContextPlugin):
""" Adds the celaction render instances """
@ -17,8 +19,10 @@ class CollectCelactionInstances(pyblish.api.ContextPlugin):
asset_entity = context.data["assetEntity"]
project_entity = context.data["projectEntity"]
asset_name = get_asset_name_identifier(asset_entity)
shared_instance_data = {
"asset": asset_entity["name"],
"asset": asset_name,
"frameStart": asset_entity["data"]["frameStart"],
"frameEnd": asset_entity["data"]["frameEnd"],
"handleStart": asset_entity["data"]["handleStart"],

View file

@ -1,5 +1,6 @@
import pyblish.api
from openpype.client import get_asset_name_identifier
import openpype.hosts.flame.api as opfapi
from openpype.hosts.flame.otio import flame_export
from openpype.pipeline.create import get_subset_name
@ -33,13 +34,15 @@ class CollecTimelineOTIO(pyblish.api.ContextPlugin):
project_settings=context.data["project_settings"]
)
asset_name = get_asset_name_identifier(asset_doc)
# adding otio timeline to context
with opfapi.maintained_segment_selection(sequence) as selected_seg:
otio_timeline = flame_export.create_otio_timeline(sequence)
instance_data = {
"name": subset_name,
"asset": asset_doc["name"],
"asset": asset_name,
"subset": subset_name,
"family": "workfile",
"families": []

View file

@ -1,6 +1,7 @@
from openpype.hosts.fusion.api import (
get_current_comp
)
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_by_name
from openpype.pipeline import (
AutoCreator,
@ -68,6 +69,13 @@ class FusionWorkfileCreator(AutoCreator):
task_name = self.create_context.get_current_task_name()
host_name = self.create_context.host_name
if existing_instance is None:
existing_instance_asset = None
elif AYON_SERVER_ENABLED:
existing_instance_asset = existing_instance["folderPath"]
else:
existing_instance_asset = existing_instance["asset"]
if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
@ -75,10 +83,13 @@ class FusionWorkfileCreator(AutoCreator):
project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(self.get_dynamic_data(
self.default_variant, task_name, asset_doc,
project_name, host_name, None
@ -91,7 +102,7 @@ class FusionWorkfileCreator(AutoCreator):
self._add_instance_to_context(new_instance)
elif (
existing_instance["asset"] != asset_name
existing_instance_asset != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -99,6 +110,9 @@ class FusionWorkfileCreator(AutoCreator):
self.default_variant, task_name, asset_doc,
project_name, host_name
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -11,7 +11,6 @@ import qargparse
from openpype.settings import get_current_project_settings
from openpype.lib import Logger
from openpype.pipeline import LoaderPlugin, LegacyCreator
from openpype.pipeline.context_tools import get_current_project_asset
from openpype.pipeline.load import get_representation_path_from_context
from . import lib
@ -32,7 +31,7 @@ def load_stylesheet():
class CreatorWidget(QtWidgets.QDialog):
# output items
items = dict()
items = {}
def __init__(self, name, info, ui_inputs, parent=None):
super(CreatorWidget, self).__init__(parent)
@ -494,9 +493,8 @@ class ClipLoader:
joint `data` key with asset.data dict into the representation
"""
asset_name = self.context["representation"]["context"]["asset"]
asset_doc = get_current_project_asset(asset_name)
log.debug("__ asset_doc: {}".format(pformat(asset_doc)))
asset_doc = self.context["asset"]
self.data["assetData"] = asset_doc["data"]
def _make_track_item(self, source_bin_item, audio=False):
@ -644,8 +642,8 @@ class PublishClip:
Returns:
hiero.core.TrackItem: hiero track item object with pype tag
"""
vertical_clip_match = dict()
tag_data = dict()
vertical_clip_match = {}
tag_data = {}
types = {
"shot": "shot",
"folder": "folder",
@ -707,9 +705,10 @@ class PublishClip:
self._create_parents()
def convert(self):
# solve track item data and add them to tag data
self._convert_to_tag_data()
tag_hierarchy_data = self._convert_to_tag_data()
self.tag_data.update(tag_hierarchy_data)
# if track name is in review track name and also if driving track name
# is not in review track name: skip tag creation
@ -723,16 +722,23 @@ class PublishClip:
if self.rename:
# rename track item
self.track_item.setName(new_name)
self.tag_data["asset"] = new_name
self.tag_data["asset_name"] = new_name
else:
self.tag_data["asset"] = self.ti_name
self.tag_data["asset_name"] = self.ti_name
self.tag_data["hierarchyData"]["shot"] = self.ti_name
# AYON unique identifier
folder_path = "/{}/{}".format(
tag_hierarchy_data["hierarchy"],
self.tag_data["asset_name"]
)
self.tag_data["folderPath"] = folder_path
if self.tag_data["heroTrack"] and self.review_layer:
self.tag_data.update({"reviewTrack": self.review_layer})
else:
self.tag_data.update({"reviewTrack": None})
# TODO: remove debug print
log.debug("___ self.tag_data: {}".format(
pformat(self.tag_data)
))
@ -891,7 +897,7 @@ class PublishClip:
tag_hierarchy_data = hero_data
# add data to return data dict
self.tag_data.update(tag_hierarchy_data)
return tag_hierarchy_data
def _solve_tag_hierarchy_data(self, hierarchy_formatting_data):
""" Solve tag data from hierarchy data and templates. """

View file

@ -5,6 +5,8 @@ import json
import pyblish.api
from openpype.client import get_asset_name_identifier
class CollectFrameTagInstances(pyblish.api.ContextPlugin):
"""Collect frames from tags.
@ -99,6 +101,9 @@ class CollectFrameTagInstances(pyblish.api.ContextPlugin):
# first collect all available subset tag frames
subset_data = {}
context_asset_doc = context.data["assetEntity"]
context_asset_name = get_asset_name_identifier(context_asset_doc)
for tag_data in sequence_tags:
frame = int(tag_data["start"])
@ -115,7 +120,7 @@ class CollectFrameTagInstances(pyblish.api.ContextPlugin):
subset_data[subset] = {
"frames": [frame],
"format": tag_data["format"],
"asset": context.data["assetEntity"]["name"]
"asset": context_asset_name
}
return subset_data

View file

@ -1,9 +1,12 @@
import pyblish
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline.editorial import is_overlapping_otio_ranges
from openpype.hosts.hiero import api as phiero
from openpype.hosts.hiero.api.otio import hiero_export
import hiero
import hiero
# # developer reload modules
from pprint import pformat
@ -80,25 +83,24 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
if k not in ("id", "applieswhole", "label")
})
asset = tag_data["asset"]
asset, asset_name = self._get_asset_data(tag_data)
subset = tag_data["subset"]
# insert family into families
family = tag_data["family"]
families = [str(f) for f in tag_data["families"]]
families.insert(0, str(family))
# form label
label = asset
if asset != clip_name:
label = "{} -".format(asset)
if asset_name != clip_name:
label += " ({})".format(clip_name)
label += " {}".format(subset)
label += " {}".format("[" + ", ".join(families) + "]")
data.update({
"name": "{}_{}".format(asset, subset),
"label": label,
"asset": asset,
"asset_name": asset_name,
"item": track_item,
"families": families,
"publish": tag_data["publish"],
@ -176,9 +178,9 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
})
def create_shot_instance(self, context, **data):
subset = "shotMain"
master_layer = data.get("heroTrack")
hierarchy_data = data.get("hierarchyData")
asset = data.get("asset")
item = data.get("item")
clip_name = item.name()
@ -189,23 +191,21 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
return
asset = data["asset"]
subset = "shotMain"
asset_name = data["asset_name"]
# insert family into families
family = "shot"
# form label
label = asset
if asset != clip_name:
label = "{} -".format(asset)
if asset_name != clip_name:
label += " ({}) ".format(clip_name)
label += " {}".format(subset)
label += " [{}]".format(family)
data.update({
"name": "{}_{}".format(asset, subset),
"label": label,
"subset": subset,
"asset": asset,
"family": family,
"families": []
})
@ -215,7 +215,33 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
self.log.debug(
"_ instance.data: {}".format(pformat(instance.data)))
def _get_asset_data(self, data):
folder_path = data.pop("folderPath", None)
if data.get("asset_name"):
asset_name = data["asset_name"]
else:
asset_name = data["asset"]
# backward compatibility for clip tags
# which are missing folderPath key
# TODO remove this in future versions
if not folder_path:
hierarchy_path = data["hierarchy"]
folder_path = "/{}/{}".format(
hierarchy_path,
asset_name
)
if AYON_SERVER_ENABLED:
asset = folder_path
else:
asset = asset_name
return asset, asset_name
def create_audio_instance(self, context, **data):
subset = "audioMain"
master_layer = data.get("heroTrack")
if not master_layer:
@ -230,23 +256,21 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
return
asset = data["asset"]
subset = "audioMain"
asset_name = data["asset_name"]
# insert family into families
family = "audio"
# form label
label = asset
if asset != clip_name:
label = "{} -".format(asset)
if asset_name != clip_name:
label += " ({}) ".format(clip_name)
label += " {}".format(subset)
label += " [{}]".format(family)
data.update({
"name": "{}_{}".format(asset, subset),
"label": label,
"subset": subset,
"asset": asset,
"family": family,
"families": ["clip"]
})

View file

@ -7,6 +7,7 @@ from qtpy.QtGui import QPixmap
import hiero.ui
from openpype import AYON_SERVER_ENABLED
from openpype.hosts.hiero.api.otio import hiero_export
@ -17,9 +18,11 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
order = pyblish.api.CollectorOrder - 0.491
def process(self, context):
asset = context.data["asset"]
subset = "workfile"
asset_name = asset
if AYON_SERVER_ENABLED:
asset_name = asset_name.split("/")[-1]
active_timeline = hiero.ui.activeSequence()
project = active_timeline.project()
fps = active_timeline.framerate().toFloat()
@ -27,7 +30,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
# adding otio timeline to context
otio_timeline = hiero_export.create_otio_timeline()
# get workfile thumnail paths
# get workfile thumbnail paths
tmp_staging = tempfile.mkdtemp(prefix="pyblish_tmp_")
thumbnail_name = "workfile_thumbnail.png"
thumbnail_path = os.path.join(tmp_staging, thumbnail_name)
@ -49,8 +52,8 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
}
# get workfile paths
curent_file = project.path()
staging_dir, base_name = os.path.split(curent_file)
current_file = project.path()
staging_dir, base_name = os.path.split(current_file)
# creating workfile representation
workfile_representation = {
@ -59,13 +62,16 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
'files': base_name,
"stagingDir": staging_dir,
}
family = "workfile"
instance_data = {
"name": "{}_{}".format(asset, subset),
"asset": asset,
"subset": "{}{}".format(asset, subset.capitalize()),
"label": "{} - {}Main".format(
asset, family),
"name": "{}_{}".format(asset_name, family),
"asset": context.data["asset"],
# TODO use 'get_subset_name'
"subset": "{}{}Main".format(asset_name, family.capitalize()),
"item": project,
"family": "workfile",
"family": family,
"families": [],
"representations": [workfile_representation, thumb_representation]
}
@ -78,7 +84,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
"activeProject": project,
"activeTimeline": active_timeline,
"otioTimeline": otio_timeline,
"currentFile": curent_file,
"currentFile": current_file,
"colorspace": self.get_colorspace(project),
"fps": fps
}

View file

@ -1,5 +1,6 @@
from pyblish import api
from openpype.client import get_assets
from openpype.client import get_assets, get_asset_name_identifier
class CollectAssetBuilds(api.ContextPlugin):
@ -19,10 +20,13 @@ class CollectAssetBuilds(api.ContextPlugin):
def process(self, context):
project_name = context.data["projectName"]
asset_builds = {}
for asset in get_assets(project_name):
if asset["data"]["entityType"] == "AssetBuild":
self.log.debug("Found \"{}\" in database.".format(asset))
asset_builds[asset["name"]] = asset
for asset_doc in get_assets(project_name):
if asset_doc["data"].get("entityType") != "AssetBuild":
continue
asset_name = get_asset_name_identifier(asset_doc)
self.log.debug("Found \"{}\" in database.".format(asset_doc))
asset_builds[asset_name] = asset_doc
for instance in context:
if instance.data["family"] != "clip":
@ -50,9 +54,7 @@ class CollectAssetBuilds(api.ContextPlugin):
# Collect asset builds.
data = {"assetbuilds": []}
for name in asset_names:
data["assetbuilds"].append(
asset_builds[name]
)
data["assetbuilds"].append(asset_builds[name])
self.log.debug(
"Found asset builds: {}".format(data["assetbuilds"])
)

View file

@ -6,6 +6,8 @@ from abc import (
)
import six
import hou
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import (
CreatorError,
LegacyCreator,
@ -142,12 +144,13 @@ class HoudiniCreatorBase(object):
@staticmethod
def create_instance_node(
node_name, parent,
node_type="geometry"):
asset_name, node_name, parent, node_type="geometry"
):
# type: (str, str, str) -> hou.Node
"""Create node representing instance.
Arguments:
asset_name (str): Asset name.
node_name (str): Name of the new node.
parent (str): Name of the parent node.
node_type (str, optional): Type of the node.
@ -182,8 +185,13 @@ class HoudiniCreator(NewCreator, HoudiniCreatorBase):
if node_type is None:
node_type = "geometry"
if AYON_SERVER_ENABLED:
asset_name = instance_data["folderPath"]
else:
asset_name = instance_data["asset"]
instance_node = self.create_instance_node(
subset_name, "/out", node_type)
asset_name, subset_name, "/out", node_type)
self.customize_node_look(instance_node)

View file

@ -17,13 +17,13 @@ class CreateHDA(plugin.HoudiniCreator):
icon = "gears"
maintain_selection = False
def _check_existing(self, subset_name):
def _check_existing(self, asset_name, subset_name):
# type: (str) -> bool
"""Check if existing subset name versions already exists."""
# Get all subsets of the current asset
project_name = self.project_name
asset_doc = get_asset_by_name(
project_name, self.data["asset"], fields=["_id"]
project_name, asset_name, fields=["_id"]
)
subset_docs = get_subsets(
project_name, asset_ids=[asset_doc["_id"]], fields=["name"]
@ -35,7 +35,8 @@ class CreateHDA(plugin.HoudiniCreator):
return subset_name.lower() in existing_subset_names_low
def create_instance_node(
self, node_name, parent, node_type="geometry"):
self, asset_name, node_name, parent, node_type="geometry"
):
parent_node = hou.node("/obj")
if self.selected_nodes:
@ -61,7 +62,7 @@ class CreateHDA(plugin.HoudiniCreator):
hda_file_name="$HIP/{}.hda".format(node_name)
)
hda_node.layoutChildren()
elif self._check_existing(node_name):
elif self._check_existing(asset_name, node_name):
raise plugin.OpenPypeCreatorError(
("subset {} is already published with different HDA"
"definition.").format(node_name))

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating workfiles."""
from openpype import AYON_SERVER_ENABLED
from openpype.hosts.houdini.api import plugin
from openpype.hosts.houdini.api.lib import read, imprint
from openpype.hosts.houdini.api.pipeline import CONTEXT_CONTAINER
@ -30,16 +31,27 @@ class CreateWorkfile(plugin.HoudiniCreatorBase, AutoCreator):
task_name = self.create_context.get_current_task_name()
host_name = self.host_name
if current_instance is None:
current_instance_asset = None
elif AYON_SERVER_ENABLED:
current_instance_asset = current_instance["folderPath"]
else:
current_instance_asset = current_instance["asset"]
if current_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(
self.get_dynamic_data(
variant, task_name, asset_doc,
@ -51,15 +63,18 @@ class CreateWorkfile(plugin.HoudiniCreatorBase, AutoCreator):
)
self._add_instance_to_context(current_instance)
elif (
current_instance["asset"] != asset_name
or current_instance["task"] != task_name
current_instance_asset != asset_name
or current_instance["task"] != task_name
):
# Update instance context if is not the same
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
current_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
current_instance["folderPath"] = asset_name
else:
current_instance["asset"] = asset_name
current_instance["task"] = task_name
current_instance["subset"] = subset_name

View file

@ -1,6 +1,10 @@
import pyblish.api
from openpype.client import get_subset_by_name, get_asset_by_name
from openpype.client import (
get_subset_by_name,
get_asset_by_name,
get_asset_name_identifier,
)
import openpype.lib.usdlib as usdlib
@ -51,8 +55,9 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
self.log.debug("Add bootstrap for: %s" % bootstrap)
project_name = instance.context.data["projectName"]
asset = get_asset_by_name(project_name, instance.data["asset"])
assert asset, "Asset must exist: %s" % asset
asset_name = instance.data["asset"]
asset_doc = get_asset_by_name(project_name, asset_name)
assert asset_doc, "Asset must exist: %s" % asset_name
# Check which are not about to be created and don't exist yet
required = {"shot": ["usdShot"], "asset": ["usdAsset"]}.get(bootstrap)
@ -67,19 +72,21 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
required += list(layers)
self.log.debug("Checking required bootstrap: %s" % required)
for subset in required:
if self._subset_exists(project_name, instance, subset, asset):
for subset_name in required:
if self._subset_exists(
project_name, instance, subset_name, asset_doc
):
continue
self.log.debug(
"Creating {0} USD bootstrap: {1} {2}".format(
bootstrap, asset["name"], subset
bootstrap, asset_name, subset_name
)
)
new = instance.context.create_instance(subset)
new.data["subset"] = subset
new.data["label"] = "{0} ({1})".format(subset, asset["name"])
new = instance.context.create_instance(subset_name)
new.data["subset"] = subset_name
new.data["label"] = "{0} ({1})".format(subset_name, asset_name)
new.data["family"] = "usd.bootstrap"
new.data["comment"] = "Automated bootstrap USD file."
new.data["publishFamilies"] = ["usd"]
@ -91,21 +98,23 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
for key in ["asset"]:
new.data[key] = instance.data[key]
def _subset_exists(self, project_name, instance, subset, asset):
def _subset_exists(self, project_name, instance, subset_name, asset_doc):
"""Return whether subset exists in current context or in database."""
# Allow it to be created during this publish session
context = instance.context
asset_doc_name = get_asset_name_identifier(asset_doc)
for inst in context:
if (
inst.data["subset"] == subset
and inst.data["asset"] == asset["name"]
inst.data["subset"] == subset_name
and inst.data["asset"] == asset_doc_name
):
return True
# Or, if they already exist in the database we can
# skip them too.
if get_subset_by_name(
project_name, subset, asset["_id"], fields=["_id"]
project_name, subset_name, asset_doc["_id"], fields=["_id"]
):
return True
return False

View file

@ -54,12 +54,13 @@ class ValidateSubsetName(pyblish.api.InstancePlugin,
rop_node = hou.node(instance.data["instance_node"])
# Check subset name
asset_doc = instance.data["assetEntity"]
subset_name = get_subset_name(
family=instance.data["family"],
variant=instance.data["variant"],
task_name=instance.data["task"],
asset_doc=instance.data["assetEntity"],
dynamic_data={"asset": instance.data["asset"]}
asset_doc=asset_doc,
dynamic_data={"asset": asset_doc["name"]}
)
if instance.data.get("subset") != subset_name:
@ -76,12 +77,13 @@ class ValidateSubsetName(pyblish.api.InstancePlugin,
rop_node = hou.node(instance.data["instance_node"])
# Check subset name
asset_doc = instance.data["assetEntity"]
subset_name = get_subset_name(
family=instance.data["family"],
variant=instance.data["variant"],
task_name=instance.data["task"],
asset_doc=instance.data["assetEntity"],
dynamic_data={"asset": instance.data["asset"]}
asset_doc=asset_doc,
dynamic_data={"asset": asset_doc["name"]}
)
instance.data["subset"] = subset_name

View file

@ -7,6 +7,7 @@ import six
from maya import cmds
from maya.app.renderSetup.model import renderSetup
from openpype import AYON_SERVER_ENABLED
from openpype.lib import BoolDef, Logger
from openpype.settings import get_project_settings
from openpype.pipeline import (
@ -449,14 +450,16 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase):
# this instance will not have the `instance_node` data yet
# until it's been saved/persisted at least once.
project_name = self.create_context.get_current_project_name()
asset_name = self.create_context.get_current_asset_name()
instance_data = {
"asset": self.create_context.get_current_asset_name(),
"task": self.create_context.get_current_task_name(),
"variant": layer.name(),
}
asset_doc = get_asset_by_name(project_name,
instance_data["asset"])
if AYON_SERVER_ENABLED:
instance_data["folderPath"] = asset_name
else:
instance_data["asset"] = asset_name
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
layer.name(),
instance_data["task"],

View file

@ -45,10 +45,14 @@ class CreateMultishotLayout(plugin.MayaCreator):
above is done.
"""
current_folder = get_folder_by_name(
project_name=get_current_project_name(),
folder_name=get_current_asset_name(),
)
project_name = get_current_project_name()
folder_path = get_current_asset_name()
if "/" in folder_path:
current_folder = get_folder_by_path(project_name, folder_path)
else:
current_folder = get_folder_by_name(
project_name, folder_name=folder_path
)
current_path_parts = current_folder["path"].split("/")
@ -154,7 +158,7 @@ class CreateMultishotLayout(plugin.MayaCreator):
# Create layout instance by the layout creator
instance_data = {
"asset": shot["name"],
"folderPath": shot["path"],
"variant": layout_creator.get_default_variant()
}
if layout_task:

View file

@ -2,6 +2,7 @@ import json
from maya import cmds
from openpype import AYON_SERVER_ENABLED
from openpype.hosts.maya.api import (
lib,
plugin
@ -43,7 +44,11 @@ class CreateReview(plugin.MayaCreator):
members = cmds.ls(selection=True)
project_name = self.project_name
asset_doc = get_asset_by_name(project_name, instance_data["asset"])
if AYON_SERVER_ENABLED:
asset_name = instance_data["folderPath"]
else:
asset_name = instance_data["asset"]
asset_doc = get_asset_by_name(project_name, asset_name)
task_name = instance_data["task"]
preset = lib.get_capture_preset(
task_name,

View file

@ -51,7 +51,7 @@ class CreateUnrealSkeletalMesh(plugin.MayaCreator):
# We reorganize the geometry that was originally added into the
# set into either 'joints_SET' or 'geometry_SET' based on the
# joint_hints from project settings
members = cmds.sets(instance_node, query=True)
members = cmds.sets(instance_node, query=True) or []
cmds.sets(clear=instance_node)
geometry_set = cmds.sets(name="geometry_SET", empty=True)

View file

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating workfiles."""
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import CreatedInstance, AutoCreator
from openpype.client import get_asset_by_name
from openpype.client import get_asset_by_name, get_asset_name_identifier
from openpype.hosts.maya.api import plugin
from maya import cmds
@ -29,16 +30,27 @@ class CreateWorkfile(plugin.MayaCreatorBase, AutoCreator):
task_name = self.create_context.get_current_task_name()
host_name = self.create_context.host_name
if current_instance is None:
current_instance_asset = None
elif AYON_SERVER_ENABLED:
current_instance_asset = current_instance["folderPath"]
else:
current_instance_asset = current_instance["asset"]
if current_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(
self.get_dynamic_data(
variant, task_name, asset_doc,
@ -50,15 +62,20 @@ class CreateWorkfile(plugin.MayaCreatorBase, AutoCreator):
)
self._add_instance_to_context(current_instance)
elif (
current_instance["asset"] != asset_name
or current_instance["task"] != task_name
current_instance_asset != asset_name
or current_instance["task"] != task_name
):
# Update instance context if is not the same
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
current_instance["asset"] = asset_name
asset_name = get_asset_name_identifier(asset_doc)
if AYON_SERVER_ENABLED:
current_instance["folderPath"] = asset_name
else:
current_instance["asset"] = asset_name
current_instance["task"] = task_name
current_instance["subset"] = subset_name

View file

@ -3,7 +3,7 @@ from maya import cmds, mel
import pyblish.api
from openpype.client import get_subset_by_name
from openpype.pipeline import legacy_io, KnownPublishError
from openpype.pipeline import KnownPublishError
from openpype.hosts.maya.api import lib
@ -116,10 +116,10 @@ class CollectReview(pyblish.api.InstancePlugin):
instance.data['remove'] = True
else:
task = legacy_io.Session["AVALON_TASK"]
legacy_subset_name = task + 'Review'
project_name = instance.context.data["projectName"]
asset_doc = instance.context.data['assetEntity']
project_name = legacy_io.active_project()
task = instance.context.data["task"]
legacy_subset_name = task + 'Review'
subset_doc = get_subset_by_name(
project_name,
legacy_subset_name,

View file

@ -13,16 +13,6 @@ from openpype.hosts.maya.api.lib import (
)
@contextmanager
def renamed(original_name, renamed_name):
# type: (str, str) -> None
try:
cmds.rename(original_name, renamed_name)
yield
finally:
cmds.rename(renamed_name, original_name)
class ExtractUnrealSkeletalMeshAbc(publish.Extractor):
"""Extract Unreal Skeletal Mesh as FBX from Maya. """

View file

@ -62,6 +62,10 @@ class ExtractUnrealSkeletalMeshFbx(publish.Extractor):
original_parent = to_extract[0].split("|")[1]
parent_node = instance.data.get("asset")
# this needs to be done for AYON
# WARNING: since AYON supports duplicity of asset names,
# this needs to be refactored throughout the pipeline.
parent_node = parent_node.split("/")[-1]
renamed_to_extract = []
for node in to_extract:

View file

@ -3,6 +3,7 @@
from __future__ import absolute_import
import pyblish.api
from openpype import AYON_SERVER_ENABLED
import openpype.hosts.maya.api.action
from openpype.pipeline.publish import (
RepairAction,
@ -66,12 +67,16 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin,
def repair(cls, instance):
context_asset = cls.get_context_asset(instance)
instance_node = instance.data["instance_node"]
if AYON_SERVER_ENABLED:
asset_name_attr = "folderPath"
else:
asset_name_attr = "asset"
cmds.setAttr(
"{}.asset".format(instance_node),
"{}.{}".format(instance_node, asset_name_attr),
context_asset,
type="string"
)
@staticmethod
def get_context_asset(instance):
return instance.context.data["assetEntity"]["name"]
return instance.context.data["asset"]

View file

@ -67,13 +67,15 @@ class ValidateModelName(pyblish.api.InstancePlugin,
regex = cls.top_level_regex
r = re.compile(regex)
m = r.match(top_group)
project_name = instance.context.data["projectName"]
current_asset_name = instance.context.data["asset"]
if m is None:
cls.log.error("invalid name on: {}".format(top_group))
cls.log.error("name doesn't match regex {}".format(regex))
invalid.append(top_group)
else:
if "asset" in r.groupindex:
if m.group("asset") != legacy_io.Session["AVALON_ASSET"]:
if m.group("asset") != current_asset_name:
cls.log.error("Invalid asset name in top level group.")
return top_group
if "subset" in r.groupindex:
@ -81,7 +83,7 @@ class ValidateModelName(pyblish.api.InstancePlugin,
cls.log.error("Invalid subset name in top level group.")
return top_group
if "project" in r.groupindex:
if m.group("project") != legacy_io.Session["AVALON_PROJECT"]:
if m.group("project") != project_name:
cls.log.error("Invalid project name in top level group.")
return top_group

View file

@ -51,7 +51,7 @@ class ValidateShaderName(pyblish.api.InstancePlugin,
descendants = cmds.ls(descendants, noIntermediate=True, long=True)
shapes = cmds.ls(descendants, type=["nurbsSurface", "mesh"], long=True)
asset_name = instance.data.get("asset", None)
asset_name = instance.data.get("asset")
# Check the number of connected shadingEngines per shape
regex_compile = re.compile(cls.regex)

View file

@ -102,7 +102,8 @@ class ValidateUnrealStaticMeshName(pyblish.api.InstancePlugin,
cl_r = re.compile(regex_collision)
mesh_name = "{}{}".format(instance.data["asset"],
asset_name = instance.data["assetEntity"]["name"]
mesh_name = "{}{}".format(asset_name,
instance.data.get("variant", []))
for obj in collision_set:

View file

@ -4,7 +4,7 @@ from collections import defaultdict
import maya.cmds as cmds
from openpype.client import get_assets
from openpype.client import get_assets, get_asset_name_identifier
from openpype.pipeline import (
remove_container,
registered_host,
@ -128,7 +128,8 @@ def create_items_from_nodes(nodes):
project_name = get_current_project_name()
asset_ids = set(id_hashes.keys())
asset_docs = get_assets(project_name, asset_ids, fields=["name"])
fields = {"_id", "name", "data.parents"}
asset_docs = get_assets(project_name, asset_ids, fields=fields)
asset_docs_by_id = {
str(asset_doc["_id"]): asset_doc
for asset_doc in asset_docs
@ -156,8 +157,9 @@ def create_items_from_nodes(nodes):
namespace = get_namespace_from_node(node)
namespaces.add(namespace)
label = get_asset_name_identifier(asset_doc)
asset_view_items.append({
"label": asset_doc["name"],
"label": label,
"asset": asset_doc,
"looks": looks,
"namespaces": namespaces

View file

@ -3,6 +3,7 @@ from collections import defaultdict
from qtpy import QtWidgets, QtCore
from openpype.client import get_asset_name_identifier
from openpype.tools.utils.models import TreeModel
from openpype.tools.utils.lib import (
preserve_expanded_rows,
@ -126,7 +127,7 @@ class AssetOutliner(QtWidgets.QWidget):
asset_namespaces = defaultdict(set)
for item in items:
asset_id = str(item["asset"]["_id"])
asset_name = item["asset"]["name"]
asset_name = get_asset_name_identifier(item["asset"])
asset_namespaces[asset_name].add(item.get("namespace"))
if asset_name in assets:

View file

@ -13,6 +13,7 @@ from collections import OrderedDict
import nuke
from qtpy import QtCore, QtWidgets
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_project,
get_asset_by_name,
@ -1107,7 +1108,9 @@ def format_anatomy(data):
Return:
path (str)
'''
anatomy = Anatomy()
project_name = get_current_project_name()
anatomy = Anatomy(project_name)
log.debug("__ anatomy.templates: {}".format(anatomy.templates))
padding = None
@ -1125,8 +1128,10 @@ def format_anatomy(data):
file = script_name()
data["version"] = get_version_from_path(file)
project_name = anatomy.project_name
asset_name = data["asset"]
if AYON_SERVER_ENABLED:
asset_name = data["folderPath"]
else:
asset_name = data["asset"]
task_name = data["task"]
host_name = get_current_host_name()
context_data = get_template_data_with_names(

View file

@ -1,5 +1,6 @@
import re
from openpype import AYON_SERVER_ENABLED
import openpype.hosts.photoshop.api as api
from openpype.client import get_asset_by_name
from openpype.lib import prepare_template_data
@ -43,6 +44,14 @@ class PSAutoCreator(AutoCreator):
asset_name = context.get_current_asset_name()
task_name = context.get_current_task_name()
host_name = context.host_name
if existing_instance is None:
existing_instance_asset = None
elif AYON_SERVER_ENABLED:
existing_instance_asset = existing_instance["folderPath"]
else:
existing_instance_asset = existing_instance["asset"]
if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
@ -50,10 +59,13 @@ class PSAutoCreator(AutoCreator):
project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
data.update(self.get_dynamic_data(
self.default_variant, task_name, asset_doc,
project_name, host_name, None
@ -70,7 +82,7 @@ class PSAutoCreator(AutoCreator):
new_instance.data_to_store())
elif (
existing_instance["asset"] != asset_name
existing_instance_asset != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -78,7 +90,10 @@ class PSAutoCreator(AutoCreator):
self.default_variant, task_name, asset_doc,
project_name, host_name
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,5 +1,6 @@
from openpype.pipeline import CreatedInstance
from openpype import AYON_SERVER_ENABLED
from openpype.lib import BoolDef
import openpype.hosts.photoshop.api as api
from openpype.hosts.photoshop.lib import PSAutoCreator, clean_subset_name
@ -37,6 +38,13 @@ class AutoImageCreator(PSAutoCreator):
host_name = context.host_name
asset_doc = get_asset_by_name(project_name, asset_name)
if existing_instance is None:
existing_instance_asset = None
elif AYON_SERVER_ENABLED:
existing_instance_asset = existing_instance["folderPath"]
else:
existing_instance_asset = existing_instance["asset"]
if existing_instance is None:
subset_name = self.get_subset_name(
self.default_variant, task_name, asset_doc,
@ -44,9 +52,12 @@ class AutoImageCreator(PSAutoCreator):
)
data = {
"asset": asset_name,
"task": task_name,
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
if not self.active_on_create:
data["active"] = False
@ -62,15 +73,17 @@ class AutoImageCreator(PSAutoCreator):
new_instance.data_to_store())
elif ( # existing instance from different context
existing_instance["asset"] != asset_name
existing_instance_asset != asset_name
or existing_instance["task"] != task_name
):
subset_name = self.get_subset_name(
self.default_variant, task_name, asset_doc,
project_name, host_name
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,5 +1,6 @@
import pyblish.api
from openpype.client import get_asset_name_identifier
from openpype.hosts.photoshop import api as photoshop
from openpype.pipeline.create import get_subset_name
@ -27,7 +28,7 @@ class CollectAutoImage(pyblish.api.ContextPlugin):
task_name = context.data["task"]
host_name = context.data["hostName"]
asset_doc = context.data["assetEntity"]
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
auto_creator = proj_settings.get(
"photoshop", {}).get(

View file

@ -7,6 +7,7 @@ Provides:
"""
import pyblish.api
from openpype.client import get_asset_name_identifier
from openpype.hosts.photoshop import api as photoshop
from openpype.pipeline.create import get_subset_name
@ -65,7 +66,8 @@ class CollectAutoReview(pyblish.api.ContextPlugin):
task_name = context.data["task"]
host_name = context.data["hostName"]
asset_doc = context.data["assetEntity"]
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
subset_name = get_subset_name(
family,

View file

@ -1,6 +1,7 @@
import os
import pyblish.api
from openpype.client import get_asset_name_identifier
from openpype.hosts.photoshop import api as photoshop
from openpype.pipeline.create import get_subset_name
@ -69,8 +70,8 @@ class CollectAutoWorkfile(pyblish.api.ContextPlugin):
task_name = context.data["task"]
host_name = context.data["hostName"]
asset_doc = context.data["assetEntity"]
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
subset_name = get_subset_name(
family,
variant,

View file

@ -1,10 +1,11 @@
import re
import uuid
import copy
import qargparse
from qtpy import QtWidgets, QtCore
from openpype.settings import get_current_project_settings
from openpype.pipeline.context_tools import get_current_project_asset
from openpype.pipeline import (
LegacyCreator,
LoaderPlugin,
@ -18,7 +19,7 @@ from .menu import load_stylesheet
class CreatorWidget(QtWidgets.QDialog):
# output items
items = dict()
items = {}
def __init__(self, name, info, ui_inputs, parent=None):
super(CreatorWidget, self).__init__(parent)
@ -100,7 +101,7 @@ class CreatorWidget(QtWidgets.QDialog):
self.close()
def value(self, data, new_data=None):
new_data = new_data or dict()
new_data = new_data or {}
for k, v in data.items():
new_data[k] = {
"target": None,
@ -289,7 +290,7 @@ class Spacer(QtWidgets.QWidget):
class ClipLoader:
active_bin = None
data = dict()
data = {}
def __init__(self, loader_obj, context, **options):
""" Initialize object
@ -386,8 +387,8 @@ class ClipLoader:
joint `data` key with asset.data dict into the representation
"""
asset_name = self.context["representation"]["context"]["asset"]
self.data["assetData"] = get_current_project_asset(asset_name)["data"]
self.data["assetData"] = copy.deepcopy(self.context["asset"]["data"])
def load(self, files):
"""Load clip into timeline
@ -587,8 +588,8 @@ class PublishClip:
Returns:
hiero.core.TrackItem: hiero track item object with openpype tag
"""
vertical_clip_match = dict()
tag_data = dict()
vertical_clip_match = {}
tag_data = {}
types = {
"shot": "shot",
"folder": "folder",
@ -664,15 +665,23 @@ class PublishClip:
new_name = self.tag_data.pop("newClipName")
if self.rename:
self.tag_data["asset"] = new_name
self.tag_data["asset_name"] = new_name
else:
self.tag_data["asset"] = self.ti_name
self.tag_data["asset_name"] = self.ti_name
# AYON unique identifier
folder_path = "/{}/{}".format(
self.tag_data["hierarchy"],
self.tag_data["asset_name"]
)
self.tag_data["folder_path"] = folder_path
# create new name for track item
if not lib.pype_marker_workflow:
# create compound clip workflow
lib.create_compound_clip(
self.timeline_item_data,
self.tag_data["asset"],
self.tag_data["asset_name"],
self.mp_folder
)
@ -764,7 +773,7 @@ class PublishClip:
# increasing steps by index of rename iteration
self.count_steps *= self.rename_index
hierarchy_formatting_data = dict()
hierarchy_formatting_data = {}
_data = self.timeline_item_default_data.copy()
if self.ui_inputs:
# adding tag metadata from ui
@ -853,8 +862,7 @@ class PublishClip:
"parents": self.parents,
"hierarchyData": hierarchy_formatting_data,
"subset": self.subset,
"family": self.subset_family,
"families": ["clip"]
"family": self.subset_family
}
def _convert_to_entity(self, key):

View file

@ -26,6 +26,7 @@ class ExtractWorkfile(publish.Extractor):
resolve_workfile_ext = ".drp"
drp_file_name = name + resolve_workfile_ext
drp_file_path = os.path.normpath(
os.path.join(staging_dir, drp_file_name))

View file

@ -9,6 +9,7 @@ from openpype.hosts.resolve.api.lib import (
get_publish_attribute,
get_otio_clip_instance_data,
)
from openpype import AYON_SERVER_ENABLED
class PrecollectInstances(pyblish.api.ContextPlugin):
@ -29,7 +30,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
for timeline_item_data in selected_timeline_items:
data = dict()
data = {}
timeline_item = timeline_item_data["clip"]["item"]
# get pype tag data
@ -60,24 +61,24 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
if k not in ("id", "applieswhole", "label")
})
asset = tag_data["asset"]
if AYON_SERVER_ENABLED:
asset = tag_data["folder_path"]
else:
asset = tag_data["asset_name"]
subset = tag_data["subset"]
# insert family into families
family = tag_data["family"]
families = [str(f) for f in tag_data["families"]]
families.insert(0, str(family))
data.update({
"name": "{} {} {}".format(asset, subset, families),
"name": "{}_{}".format(asset, subset),
"label": "{} {}".format(asset, subset),
"asset": asset,
"item": timeline_item,
"families": families,
"publish": get_publish_attribute(timeline_item),
"fps": context.data["fps"],
"handleStart": handle_start,
"handleEnd": handle_end,
"newAssetPublishing": True
"newAssetPublishing": True,
"families": ["clip"],
})
# otio clip data
@ -135,7 +136,8 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
family = "shot"
data.update({
"name": "{} {} {}".format(asset, subset, family),
"name": "{}_{}".format(asset, subset),
"label": "{} {}".format(asset, subset),
"subset": subset,
"asset": asset,
"family": family,

View file

@ -1,7 +1,9 @@
import pyblish.api
from pprint import pformat
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import get_current_asset_name
from openpype.hosts.resolve import api as rapi
from openpype.hosts.resolve.otio import davinci_export
@ -13,9 +15,12 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
order = pyblish.api.CollectorOrder - 0.5
def process(self, context):
current_asset_name = asset_name = get_current_asset_name()
asset = get_current_asset_name()
subset = "workfile"
if AYON_SERVER_ENABLED:
asset_name = current_asset_name.split("/")[-1]
subset = "workfileMain"
project = rapi.get_current_project()
fps = project.GetSetting("timelineFrameRate")
video_tracks = rapi.get_video_track_names()
@ -24,9 +29,10 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
otio_timeline = davinci_export.create_otio_timeline(project)
instance_data = {
"name": "{}_{}".format(asset, subset),
"asset": asset,
"subset": "{}{}".format(asset, subset.capitalize()),
"name": "{}_{}".format(asset_name, subset),
"label": "{} {}".format(current_asset_name, subset),
"asset": current_asset_name,
"subset": subset,
"item": project,
"family": "workfile",
"families": []

View file

@ -60,6 +60,9 @@ class CollectHarmonyScenes(pyblish.api.InstancePlugin):
# updating hierarchy data
anatomy_data_new.update({
"asset": asset_data["name"],
"folder": {
"name": asset_data["name"],
},
"task": {
"name": task,
"type": task_type,

View file

@ -56,6 +56,9 @@ class CollectHarmonyZips(pyblish.api.InstancePlugin):
anatomy_data_new.update(
{
"asset": asset_data["name"],
"folder": {
"name": asset_data["name"],
},
"task": {
"name": task,
"type": task_type,

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating workfiles."""
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import CreatedInstance, AutoCreator
from openpype.client import get_asset_by_name
@ -41,6 +42,13 @@ class CreateWorkfile(AutoCreator):
if instance.creator_identifier == self.identifier
), None)
if current_instance is None:
current_instance_asset = None
elif AYON_SERVER_ENABLED:
current_instance_asset = current_instance["folderPath"]
else:
current_instance_asset = current_instance["asset"]
if current_instance is None:
self.log.info("Auto-creating workfile instance...")
asset_doc = get_asset_by_name(project_name, asset_name)
@ -48,22 +56,28 @@ class CreateWorkfile(AutoCreator):
variant, task_name, asset_doc, project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
current_instance = self.create_instance_in_context(subset_name,
data)
elif (
current_instance["asset"] != asset_name
or current_instance["task"] != task_name
current_instance_asset != asset_name
or current_instance["task"] != task_name
):
# Update instance context if is not the same
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
current_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
current_instance["folderPath"] = asset_name
else:
current_instance["asset"] = asset_name
current_instance["task"] = task_name
current_instance["subset"] = subset_name

View file

@ -53,11 +53,11 @@ class ShotMetadataSolver:
try:
# format to new shot name
return shot_rename_template.format(**data)
except KeyError as _E:
except KeyError as _error:
raise CreatorError((
"Make sure all keys in settings are correct:: \n\n"
f"From template string {shot_rename_template} > "
f"`{_E}` has no equivalent in \n"
f"`{_error}` has no equivalent in \n"
f"{list(data.keys())} input formatting keys!"
))
@ -100,7 +100,7 @@ class ShotMetadataSolver:
"at your project settings..."
))
# QUESTION:how to refactory `match[-1]` to some better way?
# QUESTION:how to refactor `match[-1]` to some better way?
output_data[token_key] = match[-1]
return output_data
@ -130,10 +130,10 @@ class ShotMetadataSolver:
parent_token["name"]: parent_token["value"].format(**data)
for parent_token in hierarchy_parents
}
except KeyError as _E:
except KeyError as _error:
raise CreatorError((
"Make sure all keys in settings are correct : \n"
f"`{_E}` has no equivalent in \n{list(data.keys())}"
f"`{_error}` has no equivalent in \n{list(data.keys())}"
))
_parent_tokens_type = {
@ -147,10 +147,10 @@ class ShotMetadataSolver:
try:
parent_name = _parent.format(
**_parent_tokens_formatting_data)
except KeyError as _E:
except KeyError as _error:
raise CreatorError((
"Make sure all keys in settings are correct : \n\n"
f"`{_E}` from template string "
f"`{_error}` from template string "
f"{shot_hierarchy['parents_path']}, "
f" has no equivalent in \n"
f"{list(_parent_tokens_formatting_data.keys())} parents"
@ -319,8 +319,16 @@ class ShotMetadataSolver:
tasks = self._generate_tasks_from_settings(
project_doc)
# generate hierarchy path from parents
hierarchy_path = self._create_hierarchy_path(parents)
if hierarchy_path:
folder_path = f"/{hierarchy_path}/{shot_name}"
else:
folder_path = f"/{shot_name}"
return shot_name, {
"hierarchy": self._create_hierarchy_path(parents),
"hierarchy": hierarchy_path,
"folderPath": folder_path,
"parents": parents,
"tasks": tasks
}

View file

@ -1,7 +1,9 @@
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_assets,
get_subsets,
get_last_versions,
get_asset_name_identifier,
)
from openpype.lib.attribute_definitions import (
FileDef,
@ -114,7 +116,10 @@ class SettingsCreator(TrayPublishCreator):
# Fill 'version_to_use' if version control is enabled
if self.allow_version_control:
asset_name = data["asset"]
if AYON_SERVER_ENABLED:
asset_name = data["folderPath"]
else:
asset_name = data["asset"]
subset_docs_by_asset_id = self._prepare_next_versions(
[asset_name], [subset_name])
version = subset_docs_by_asset_id[asset_name].get(subset_name)
@ -162,10 +167,10 @@ class SettingsCreator(TrayPublishCreator):
asset_docs = get_assets(
self.project_name,
asset_names=asset_names,
fields=["_id", "name"]
fields=["_id", "name", "data.parents"]
)
asset_names_by_id = {
asset_doc["_id"]: asset_doc["name"]
asset_doc["_id"]: get_asset_name_identifier(asset_doc)
for asset_doc in asset_docs
}
subset_docs = list(get_subsets(

View file

@ -6,6 +6,7 @@ production type `ociolook`. All files are published as representation.
"""
from pathlib import Path
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_by_name
from openpype.lib.attribute_definitions import (
FileDef, EnumDef, TextDef, UISeparatorDef
@ -54,8 +55,12 @@ This creator publishes color space look file (LUT).
# this should never happen
raise CreatorError("Missing files from representation")
if AYON_SERVER_ENABLED:
asset_name = instance_data["folderPath"]
else:
asset_name = instance_data["asset"]
asset_doc = get_asset_by_name(
self.project_name, instance_data["asset"])
self.project_name, asset_name)
subset_name = self.get_subset_name(
variant=instance_data["variant"],

View file

@ -1,6 +1,7 @@
import os
from copy import deepcopy
import opentimelineio as otio
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_asset_by_name,
get_project
@ -101,14 +102,23 @@ class EditorialShotInstanceCreator(EditorialClipInstanceCreatorBase):
label = "Editorial Shot"
def get_instance_attr_defs(self):
attr_defs = [
TextDef(
"asset_name",
label="Asset name",
instance_attributes = []
if AYON_SERVER_ENABLED:
instance_attributes.append(
TextDef(
"folderPath",
label="Folder path"
)
)
]
attr_defs.extend(CLIP_ATTR_DEFS)
return attr_defs
else:
instance_attributes.append(
TextDef(
"shotName",
label="Shot name"
)
)
instance_attributes.extend(CLIP_ATTR_DEFS)
return instance_attributes
class EditorialPlateInstanceCreator(EditorialClipInstanceCreatorBase):
@ -214,8 +224,11 @@ or updating already created. Publishing will create OTIO file.
i["family"] for i in self._creator_settings["family_presets"]
]
}
# Create otio editorial instance
asset_name = instance_data["asset"]
if AYON_SERVER_ENABLED:
asset_name = instance_data["folderPath"]
else:
asset_name = instance_data["asset"]
asset_doc = get_asset_by_name(self.project_name, asset_name)
if pre_create_data["fps"] == "from_selection":
@ -595,19 +608,23 @@ or updating already created. Publishing will create OTIO file.
Returns:
str: label string
"""
shot_name = instance_data["shotName"]
if AYON_SERVER_ENABLED:
asset_name = instance_data["creator_attributes"]["folderPath"]
else:
asset_name = instance_data["creator_attributes"]["shotName"]
variant_name = instance_data["variant"]
family = preset["family"]
# get variant name from preset or from inharitance
# get variant name from preset or from inheritance
_variant_name = preset.get("variant") or variant_name
# subset name
subset_name = "{}{}".format(
family, _variant_name.capitalize()
)
label = "{}_{}".format(
shot_name,
label = "{} {}".format(
asset_name,
subset_name
)
@ -666,7 +683,10 @@ or updating already created. Publishing will create OTIO file.
}
)
self._validate_name_uniqueness(shot_name)
# It should be validated only in openpype since we are supporting
# publishing to AYON with folder path and uniqueness is not an issue
if not AYON_SERVER_ENABLED:
self._validate_name_uniqueness(shot_name)
timing_data = self._get_timing_data(
otio_clip,
@ -677,35 +697,43 @@ or updating already created. Publishing will create OTIO file.
# create creator attributes
creator_attributes = {
"asset_name": shot_name,
"Parent hierarchy path": shot_metadata["hierarchy"],
"workfile_start_frame": workfile_start_frame,
"fps": fps,
"handle_start": int(handle_start),
"handle_end": int(handle_end)
}
# add timing data
creator_attributes.update(timing_data)
# create shared new instance data
# create base instance data
base_instance_data = {
"shotName": shot_name,
"variant": variant_name,
# HACK: just for temporal bug workaround
# TODO: should loockup shot name for update
"asset": parent_asset_name,
"task": "",
"newAssetPublishing": True,
# parent time properties
"trackStartFrame": track_start_frame,
"timelineOffset": timeline_offset,
"isEditorial": True,
# creator_attributes
"creator_attributes": creator_attributes
}
# update base instance data with context data
# and also update creator attributes with context data
if AYON_SERVER_ENABLED:
# TODO: this is here just to be able to publish
# to AYON with folder path
creator_attributes["folderPath"] = shot_metadata.pop("folderPath")
base_instance_data["folderPath"] = parent_asset_name
else:
creator_attributes.update({
"shotName": shot_name,
"Parent hierarchy path": shot_metadata["hierarchy"]
})
base_instance_data["asset"] = parent_asset_name
# add creator attributes to shared instance data
base_instance_data["creator_attributes"] = creator_attributes
# add hierarchy shot metadata
base_instance_data.update(shot_metadata)

View file

@ -2,6 +2,8 @@ import copy
import os
import re
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_name_identifier
from openpype.lib import (
FileDef,
BoolDef,
@ -64,8 +66,13 @@ class BatchMovieCreator(TrayPublishCreator):
subset_name, task_name = self._get_subset_and_task(
asset_doc, data["variant"], self.project_name)
asset_name = get_asset_name_identifier(asset_doc)
instance_data["task"] = task_name
instance_data["asset"] = asset_doc["name"]
if AYON_SERVER_ENABLED:
instance_data["folderPath"] = asset_name
else:
instance_data["asset"] = asset_name
# Create new instance
new_instance = CreatedInstance(self.family, subset_name,

View file

@ -28,9 +28,9 @@ class CollectSequenceFrameData(
return
# editorial would fail since they might not be in database yet
is_editorial = instance.data.get("isEditorial")
if is_editorial:
self.log.debug("Instance is Editorial. Skipping.")
new_asset_publishing = instance.data.get("newAssetPublishing")
if new_asset_publishing:
self.log.debug("Instance is creating new asset. Skipping.")
return
frame_data = self.get_frame_data_from_repre_sequence(instance)

View file

@ -2,6 +2,8 @@ from pprint import pformat
import pyblish.api
import opentimelineio as otio
from openpype import AYON_SERVER_ENABLED
class CollectShotInstance(pyblish.api.InstancePlugin):
""" Collect shot instances
@ -119,8 +121,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
frame_end = _cr_attrs["frameEnd"]
frame_dur = frame_end - frame_start
return {
"asset": _cr_attrs["asset_name"],
data = {
"fps": float(_cr_attrs["fps"]),
"handleStart": _cr_attrs["handle_start"],
"handleEnd": _cr_attrs["handle_end"],
@ -133,6 +134,12 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
"sourceOut": _cr_attrs["sourceOut"],
"workfileFrameStart": workfile_start_frame
}
if AYON_SERVER_ENABLED:
data["asset"] = _cr_attrs["folderPath"]
else:
data["asset"] = _cr_attrs["shotName"]
return data
def _solve_hierarchy_context(self, instance):
""" Adding hierarchy data to context shared data.
@ -148,7 +155,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
else {}
)
name = instance.data["asset"]
asset_name = instance.data["asset"]
# get handles
handle_start = int(instance.data["handleStart"])
@ -170,7 +177,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
parents = instance.data.get('parents', [])
actual = {name: in_info}
actual = {asset_name: in_info}
for parent in reversed(parents):
parent_name = parent["entity_name"]

View file

@ -31,9 +31,9 @@ class ValidateFrameRange(OptionalPyblishPluginMixin,
return
# editorial would fail since they might not be in database yet
is_editorial = instance.data.get("isEditorial")
if is_editorial:
self.log.debug("Instance is Editorial. Skipping.")
new_asset_publishing = instance.data.get("newAssetPublishing")
if new_asset_publishing:
self.log.debug("Instance is creating new asset. Skipping.")
return
if (self.skip_timelines_check and

View file

@ -37,7 +37,8 @@ Todos:
import collections
from typing import Any, Optional, Union
from openpype.client import get_asset_by_name
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_by_name, get_asset_name_identifier
from openpype.lib import (
prepare_template_data,
AbstractAttrDef,
@ -784,18 +785,25 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
project_name,
host_name=self.create_context.host_name,
)
asset_name = get_asset_name_identifier(asset_doc)
if existing_instance is not None:
existing_instance["asset"] = asset_doc["name"]
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name
return existing_instance
instance_data: dict[str, str] = {
"asset": asset_doc["name"],
"task": task_name,
"family": creator.family,
"variant": variant
}
if AYON_SERVER_ENABLED:
instance_data["folderPath"] = asset_name
else:
instance_data["asset"] = asset_name
pre_create_data: dict[str, str] = {
"group_id": group_id,
"mark_for_review": mark_for_review
@ -820,6 +828,8 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
for layer_name in render_pass["layer_names"]:
render_pass_by_layer_name[layer_name] = render_pass
asset_name = get_asset_name_identifier(asset_doc)
for layer in layers:
layer_name = layer["name"]
variant = layer_name
@ -838,17 +848,25 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
)
if render_pass is not None:
render_pass["asset"] = asset_doc["name"]
if AYON_SERVER_ENABLED:
render_pass["folderPath"] = asset_name
else:
render_pass["asset"] = asset_name
render_pass["task"] = task_name
render_pass["subset"] = subset_name
continue
instance_data: dict[str, str] = {
"asset": asset_doc["name"],
"task": task_name,
"family": creator.family,
"variant": variant
}
if AYON_SERVER_ENABLED:
instance_data["folderPath"] = asset_name
else:
instance_data["asset"] = asset_name
pre_create_data: dict[str, Any] = {
"render_layer_instance_id": render_layer_instance.id,
"layer_names": [layer_name],
@ -882,9 +900,13 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
def create(self, subset_name, instance_data, pre_create_data):
project_name: str = self.create_context.get_current_project_name()
asset_name: str = instance_data["asset"]
if AYON_SERVER_ENABLED:
asset_name: str = instance_data["folderPath"]
else:
asset_name: str = instance_data["asset"]
task_name: str = instance_data["task"]
asset_doc: dict[str, Any] = get_asset_by_name(project_name, asset_name)
asset_doc: dict[str, Any] = get_asset_by_name(
project_name, asset_name)
render_layers_by_group_id: dict[int, CreatedInstance] = {}
render_passes_by_render_layer_id: dict[int, list[CreatedInstance]] = (
@ -1061,7 +1083,6 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator):
host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant,
"creator_attributes": {
@ -1073,6 +1094,10 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator):
self.default_pass_name
)
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
if not self.active_on_create:
data["active"] = False
@ -1101,8 +1126,14 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator):
asset_name = create_context.get_current_asset_name()
task_name = create_context.get_current_task_name()
existing_name = None
if AYON_SERVER_ENABLED:
existing_name = existing_instance.get("folderPath")
if existing_name is None:
existing_name = existing_instance["asset"]
if (
existing_instance["asset"] != asset_name
existing_name != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -1114,7 +1145,10 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator):
host_name,
existing_instance
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,3 +1,4 @@
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_by_name
from openpype.pipeline import CreatedInstance
from openpype.hosts.tvpaint.api.plugin import TVPaintAutoCreator
@ -33,6 +34,13 @@ class TVPaintReviewCreator(TVPaintAutoCreator):
asset_name = create_context.get_current_asset_name()
task_name = create_context.get_current_task_name()
if existing_instance is None:
existing_asset_name = None
elif AYON_SERVER_ENABLED:
existing_asset_name = existing_instance["folderPath"]
else:
existing_asset_name = existing_instance["asset"]
if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
@ -43,10 +51,14 @@ class TVPaintReviewCreator(TVPaintAutoCreator):
host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
if not self.active_on_create:
data["active"] = False
@ -59,7 +71,7 @@ class TVPaintReviewCreator(TVPaintAutoCreator):
self._add_instance_to_context(new_instance)
elif (
existing_instance["asset"] != asset_name
existing_asset_name != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -71,6 +83,9 @@ class TVPaintReviewCreator(TVPaintAutoCreator):
host_name,
existing_instance
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,3 +1,4 @@
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_asset_by_name
from openpype.pipeline import CreatedInstance
from openpype.hosts.tvpaint.api.plugin import TVPaintAutoCreator
@ -29,6 +30,13 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator):
asset_name = create_context.get_current_asset_name()
task_name = create_context.get_current_task_name()
if existing_instance is None:
existing_asset_name = None
elif AYON_SERVER_ENABLED:
existing_asset_name = existing_instance["folderPath"]
else:
existing_asset_name = existing_instance["asset"]
if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
@ -39,10 +47,13 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator):
host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": self.default_variant
}
if AYON_SERVER_ENABLED:
data["folderPath"] = asset_name
else:
data["asset"] = asset_name
new_instance = CreatedInstance(
self.family, subset_name, data, self
@ -53,7 +64,7 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator):
self._add_instance_to_context(new_instance)
elif (
existing_instance["asset"] != asset_name
existing_asset_name != asset_name
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
@ -65,6 +76,9 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator):
host_name,
existing_instance
)
existing_instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
existing_instance["folderPath"] = asset_name
else:
existing_instance["asset"] = asset_name
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name

View file

@ -1,4 +1,5 @@
import pyblish.api
from openpype import AYON_SERVER_ENABLED
from openpype.pipeline import (
PublishXmlValidationError,
OptionalPyblishPluginMixin,
@ -24,12 +25,19 @@ class FixAssetNames(pyblish.api.Action):
old_instance_items = list_instances()
new_instance_items = []
for instance_item in old_instance_items:
instance_asset_name = instance_item.get("asset")
if AYON_SERVER_ENABLED:
instance_asset_name = instance_item.get("folderPath")
else:
instance_asset_name = instance_item.get("asset")
if (
instance_asset_name
and instance_asset_name != context_asset_name
):
instance_item["asset"] = context_asset_name
if AYON_SERVER_ENABLED:
instance_item["folderPath"] = context_asset_name
else:
instance_item["asset"] = context_asset_name
new_instance_items.append(instance_item)
write_instances(new_instance_items)

View file

@ -12,6 +12,7 @@ from abc import ABCMeta, abstractmethod
import six
from openpype import AYON_SERVER_ENABLED, PACKAGE_DIR
from openpype.client import get_asset_name_identifier
from openpype.settings import (
get_system_settings,
get_project_settings,
@ -1728,7 +1729,9 @@ def prepare_context_environments(data, env_group=None, modules_manager=None):
"AVALON_APP_NAME": app.full_name
}
if asset_doc:
context_env["AVALON_ASSET"] = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
context_env["AVALON_ASSET"] = asset_name
if task_name:
context_env["AVALON_TASK"] = task_name

View file

@ -72,6 +72,10 @@ IGNORED_FILENAMES_IN_AYON = {
"slack",
"kitsu",
}
IGNORED_HOSTS_IN_AYON = {
"flame",
"harmony",
}
# Inherit from `object` for Python 2 hosts
@ -540,6 +544,11 @@ def _load_modules():
addons_dir = os.path.join(os.path.dirname(current_dir), "addons")
module_dirs.append(addons_dir)
ignored_host_names = set(IGNORED_HOSTS_IN_AYON)
ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES)
if AYON_SERVER_ENABLED:
ignored_current_dir_filenames |= IGNORED_FILENAMES_IN_AYON
processed_paths = set()
for dirpath in frozenset(module_dirs):
# Skip already processed paths
@ -555,9 +564,6 @@ def _load_modules():
is_in_current_dir = dirpath == current_dir
is_in_host_dir = dirpath == hosts_dir
ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES)
if AYON_SERVER_ENABLED:
ignored_current_dir_filenames |= IGNORED_FILENAMES_IN_AYON
for filename in os.listdir(dirpath):
# Ignore filenames
@ -570,6 +576,12 @@ def _load_modules():
):
continue
if (
is_in_host_dir
and filename in ignored_host_names
):
continue
fullpath = os.path.join(dirpath, filename)
basename, ext = os.path.splitext(filename)

View file

@ -189,7 +189,7 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin,
environment = RREnvList({
"AVALON_PROJECT": anatomy_data["project"]["name"],
"AVALON_ASSET": anatomy_data["asset"],
"AVALON_ASSET": instance.context.data["asset"],
"AVALON_TASK": anatomy_data["task"]["name"],
"OPENPYPE_USERNAME": anatomy_data["user"]
})

View file

@ -247,7 +247,7 @@ class TimersManager(
return {
"project_name": project_name,
"asset_id": str(asset_doc["_id"]),
"asset_name": asset_doc["name"],
"asset_name": asset_name,
"task_name": task_name,
"task_type": task_type,
"hierarchy": hierarchy_items

View file

@ -18,6 +18,7 @@ from openpype.client import (
get_asset_by_id,
get_asset_by_name,
version_is_latest,
get_asset_name_identifier,
get_ayon_server_api_connection,
)
from openpype.lib.events import emit_event
@ -44,7 +45,7 @@ from . import (
_is_installed = False
_process_id = None
_registered_root = {"_": ""}
_registered_root = {"_": {}}
_registered_host = {"_": None}
# Keep modules manager (and it's modules) in memory
# - that gives option to register modules' callbacks
@ -85,15 +86,22 @@ def register_root(path):
def registered_root():
"""Return currently registered root"""
root = _registered_root["_"]
if root:
return root
"""Return registered roots from current project anatomy.
root = legacy_io.Session.get("AVALON_PROJECTS")
if root:
return os.path.normpath(root)
return ""
Consider this does return roots only for current project and current
platforms, only if host was installer using 'install_host'.
Deprecated:
Please use project 'Anatomy' to get roots. This function is still used
at current core functions of load logic, but that will change
in future and this function will be removed eventually. Using this
function at new places can cause problems in the future.
Returns:
dict[str, str]: Root paths.
"""
return _registered_root["_"]
def install_host(host):
@ -592,14 +600,12 @@ def compute_session_changes(
Dict[str, str]: Changes in the Session dictionary.
"""
changes = {}
# Get asset document and asset
if not asset_doc:
task_name = None
asset_name = None
else:
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
# Detect any changes compared session
mapping = {

View file

@ -11,7 +11,12 @@ from contextlib import contextmanager
import pyblish.logic
import pyblish.api
from openpype.client import get_assets, get_asset_by_name
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_assets,
get_asset_by_name,
get_asset_name_identifier,
)
from openpype.settings import (
get_system_settings,
get_project_settings
@ -922,9 +927,19 @@ class CreatedInstance:
self._orig_data = copy.deepcopy(data)
# Pop family and subset to prevent unexpected changes
# TODO change to 'productType' and 'productName' in AYON
data.pop("family", None)
data.pop("subset", None)
if AYON_SERVER_ENABLED:
asset_name = data.pop("asset", None)
if "folderPath" not in data:
data["folderPath"] = asset_name
elif "folderPath" in data:
asset_name = data.pop("folderPath").split("/")[-1]
if "asset" not in data:
data["asset"] = asset_name
# QUESTION Does it make sense to have data stored as ordered dict?
self._data = collections.OrderedDict()
@ -1268,6 +1283,8 @@ class CreatedInstance:
def has_set_asset(self):
"""Asset name is set in data."""
if AYON_SERVER_ENABLED:
return "folderPath" in self._data
return "asset" in self._data
@property
@ -2003,8 +2020,14 @@ class CreateContext:
project_name,
self.host_name
)
asset_name = get_asset_name_identifier(asset_doc)
if AYON_SERVER_ENABLED:
asset_name_key = "folderPath"
else:
asset_name_key = "asset"
instance_data = {
"asset": asset_doc["name"],
asset_name_key: asset_name,
"task": task_name,
"family": creator.family,
"variant": variant
@ -2229,34 +2252,51 @@ class CreateContext:
task_names_by_asset_name = {}
for instance in instances:
task_name = instance.get("task")
asset_name = instance.get("asset")
if AYON_SERVER_ENABLED:
asset_name = instance.get("folderPath")
else:
asset_name = instance.get("asset")
if asset_name:
task_names_by_asset_name[asset_name] = set()
if task_name:
task_names_by_asset_name[asset_name].add(task_name)
asset_names = [
asset_names = {
asset_name
for asset_name in task_names_by_asset_name.keys()
if asset_name is not None
]
}
fields = {"name", "data.tasks"}
if AYON_SERVER_ENABLED:
fields |= {"data.parents"}
asset_docs = list(get_assets(
self.project_name,
asset_names=asset_names,
fields=["name", "data.tasks"]
fields=fields
))
task_names_by_asset_name = {}
asset_docs_by_name = collections.defaultdict(list)
for asset_doc in asset_docs:
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
tasks = asset_doc.get("data", {}).get("tasks") or {}
task_names_by_asset_name[asset_name] = set(tasks.keys())
asset_docs_by_name[asset_doc["name"]].append(asset_doc)
for instance in instances:
if not instance.has_valid_asset or not instance.has_valid_task:
continue
asset_name = instance["asset"]
if AYON_SERVER_ENABLED:
asset_name = instance["folderPath"]
if asset_name and "/" not in asset_name:
asset_docs = asset_docs_by_name.get(asset_name)
if len(asset_docs) == 1:
asset_name = get_asset_name_identifier(asset_docs[0])
instance["folderPath"] = asset_name
else:
asset_name = instance["asset"]
if asset_name not in task_names_by_asset_name:
instance.set_asset_invalid(True)
continue

View file

@ -1,6 +1,11 @@
import collections
from openpype.client import get_assets, get_subsets, get_last_versions
from openpype.client import (
get_assets,
get_subsets,
get_last_versions,
get_asset_name_identifier,
)
def get_last_versions_for_instances(
@ -52,10 +57,10 @@ def get_last_versions_for_instances(
asset_docs = get_assets(
project_name,
asset_names=subset_names_by_asset_name.keys(),
fields=["name", "_id"]
fields=["name", "_id", "data.parents"]
)
asset_names_by_id = {
asset_doc["_id"]: asset_doc["name"]
asset_doc["_id"]: get_asset_name_identifier(asset_doc)
for asset_doc in asset_docs
}
if not asset_names_by_id:

View file

@ -30,7 +30,7 @@ def install():
session = session_data_from_environment(context_keys=True)
session["schema"] = "openpype:session-3.0"
session["schema"] = "openpype:session-4.0"
try:
schema.validate(session)
except schema.ValidationError as e:

View file

@ -62,8 +62,6 @@ def auto_reconnect(func):
SESSION_CONTEXT_KEYS = (
# Root directory of projects on disk
"AVALON_PROJECTS",
# Name of current Project
"AVALON_PROJECT",
# Name of current Asset

View file

@ -0,0 +1,61 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "openpype:session-4.0",
"description": "The Avalon environment",
"type": "object",
"additionalProperties": true,
"required": [
"AVALON_PROJECT"
],
"properties": {
"AVALON_PROJECT": {
"description": "Name of project",
"type": "string",
"pattern": "^\\w*$",
"example": "Hulk"
},
"AVALON_ASSET": {
"description": "Name of asset",
"type": "string",
"pattern": "^[\\/\\w]*$",
"example": "Bruce"
},
"AVALON_TASK": {
"description": "Name of task",
"type": "string",
"pattern": "^\\w*$",
"example": "modeling"
},
"AVALON_APP": {
"description": "Name of host",
"type": "string",
"pattern": "^\\w*$",
"example": "maya"
},
"AVALON_DB": {
"description": "Name of database",
"type": "string",
"pattern": "^\\w*$",
"example": "avalon",
"default": "avalon"
},
"AVALON_LABEL": {
"description": "Nice name of Avalon, used in e.g. graphical user interfaces",
"type": "string",
"example": "MyLabel",
"default": "Avalon"
},
"AVALON_TIMEOUT": {
"description": "Wherever there is a need for a timeout, this is the default value.",
"type": "string",
"pattern": "^[0-9]*$",
"default": "1000",
"example": "1000"
}
}
}

View file

@ -30,7 +30,8 @@ import pyblish.api
from openpype.client import (
get_assets,
get_subsets,
get_last_versions
get_last_versions,
get_asset_name_identifier,
)
from openpype.pipeline.version_start import get_versioning_start
@ -60,6 +61,9 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
self.log.debug("Querying asset documents for instances.")
context_asset_doc = context.data.get("assetEntity")
context_asset_name = None
if context_asset_doc:
context_asset_name = get_asset_name_identifier(context_asset_doc)
instances_with_missing_asset_doc = collections.defaultdict(list)
for instance in context:
@ -68,15 +72,15 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
# There is possibility that assetEntity on instance is already set
# which can happen in standalone publisher
if (
instance_asset_doc
and instance_asset_doc["name"] == _asset_name
):
continue
if instance_asset_doc:
instance_asset_name = get_asset_name_identifier(
instance_asset_doc)
if instance_asset_name == _asset_name:
continue
# Check if asset name is the same as what is in context
# - they may be different, e.g. in NukeStudio
if context_asset_doc and context_asset_doc["name"] == _asset_name:
if context_asset_name and context_asset_name == _asset_name:
instance.data["assetEntity"] = context_asset_doc
else:
@ -93,7 +97,7 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
asset_docs = get_assets(project_name, asset_names=asset_names)
asset_docs_by_name = {
asset_doc["name"]: asset_doc
get_asset_name_identifier(asset_doc): asset_doc
for asset_doc in asset_docs
}
@ -183,35 +187,29 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
self.log.debug("Storing anatomy data to instance data.")
project_doc = context.data["projectEntity"]
context_asset_doc = context.data.get("assetEntity")
project_task_types = project_doc["config"]["tasks"]
for instance in context:
asset_doc = instance.data.get("assetEntity")
anatomy_updates = {
"asset": instance.data["asset"],
"folder": {
"name": instance.data["asset"],
},
"family": instance.data["family"],
"subset": instance.data["subset"],
}
# Hierarchy
asset_doc = instance.data.get("assetEntity")
if (
asset_doc
and (
not context_asset_doc
or asset_doc["_id"] != context_asset_doc["_id"]
)
):
if asset_doc:
parents = asset_doc["data"].get("parents") or list()
parent_name = project_doc["name"]
if parents:
parent_name = parents[-1]
anatomy_updates["hierarchy"] = "/".join(parents)
anatomy_updates["parent"] = parent_name
hierarchy = "/".join(parents)
anatomy_updates.update({
"asset": asset_doc["name"],
"hierarchy": hierarchy,
"parent": parent_name,
"folder": {
"name": asset_doc["name"],
},
})
# Task
task_type = None

View file

@ -6,6 +6,7 @@ from openpype.client import (
get_subsets,
get_last_versions,
get_representations,
get_asset_name_identifier,
)
from openpype.pipeline.load import get_representation_path_with_anatomy
@ -121,12 +122,13 @@ class CollectAudio(pyblish.api.ContextPlugin):
asset_docs = get_assets(
project_name,
asset_names=asset_names,
fields=["_id", "name"]
fields=["_id", "name", "data.parents"]
)
asset_id_by_name = {}
for asset_doc in asset_docs:
asset_id_by_name[asset_doc["name"]] = asset_doc["_id"]
asset_id_by_name = {
get_asset_name_identifier(asset_doc): asset_doc["_id"]
for asset_doc in asset_docs
}
asset_ids = set(asset_id_by_name.values())
# Query subsets with name define by 'audio_subset_name' attr

View file

@ -4,6 +4,7 @@
import os
import pyblish.api
from openpype import AYON_SERVER_ENABLED
from openpype.host import IPublishHost
from openpype.pipeline import legacy_io, registered_host
from openpype.pipeline.create import CreateContext
@ -38,6 +39,8 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin):
for created_instance in create_context.instances:
instance_data = created_instance.data_to_store()
if AYON_SERVER_ENABLED:
instance_data["asset"] = instance_data.pop("folderPath")
if instance_data["active"]:
thumbnail_path = thumbnail_paths_by_instance_id.get(
created_instance.id

View file

@ -69,9 +69,9 @@ class CollectResourcesPath(pyblish.api.InstancePlugin):
def process(self, instance):
# editorial would fail since they might not be in database yet
is_editorial = instance.data.get("isEditorial")
if is_editorial:
self.log.debug("Instance is Editorial. Skipping.")
new_asset_publishing = instance.data.get("newAssetPublishing")
if new_asset_publishing:
self.log.debug("Instance is creating new asset. Skipping.")
return
anatomy = instance.context.data["anatomy"]

View file

@ -8,7 +8,7 @@ from ayon_api import slugify_string
from ayon_api.entity_hub import EntityHub
from openpype import AYON_SERVER_ENABLED
from openpype.client import get_assets
from openpype.client import get_assets, get_asset_name_identifier
from openpype.pipeline.template_data import (
get_asset_template_data,
get_task_template_data,
@ -58,7 +58,7 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
project_name, asset_names=instances_by_asset_name.keys()
)
asset_docs_by_name = {
asset_doc["name"]: asset_doc
get_asset_name_identifier(asset_doc): asset_doc
for asset_doc in asset_docs
}
for asset_name, instances in instances_by_asset_name.items():
@ -191,15 +191,15 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
"""
# filter only the active publishing instances
active_folder_names = set()
active_folder_paths = set()
for instance in context:
if instance.data.get("publish") is not False:
active_folder_names.add(instance.data.get("asset"))
active_folder_paths.add(instance.data.get("asset"))
active_folder_names.discard(None)
active_folder_paths.discard(None)
self.log.debug("Active folder names: {}".format(active_folder_names))
if not active_folder_names:
self.log.debug("Active folder paths: {}".format(active_folder_paths))
if not active_folder_paths:
return None
project_item = None
@ -230,12 +230,13 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
if not children_context:
continue
for asset_name, asset_info in children_context.items():
for asset, asset_info in children_context.items():
if (
asset_name not in active_folder_names
asset not in active_folder_paths
and not asset_info.get("childs")
):
continue
asset_name = asset.split("/")[-1]
item_id = uuid.uuid4().hex
new_item = copy.deepcopy(asset_info)
new_item["name"] = asset_name
@ -252,7 +253,7 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
items_by_id[item_id] = new_item
parent_id_by_item_id[item_id] = parent_id
if asset_name in active_folder_names:
if asset in active_folder_paths:
valid_ids.add(item_id)
hierarchy_queue.append((item_id, new_children_context))

View file

@ -2,7 +2,7 @@ from pprint import pformat
import pyblish.api
from openpype.client import get_assets
from openpype.client import get_assets, get_asset_name_identifier
class ValidateEditorialAssetName(pyblish.api.ContextPlugin):
@ -34,8 +34,11 @@ class ValidateEditorialAssetName(pyblish.api.ContextPlugin):
self.log.debug("__ db_assets: {}".format(db_assets))
asset_db_docs = {
str(e["name"]): [str(p) for p in e["data"]["parents"]]
for e in db_assets}
get_asset_name_identifier(asset_doc): list(
asset_doc["data"]["parents"]
)
for asset_doc in db_assets
}
self.log.debug("__ project_entities: {}".format(
pformat(asset_db_docs)))

View file

@ -402,12 +402,12 @@ class ActionsModel:
)
def _prepare_session(self, project_name, folder_id, task_id):
folder_name = None
folder_path = None
if folder_id:
folder = self._controller.get_folder_entity(
project_name, folder_id)
if folder:
folder_name = folder["name"]
folder_path = folder["path"]
task_name = None
if task_id:
@ -417,7 +417,7 @@ class ActionsModel:
return {
"AVALON_PROJECT": project_name,
"AVALON_ASSET": folder_name,
"AVALON_ASSET": folder_path,
"AVALON_TASK": task_name,
}

View file

@ -290,7 +290,7 @@ class LoaderController(BackendLoaderController, FrontendLoaderController):
project_name = context.get("project_name")
asset_name = context.get("asset_name")
if project_name and asset_name:
folder = ayon_api.get_folder_by_name(
folder = ayon_api.get_folder_by_path(
project_name, asset_name, fields=["id"]
)
if folder:

View file

@ -70,19 +70,12 @@ class SceneInventoryController:
context = self.get_current_context()
project_name = context["project_name"]
folder_path = context.get("folder_path")
folder_name = context.get("asset_name")
folder_id = None
if folder_path:
folder = ayon_api.get_folder_by_path(project_name, folder_path)
if folder_name:
folder = ayon_api.get_folder_by_path(project_name, folder_name)
if folder:
folder_id = folder["id"]
elif folder_name:
for folder in ayon_api.get_folders(
project_name, folder_names=[folder_name]
):
folder_id = folder["id"]
break
self._current_folder_id = folder_id
self._current_folder_set = True

View file

@ -473,7 +473,7 @@ class BaseWorkfileController(
current_file = self.get_current_workfile()
folder_id = None
if folder_name:
folder = ayon_api.get_folder_by_name(project_name, folder_name)
folder = ayon_api.get_folder_by_path(project_name, folder_name)
if folder:
folder_id = folder["id"]

View file

@ -214,7 +214,7 @@ class CreatorWindow(QtWidgets.QDialog):
asset_name = self._asset_name_input.text()
# Early exit if no asset name
if not asset_name.strip():
if not asset_name:
self._build_menu()
self.echo("Asset name is required ..")
self._set_valid_state(False)

View file

@ -12,10 +12,12 @@ from abc import ABCMeta, abstractmethod
import six
import pyblish.api
from openpype import AYON_SERVER_ENABLED
from openpype.client import (
get_assets,
get_asset_by_id,
get_subsets,
get_asset_name_identifier,
)
from openpype.lib.events import EventSystem
from openpype.lib.attribute_definitions import (
@ -73,6 +75,8 @@ class AssetDocsCache:
"data.visualParent": True,
"data.tasks": True
}
if AYON_SERVER_ENABLED:
projection["data.parents"] = True
def __init__(self, controller):
self._controller = controller
@ -105,7 +109,7 @@ class AssetDocsCache:
elif "tasks" not in asset_doc["data"]:
asset_doc["data"]["tasks"] = {}
asset_name = asset_doc["name"]
asset_name = get_asset_name_identifier(asset_doc)
asset_tasks = asset_doc["data"]["tasks"]
task_names_by_asset_name[asset_name] = list(asset_tasks.keys())
asset_docs_by_name[asset_name] = asset_doc

View file

@ -11,7 +11,8 @@ from openpype.tools.utils import (
from openpype.tools.utils.assets_widget import (
SingleSelectAssetsWidget,
ASSET_ID_ROLE,
ASSET_NAME_ROLE
ASSET_NAME_ROLE,
ASSET_PATH_ROLE,
)
@ -31,6 +32,15 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
self._last_filter_height = None
def get_selected_asset_name(self):
if AYON_SERVER_ENABLED:
selection_model = self._view.selectionModel()
indexes = selection_model.selectedRows()
for index in indexes:
return index.data(ASSET_PATH_ROLE)
return None
return super(CreateWidgetAssetsWidget, self).get_selected_asset_name()
def _check_header_height(self):
"""Catch header height changes.
@ -100,21 +110,24 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel):
self._controller = controller
self._items_by_name = {}
self._items_by_path = {}
self._items_by_asset_id = {}
def reset(self):
self.clear()
self._items_by_name = {}
self._items_by_path = {}
self._items_by_asset_id = {}
assets_by_parent_id = self._controller.get_asset_hierarchy()
items_by_name = {}
items_by_path = {}
items_by_asset_id = {}
_queue = collections.deque()
_queue.append((self.invisibleRootItem(), None))
_queue.append((self.invisibleRootItem(), None, None))
while _queue:
parent_item, parent_id = _queue.popleft()
parent_item, parent_id, parent_path = _queue.popleft()
children = assets_by_parent_id.get(parent_id)
if not children:
continue
@ -127,6 +140,11 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel):
for name in sorted(children_by_name.keys()):
child = children_by_name[name]
child_id = child["_id"]
if parent_path:
child_path = "{}/{}".format(parent_path, name)
else:
child_path = "/{}".format(name)
has_children = bool(assets_by_parent_id.get(child_id))
icon = get_asset_icon(child, has_children)
@ -138,15 +156,18 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel):
item.setData(icon, QtCore.Qt.DecorationRole)
item.setData(child_id, ASSET_ID_ROLE)
item.setData(name, ASSET_NAME_ROLE)
item.setData(child_path, ASSET_PATH_ROLE)
items_by_name[name] = item
items_by_path[child_path] = item
items_by_asset_id[child_id] = item
items.append(item)
_queue.append((item, child_id))
_queue.append((item, child_id, child_path))
parent_item.appendRows(items)
self._items_by_name = items_by_name
self._items_by_path = items_by_path
self._items_by_asset_id = items_by_asset_id
def get_index_by_asset_id(self, asset_id):
@ -156,12 +177,20 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel):
return QtCore.QModelIndex()
def get_index_by_asset_name(self, asset_name):
item = self._items_by_name.get(asset_name)
item = None
if AYON_SERVER_ENABLED:
item = self._items_by_path.get(asset_name)
if item is None:
item = self._items_by_name.get(asset_name)
if item is None:
return QtCore.QModelIndex()
return item.index()
def name_is_valid(self, item_name):
if AYON_SERVER_ENABLED and item_name in self._items_by_path:
return True
return item_name in self._items_by_name
@ -296,7 +325,10 @@ class AssetsDialog(QtWidgets.QDialog):
index = self._asset_view.currentIndex()
asset_name = None
if index.isValid():
asset_name = index.data(ASSET_NAME_ROLE)
if AYON_SERVER_ENABLED:
asset_name = index.data(ASSET_PATH_ROLE)
else:
asset_name = index.data(ASSET_NAME_ROLE)
self._selected_asset = asset_name
self.done(1)

View file

@ -816,8 +816,13 @@ class CreateWidget(QtWidgets.QWidget):
# Where to define these data?
# - what data show be stored?
if AYON_SERVER_ENABLED:
asset_key = "folderPath"
else:
asset_key = "asset"
instance_data = {
"asset": asset_name,
asset_key: asset_name,
"task": task_name,
"variant": variant,
"family": family

View file

@ -540,6 +540,7 @@ class AssetsField(BaseClickableFrame):
Does not change selected items (assets).
"""
self._name_input.setText(text)
self._name_input.end(False)
def set_selected_items(self, asset_names=None):
"""Set asset names for selection of instances.
@ -1187,7 +1188,10 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
asset_names = []
for instance in self._current_instances:
new_variant_value = instance.get("variant")
new_asset_name = instance.get("asset")
if AYON_SERVER_ENABLED:
new_asset_name = instance.get("folderPath")
else:
new_asset_name = instance.get("asset")
new_task_name = instance.get("task")
if variant_value is not None:
new_variant_value = variant_value
@ -1219,7 +1223,11 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
instance["variant"] = variant_value
if asset_name is not None:
instance["asset"] = asset_name
if AYON_SERVER_ENABLED:
instance["folderPath"] = asset_name
else:
instance["asset"] = asset_name
instance.set_asset_invalid(False)
if task_name is not None:
@ -1317,7 +1325,10 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
variants.add(instance.get("variant") or self.unknown_value)
families.add(instance.get("family") or self.unknown_value)
asset_name = instance.get("asset") or self.unknown_value
if AYON_SERVER_ENABLED:
asset_name = instance.get("folderPath") or self.unknown_value
else:
asset_name = instance.get("asset") or self.unknown_value
task_name = instance.get("task") or ""
asset_names.add(asset_name)
asset_task_combinations.append((asset_name, task_name))

View file

@ -36,6 +36,7 @@ ASSET_ID_ROLE = QtCore.Qt.UserRole + 1
ASSET_NAME_ROLE = QtCore.Qt.UserRole + 2
ASSET_LABEL_ROLE = QtCore.Qt.UserRole + 3
ASSET_UNDERLINE_COLORS_ROLE = QtCore.Qt.UserRole + 4
ASSET_PATH_ROLE = QtCore.Qt.UserRole + 5
class AssetsView(TreeViewSpinner, DeselectableTreeView):

View file

@ -33,6 +33,20 @@ IGNORE_FILE_PATTERNS: List[Pattern] = [
}
]
IGNORED_HOSTS = [
"flame",
"harmony",
]
IGNORED_MODULES = [
"ftrack",
"shotgrid",
"sync_server",
"example_addons",
"slack",
"kitsu",
]
class ZipFileLongPaths(zipfile.ZipFile):
"""Allows longer paths in zip files.
@ -202,16 +216,6 @@ def create_openpype_package(
str(pyproject_path),
(private_dir / pyproject_path.name)
)
ignored_hosts = []
ignored_modules = [
"ftrack",
"shotgrid",
"sync_server",
"example_addons",
"slack",
"kitsu",
]
# Subdirs that won't be added to output zip file
ignored_subpaths = [
["addons"],
@ -219,11 +223,11 @@ def create_openpype_package(
]
ignored_subpaths.extend(
["hosts", host_name]
for host_name in ignored_hosts
for host_name in IGNORED_HOSTS
)
ignored_subpaths.extend(
["modules", module_name]
for module_name in ignored_modules
for module_name in IGNORED_MODULES
)
# Zip client
@ -297,6 +301,7 @@ def main(
# Make sure output dir is created
output_dir.mkdir(parents=True, exist_ok=True)
ignored_addons = set(IGNORED_HOSTS) | set(IGNORED_MODULES)
for addon_dir in current_dir.iterdir():
if not addon_dir.is_dir():
continue
@ -304,6 +309,9 @@ def main(
if addons and addon_dir.name not in addons:
continue
if addon_dir.name in ignored_addons:
continue
server_dir = addon_dir / "server"
if not server_dir.exists():
continue