Merge branch 'develop' into bugfix/inventory_latest_version

This commit is contained in:
Roy Nieterau 2024-03-25 13:13:56 +01:00 committed by GitHub
commit edf87575f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 273 additions and 36 deletions

View file

@ -67,8 +67,6 @@ class Commands:
install_ayon_plugins,
get_global_context,
)
from ayon_core.tools.utils.host_tools import show_publish
from ayon_core.tools.utils.lib import qt_app_context
# Register target and host
import pyblish.api
@ -134,6 +132,8 @@ class Commands:
print(plugin)
if gui:
from ayon_core.tools.utils.host_tools import show_publish
from ayon_core.tools.utils.lib import qt_app_context
with qt_app_context():
show_publish()
else:

View file

@ -37,7 +37,8 @@ class ValidateFileSaved(pyblish.api.ContextPlugin,
if not context.data["currentFile"]:
# File has not been saved at all and has no filename
raise PublishValidationError(
"Current file is empty. Save the file before continuing."
"Current workfile has not been saved yet.\n"
"Save the workfile before continuing."
)
# Do not validate workfile has unsaved changes if only instances

View file

@ -0,0 +1,94 @@
import inspect
from typing import List
import bpy
import pyblish.api
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
OptionalPyblishPluginMixin,
PublishValidationError,
RepairAction
)
import ayon_core.hosts.blender.api.action
class ValidateModelMeshUvMap1(
pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin,
):
"""Validate model mesh uvs are named `map1`.
This is solely to get them to work nicely for the Maya pipeline.
"""
order = ValidateContentsOrder
hosts = ["blender"]
families = ["model"]
label = "Mesh UVs named map1"
actions = [ayon_core.hosts.blender.api.action.SelectInvalidAction,
RepairAction]
optional = True
enabled = False
@classmethod
def get_invalid(cls, instance) -> List:
invalid = []
for obj in instance:
if obj.mode != "OBJECT":
cls.log.warning(
f"Mesh object {obj.name} should be in 'OBJECT' mode"
" to be properly checked."
)
obj_data = obj.data
if isinstance(obj_data, bpy.types.Mesh):
mesh = obj_data
# Ignore mesh without UVs
if not mesh.uv_layers:
continue
# If mesh has map1 all is ok
if mesh.uv_layers.get("map1"):
continue
cls.log.warning(
f"Mesh object {obj.name} should be in 'OBJECT' mode"
" to be properly checked."
)
invalid.append(obj)
return invalid
@classmethod
def repair(cls, instance):
for obj in cls.get_invalid(instance):
mesh = obj.data
# Rename the first UV set to map1
mesh.uv_layers[0].name = "map1"
def process(self, instance):
if not self.is_active(instance.data):
return
invalid = self.get_invalid(instance)
if invalid:
raise PublishValidationError(
f"Meshes found in instance without valid UV's: {invalid}",
description=self.get_description()
)
def get_description(self):
return inspect.cleandoc(
"""## Meshes must have map1 uv set
To accompany a better Maya-focused pipeline with Alembics it is
expected that a Mesh has a `map1` UV set. Blender defaults to
a UV set named `UVMap` and thus needs to be renamed.
"""
)

View file

@ -1,3 +1,4 @@
import inspect
from typing import List
import mathutils
@ -5,29 +6,26 @@ import bpy
import pyblish.api
from ayon_core.hosts.blender.api import plugin, lib
import ayon_core.hosts.blender.api.action
from ayon_core.pipeline.publish import (
ValidateContentsOrder,
OptionalPyblishPluginMixin,
PublishValidationError
PublishValidationError,
RepairAction
)
class ValidateTransformZero(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Transforms can't have any values
To solve this issue, try freezing the transforms. So long
as the transforms, rotation and scale values are zero,
you're all good.
"""
"""Transforms can't have any values"""
order = ValidateContentsOrder
hosts = ["blender"]
families = ["model"]
label = "Transform Zero"
actions = [ayon_core.hosts.blender.api.action.SelectInvalidAction]
actions = [ayon_core.hosts.blender.api.action.SelectInvalidAction,
RepairAction]
_identity = mathutils.Matrix()
@ -51,5 +49,46 @@ class ValidateTransformZero(pyblish.api.InstancePlugin,
names = ", ".join(obj.name for obj in invalid)
raise PublishValidationError(
"Objects found in instance which do not"
f" have transform set to zero: {names}"
f" have transform set to zero: {names}",
description=self.get_description()
)
@classmethod
def repair(cls, instance):
invalid = cls.get_invalid(instance)
if not invalid:
return
context = plugin.create_blender_context(
active=invalid[0], selected=invalid
)
with lib.maintained_selection():
with bpy.context.temp_override(**context):
plugin.deselect_all()
for obj in invalid:
obj.select_set(True)
# TODO: Preferably this does allow custom pivot point locations
# and if so, this should likely apply to the delta instead
# using `bpy.ops.object.transforms_to_deltas(mode="ALL")`
bpy.ops.object.transform_apply(location=True,
rotation=True,
scale=True)
def get_description(self):
return inspect.cleandoc(
"""## Transforms can't have any values.
The location, rotation and scale on the transform must be at
the default values. This also goes for the delta transforms.
To solve this issue, try freezing the transforms:
- `Object` > `Apply` > `All Transforms`
Using the Repair action directly will do the same.
So long as the transforms, rotation and scale values are zero,
you're all good.
"""
)

View file

@ -1,7 +1,6 @@
from ayon_core.lib import NumberDef
from ayon_core.hosts.fusion.api.plugin import GenericCreateSaver
from ayon_core.hosts.fusion.api import get_current_comp
class CreateImageSaver(GenericCreateSaver):

View file

@ -50,11 +50,11 @@ class ImportTemplateLoader(load.LoaderPlugin):
self.__class__.__name__
)
def update(self, container, context):
pass
def update(self, container, context):
pass
def remove(self, container):
pass
def remove(self, container):
pass
class ImportWorkfileLoader(ImportTemplateLoader):

View file

@ -147,7 +147,6 @@ class HoudiniCreatorBase(object):
def create_instance_node(
folder_path, node_name, parent, node_type="geometry"
):
# type: (str, str, str) -> hou.Node
"""Create node representing instance.
Arguments:

View file

@ -16,7 +16,7 @@ class CreateHDA(plugin.HoudiniCreator):
maintain_selection = False
def _check_existing(self, folder_path, product_name):
# type: (str) -> bool
# type: (str, str) -> bool
"""Check if existing product name versions already exists."""
# Get all products of the current folder
project_name = self.project_name

View file

@ -40,9 +40,11 @@ class _NodeTypeAttrib(object):
return "{}.{}".format(node, self.colour_space)
def __str__(self):
return "_NodeTypeAttrib(name={}, fname={}, "
"computed_fname={}, colour_space={})".format(
self.name, self.fname, self.computed_fname, self.colour_space)
return (
"_NodeTypeAttrib(name={}, fname={}, "
"computed_fname={}, colour_space={})".format(
self.name, self.fname, self.computed_fname, self.colour_space)
)
NODETYPES = {

View file

@ -9,7 +9,6 @@ class CollectAutoImage(pyblish.api.ContextPlugin):
"""
label = "Collect Auto Image"
order = pyblish.api.CollectorOrder
hosts = ["photoshop"]
order = pyblish.api.CollectorOrder + 0.2

View file

@ -8,7 +8,6 @@ class CollectAutoImageRefresh(pyblish.api.ContextPlugin):
"""
label = "Collect Auto Image Refresh"
order = pyblish.api.CollectorOrder
hosts = ["photoshop"]
order = pyblish.api.CollectorOrder + 0.2

View file

@ -10,6 +10,87 @@ class _Cache:
initialized = False
def _new_get_last_versions(
self,
project_name,
product_ids,
active=True,
fields=None,
own_attributes=False
):
"""Query last version entities by product ids.
Args:
project_name (str): Project where to look for representation.
product_ids (Iterable[str]): Product ids.
active (Optional[bool]): Receive active/inactive entities.
Both are returned when 'None' is passed.
fields (Optional[Iterable[str]]): fields to be queried
for representations.
own_attributes (Optional[bool]): Attribute values that are
not explicitly set on entity will have 'None' value.
Returns:
dict[str, dict[str, Any]]: Last versions by product id.
"""
if fields:
fields = set(fields)
fields.add("productId")
versions = self.get_versions(
project_name,
product_ids=product_ids,
latest=True,
hero=False,
active=active,
fields=fields,
own_attributes=own_attributes
)
return {
version["productId"]: version
for version in versions
}
def _new_get_last_version_by_product_id(
self,
project_name,
product_id,
active=True,
fields=None,
own_attributes=False
):
"""Query last version entity by product id.
Args:
project_name (str): Project where to look for representation.
product_id (str): Product id.
active (Optional[bool]): Receive active/inactive entities.
Both are returned when 'None' is passed.
fields (Optional[Iterable[str]]): fields to be queried
for representations.
own_attributes (Optional[bool]): Attribute values that are
not explicitly set on entity will have 'None' value.
Returns:
Union[dict[str, Any], None]: Queried version entity or None.
"""
versions = self.get_versions(
project_name,
product_ids=[product_id],
latest=True,
hero=False,
active=active,
fields=fields,
own_attributes=own_attributes
)
for version in versions:
return version
return None
def _new_get_last_version_by_product_name(
self,
project_name,
@ -73,9 +154,15 @@ def initialize_ayon_connection(force=False):
semver.VersionInfo.parse(ayon_api.__version__).to_tuple()
)
# TODO remove mokey patching after when AYON api is safely updated
fix_last_version_by_product_name = ayon_api_version < (1, 0, 2)
fix_before_1_0_2 = ayon_api_version < (1, 0, 2)
# Monkey patching to fix 'get_last_version_by_product_name'
if fix_last_version_by_product_name:
if fix_before_1_0_2:
ayon_api.ServerAPI.get_last_versions = (
_new_get_last_versions
)
ayon_api.ServerAPI.get_last_version_by_product_id = (
_new_get_last_version_by_product_id
)
ayon_api.ServerAPI.get_last_version_by_product_name = (
_new_get_last_version_by_product_name
)
@ -85,12 +172,22 @@ def initialize_ayon_connection(force=False):
if ayon_api.is_connection_created():
con = ayon_api.get_server_api_connection()
# Monkey patching to fix 'get_last_version_by_product_name'
if fix_last_version_by_product_name:
def _con_wrapper(*args, **kwargs):
if fix_before_1_0_2:
def _lvs_wrapper(*args, **kwargs):
return _new_get_last_versions(
con, *args, **kwargs
)
def _lv_by_pi_wrapper(*args, **kwargs):
return _new_get_last_version_by_product_id(
con, *args, **kwargs
)
def _lv_by_pn_wrapper(*args, **kwargs):
return _new_get_last_version_by_product_name(
con, *args, **kwargs
)
con.get_last_version_by_product_name = _con_wrapper
con.get_last_versions = _lvs_wrapper
con.get_last_version_by_product_id = _lv_by_pi_wrapper
con.get_last_version_by_product_name = _lv_by_pn_wrapper
con.set_site_id(site_id)
con.set_client_version(version)
else:

View file

@ -46,7 +46,6 @@ class DeadlineModule(AYONAddon, IPluginPaths):
@staticmethod
def get_deadline_pools(webservice, log=None):
# type: (str) -> list
"""Get pools from Deadline.
Args:
webservice (str): Server url.

View file

@ -9,11 +9,11 @@ class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin):
DL webservice addresses must be configured first in System Settings for
project settings enum to work.
Default webservice could be overriden by
Default webservice could be overridden by
`project_settings/deadline/deadline_servers`. Currently only single url
is expected.
This url could be overriden by some hosts directly on instances with
This url could be overridden by some hosts directly on instances with
`CollectDeadlineServerFromInstance`.
"""

View file

@ -149,7 +149,7 @@ class ValidateExpectedFiles(pyblish.api.InstancePlugin):
"""
# no frames in file name at all, eg 'renderCompositingMain.withLut.mov'
if not frame_placeholder:
return set([file_name_template])
return {file_name_template}
real_expected_rendered = set()
src_padding_exp = "%0{}d".format(len(frame_placeholder))

View file

@ -404,7 +404,7 @@ class OpenPypeTileAssembler(DeadlinePlugin):
Args:
output_width (int): Width of output image.
output_height (int): Height of output image.
tiles_info (list): List of tile items, each item must be
tile_info (list): List of tile items, each item must be
dictionary with `filepath`, `pos_x` and `pos_y` keys
representing path to file and x, y coordinates on output
image where top-left point of tile item should start.

View file

@ -89,6 +89,10 @@ class PublishPuginsModel(BaseSettingsModel):
default_factory=ValidatePluginModel,
title="Validate Mesh No Negative Scale"
)
ValidateModelMeshUvMap1: ValidatePluginModel = SettingsField(
default_factory=ValidatePluginModel,
title="Validate Model Mesh Has UV map named map1"
)
ValidateTransformZero: ValidatePluginModel = SettingsField(
default_factory=ValidatePluginModel,
title="Validate Transform Zero"
@ -181,6 +185,11 @@ DEFAULT_BLENDER_PUBLISH_SETTINGS = {
"optional": False,
"active": True
},
"ValidateModelMeshUvMap1": {
"enabled": False,
"optional": True,
"active": True
},
"ValidateTransformZero": {
"enabled": False,
"optional": True,

View file

@ -1 +1 @@
__version__ = "0.1.7"
__version__ = "0.1.8"