mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
🎨 add support for product base type to basic creator logic
This commit is contained in:
parent
9e730a6b5b
commit
d237e5f54c
5 changed files with 119 additions and 56 deletions
|
|
@ -32,7 +32,7 @@ from ayon_core.host import IPublishHost, IWorkfileHost
|
|||
from ayon_core.pipeline import Anatomy
|
||||
from ayon_core.pipeline.template_data import get_template_data
|
||||
from ayon_core.pipeline.plugin_discover import DiscoverResult
|
||||
from ayon_core.pipeline import is_supporting_product_base_type
|
||||
from ayon_core.pipeline.compatibility import is_supporting_product_base_type
|
||||
|
||||
from .exceptions import (
|
||||
CreatorError,
|
||||
|
|
|
|||
|
|
@ -317,7 +317,6 @@ class BaseCreator(ABC):
|
|||
identifier = f"{identifier}.{self.product_type}"
|
||||
return identifier
|
||||
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def product_type(self):
|
||||
|
|
@ -562,14 +561,15 @@ class BaseCreator(ABC):
|
|||
|
||||
def get_product_name(
|
||||
self,
|
||||
project_name,
|
||||
folder_entity,
|
||||
task_entity,
|
||||
variant,
|
||||
host_name=None,
|
||||
instance=None,
|
||||
project_entity=None,
|
||||
):
|
||||
project_name: str,
|
||||
folder_entity: dict[str, Any],
|
||||
task_entity: dict[str, Any],
|
||||
variant: str,
|
||||
host_name: Optional[str] = None,
|
||||
instance: Optional[CreatedInstance] = None,
|
||||
project_entity: Optional[dict[str, Any]] = None,
|
||||
product_base_type: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Return product name for passed context.
|
||||
|
||||
Method is also called on product name update. In that case origin
|
||||
|
|
@ -586,8 +586,12 @@ class BaseCreator(ABC):
|
|||
for which is product name updated. Passed only on product name
|
||||
update.
|
||||
project_entity (Optional[dict[str, Any]]): Project entity.
|
||||
product_base_type (Optional[str]): Product base type.
|
||||
|
||||
"""
|
||||
if is_supporting_product_base_type() and (instance and hasattr(instance, "product_base_type")): # noqa: E501
|
||||
product_base_type = instance.product_base_type
|
||||
|
||||
if host_name is None:
|
||||
host_name = self.create_context.host_name
|
||||
|
||||
|
|
@ -619,6 +623,7 @@ class BaseCreator(ABC):
|
|||
dynamic_data=dynamic_data,
|
||||
project_settings=self.project_settings,
|
||||
project_entity=project_entity,
|
||||
product_base_type=product_base_type
|
||||
)
|
||||
|
||||
def get_instance_attr_defs(self):
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
"""Functions for handling product names."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Optional, Union
|
||||
from warnings import warn
|
||||
|
||||
import ayon_api
|
||||
from ayon_core.lib import (
|
||||
StringTemplate,
|
||||
filter_profiles,
|
||||
prepare_template_data,
|
||||
)
|
||||
from ayon_core.pipeline.compatibility import is_supporting_product_base_type
|
||||
from ayon_core.settings import get_project_settings
|
||||
|
||||
from .constants import DEFAULT_PRODUCT_TEMPLATE
|
||||
|
|
@ -11,14 +18,15 @@ from .exceptions import TaskNotSetError, TemplateFillError
|
|||
|
||||
|
||||
def get_product_name_template(
|
||||
project_name,
|
||||
product_type,
|
||||
task_name,
|
||||
task_type,
|
||||
host_name,
|
||||
default_template=None,
|
||||
project_settings=None
|
||||
):
|
||||
project_name: str,
|
||||
product_type: str,
|
||||
task_name: str,
|
||||
task_type: str,
|
||||
host_name: str,
|
||||
default_template: Optional[str] = None,
|
||||
project_settings: Optional[dict[str, Any]] = None,
|
||||
product_base_type: Optional[str] = None
|
||||
) -> str:
|
||||
"""Get product name template based on passed context.
|
||||
|
||||
Args:
|
||||
|
|
@ -28,13 +36,17 @@ def get_product_name_template(
|
|||
host_name (str): Name of host in which the product name is calculated.
|
||||
task_name (str): Name of task in which context the product is created.
|
||||
task_type (str): Type of task in which context the product is created.
|
||||
default_template (Union[str, None]): Default template which is used if
|
||||
default_template (Optional, str): Default template which is used if
|
||||
settings won't find any matching possibility. Constant
|
||||
'DEFAULT_PRODUCT_TEMPLATE' is used if not defined.
|
||||
project_settings (Union[Dict[str, Any], None]): Prepared settings for
|
||||
project. Settings are queried if not passed.
|
||||
"""
|
||||
product_base_type (Optional[str]): Base type of product.
|
||||
|
||||
Returns:
|
||||
str: Product name template.
|
||||
|
||||
"""
|
||||
if project_settings is None:
|
||||
project_settings = get_project_settings(project_name)
|
||||
tools_settings = project_settings["core"]["tools"]
|
||||
|
|
@ -46,6 +58,15 @@ def get_product_name_template(
|
|||
"task_types": task_type
|
||||
}
|
||||
|
||||
if is_supporting_product_base_type():
|
||||
if product_base_type:
|
||||
filtering_criteria["product_base_types"] = product_base_type
|
||||
else:
|
||||
warn(
|
||||
"Product base type is not provided, please update your"
|
||||
"creation code to include it. It will be required in "
|
||||
"the future.", DeprecationWarning, stacklevel=2)
|
||||
|
||||
matching_profile = filter_profiles(profiles, filtering_criteria)
|
||||
template = None
|
||||
if matching_profile:
|
||||
|
|
@ -70,17 +91,18 @@ def get_product_name_template(
|
|||
|
||||
|
||||
def get_product_name(
|
||||
project_name,
|
||||
task_name,
|
||||
task_type,
|
||||
host_name,
|
||||
product_type,
|
||||
variant,
|
||||
default_template=None,
|
||||
dynamic_data=None,
|
||||
project_settings=None,
|
||||
product_type_filter=None,
|
||||
project_entity=None,
|
||||
project_name: str,
|
||||
task_name: str,
|
||||
task_type: str,
|
||||
host_name: str,
|
||||
product_type: str,
|
||||
variant: str,
|
||||
default_template: Optional[str] = None,
|
||||
dynamic_data: Optional[dict[str, Any]] = None,
|
||||
project_settings: Optional[dict[str, Any]] = None,
|
||||
product_type_filter: Optional[str] = None,
|
||||
project_entity: Optional[dict[str, Any]] = None,
|
||||
product_base_type: Optional[str] = None
|
||||
):
|
||||
"""Calculate product name based on passed context and AYON settings.
|
||||
|
||||
|
|
@ -92,14 +114,20 @@ def get_product_name(
|
|||
That's main reason why so many arguments are required to calculate product
|
||||
name.
|
||||
|
||||
Deprecation:
|
||||
The `product_base_type` argument is optional now, but it will be
|
||||
mandatory in future versions. It is recommended to pass it now to
|
||||
avoid issues in the future. If it is not passed, a warning will be raised
|
||||
to inform about this change.
|
||||
|
||||
Todos:
|
||||
Find better filtering options to avoid requirement of
|
||||
argument 'family_filter'.
|
||||
|
||||
Args:
|
||||
project_name (str): Project name.
|
||||
task_name (Union[str, None]): Task name.
|
||||
task_type (Union[str, None]): Task type.
|
||||
task_name (str): Task name.
|
||||
task_type (str): Task type.
|
||||
host_name (str): Host name.
|
||||
product_type (str): Product type.
|
||||
variant (str): In most of the cases it is user input during creation.
|
||||
|
|
@ -115,6 +143,8 @@ def get_product_name(
|
|||
not passed.
|
||||
project_entity (Optional[Dict[str, Any]]): Project entity used when
|
||||
task short name is required by template.
|
||||
product_base_type (Optional[str]): Base type of product.
|
||||
This will be mandatory in future versions.
|
||||
|
||||
Returns:
|
||||
str: Product name.
|
||||
|
|
@ -129,13 +159,14 @@ def get_product_name(
|
|||
return ""
|
||||
|
||||
template = get_product_name_template(
|
||||
project_name,
|
||||
product_type_filter or product_type,
|
||||
task_name,
|
||||
task_type,
|
||||
host_name,
|
||||
project_name=project_name,
|
||||
product_type=product_type_filter or product_type,
|
||||
task_name=task_name,
|
||||
task_type=task_type,
|
||||
host_name=host_name,
|
||||
default_template=default_template,
|
||||
project_settings=project_settings
|
||||
project_settings=project_settings,
|
||||
product_base_type=product_base_type,
|
||||
)
|
||||
# Simple check of task name existence for template with {task} in
|
||||
# - missing task should be possible only in Standalone publisher
|
||||
|
|
@ -147,7 +178,7 @@ def get_product_name(
|
|||
"type": task_type,
|
||||
}
|
||||
if "{task}" in template.lower():
|
||||
task_value = task_name
|
||||
task_value["name"] = task_name
|
||||
|
||||
elif "{task[short]}" in template.lower():
|
||||
if project_entity is None:
|
||||
|
|
@ -159,14 +190,25 @@ def get_product_name(
|
|||
task_short = task_types_by_name.get(task_type, {}).get("shortName")
|
||||
task_value["short"] = task_short
|
||||
|
||||
fill_pairs = {
|
||||
# look what we have to do to make mypy happy. We should stop using
|
||||
# those undefined dict based types.
|
||||
product: dict[str, str] = {"type": product_type}
|
||||
if is_supporting_product_base_type():
|
||||
if product_base_type:
|
||||
product["baseType"] = product_base_type
|
||||
elif "{product[basetype]}" in template.lower():
|
||||
warn(
|
||||
"You have Product base type in product name template,"
|
||||
"but it is not provided by the creator, please update your"
|
||||
"creation code to include it. It will be required in "
|
||||
"the future.", DeprecationWarning, stacklevel=2)
|
||||
fill_pairs: dict[str, Union[str, dict[str, str]]] = {
|
||||
"variant": variant,
|
||||
"family": product_type,
|
||||
"task": task_value,
|
||||
"product": {
|
||||
"type": product_type
|
||||
}
|
||||
"product": product,
|
||||
}
|
||||
|
||||
if dynamic_data:
|
||||
# Dynamic data may override default values
|
||||
for key, value in dynamic_data.items():
|
||||
|
|
@ -178,7 +220,8 @@ def get_product_name(
|
|||
data=prepare_template_data(fill_pairs)
|
||||
)
|
||||
except KeyError as exp:
|
||||
raise TemplateFillError(
|
||||
"Value for {} key is missing in template '{}'."
|
||||
" Available values are {}".format(str(exp), template, fill_pairs)
|
||||
msg = (
|
||||
f"Value for {exp} key is missing in template '{template}'."
|
||||
f" Available values are {fill_pairs}"
|
||||
)
|
||||
raise TemplateFillError(msg) from exp
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import collections
|
|||
from uuid import uuid4
|
||||
import typing
|
||||
from typing import Optional, Dict, List, Any
|
||||
import warnings
|
||||
from warnings import warn
|
||||
|
||||
from ayon_core.lib.attribute_definitions import (
|
||||
AbstractAttrDef,
|
||||
|
|
@ -465,6 +465,10 @@ class CreatedInstance:
|
|||
data (Dict[str, Any]): Data used for filling product name or override
|
||||
data from already existing instance.
|
||||
creator (BaseCreator): Creator responsible for instance.
|
||||
product_base_type (Optional[str]): Product base type that will be
|
||||
created. If not provided then product base type is taken from
|
||||
creator plugin. If creator does not have product base type then
|
||||
deprecation warning is raised.
|
||||
"""
|
||||
|
||||
# Keys that can't be changed or removed from data after loading using
|
||||
|
|
@ -497,14 +501,18 @@ class CreatedInstance:
|
|||
transient_data: Optional[Dict[str, Any]] = None,
|
||||
product_base_type: Optional[str] = None
|
||||
):
|
||||
|
||||
if is_supporting_product_base_type() and product_base_type is None:
|
||||
warnings.warn(
|
||||
f"Creator {creator!r} doesn't support "
|
||||
"product base type. This will be required in future.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
"""Initialize CreatedInstance."""
|
||||
if is_supporting_product_base_type():
|
||||
if not hasattr(creator, "product_base_type"):
|
||||
warn(
|
||||
f"Provided creator {creator!r} doesn't have "
|
||||
"product base type attribute defined. This will be "
|
||||
"required in future.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
elif not product_base_type:
|
||||
product_base_type = creator.product_base_type
|
||||
|
||||
self._creator = creator
|
||||
creator_identifier = creator.identifier
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ from ayon_core.pipeline.create import (
|
|||
ConvertorsOperationFailed,
|
||||
ConvertorItem,
|
||||
)
|
||||
from ayon_core.pipeline.compatibility import is_supporting_product_base_type
|
||||
|
||||
from ayon_core.tools.publisher.abstract import (
|
||||
AbstractPublisherBackend,
|
||||
CardMessageTypes,
|
||||
|
|
@ -631,12 +633,17 @@ class CreateModel:
|
|||
"instance": instance,
|
||||
"project_entity": project_entity,
|
||||
}
|
||||
|
||||
if is_supporting_product_base_type() and hasattr(creator, "product_base_type"): # noqa: E501
|
||||
kwargs["product_base_type"] = creator.product_base_type
|
||||
|
||||
# Backwards compatibility for 'project_entity' argument
|
||||
# - 'get_product_name' signature changed 24/07/08
|
||||
if not is_func_signature_supported(
|
||||
creator.get_product_name, *args, **kwargs
|
||||
):
|
||||
kwargs.pop("project_entity")
|
||||
kwargs.pop("product_base_type")
|
||||
return creator.get_product_name(*args, **kwargs)
|
||||
|
||||
def create(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue