diff --git a/client/ayon_core/pipeline/publish/lib.py b/client/ayon_core/pipeline/publish/lib.py index 464b2b6d8f..fbd6ed0b0b 100644 --- a/client/ayon_core/pipeline/publish/lib.py +++ b/client/ayon_core/pipeline/publish/lib.py @@ -1052,16 +1052,15 @@ def main_cli_publish( log.info("Running publish ...") - plugins = pyblish.api.discover() - print("Using plugins:") - for plugin in plugins: - print(plugin) + discover_result = publish_plugins_discover() + publish_plugins = discover_result.plugins + print("\n".join(discover_result.get_report(only_errors=False))) # Error exit as soon as any error occurs. error_format = ("Failed {plugin.__name__}: " "{error} -- {error.traceback}") - for result in pyblish.util.publish_iter(): + for result in pyblish.util.publish_iter(plugins=publish_plugins): if result["error"]: log.error(error_format.format(**result)) # uninstall() diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 0ee4cbff07..a5f541225c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -7,7 +7,6 @@ import shutil import subprocess from abc import ABC, abstractmethod from typing import Any, Optional -from dataclasses import dataclass, field import tempfile import clique @@ -37,37 +36,68 @@ from ayon_core.pipeline.publish import ( from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup -@dataclass class TempData: """Temporary data used across extractor's process.""" - fps: float - frame_start: int - frame_end: int - handle_start: int - handle_end: int - frame_start_handle: int - frame_end_handle: int - output_frame_start: int - output_frame_end: int - pixel_aspect: float - resolution_width: int - resolution_height: int - origin_repre: dict[str, Any] - input_is_sequence: bool - first_sequence_frame: int - input_allow_bg: bool - with_audio: bool - without_handles: bool - handles_are_set: bool - input_ext: str - explicit_input_paths: list[str] - paths_to_remove: list[str] + def __init__( + self, + fps: float, + frame_start: int, + frame_end: int, + handle_start: int, + handle_end: int, + frame_start_handle: int, + frame_end_handle: int, + output_frame_start: int, + output_frame_end: int, + pixel_aspect: float, + resolution_width: int, + resolution_height: int, + origin_repre: dict[str, Any], + input_is_sequence: bool, + first_sequence_frame: int, + input_allow_bg: bool, + with_audio: bool, + without_handles: bool, + handles_are_set: bool, + input_ext: str, + explicit_input_paths: list[str], + paths_to_remove: list[str], - # Set later - full_output_path: str = "" - filled_files: dict[int, str] = field(default_factory=dict) - output_ext_is_image: bool = True - output_is_sequence: bool = True + # Set later + full_output_path: str = "", + filled_files: dict[int, str] = None, + output_ext_is_image: bool = True, + output_is_sequence: bool = True, + ): + if filled_files is None: + filled_files = {} + self.fps = fps + self.frame_start = frame_start + self.frame_end = frame_end + self.handle_start = handle_start + self.handle_end = handle_end + self.frame_start_handle = frame_start_handle + self.frame_end_handle = frame_end_handle + self.output_frame_start = output_frame_start + self.output_frame_end = output_frame_end + self.pixel_aspect = pixel_aspect + self.resolution_width = resolution_width + self.resolution_height = resolution_height + self.origin_repre = origin_repre + self.input_is_sequence = input_is_sequence + self.first_sequence_frame = first_sequence_frame + self.input_allow_bg = input_allow_bg + self.with_audio = with_audio + self.without_handles = without_handles + self.handles_are_set = handles_are_set + self.input_ext = input_ext + self.explicit_input_paths = explicit_input_paths + self.paths_to_remove = paths_to_remove + + self.full_output_path = full_output_path + self.filled_files = filled_files + self.output_ext_is_image = output_ext_is_image + self.output_is_sequence = output_is_sequence def frame_to_timecode(frame: int, fps: float) -> str: diff --git a/client/ayon_core/plugins/publish/integrate_traits.py b/client/ayon_core/plugins/publish/integrate_traits.py index 38c9ecdeb4..45f32be4a0 100644 --- a/client/ayon_core/plugins/publish/integrate_traits.py +++ b/client/ayon_core/plugins/publish/integrate_traits.py @@ -1,11 +1,9 @@ """Integrate representations with traits.""" from __future__ import annotations - import contextlib import copy import hashlib import json -from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING, Any @@ -64,7 +62,6 @@ if TYPE_CHECKING: ) -@dataclass(frozen=True) class TransferItem: """Represents a single transfer item. @@ -91,6 +88,25 @@ class TransferItem: representation: Representation related_trait: FileLocation + def __init__(self, + source: Path, + destination: Path, + size: int, + checksum: str, + template: str, + template_data: dict[str, Any], + representation: Representation, + related_trait: FileLocation): + + self.source = source + self.destination = destination + self.size = size + self.checksum = checksum + self.template = template + self.template_data = template_data + self.representation = representation + self.related_trait = related_trait + @staticmethod def get_size(file_path: Path) -> int: """Get the size of the file. @@ -120,7 +136,6 @@ class TransferItem: ).hexdigest() -@dataclass class TemplateItem: """Represents single template item. @@ -135,10 +150,28 @@ class TemplateItem: anatomy: Anatomy template: str template_data: dict[str, Any] - template_object: AnatomyTemplateItem + template_object: "AnatomyTemplateItem" + + def __init__(self, + anatomy: "Anatomy", + template: str, + template_data: dict[str, Any], + template_object: "AnatomyTemplateItem"): + """Initialize TemplateItem. + + Args: + anatomy (Anatomy): Anatomy object. + template (str): Template path. + template_data (dict[str, Any]): Template data. + template_object (AnatomyTemplateItem): Template object. + + """ + self.anatomy = anatomy + self.template = template + self.template_data = template_data + self.template_object = template_object -@dataclass class RepresentationEntity: """Representation entity data.""" id: str @@ -150,6 +183,37 @@ class RepresentationEntity: tags: list[str] status: str + def __init__(self, + id: str, + versionId: str, # noqa: N815 + name: str, + files: dict[str, Any], + attrib: dict[str, Any], + data: str, + tags: list[str], + status: str): + """Initialize RepresentationEntity. + + Args: + id (str): Entity ID. + versionId (str): Version ID. + name (str): Representation name. + files (dict[str, Any]): Files in the representation. + attrib (dict[str, Any]): Attributes of the representation. + data (str): Data of the representation. + tags (list[str]): Tags of the representation. + status (str): Status of the representation. + + """ + self.id = id + self.versionId = versionId + self.name = name + self.files = files + self.attrib = attrib + self.data = data + self.tags = tags + self.status = status + def get_instance_families(instance: pyblish.api.Instance) -> list[str]: """Get all families of the instance. @@ -177,7 +241,7 @@ def get_instance_families(instance: pyblish.api.Instance) -> list[str]: def get_changed_attributes( - old_entity: dict, new_entity: dict) -> (dict[str, Any]): + old_entity: dict, new_entity: dict) -> dict[str, Any]: """Prepare changes for entity update. Todo: @@ -246,7 +310,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): label = "Integrate Traits of an Asset" order = pyblish.api.IntegratorOrder - log: logging.Logger + log: "logging.Logger" def process(self, instance: pyblish.api.Instance) -> None: """Integrate representations with traits. @@ -471,7 +535,8 @@ class IntegrateTraits(pyblish.api.InstancePlugin): @staticmethod def filter_lifecycle( - representations: list[Representation]) -> list[Representation]: + representations: list[Representation] + ) -> list[Representation]: """Filter representations based on LifeCycle traits. Args: @@ -535,7 +600,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): return path_template_obj.template.replace("\\", "/") def get_publish_template_object( - self, instance: pyblish.api.Instance) -> AnatomyTemplateItem: + self, instance: pyblish.api.Instance) -> "AnatomyTemplateItem": """Return anatomy template object to use for integration. Note: What is the actual type of the object? @@ -756,7 +821,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): return version_data - def get_rootless_path(self, anatomy: Anatomy, path: str) -> str: + def get_rootless_path(self, anatomy: "Anatomy", path: str) -> str: r"""Get rootless variant of the path. Returns, if possible, a path without an absolute portion from the root @@ -1015,7 +1080,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): """ udim: UDIM = representation.get_trait(UDIM) - path_template_object: AnatomyStringTemplate = ( + path_template_object: "AnatomyStringTemplate" = ( template_item.template_object["path"] ) for file_loc in representation.get_trait( @@ -1070,7 +1135,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): template_item (TemplateItem): Template item. """ - path_template_object: AnatomyStringTemplate = ( + path_template_object: "AnatomyStringTemplate" = ( template_item.template_object["path"] ) template_item.template_data["ext"] = ( @@ -1152,7 +1217,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): ) def _prepare_file_info( - self, path: Path, anatomy: Anatomy) -> dict[str, Any]: + self, path: Path, anatomy: "Anatomy") -> dict[str, Any]: """Prepare information for one file (asset or resource). Arguments: @@ -1183,7 +1248,7 @@ class IntegrateTraits(pyblish.api.InstancePlugin): self, transfer_items: list[TransferItem], representation: Representation, - anatomy: Anatomy, + anatomy: "Anatomy", ) -> list[dict[str, str]]: """Get legacy files for a given representation.