Merge branch 'develop' into feature/911-new-traits-based-integrator

This commit is contained in:
Ondřej Samohel 2025-04-16 15:30:13 +02:00 committed by GitHub
commit cbbe1297cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 51 additions and 56 deletions

View file

@ -37,7 +37,7 @@ def _handle_error(
if process_context.headless: if process_context.headless:
if detail: if detail:
print(detail) print(detail)
print(f"{10*'*'}\n{message}\n{10*'*'}") print(f"{10 * '*'}\n{message}\n{10 * '*'}")
return return
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = os.path.dirname(os.path.abspath(__file__))

View file

@ -24,7 +24,6 @@ from ayon_core.lib.env_tools import (
) )
@click.group(invoke_without_command=True) @click.group(invoke_without_command=True)
@click.pass_context @click.pass_context
@click.option("--use-staging", is_flag=True, @click.option("--use-staging", is_flag=True,
@ -173,7 +172,6 @@ def contextselection(
main(output_path, project, folder, strict) main(output_path, project, folder, strict)
@main_cli.command( @main_cli.command(
context_settings=dict( context_settings=dict(
ignore_unknown_options=True, ignore_unknown_options=True,

View file

@ -22,12 +22,10 @@ import clique
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from typing import Self, Tuple, Union, TypedDict, Pattern from typing import Self, Tuple, Union, TypedDict, Pattern
class EnumItemDict(TypedDict): class EnumItemDict(TypedDict):
label: str label: str
value: Any value: Any
EnumItemsInputType = Union[ EnumItemsInputType = Union[
Dict[Any, str], Dict[Any, str],
List[Tuple[Any, str]], List[Tuple[Any, str]],
@ -35,7 +33,6 @@ if typing.TYPE_CHECKING:
List[EnumItemDict] List[EnumItemDict]
] ]
class FileDefItemDict(TypedDict): class FileDefItemDict(TypedDict):
directory: str directory: str
filenames: List[str] filenames: List[str]
@ -289,6 +286,7 @@ AttrDefType = TypeVar("AttrDefType", bound=AbstractAttrDef)
# UI attribute definitions won't hold value # UI attribute definitions won't hold value
# ----------------------------------------- # -----------------------------------------
class UIDef(AbstractAttrDef): class UIDef(AbstractAttrDef):
is_value_def = False is_value_def = False

View file

@ -177,10 +177,12 @@ def initialize_ayon_connection(force=False):
return _new_get_last_versions( return _new_get_last_versions(
con, *args, **kwargs con, *args, **kwargs
) )
def _lv_by_pi_wrapper(*args, **kwargs): def _lv_by_pi_wrapper(*args, **kwargs):
return _new_get_last_version_by_product_id( return _new_get_last_version_by_product_id(
con, *args, **kwargs con, *args, **kwargs
) )
def _lv_by_pn_wrapper(*args, **kwargs): def _lv_by_pn_wrapper(*args, **kwargs):
return _new_get_last_version_by_product_name( return _new_get_last_version_by_product_name(
con, *args, **kwargs con, *args, **kwargs

View file

@ -39,6 +39,7 @@ class Terminal:
""" """
from ayon_core.lib import env_value_to_bool from ayon_core.lib import env_value_to_bool
log_no_colors = env_value_to_bool( log_no_colors = env_value_to_bool(
"AYON_LOG_NO_COLORS", default=None "AYON_LOG_NO_COLORS", default=None
) )

View file

@ -162,7 +162,7 @@ def find_tool_in_custom_paths(paths, tool, validation_func=None):
# Handle cases when path is just an executable # Handle cases when path is just an executable
# - it allows to use executable from PATH # - it allows to use executable from PATH
# - basename must match 'tool' value (without extension) # - basename must match 'tool' value (without extension)
extless_path, ext = os.path.splitext(path) extless_path, _ext = os.path.splitext(path)
if extless_path == tool: if extless_path == tool:
executable_path = find_executable(tool) executable_path = find_executable(tool)
if executable_path and ( if executable_path and (
@ -181,7 +181,7 @@ def find_tool_in_custom_paths(paths, tool, validation_func=None):
# If path is a file validate it # If path is a file validate it
if os.path.isfile(normalized): if os.path.isfile(normalized):
basename, ext = os.path.splitext(os.path.basename(path)) basename, _ext = os.path.splitext(os.path.basename(path))
# Check if the filename has actually the sane bane as 'tool' # Check if the filename has actually the sane bane as 'tool'
if basename == tool: if basename == tool:
executable_path = find_executable(normalized) executable_path = find_executable(normalized)

View file

@ -872,7 +872,7 @@ class CreateContext:
""" """
return self._event_hub.add_callback(INSTANCE_ADDED_TOPIC, callback) return self._event_hub.add_callback(INSTANCE_ADDED_TOPIC, callback)
def add_instances_removed_callback (self, callback): def add_instances_removed_callback(self, callback):
"""Register callback for removed instances. """Register callback for removed instances.
Event is triggered when instances are already removed from context. Event is triggered when instances are already removed from context.
@ -933,7 +933,7 @@ class CreateContext:
""" """
self._event_hub.add_callback(VALUE_CHANGED_TOPIC, callback) self._event_hub.add_callback(VALUE_CHANGED_TOPIC, callback)
def add_pre_create_attr_defs_change_callback (self, callback): def add_pre_create_attr_defs_change_callback(self, callback):
"""Register callback to listen pre-create attribute changes. """Register callback to listen pre-create attribute changes.
Create plugin can trigger refresh of pre-create attributes. Usage of Create plugin can trigger refresh of pre-create attributes. Usage of
@ -961,7 +961,7 @@ class CreateContext:
PRE_CREATE_ATTR_DEFS_CHANGED_TOPIC, callback PRE_CREATE_ATTR_DEFS_CHANGED_TOPIC, callback
) )
def add_create_attr_defs_change_callback (self, callback): def add_create_attr_defs_change_callback(self, callback):
"""Register callback to listen create attribute changes. """Register callback to listen create attribute changes.
Create plugin changed attribute definitions of instance. Create plugin changed attribute definitions of instance.
@ -986,7 +986,7 @@ class CreateContext:
""" """
self._event_hub.add_callback(CREATE_ATTR_DEFS_CHANGED_TOPIC, callback) self._event_hub.add_callback(CREATE_ATTR_DEFS_CHANGED_TOPIC, callback)
def add_publish_attr_defs_change_callback (self, callback): def add_publish_attr_defs_change_callback(self, callback):
"""Register callback to listen publish attribute changes. """Register callback to listen publish attribute changes.
Publish plugin changed attribute definitions of instance of context. Publish plugin changed attribute definitions of instance of context.

View file

@ -369,7 +369,7 @@ class PublishAttributes:
return copy.deepcopy(self._origin_data) return copy.deepcopy(self._origin_data)
def attribute_value_changed(self, key, changes): def attribute_value_changed(self, key, changes):
self._parent.publish_attribute_value_changed(key, changes) self._parent.publish_attribute_value_changed(key, changes)
def set_publish_plugin_attr_defs( def set_publish_plugin_attr_defs(
self, self,

View file

@ -255,7 +255,7 @@ def deliver_sequence(
report_items[""].append(msg) report_items[""].append(msg)
return report_items, 0 return report_items, 0
dir_path, file_name = os.path.split(str(src_path)) dir_path, _file_name = os.path.split(str(src_path))
context = repre["context"] context = repre["context"]
ext = context.get("ext", context.get("representation")) ext = context.get("ext", context.get("representation"))
@ -270,7 +270,7 @@ def deliver_sequence(
# context.representation could be .psd # context.representation could be .psd
ext = ext.replace("..", ".") ext = ext.replace("..", ".")
src_collections, remainder = clique.assemble(os.listdir(dir_path)) src_collections, _remainder = clique.assemble(os.listdir(dir_path))
src_collection = None src_collection = None
for col in src_collections: for col in src_collections:
if col.tail != ext: if col.tail != ext:

View file

@ -1,4 +1,4 @@
from __future__ import annotations from __future__ import annotations
import copy import copy
import os import os
import re import re
@ -1168,7 +1168,7 @@ def prepare_cache_representations(skeleton_data, exp_files, anatomy):
""" """
representations = [] representations = []
collections, remainders = clique.assemble(exp_files) collections, _remainders = clique.assemble(exp_files)
log = Logger.get_logger("farm_publishing") log = Logger.get_logger("farm_publishing")

View file

@ -41,7 +41,7 @@ def validate(data, schema=None):
if not _CACHED: if not _CACHED:
_precache() _precache()
root, schema = data["schema"].rsplit(":", 1) _root, schema = data["schema"].rsplit(":", 1)
if isinstance(schema, str): if isinstance(schema, str):
schema = _cache[schema + ".json"] schema = _cache[schema + ".json"]

View file

@ -209,7 +209,7 @@ def get_staging_dir_info(
staging_dir_config = get_staging_dir_config( staging_dir_config = get_staging_dir_config(
project_entity["name"], project_entity["name"],
task_type, task_type,
task_name , task_name,
product_type, product_type,
product_name, product_name,
host_name, host_name,

View file

@ -329,9 +329,9 @@ def get_last_workfile(
Returns: Returns:
str: Last or first workfile as filename of full path to filename. str: Last or first workfile as filename of full path to filename.
"""
filename, version = get_last_workfile_with_version( """
filename, _version = get_last_workfile_with_version(
workdir, file_template, fill_data, extensions workdir, file_template, fill_data, extensions
) )
if filename is None: if filename is None:

View file

@ -211,7 +211,7 @@ class DeleteOldVersions(load.ProductLoaderPlugin):
f"This will keep only the last {versions_to_keep} " f"This will keep only the last {versions_to_keep} "
f"versions for the {num_contexts} selected product{s}." f"versions for the {num_contexts} selected product{s}."
) )
informative_text="Warning: This will delete files from disk" informative_text = "Warning: This will delete files from disk"
detailed_text = ( detailed_text = (
f"Keep only {versions_to_keep} versions for:\n{contexts_list}" f"Keep only {versions_to_keep} versions for:\n{contexts_list}"
) )

View file

@ -22,6 +22,7 @@ from ayon_core.tools.utils import show_message_dialog
OTIO = None OTIO = None
FRAME_SPLITTER = "__frame_splitter__" FRAME_SPLITTER = "__frame_splitter__"
def _import_otio(): def _import_otio():
global OTIO global OTIO
if OTIO is None: if OTIO is None:

View file

@ -394,7 +394,6 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
if aov: if aov:
anatomy_data["aov"] = aov anatomy_data["aov"] = aov
def _fill_folder_data(self, instance, project_entity, anatomy_data): def _fill_folder_data(self, instance, project_entity, anatomy_data):
# QUESTION: should we make sure that all folder data are popped if # QUESTION: should we make sure that all folder data are popped if
# folder data cannot be found? # folder data cannot be found?

View file

@ -43,4 +43,3 @@ class CollectCoreJobEnvVars(pyblish.api.ContextPlugin):
if value: if value:
self.log.debug(f"Setting job env: {key}: {value}") self.log.debug(f"Setting job env: {key}: {value}")
env[key] = value env[key] = value

View file

@ -50,7 +50,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
"comments": instance.data.get("comments", []), "comments": instance.data.get("comments", []),
} }
shot_data["attributes"] = {} shot_data["attributes"] = {}
SHOT_ATTRS = ( SHOT_ATTRS = (
"handleStart", "handleStart",
"handleEnd", "handleEnd",

View file

@ -194,7 +194,6 @@ class CollectOtioSubsetResources(
repre = self._create_representation( repre = self._create_representation(
frame_start, frame_end, file=filename) frame_start, frame_end, file=filename)
else: else:
_trim = False _trim = False
dirname, filename = os.path.split(media_ref.target_url) dirname, filename = os.path.split(media_ref.target_url)
@ -209,7 +208,6 @@ class CollectOtioSubsetResources(
repre = self._create_representation( repre = self._create_representation(
frame_start, frame_end, file=filename, trim=_trim) frame_start, frame_end, file=filename, trim=_trim)
instance.data["originalDirname"] = self.staging_dir instance.data["originalDirname"] = self.staging_dir
# add representation to instance data # add representation to instance data
@ -221,7 +219,6 @@ class CollectOtioSubsetResources(
instance.data["representations"].append(repre) instance.data["representations"].append(repre)
self.log.debug(instance.data) self.log.debug(instance.data)
def _create_representation(self, start, end, **kwargs): def _create_representation(self, start, end, **kwargs):

View file

@ -1333,7 +1333,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
bg_red, bg_green, bg_blue = overscan_color bg_red, bg_green, bg_blue = overscan_color
else: else:
# Backwards compatibility # Backwards compatibility
bg_red, bg_green, bg_blue, _ = overscan_color bg_red, bg_green, bg_blue, _ = overscan_color
overscan_color_value = "#{0:0>2X}{1:0>2X}{2:0>2X}".format( overscan_color_value = "#{0:0>2X}{1:0>2X}{2:0>2X}".format(
bg_red, bg_green, bg_blue bg_red, bg_green, bg_blue

View file

@ -683,7 +683,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin):
elif is_sequence_representation: elif is_sequence_representation:
# Collection of files (sequence) # Collection of files (sequence)
src_collections, remainders = clique.assemble(files) src_collections, _remainders = clique.assemble(files)
src_collection = src_collections[0] src_collection = src_collections[0]
destination_indexes = list(src_collection.indexes) destination_indexes = list(src_collection.indexes)

View file

@ -7,7 +7,7 @@ class IntegrateResourcesPath(pyblish.api.InstancePlugin):
label = "Integrate Resources Path" label = "Integrate Resources Path"
order = pyblish.api.IntegratorOrder - 0.05 order = pyblish.api.IntegratorOrder - 0.05
families = ["clip", "projectfile", "plate"] families = ["clip", "projectfile", "plate"]
def process(self, instance): def process(self, instance):
resources = instance.data.get("resources") or [] resources = instance.data.get("resources") or []

View file

@ -173,7 +173,6 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins):
if frame_end is not None: if frame_end is not None:
options["frame_end"] = frame_end options["frame_end"] = frame_end
options["label"] = align options["label"] = align
self._add_burnin(text, align, options, DRAWTEXT) self._add_burnin(text, align, options, DRAWTEXT)

View file

@ -175,7 +175,7 @@ class BaseObj:
self.log.warning("Invalid range '{}'".format(part)) self.log.warning("Invalid range '{}'".format(part))
continue continue
for idx in range(sub_parts[0], sub_parts[1]+1): for idx in range(sub_parts[0], sub_parts[1] + 1):
indexes.append(idx) indexes.append(idx)
return indexes return indexes
@ -353,7 +353,6 @@ class BaseObj:
self.items[item.id] = item self.items[item.id] = item
item.fill_data_format() item.fill_data_format()
def reset(self): def reset(self):
for item in self.items.values(): for item in self.items.values():
item.reset() item.reset()

View file

@ -282,7 +282,7 @@ class ItemTable(BaseItem):
value.draw(image, drawer) value.draw(image, drawer)
def value_width(self): def value_width(self):
row_heights, col_widths = self.size_values _row_heights, col_widths = self.size_values
width = 0 width = 0
for _width in col_widths: for _width in col_widths:
width += _width width += _width
@ -292,7 +292,7 @@ class ItemTable(BaseItem):
return width return width
def value_height(self): def value_height(self):
row_heights, col_widths = self.size_values row_heights, _col_widths = self.size_values
height = 0 height = 0
for _height in row_heights: for _height in row_heights:
height += _height height += _height
@ -569,21 +569,21 @@ class TableField(BaseItem):
@property @property
def item_pos_x(self): def item_pos_x(self):
pos_x, pos_y, width, height = ( pos_x, _pos_y, _width, _height = (
self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx) self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx)
) )
return pos_x return pos_x
@property @property
def item_pos_y(self): def item_pos_y(self):
pos_x, pos_y, width, height = ( _pos_x, pos_y, _width, _height = (
self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx) self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx)
) )
return pos_y return pos_y
@property @property
def value_pos_x(self): def value_pos_x(self):
pos_x, pos_y, width, height = ( pos_x, _pos_y, width, _height = (
self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx) self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx)
) )
alignment_hor = self.style["alignment-horizontal"].lower() alignment_hor = self.style["alignment-horizontal"].lower()
@ -605,7 +605,7 @@ class TableField(BaseItem):
@property @property
def value_pos_y(self): def value_pos_y(self):
pos_x, pos_y, width, height = ( _pos_x, pos_y, _width, height = (
self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx) self.parent.content_pos_info_by_cord(self.row_idx, self.col_idx)
) )

View file

@ -248,4 +248,3 @@ class EnhancedTabBar(QtWidgets.QTabBar):
else: else:
super().mouseReleaseEvent(event) super().mouseReleaseEvent(event)

View file

@ -492,7 +492,7 @@ def show(parent=None):
try: try:
module.window.close() module.window.close()
del(module.window) del module.window
except (AttributeError, RuntimeError): except (AttributeError, RuntimeError):
pass pass

View file

@ -32,7 +32,7 @@ from qtpy import QtWidgets, QtCore, QtGui
import pyblish.api import pyblish.api
from ayon_core import style from ayon_core import style
TAB = 4* " " TAB = 4 * " "
HEADER_SIZE = "15px" HEADER_SIZE = "15px"
KEY_COLOR = QtGui.QColor("#ffffff") KEY_COLOR = QtGui.QColor("#ffffff")
@ -243,7 +243,7 @@ class DebugUI(QtWidgets.QDialog):
self._set_window_title(plugin=result["plugin"]) self._set_window_title(plugin=result["plugin"])
print(10*"<", result["plugin"].__name__, 10*">") print(10 * "<", result["plugin"].__name__, 10 * ">")
plugin_order = result["plugin"].order plugin_order = result["plugin"].order
plugin_name = result["plugin"].__name__ plugin_name = result["plugin"].__name__

View file

@ -519,9 +519,9 @@ class LoaderWindow(QtWidgets.QWidget):
thumbnail_paths.discard(None) thumbnail_paths.discard(None)
if thumbnail_paths: if thumbnail_paths:
self._thumbnails_widget.set_current_thumbnail_paths( self._thumbnails_widget.set_current_thumbnail_paths(
thumbnail_paths thumbnail_paths
) )
else: else:
self._thumbnails_widget.set_current_thumbnails(None) self._thumbnails_widget.set_current_thumbnails(None)

View file

@ -461,19 +461,19 @@ class CreateModel:
self._create_context.add_instances_added_callback( self._create_context.add_instances_added_callback(
self._cc_added_instance self._cc_added_instance
) )
self._create_context.add_instances_removed_callback ( self._create_context.add_instances_removed_callback(
self._cc_removed_instance self._cc_removed_instance
) )
self._create_context.add_value_changed_callback( self._create_context.add_value_changed_callback(
self._cc_value_changed self._cc_value_changed
) )
self._create_context.add_pre_create_attr_defs_change_callback ( self._create_context.add_pre_create_attr_defs_change_callback(
self._cc_pre_create_attr_changed self._cc_pre_create_attr_changed
) )
self._create_context.add_create_attr_defs_change_callback ( self._create_context.add_create_attr_defs_change_callback(
self._cc_create_attr_changed self._cc_create_attr_changed
) )
self._create_context.add_publish_attr_defs_change_callback ( self._create_context.add_publish_attr_defs_change_callback(
self._cc_publish_attr_changed self._cc_publish_attr_changed
) )

View file

@ -358,7 +358,7 @@ class PublishReportMaker:
exception = result.get("error") exception = result.get("error")
if exception: if exception:
fname, line_no, func, exc = exception.traceback fname, line_no, func, _ = exception.traceback
# Conversion of exception into string may crash # Conversion of exception into string may crash
try: try:

View file

@ -738,4 +738,3 @@ def main(force=False):
sys.exit(1) sys.exit(1)
main() main()

View file

@ -575,7 +575,7 @@ class TasksWidget(QtWidgets.QWidget):
if self._tasks_model.is_refreshing: if self._tasks_model.is_refreshing:
return return
parent_id, task_id, task_name, _ = self._get_selected_item_ids() _parent_id, task_id, task_name, _ = self._get_selected_item_ids()
self._controller.set_selected_task(task_id, task_name) self._controller.set_selected_task(task_id, task_name)
self.selection_changed.emit() self.selection_changed.emit()

View file

@ -462,7 +462,7 @@ class WorkfileEntitiesModel:
anatomy = self._controller.project_anatomy anatomy = self._controller.project_anatomy
workdir, filename = os.path.split(filepath) workdir, filename = os.path.split(filepath)
success, rootless_dir = anatomy.find_root_template_from_path(workdir) _, rootless_dir = anatomy.find_root_template_from_path(workdir)
return "/".join([ return "/".join([
os.path.normpath(rootless_dir).replace("\\", "/"), os.path.normpath(rootless_dir).replace("\\", "/"),
filename filename

View file

@ -101,6 +101,7 @@ def test_image_sequence():
expected_data, expected_data,
) )
def test_media_retimed(): def test_media_retimed():
""" """
EXR image sequence. EXR image sequence.

View file

@ -215,6 +215,7 @@ def test_short_movie_tail_gap_handles():
assert calls == expected assert calls == expected
def test_multiple_review_clips_no_gap(): def test_multiple_review_clips_no_gap():
""" """
Use multiple review clips (image sequence). Use multiple review clips (image sequence).
@ -298,6 +299,7 @@ def test_multiple_review_clips_no_gap():
assert calls == expected assert calls == expected
def test_multiple_review_clips_with_gap(): def test_multiple_review_clips_with_gap():
""" """
Use multiple review clips (image sequence) with gap. Use multiple review clips (image sequence) with gap.

View file

@ -257,7 +257,6 @@ def test_movie_timewarp():
) )
def test_img_sequence_no_handles(): def test_img_sequence_no_handles():
""" """
Img sequence clip (no embedded timecode) Img sequence clip (no embedded timecode)
@ -334,6 +333,7 @@ def test_img_sequence_relative_source_range():
expected_data expected_data
) )
def test_img_sequence_conform_to_23_976fps(): def test_img_sequence_conform_to_23_976fps():
""" """
Img sequence clip Img sequence clip
@ -409,6 +409,7 @@ def test_img_sequence_reverse_speed_no_tc():
handle_end=0, handle_end=0,
) )
def test_img_sequence_reverse_speed_from_24_to_23_976fps(): def test_img_sequence_reverse_speed_from_24_to_23_976fps():
""" """
Img sequence clip Img sequence clip