From f5c38eb8d794fc6f3f3517322a796d18d8036d82 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 5 Feb 2024 10:25:01 +0000 Subject: [PATCH 01/29] Thumbnail subset filtering --- openpype/plugins/publish/extract_thumbnail.py | 30 +++++++++++++++++-- .../defaults/project_settings/global.json | 1 + .../schemas/schema_global_publish.json | 6 ++++ .../core/server/settings/publish_plugins.py | 5 ++++ server_addon/core/server/version.py | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 10eb261482..6008b8323d 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -2,6 +2,7 @@ import copy import os import subprocess import tempfile +import re import pyblish.api from openpype.lib import ( @@ -14,9 +15,10 @@ from openpype.lib import ( path_to_subprocess_arg, run_subprocess, ) -from openpype.lib.transcoding import convert_colorspace - -from openpype.lib.transcoding import VIDEO_EXTENSIONS +from openpype.lib.transcoding import ( + convert_colorspace, + VIDEO_EXTENSIONS, +) class ExtractThumbnail(pyblish.api.InstancePlugin): @@ -49,6 +51,8 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # attribute presets from settings oiiotool_defaults = None ffmpeg_args = None + subsets = [] + product_names = [] def process(self, instance): # run main process @@ -103,6 +107,26 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): self.log.debug("Skipping crypto passes.") return + # We only want to process the subsets needed from settings. + def validate_string_against_patterns(input_str, patterns): + for pattern in patterns: + if re.match(pattern, input_str): + return True + return False + + product_names = self.subsets + self.product_names + if product_names: + result = validate_string_against_patterns( + instance.data["subset"], product_names + ) + if not result: + self.log.debug( + "Subset \"{}\" did not match any valid subsets: {}".format( + instance.data["subset"], product_names + ) + ) + return + # first check for any explicitly marked representations for thumbnail explicit_repres = self._get_explicit_repres_for_thumbnail(instance) if explicit_repres: diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index bb7e3266bd..782fff1052 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -70,6 +70,7 @@ }, "ExtractThumbnail": { "enabled": true, + "subsets": [], "integrate_thumbnail": false, "background_color": [ 0, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index 64f292a140..226a190dd4 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -202,6 +202,12 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "list", + "object_type": "text", + "key": "subsets", + "label": "Subsets" + }, { "type": "boolean", "key": "integrate_thumbnail", diff --git a/server_addon/core/server/settings/publish_plugins.py b/server_addon/core/server/settings/publish_plugins.py index 7aa86aafa6..8506801e7e 100644 --- a/server_addon/core/server/settings/publish_plugins.py +++ b/server_addon/core/server/settings/publish_plugins.py @@ -176,6 +176,10 @@ class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): class ExtractThumbnailModel(BaseSettingsModel): _isGroup = True enabled: bool = SettingsField(True) + product_names: list[str] = SettingsField( + default_factory=list, + title="Product names" + ) integrate_thumbnail: bool = SettingsField( True, title="Integrate Thumbnail Representation" @@ -844,6 +848,7 @@ DEFAULT_PUBLISH_VALUES = { }, "ExtractThumbnail": { "enabled": True, + "product_names": [], "integrate_thumbnail": True, "target_size": { "type": "source" diff --git a/server_addon/core/server/version.py b/server_addon/core/server/version.py index bbab0242f6..1276d0254f 100644 --- a/server_addon/core/server/version.py +++ b/server_addon/core/server/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.1.5" From 02b371139a2c671e04cfdff2de5817975cdeb73c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 14:45:14 +0100 Subject: [PATCH 02/29] reduce usage of legay_io --- client/ayon_core/host/host.py | 3 - .../hosts/aftereffects/api/launch_logic.py | 5 +- .../ayon_core/hosts/blender/api/pipeline.py | 3 +- client/ayon_core/hosts/fusion/api/plugin.py | 3 +- client/ayon_core/hosts/maya/api/pipeline.py | 7 +- .../maya/plugins/load/load_arnold_standin.py | 8 +- .../maya/plugins/publish/collect_vrayscene.py | 5 - .../plugins/publish/validate_model_name.py | 1 - .../publish/validate_node_ids_in_database.py | 1 - .../publish/validate_renderlayer_aovs.py | 1 - .../validate_unreal_staticmesh_naming.py | 2 - .../plugins/publish/collect_batch_data.py | 3 - .../hosts/traypublisher/api/pipeline.py | 4 - .../ayon_core/hosts/tvpaint/api/pipeline.py | 6 +- .../plugins/publish/collect_workfile_data.py | 2 - .../publish/collect_sequences_from_job.py | 3 - .../publish/create_publish_royalrender_job.py | 4 - client/ayon_core/pipeline/context_tools.py | 176 +++++++----------- client/ayon_core/pipeline/create/context.py | 15 +- .../ayon_core/pipeline/create/subset_name.py | 3 +- client/ayon_core/pipeline/load/plugins.py | 5 +- .../publish/collect_from_create_context.py | 3 +- .../ayon_core/tools/sceneinventory/control.py | 3 +- client/ayon_core/tools/texture_copy/app.py | 7 +- .../tools/workfile_template_build/window.py | 5 +- 25 files changed, 90 insertions(+), 188 deletions(-) diff --git a/client/ayon_core/host/host.py b/client/ayon_core/host/host.py index 6d129e18d9..2dd98c8126 100644 --- a/client/ayon_core/host/host.py +++ b/client/ayon_core/host/host.py @@ -49,7 +49,6 @@ class HostBase(object): Todo: - move content of 'install_host' as method of this class - register host object - - install legacy_io - install global plugin paths - store registered plugin paths to this object - handle current context (project, asset, task) @@ -133,8 +132,6 @@ class HostBase(object): can be opened multiple workfiles at one moment and change of context can't be caught properly. - Default implementation returns values from 'legacy_io.Session'. - Returns: Dict[str, Union[str, None]]: Context with 3 keys 'project_name', 'asset_name' and 'task_name'. All of them can be 'None'. diff --git a/client/ayon_core/hosts/aftereffects/api/launch_logic.py b/client/ayon_core/hosts/aftereffects/api/launch_logic.py index ad521c2f01..3d09f4d53c 100644 --- a/client/ayon_core/hosts/aftereffects/api/launch_logic.py +++ b/client/ayon_core/hosts/aftereffects/api/launch_logic.py @@ -17,7 +17,7 @@ from qtpy import QtCore from ayon_core.lib import Logger from ayon_core.tests.lib import is_in_tests -from ayon_core.pipeline import install_host, legacy_io +from ayon_core.pipeline import install_host from ayon_core.addon import AddonsManager from ayon_core.tools.utils import host_tools, get_ayon_qt_app from ayon_core.tools.adobe_webserver.app import WebServerTool @@ -298,13 +298,10 @@ class AfterEffectsRoute(WebSocketRoute): log.info("Setting context change") log.info("project {} asset {} ".format(project, asset)) if project: - legacy_io.Session["AVALON_PROJECT"] = project os.environ["AVALON_PROJECT"] = project if asset: - legacy_io.Session["AVALON_ASSET"] = asset os.environ["AVALON_ASSET"] = asset if task: - legacy_io.Session["AVALON_TASK"] = task os.environ["AVALON_TASK"] = task async def read(self): diff --git a/client/ayon_core/hosts/blender/api/pipeline.py b/client/ayon_core/hosts/blender/api/pipeline.py index 6801b1f71b..77731a0fd3 100644 --- a/client/ayon_core/hosts/blender/api/pipeline.py +++ b/client/ayon_core/hosts/blender/api/pipeline.py @@ -19,7 +19,6 @@ from ayon_core.host import ( from ayon_core.client import get_asset_by_name from ayon_core.pipeline import ( schema, - legacy_io, get_current_project_name, get_current_asset_name, register_loader_plugin_path, @@ -380,7 +379,7 @@ def _on_task_changed(): # `directory` attribute, so it opens in that directory (does it?). # https://docs.blender.org/api/blender2.8/bpy.types.Operator.html#calling-a-file-selector # https://docs.blender.org/api/blender2.8/bpy.types.WindowManager.html#bpy.types.WindowManager.fileselect_add - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") log.debug("New working directory: %s", workdir) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index 12a29d2986..80e194ea68 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -11,7 +11,6 @@ from ayon_core.lib import ( EnumDef, ) from ayon_core.pipeline import ( - legacy_io, Creator, CreatedInstance ) @@ -136,7 +135,7 @@ class GenericCreateSaver(Creator): ext = data["creator_attributes"]["image_format"] # Subset change detected - workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) + workdir = os.path.normpath(os.getenv("AVALON_WORKDIR")) formatting_data.update({ "workdir": workdir, "frame": "0" * frame_padding, diff --git a/client/ayon_core/hosts/maya/api/pipeline.py b/client/ayon_core/hosts/maya/api/pipeline.py index 95617cb90a..dc6353618a 100644 --- a/client/ayon_core/hosts/maya/api/pipeline.py +++ b/client/ayon_core/hosts/maya/api/pipeline.py @@ -26,7 +26,6 @@ from ayon_core.lib import ( emit_event ) from ayon_core.pipeline import ( - legacy_io, get_current_project_name, register_loader_plugin_path, register_inventory_action_path, @@ -247,7 +246,7 @@ def _set_project(): None """ - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") try: os.makedirs(workdir) @@ -629,7 +628,7 @@ def on_task_changed(): # Run menu.update_menu_task_label() - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") if os.path.exists(workdir): log.info("Updating Maya workspace for task change to %s", workdir) _set_project() @@ -678,7 +677,7 @@ def workfile_save_before_xgen(event): import xgenm - current_work_dir = legacy_io.Session["AVALON_WORKDIR"].replace("\\", "/") + current_work_dir = os.getenv("AVALON_WORKDIR").replace("\\", "/") expected_work_dir = event.data["workdir_path"].replace("\\", "/") if current_work_dir == expected_work_dir: return diff --git a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py index c690d1c205..97407fbcc2 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py @@ -6,7 +6,6 @@ import maya.cmds as cmds from ayon_core.settings import get_project_settings from ayon_core.pipeline import ( load, - legacy_io, get_representation_path ) from ayon_core.hosts.maya.api.lib import ( @@ -26,11 +25,6 @@ def is_sequence(files): return sequence -def get_current_session_fps(): - session_fps = float(legacy_io.Session.get('AVALON_FPS', 25)) - return convert_to_maya_fps(session_fps) - - class ArnoldStandinLoader(load.LoaderPlugin): """Load as Arnold standin""" @@ -99,7 +93,7 @@ class ArnoldStandinLoader(load.LoaderPlugin): sequence = is_sequence(os.listdir(os.path.dirname(repre_path))) cmds.setAttr(standin_shape + ".useFrameExtension", sequence) - fps = float(version["data"].get("fps"))or get_current_session_fps() + fps = float(version["data"].get("fps")) or 25 cmds.setAttr(standin_shape + ".abcFPS", fps) nodes = [root, standin, standin_shape] diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py b/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py index 0efefe72c7..db008cc2be 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py @@ -1,13 +1,8 @@ # -*- coding: utf-8 -*- """Collect Vray Scene and prepare it for extraction and publishing.""" -import re - -import maya.app.renderSetup.model.renderSetup as renderSetup -from maya import cmds import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.lib import get_formatted_current_time from ayon_core.hosts.maya.api import lib diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py index 7812877fd3..cf2bbcd77c 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py @@ -12,7 +12,6 @@ import ayon_core.hosts.maya.api.action from ayon_core.client.mongo import OpenPypeMongoConnection from ayon_core.hosts.maya.api.shader_definition_editor import ( DEFINITION_FILENAME) -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( OptionalPyblishPluginMixin, PublishValidationError, ValidateContentsOrder) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py index bf12def5e9..de86ffe575 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py @@ -3,7 +3,6 @@ import pyblish.api import ayon_core.hosts.maya.api.action from ayon_core.client import get_assets from ayon_core.hosts.maya.api import lib -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( PublishValidationError, ValidatePipelineOrder) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py b/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py index 71cd6d7112..b5bfdcc9ec 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py @@ -2,7 +2,6 @@ import pyblish.api import ayon_core.hosts.maya.api.action from ayon_core.client import get_subset_by_name -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import PublishValidationError diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py index d43e04da60..21ea827f68 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py @@ -5,8 +5,6 @@ import re import pyblish.api import ayon_core.hosts.maya.api.action -from ayon_core.pipeline import legacy_io -from ayon_core.settings import get_project_settings from ayon_core.pipeline.publish import ( ValidateContentsOrder, OptionalPyblishPluginMixin, diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py index 5e43a021c3..6639040bd7 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py @@ -17,7 +17,6 @@ import os import pyblish.api -from ayon_core.pipeline import legacy_io from openpype_modules.webpublisher.lib import ( get_batch_asset_task_info, parse_json @@ -71,8 +70,6 @@ class CollectBatchData(pyblish.api.ContextPlugin): os.environ["AVALON_ASSET"] = asset_name os.environ["AVALON_TASK"] = task_name - legacy_io.Session["AVALON_ASSET"] = asset_name - legacy_io.Session["AVALON_TASK"] = task_name context.data["asset"] = asset_name context.data["task"] = task_name diff --git a/client/ayon_core/hosts/traypublisher/api/pipeline.py b/client/ayon_core/hosts/traypublisher/api/pipeline.py index 87177705c9..88fa3239a5 100644 --- a/client/ayon_core/hosts/traypublisher/api/pipeline.py +++ b/client/ayon_core/hosts/traypublisher/api/pipeline.py @@ -7,7 +7,6 @@ import pyblish.api from ayon_core.pipeline import ( register_creator_plugin_path, - legacy_io, ) from ayon_core.host import HostBase, IPublishHost @@ -24,7 +23,6 @@ class TrayPublisherHost(HostBase, IPublishHost): def install(self): os.environ["AVALON_APP"] = self.name - legacy_io.Session["AVALON_APP"] = self.name pyblish.api.register_host("traypublisher") pyblish.api.register_plugin_path(PUBLISH_PATH) @@ -43,8 +41,6 @@ class TrayPublisherHost(HostBase, IPublishHost): # TODO Deregister project specific plugins and register new project # plugins os.environ["AVALON_PROJECT"] = project_name - legacy_io.Session["AVALON_PROJECT"] = project_name - legacy_io.install() HostContext.set_project_name(project_name) diff --git a/client/ayon_core/hosts/tvpaint/api/pipeline.py b/client/ayon_core/hosts/tvpaint/api/pipeline.py index 1360b423b3..d636e68cfa 100644 --- a/client/ayon_core/hosts/tvpaint/api/pipeline.py +++ b/client/ayon_core/hosts/tvpaint/api/pipeline.py @@ -13,7 +13,6 @@ from ayon_core.hosts.tvpaint import TVPAINT_ROOT_DIR from ayon_core.settings import get_current_project_settings from ayon_core.lib import register_event_callback from ayon_core.pipeline import ( - legacy_io, register_loader_plugin_path, register_creator_plugin_path, AVALON_CONTAINER_ID, @@ -66,11 +65,10 @@ class TVPaintHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): def install(self): """Install TVPaint-specific functionality.""" - log.info("OpenPype - Installing TVPaint integration") - legacy_io.install() + log.info("AYON - Installing TVPaint integration") # Create workdir folder if does not exist yet - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") if not os.path.exists(workdir): os.makedirs(workdir) diff --git a/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py b/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py index 9fbf67863a..05ceb143e9 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py +++ b/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py @@ -4,7 +4,6 @@ import tempfile import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.hosts.tvpaint.api.lib import ( execute_george, execute_george_through_file, @@ -90,7 +89,6 @@ class CollectWorkfileData(pyblish.api.ContextPlugin): ("AVALON_TASK", "task_name") ) for env_key, key in key_map: - legacy_io.Session[env_key] = workfile_context[key] os.environ[env_key] = workfile_context[key] self.log.info("Context changed to: {}".format(workfile_context)) diff --git a/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py b/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py index a253a1ec5b..cd34ba9bb3 100644 --- a/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py +++ b/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py @@ -8,8 +8,6 @@ from pprint import pformat import pyblish.api -from ayon_core.pipeline import legacy_io - def collect(root, regex=None, @@ -132,7 +130,6 @@ class CollectSequencesFromJob(pyblish.api.ContextPlugin): session = metadata.get("session") if session: self.log.info("setting session using metadata") - legacy_io.Session.update(session) os.environ.update(session) else: diff --git a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py index 680795a329..abc8d7dccd 100644 --- a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py +++ b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py @@ -13,9 +13,6 @@ from ayon_core.modules.royalrender.rr_job import ( get_rr_platform ) from ayon_core.pipeline.publish import KnownPublishError -from ayon_core.pipeline import ( - legacy_io, -) from ayon_core.pipeline.farm.pyblish_functions import ( create_skeleton_instance, create_instances_for_aov, @@ -145,7 +142,6 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": attr.asdict(rr_job), - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 197b1eb6e6..64d8e1f6d6 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -29,11 +29,11 @@ from .publish.lib import filter_pyblish_plugins from .anatomy import Anatomy from .template_data import get_template_data_with_names from .workfile import ( + get_workdir, get_workfile_template_key, get_custom_workfile_template_by_string_context, ) from . import ( - legacy_io, register_loader_plugin_path, register_inventory_action_path, register_creator_plugin_path, @@ -116,22 +116,15 @@ def install_host(host): # Make sure global AYON connection has set site id and version get_ayon_server_api_connection() - legacy_io.install() addons_manager = _get_addons_manager() - missing = list() - for key in ("AVALON_PROJECT", "AVALON_ASSET"): - if key not in legacy_io.Session: - missing.append(key) + project_name = os.getenv("AVALON_PROJECT") + if not project_name: + raise ValueError( + "AVALON_PROJECT is missing in environment variables." + ) - assert not missing, ( - "%s missing from environment, %s" % ( - ", ".join(missing), - json.dumps(legacy_io.Session, indent=4, sort_keys=True) - )) - - project_name = legacy_io.Session["AVALON_PROJECT"] - log.info("Activating %s.." % project_name) + log.info("Activating {}..".format(project_name)) # Optional host install function if hasattr(host, "install"): @@ -158,7 +151,6 @@ def install_host(host): print("Registering pyblish target: automated") pyblish.api.register_target("automated") - project_name = os.environ.get("AVALON_PROJECT") host_name = os.environ.get("AVALON_APP") # Give option to handle host installation @@ -256,8 +248,6 @@ def uninstall_host(): deregister_host() - legacy_io.uninstall() - log.info("Successfully uninstalled Avalon!") @@ -482,13 +472,17 @@ def get_template_data_from_session(session=None, system_settings=None): Dict[str, Any]: All available data from session. """ - if session is None: - session = legacy_io.Session - - project_name = session["AVALON_PROJECT"] - asset_name = session["AVALON_ASSET"] - task_name = session["AVALON_TASK"] - host_name = session["AVALON_APP"] + if session is not None: + project_name = session["AVALON_PROJECT"] + asset_name = session["AVALON_ASSET"] + task_name = session["AVALON_TASK"] + host_name = session["AVALON_APP"] + else: + context = get_current_context() + project_name = context["project_name"] + asset_name = context["asset_name"] + task_name = context["task_name"] + host_name = get_current_host_name() return get_template_data_with_names( project_name, asset_name, task_name, host_name, system_settings @@ -529,10 +523,12 @@ def get_workdir_from_session(session=None, template_key=None): str: Workdir path. """ - if session is None: - session = legacy_io.Session - project_name = session["AVALON_PROJECT"] - host_name = session["AVALON_APP"] + if session is not None: + project_name = session["AVALON_PROJECT"] + host_name = session["AVALON_APP"] + else: + project_name = get_current_project_name() + host_name = get_current_host_name() template_data = get_template_data_from_session(session) if not template_key: @@ -556,86 +552,39 @@ def get_custom_workfile_template_from_session( ): """Filter and fill workfile template profiles by current context. - Current context is defined by `legacy_io.Session`. That's why this - function should be used only inside host where context is set and stable. + This function cab be used only inside host where context is set. Args: - session (Union[None, Dict[str, str]]): Session from which are taken + session (Optional[Dict[str, str]]): Session from which are taken data. - project_settings(Dict[str, Any]): Template profiles from settings. + project_settings(Optional[Dict[str, Any]]): Project settings. Returns: str: Path to template or None if none of profiles match current context. (Existence of formatted path is not validated.) """ - if session is None: - session = legacy_io.Session + if session is not None: + project_name = session["AVALON_PROJECT"] + asset_name = session["AVALON_ASSET"] + task_name = session["AVALON_TASK"] + host_name = session["AVALON_APP"] + else: + context = get_current_context() + project_name = context["project_name"] + asset_name = context["asset_name"] + task_name = context["task_name"] + host_name = get_current_host_name() return get_custom_workfile_template_by_string_context( - session["AVALON_PROJECT"], - session["AVALON_ASSET"], - session["AVALON_TASK"], - session["AVALON_APP"], + project_name, + asset_name, + task_name, + host_name, project_settings=project_settings ) -def compute_session_changes( - session, asset_doc, task_name, template_key=None -): - """Compute the changes for a session object on task under asset. - - Function does not change the session object, only returns changes. - - Args: - session (Dict[str, str]): The initial session to compute changes to. - This is required for computing the full Work Directory, as that - also depends on the values that haven't changed. - asset_doc (Dict[str, Any]): Asset document to switch to. - task_name (str): Name of task to switch to. - template_key (Union[str, None]): Prepare workfile template key in - anatomy templates. - - Returns: - Dict[str, str]: Changes in the Session dictionary. - """ - - # Get asset document and asset - if not asset_doc: - task_name = None - asset_name = None - else: - asset_name = get_asset_name_identifier(asset_doc) - - # Detect any changes compared session - mapping = { - "AVALON_ASSET": asset_name, - "AVALON_TASK": task_name, - } - changes = { - key: value - for key, value in mapping.items() - if value != session.get(key) - } - if not changes: - return changes - - # Compute work directory (with the temporary changed session so far) - changed_session = session.copy() - changed_session.update(changes) - - workdir = None - if asset_doc: - workdir = get_workdir_from_session( - changed_session, template_key - ) - - changes["AVALON_WORKDIR"] = workdir - - return changes - - def change_current_context(asset_doc, task_name, template_key=None): """Update active Session to a new task work area. @@ -651,32 +600,47 @@ def change_current_context(asset_doc, task_name, template_key=None): Dict[str, str]: The changed key, values in the current Session. """ - changes = compute_session_changes( - legacy_io.Session, - asset_doc, - task_name, - template_key=template_key - ) + project_name = get_current_project_name() + workdir = None + if asset_doc: + project_doc = get_project(project_name) + host_name = get_current_host_name() + workdir = get_workdir( + project_doc, + asset_doc, + task_name, + host_name, + template_key=template_key + ) + + folder_path = get_asset_name_identifier(asset_doc) + envs = { + "AVALON_PROJECT": project_name, + "AVALON_ASSET": folder_path, + "AVALON_TASK": task_name, + "AVALON_WORKDIR": workdir, + } # Update the Session and environments. Pop from environments all keys with # value set to None. - for key, value in changes.items(): - legacy_io.Session[key] = value + for key, value in envs.items(): if value is None: os.environ.pop(key, None) else: os.environ[key] = value - data = changes.copy() + data = envs.copy() + # Convert env keys to human readable keys - data["project_name"] = legacy_io.Session["AVALON_PROJECT"] - data["asset_name"] = legacy_io.Session["AVALON_ASSET"] - data["task_name"] = legacy_io.Session["AVALON_TASK"] + data["project_name"] = project_name + data["asset_name"] = get_asset_name_identifier(asset_doc) + data["task_name"] = task_name + data["workdir_path"] = workdir # Emit session change emit_event("taskChanged", data) - return changes + return data def get_process_id(): diff --git a/client/ayon_core/pipeline/create/context.py b/client/ayon_core/pipeline/create/context.py index 8990d50324..be685ea2cc 100644 --- a/client/ayon_core/pipeline/create/context.py +++ b/client/ayon_core/pipeline/create/context.py @@ -27,7 +27,7 @@ from ayon_core.lib.attribute_definitions import ( get_default_values, ) from ayon_core.host import IPublishHost, IWorkfileHost -from ayon_core.pipeline import legacy_io, Anatomy +from ayon_core.pipeline import Anatomy from ayon_core.pipeline.plugin_discover import DiscoverResult from .creator_plugins import ( @@ -1684,25 +1684,16 @@ class CreateContext: if isinstance(self.host, IWorkfileHost): workfile_path = self.host.get_current_workfile() - # --- TODO remove these conditions --- - if not project_name: - project_name = legacy_io.Session.get("AVALON_PROJECT") - if not asset_name: - asset_name = legacy_io.Session.get("AVALON_ASSET") - if not task_name: - task_name = legacy_io.Session.get("AVALON_TASK") - # --- return project_name, asset_name, task_name, workfile_path def reset_current_context(self): """Refresh current context. Reset is based on optional host implementation of `get_current_context` - function or using `legacy_io.Session`. + function. Some hosts have ability to change context file without using workfiles - tool but that change is not propagated to 'legacy_io.Session' - nor 'os.environ'. + tool but that change is not propagated to 'os.environ'. Todos: UI: Current context should be also checked on save - compare diff --git a/client/ayon_core/pipeline/create/subset_name.py b/client/ayon_core/pipeline/create/subset_name.py index 3892971ce8..2973b1e54e 100644 --- a/client/ayon_core/pipeline/create/subset_name.py +++ b/client/ayon_core/pipeline/create/subset_name.py @@ -2,7 +2,6 @@ import os from ayon_core.settings import get_project_settings from ayon_core.lib import filter_profiles, prepare_template_data -from ayon_core.pipeline import legacy_io from .constants import DEFAULT_SUBSET_TEMPLATE @@ -135,7 +134,7 @@ def get_subset_name( family = family.rsplit(".", 1)[-1] if project_name is None: - project_name = legacy_io.Session["AVALON_PROJECT"] + project_name = os.environ.get("AVALON_PROJECT") asset_tasks = asset_doc.get("data", {}).get("tasks") or {} task_info = asset_tasks.get(task_name) or {} diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index e13260d296..fc64edf2ae 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -2,10 +2,7 @@ import os import logging from ayon_core.settings import get_system_settings, get_project_settings -from ayon_core.pipeline import ( - schema, - legacy_io, -) +from ayon_core.pipeline import schema from ayon_core.pipeline.plugin_discover import ( discover, register_plugin, diff --git a/client/ayon_core/plugins/publish/collect_from_create_context.py b/client/ayon_core/plugins/publish/collect_from_create_context.py index d38138b2e9..d8e803a43c 100644 --- a/client/ayon_core/plugins/publish/collect_from_create_context.py +++ b/client/ayon_core/plugins/publish/collect_from_create_context.py @@ -5,7 +5,7 @@ import os import pyblish.api from ayon_core.host import IPublishHost -from ayon_core.pipeline import legacy_io, registered_host +from ayon_core.pipeline import registered_host from ayon_core.pipeline.create import CreateContext @@ -61,7 +61,6 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin): ("AVALON_ASSET", asset_name), ("AVALON_TASK", task_name) ): - legacy_io.Session[key] = value os.environ[key] = value def create_instance( diff --git a/client/ayon_core/tools/sceneinventory/control.py b/client/ayon_core/tools/sceneinventory/control.py index 409f92b506..54e4e9941e 100644 --- a/client/ayon_core/tools/sceneinventory/control.py +++ b/client/ayon_core/tools/sceneinventory/control.py @@ -14,8 +14,7 @@ from .models import SiteSyncModel class SceneInventoryController: """This is a temporary controller for AYON. - Goal of this temporary controller is to provide a way to get current - context instead of using 'AvalonMongoDB' object (or 'legacy_io'). + Goal of this controller is to provide a way to get current context. Also provides (hopefully) cleaner api for site sync. """ diff --git a/client/ayon_core/tools/texture_copy/app.py b/client/ayon_core/tools/texture_copy/app.py index 064f4e5577..9b4406d8e7 100644 --- a/client/ayon_core/tools/texture_copy/app.py +++ b/client/ayon_core/tools/texture_copy/app.py @@ -6,7 +6,7 @@ import speedcopy from ayon_core.client import get_project, get_asset_by_name from ayon_core.lib import Terminal -from ayon_core.pipeline import legacy_io, Anatomy +from ayon_core.pipeline import Anatomy t = Terminal() @@ -16,11 +16,6 @@ texture_extensions = ['.tif', '.tiff', '.jpg', '.jpeg', '.tx', '.png', '.tga', class TextureCopy: - - def __init__(self): - if not legacy_io.Session: - legacy_io.install() - def _get_textures(self, path): textures = [] for dir, subdir, files in os.walk(path): diff --git a/client/ayon_core/tools/workfile_template_build/window.py b/client/ayon_core/tools/workfile_template_build/window.py index 7f95bac60a..ae4946d41d 100644 --- a/client/ayon_core/tools/workfile_template_build/window.py +++ b/client/ayon_core/tools/workfile_template_build/window.py @@ -1,8 +1,9 @@ +import os + from qtpy import QtWidgets from ayon_core import style from ayon_core.lib import Logger -from ayon_core.pipeline import legacy_io from ayon_core.tools.attribute_defs import AttributeDefinitionsWidget @@ -26,7 +27,7 @@ class WorkfileBuildPlaceholderDialog(QtWidgets.QDialog): host_name = getattr(self._host, "name", None) if not host_name: - host_name = legacy_io.Session.get("AVALON_APP") or "NA" + host_name = os.getenv("AVALON_APP") or "NA" self._host_name = host_name plugins_combo = QtWidgets.QComboBox(self) From e40cc563004524b7c576f17c6e83d279f9f17e28 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 14:51:15 +0100 Subject: [PATCH 03/29] don't use legacy_io in farm deadline --- .../publish/submit_aftereffects_deadline.py | 9 ++++-- .../publish/submit_blender_deadline.py | 9 ++++-- .../plugins/publish/submit_fusion_deadline.py | 9 ++++-- .../publish/submit_harmony_deadline.py | 9 ++++-- .../publish/submit_houdini_cache_deadline.py | 9 ++++-- .../publish/submit_houdini_render_deadline.py | 10 +++++-- .../plugins/publish/submit_max_deadline.py | 9 ++++-- .../plugins/publish/submit_maya_deadline.py | 9 ++++-- .../submit_maya_remote_publish_deadline.py | 10 ++++--- .../plugins/publish/submit_nuke_deadline.py | 8 ++++-- .../publish/submit_publish_cache_job.py | 5 ++-- .../plugins/publish/submit_publish_job.py | 5 ++-- .../plugins/publish/collect_rendered_files.py | 28 +++++++++++-------- 13 files changed, 80 insertions(+), 49 deletions(-) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py index f7bc5529fb..618b71bbaf 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py @@ -8,7 +8,6 @@ from ayon_core.lib import ( env_value_to_bool, collect_frames, ) -from ayon_core.pipeline import legacy_io from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo from ayon_core.tests.lib import is_in_tests @@ -84,13 +83,17 @@ class AfterEffectsSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) if value: diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py index c8b72ca52b..af864ace5b 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py @@ -11,7 +11,6 @@ from ayon_core.lib import ( NumberDef, TextDef, ) -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import AYONPyblishPluginMixin from ayon_core.pipeline.farm.tools import iter_expected_files from ayon_core.tests.lib import is_in_tests @@ -106,12 +105,16 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py index 77505eb623..7aa8546bb6 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py @@ -6,7 +6,6 @@ import requests import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( AYONPyblishPluginMixin ) @@ -224,14 +223,18 @@ class FusionSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", "IS_TEST", "AYON_BUNDLE_NAME", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } # to recognize render jobs environment["AYON_RENDER_JOB"] = "1" diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py index f2f1c90559..4d375299fa 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py @@ -10,7 +10,6 @@ from datetime import datetime import attr import pyblish.api -from ayon_core.pipeline import legacy_io from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo from ayon_core.tests.lib import is_in_tests @@ -277,13 +276,17 @@ class HarmonySubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS" "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) if value: diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py index eed930e372..96ee80c4d7 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py @@ -9,7 +9,6 @@ from ayon_core.lib import ( NumberDef, ) from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.tests.lib import is_in_tests @@ -102,12 +101,16 @@ class HoudiniCacheSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py index 9988248957..d7a062c9a6 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py @@ -5,7 +5,7 @@ from datetime import datetime import pyblish.api -from ayon_core.pipeline import legacy_io, AYONPyblishPluginMixin +from ayon_core.pipeline import AYONPyblishPluginMixin from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo @@ -207,12 +207,16 @@ class HoudiniSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py index 0a7c96008e..8908283164 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py @@ -9,7 +9,6 @@ from ayon_core.lib import ( NumberDef, ) from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.pipeline.publish.lib import ( @@ -110,12 +109,16 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py index 84e6e93e6a..2b7a7cf698 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -29,7 +29,6 @@ from collections import OrderedDict import attr from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.lib import ( @@ -203,12 +202,16 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 02338c5c32..ed360d84ae 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -2,7 +2,7 @@ import os import attr from datetime import datetime -from ayon_core.pipeline import legacy_io, PublishXmlValidationError +from ayon_core.pipeline import PublishXmlValidationError from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo @@ -98,10 +98,12 @@ class MayaSubmitRemotePublishDeadline( "FTRACK_SERVER" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } - # TODO replace legacy_io with context.data environment["AVALON_PROJECT"] = project_name environment["AVALON_ASSET"] = instance.context.data["asset"] environment["AVALON_TASK"] = instance.context.data["task"] diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py index 9fff8edee6..61a334e184 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -7,7 +7,6 @@ from datetime import datetime import requests import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( AYONPyblishPluginMixin ) @@ -393,8 +392,11 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, if self.env_allowed_keys: keys += self.env_allowed_keys - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } # to recognize render jobs environment["AYON_RENDER_JOB"] = "1" diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py index a90397baa2..38ea31ab7b 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py @@ -11,8 +11,8 @@ import pyblish.api from ayon_core.client import ( get_last_version_by_subset_name, ) -from ayon_core.pipeline import publish, legacy_io -from ayon_core.lib import EnumDef, is_running_from_build +from ayon_core.pipeline import publish +from ayon_core.lib import EnumDef from ayon_core.tests.lib import is_in_tests from ayon_core.pipeline.version_start import get_versioning_start @@ -370,7 +370,6 @@ class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": render_job or None, - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py index bd343e103a..c4ab6a2932 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py @@ -12,8 +12,8 @@ import pyblish.api from ayon_core.client import ( get_last_version_by_subset_name, ) -from ayon_core.pipeline import publish, legacy_io -from ayon_core.lib import EnumDef, is_running_from_build +from ayon_core.pipeline import publish +from ayon_core.lib import EnumDef from ayon_core.tests.lib import is_in_tests from ayon_core.pipeline.version_start import get_versioning_start @@ -604,7 +604,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": render_job or None, - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 5ffcd669a0..714d790269 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -12,7 +12,7 @@ import json import pyblish.api -from ayon_core.pipeline import legacy_io, KnownPublishError +from ayon_core.pipeline import KnownPublishError from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup @@ -165,24 +165,28 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): path = anatomy.fill_root(path) data = self._load_json(path) assert data, "failed to load json file" - if not session_is_set: - session_data = data["session"] - remapped = anatomy.roots_obj.path_remapper( - session_data["AVALON_WORKDIR"] - ) - if remapped: - session_data["AVALON_WORKDIR"] = remapped - - self.log.debug("Setting session using data from file") - legacy_io.Session.update(session_data) - os.environ.update(session_data) + session_data = data.get("session") + if not session_is_set and session_data: session_is_set = True + self.log.debug("Setting session using data from file") + os.environ.update(session_data) + staging_dir_persistent = self._process_path(data, anatomy) if not staging_dir_persistent: context.data["cleanupFullPaths"].append(path) context.data["cleanupEmptyDirs"].append( os.path.dirname(path) ) + + # Remap workdir if it's set + workdir = os.getenv("AVALON_WORKDIR") + remapped_workdir = None + if workdir: + remapped_workdir = anatomy.roots_obj.path_remapper( + os.getenv("AVALON_WORKDIR") + ) + if remapped_workdir: + os.environ["AVALON_WORKDIR"] = remapped_workdir except Exception as e: self.log.error(e, exc_info=True) raise Exception("Error") from e From acaefb0a71f84186825432bfb3a150cbf3a37e0c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 18:28:25 +0100 Subject: [PATCH 04/29] AssetsWidget does not expect 'dbcon' --- client/ayon_core/hosts/houdini/api/usd.py | 5 +- .../tools/publisher/widgets/assets_widget.py | 9 ++- .../tools/publisher/widgets/create_widget.py | 2 +- client/ayon_core/tools/utils/assets_widget.py | 65 +++++++++---------- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/client/ayon_core/hosts/houdini/api/usd.py b/client/ayon_core/hosts/houdini/api/usd.py index e900bc5fac..e9c02a0307 100644 --- a/client/ayon_core/hosts/houdini/api/usd.py +++ b/client/ayon_core/hosts/houdini/api/usd.py @@ -7,7 +7,7 @@ from qtpy import QtWidgets, QtCore, QtGui from ayon_core import style from ayon_core.client import get_asset_by_name -from ayon_core.pipeline import legacy_io, get_current_project_name +from ayon_core.pipeline import get_current_project_name from ayon_core.tools.utils.assets_widget import SingleSelectAssetsWidget from pxr import Sdf @@ -27,7 +27,8 @@ class SelectAssetDialog(QtWidgets.QWidget): self.setWindowTitle("Pick Asset") self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup) - assets_widget = SingleSelectAssetsWidget(legacy_io, parent=self) + assets_widget = SingleSelectAssetsWidget(self) + assets_widget.set_project_name(get_current_project_name(), False) layout = QtWidgets.QHBoxLayout(self) layout.addWidget(assets_widget) diff --git a/client/ayon_core/tools/publisher/widgets/assets_widget.py b/client/ayon_core/tools/publisher/widgets/assets_widget.py index 8a72c03e8b..faad37104d 100644 --- a/client/ayon_core/tools/publisher/widgets/assets_widget.py +++ b/client/ayon_core/tools/publisher/widgets/assets_widget.py @@ -21,7 +21,7 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): def __init__(self, controller, parent): self._controller = controller - super(CreateWidgetAssetsWidget, self).__init__(None, parent) + super(CreateWidgetAssetsWidget, self).__init__(parent) self.set_refresh_btn_visibility(False) self.set_current_asset_btn_visibility(False) @@ -31,6 +31,9 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): self._last_filter_height = None + def get_project_name(self): + return self._controller.project_name + def get_selected_asset_name(self): selection_model = self._view.selectionModel() indexes = selection_model.selectedRows() @@ -79,10 +82,10 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): def update_current_asset(self): # Hide set current asset if there is no one - asset_name = self._get_current_session_asset() + asset_name = self._get_current_asset_name() self.set_current_asset_btn_visibility(bool(asset_name)) - def _get_current_session_asset(self): + def _get_current_asset_name(self): return self._controller.current_asset_name def _create_source_model(self): diff --git a/client/ayon_core/tools/publisher/widgets/create_widget.py b/client/ayon_core/tools/publisher/widgets/create_widget.py index 12135c6891..8eae205882 100644 --- a/client/ayon_core/tools/publisher/widgets/create_widget.py +++ b/client/ayon_core/tools/publisher/widgets/create_widget.py @@ -565,7 +565,7 @@ class CreateWidget(QtWidgets.QWidget): self._last_thumbnail_path = None def _on_current_session_context_request(self): - self._assets_widget.set_current_session_asset() + self._assets_widget.select_current_asset() task_name = self.current_task_name if task_name: self._tasks_widget.select_task_name(task_name) diff --git a/client/ayon_core/tools/utils/assets_widget.py b/client/ayon_core/tools/utils/assets_widget.py index c05f3de850..7bacf3291d 100644 --- a/client/ayon_core/tools/utils/assets_widget.py +++ b/client/ayon_core/tools/utils/assets_widget.py @@ -111,7 +111,6 @@ class _AssetModel(QtGui.QStandardItemModel): 'refreshed' signal. Args: - dbcon (AvalonMongoDB): Ready to use connection to mongo with. parent (QObject): Parent Qt object. """ @@ -128,9 +127,8 @@ class _AssetModel(QtGui.QStandardItemModel): "data.color": 1 } - def __init__(self, dbcon, parent=None): + def __init__(self, parent=None): super(_AssetModel, self).__init__(parent=parent) - self.dbcon = dbcon self._refreshing = False self._doc_fetching_thread = None @@ -142,6 +140,7 @@ class _AssetModel(QtGui.QStandardItemModel): self._item_ids_with_color = set() self._items_by_asset_id = {} + self._project_name = None self._last_project_name = None @property @@ -185,6 +184,16 @@ class _AssetModel(QtGui.QStandardItemModel): return self.get_indexes_by_asset_ids(asset_ids) + def get_project_name(self): + return self._project_name + + def set_project_name(self, project_name, refresh): + if self._project_name == project_name: + return + self._project_name = project_name + if refresh: + self.refresh() + def refresh(self, force=False): """Refresh the data for the model. @@ -197,7 +206,7 @@ class _AssetModel(QtGui.QStandardItemModel): return self.stop_refresh() - project_name = self.dbcon.Session.get("AVALON_PROJECT") + project_name = self._project_name clear_model = False if project_name != self._last_project_name: clear_model = True @@ -216,23 +225,6 @@ class _AssetModel(QtGui.QStandardItemModel): def stop_refresh(self): self._stop_fetch_thread() - def clear_underlines(self): - for asset_id in set(self._item_ids_with_color): - self._item_ids_with_color.remove(asset_id) - item = self._items_by_asset_id.get(asset_id) - if item is not None: - item.setData(None, ASSET_UNDERLINE_COLORS_ROLE) - - def set_underline_colors(self, colors_by_asset_id): - self.clear_underlines() - - for asset_id, colors in colors_by_asset_id.items(): - item = self._items_by_asset_id.get(asset_id) - if item is None: - continue - item.setData(colors, ASSET_UNDERLINE_COLORS_ROLE) - self._item_ids_with_color.add(asset_id) - def _clear_items(self): root_item = self.invisibleRootItem() root_item.removeRows(0, root_item.rowCount()) @@ -357,7 +349,7 @@ class _AssetModel(QtGui.QStandardItemModel): self._doc_fetched.emit() def _fetch_asset_docs(self): - project_name = self.dbcon.current_project() + project_name = self.get_project_name() if not project_name: return [] @@ -392,7 +384,6 @@ class _AssetsWidget(QtWidgets.QWidget): inheritance changes. Args: - dbcon (AvalonMongoDB): Connection to avalon mongo db. parent (QWidget): Parent Qt widget. """ @@ -404,11 +395,9 @@ class _AssetsWidget(QtWidgets.QWidget): # It was double clicked on view double_clicked = QtCore.Signal() - def __init__(self, dbcon, parent=None): + def __init__(self, parent=None): super(_AssetsWidget, self).__init__(parent=parent) - self.dbcon = dbcon - # Tree View model = self._create_source_model() proxy = self._create_proxy_model(model) @@ -477,18 +466,28 @@ class _AssetsWidget(QtWidgets.QWidget): self._model = model self._proxy = proxy self._view = view - self._last_project_name = None self._last_btns_height = None + self._current_asset_name = None + self.model_selection = {} @property def header_widget(self): return self._header_widget + def get_project_name(self): + self._model.get_project_name() + + def set_project_name(self, project_name, refresh=True): + self._model.set_project_name(project_name, refresh) + + def set_current_asset_name(self, asset_name): + self._current_asset_name = asset_name + def _create_source_model(self): - model = _AssetModel(dbcon=self.dbcon, parent=self) + model = _AssetModel(parent=self) model.refreshed.connect(self._on_model_refresh) return model @@ -509,8 +508,8 @@ class _AssetsWidget(QtWidgets.QWidget): def stop_refresh(self): self._model.stop_refresh() - def _get_current_session_asset(self): - return self.dbcon.Session.get("AVALON_ASSET") + def _get_current_asset_name(self): + return self._current_asset_name def _on_current_asset_click(self): """Trigger change of asset to current context asset. @@ -518,10 +517,10 @@ class _AssetsWidget(QtWidgets.QWidget): in differnt way. """ - self.set_current_session_asset() + self.select_current_asset() - def set_current_session_asset(self): - asset_name = self._get_current_session_asset() + def select_current_asset(self): + asset_name = self._get_current_asset_name() if asset_name: self.select_asset_by_name(asset_name) From a6a04bb443c0a9b047de57798c8839dc88f322e6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 18:55:58 +0100 Subject: [PATCH 05/29] moved TasksWidget to publisher --- .../tools/publisher/widgets/tasks_widget.py | 171 +++++++++- client/ayon_core/tools/utils/tasks_widget.py | 303 ------------------ 2 files changed, 157 insertions(+), 317 deletions(-) delete mode 100644 client/ayon_core/tools/utils/tasks_widget.py diff --git a/client/ayon_core/tools/publisher/widgets/tasks_widget.py b/client/ayon_core/tools/publisher/widgets/tasks_widget.py index 44e290408a..9a1b22b9a5 100644 --- a/client/ayon_core/tools/publisher/widgets/tasks_widget.py +++ b/client/ayon_core/tools/publisher/widgets/tasks_widget.py @@ -1,8 +1,12 @@ -from qtpy import QtCore, QtGui +from qtpy import QtWidgets, QtCore, QtGui -from ayon_core.tools.utils.tasks_widget import TasksWidget, TASK_NAME_ROLE +from ayon_core.tools.utils.views import DeselectableTreeView from ayon_core.tools.utils.lib import get_default_task_icon +TASK_NAME_ROLE = QtCore.Qt.UserRole + 1 +TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2 +TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3 + class TasksModel(QtGui.QStandardItemModel): """Tasks model. @@ -141,15 +145,159 @@ class TasksModel(QtGui.QStandardItemModel): return super(TasksModel, self).headerData(section, orientation, role) -class CreateWidgetTasksWidget(TasksWidget): +class TasksProxyModel(QtCore.QSortFilterProxyModel): + def lessThan(self, x_index, y_index): + x_order = x_index.data(TASK_ORDER_ROLE) + y_order = y_index.data(TASK_ORDER_ROLE) + if x_order is not None and y_order is not None: + if x_order < y_order: + return True + if x_order > y_order: + return False + + elif x_order is None and y_order is not None: + return True + + elif y_order is None and x_order is not None: + return False + + x_name = x_index.data(QtCore.Qt.DisplayRole) + y_name = y_index.data(QtCore.Qt.DisplayRole) + if x_name == y_name: + return True + + if x_name == tuple(sorted((x_name, y_name)))[0]: + return True + return False + + +class CreateWidgetTasksWidget(QtWidgets.QWidget): + """Widget showing active Tasks + + Deprecated: + This widget will be removed soon. Please do not use it in new code. + """ + + task_changed = QtCore.Signal() + def __init__(self, controller, parent): self._controller = controller - super(CreateWidgetTasksWidget, self).__init__(None, parent) self._enabled = None - def _create_source_model(self): - return TasksModel(self._controller) + super(CreateWidgetTasksWidget, self).__init__(parent) + + tasks_view = DeselectableTreeView(self) + tasks_view.setIndentation(0) + tasks_view.setSortingEnabled(True) + tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + + header_view = tasks_view.header() + header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder) + + tasks_model = TasksModel(self._controller) + tasks_proxy = TasksProxyModel() + tasks_proxy.setSourceModel(tasks_model) + tasks_view.setModel(tasks_proxy) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(tasks_view) + + selection_model = tasks_view.selectionModel() + selection_model.selectionChanged.connect(self._on_task_change) + + self._tasks_model = tasks_model + self._tasks_proxy = tasks_proxy + self._tasks_view = tasks_view + + self._last_selected_task_name = None + + def refresh(self): + self._tasks_model.refresh() + + def set_asset_id(self, asset_id): + # Try and preserve the last selected task and reselect it + # after switching assets. If there's no currently selected + # asset keep whatever the "last selected" was prior to it. + current = self.get_selected_task_name() + if current: + self._last_selected_task_name = current + + self._tasks_model.set_asset_id(asset_id) + + if self._last_selected_task_name: + self.select_task_name(self._last_selected_task_name) + + # Force a task changed emit. + self.task_changed.emit() + + def _clear_selection(self): + selection_model = self._tasks_view.selectionModel() + selection_model.clearSelection() + + def select_task_name(self, task_name): + """Select a task by name. + + If the task does not exist in the current model then selection is only + cleared. + + Args: + task_name (str): Name of the task to select. + + """ + task_view_model = self._tasks_view.model() + if not task_view_model: + return + + # Clear selection + selection_model = self._tasks_view.selectionModel() + selection_model.clearSelection() + + # Select the task + mode = ( + QtCore.QItemSelectionModel.Select + | QtCore.QItemSelectionModel.Rows + ) + for row in range(task_view_model.rowCount()): + index = task_view_model.index(row, 0) + name = index.data(TASK_NAME_ROLE) + if name == task_name: + selection_model.select(index, mode) + + # Set the currently active index + self._tasks_view.setCurrentIndex(index) + break + + last_selected_task_name = self.get_selected_task_name() + if last_selected_task_name: + self._last_selected_task_name = last_selected_task_name + + if not self._enabled: + current = self.get_selected_task_name() + if current: + self._last_selected_task_name = current + self._clear_selection() + + def get_selected_task_name(self): + """Return name of task at current index (selected) + + Returns: + str: Name of the current task. + + """ + index = self._tasks_view.currentIndex() + selection_model = self._tasks_view.selectionModel() + if index.isValid() and selection_model.isSelected(index): + return index.data(TASK_NAME_ROLE) + return None + + def get_selected_task_type(self): + index = self._tasks_view.currentIndex() + selection_model = self._tasks_view.selectionModel() + if index.isValid() and selection_model.isSelected(index): + return index.data(TASK_TYPE_ROLE) + return None def set_asset_name(self, asset_name): current = self.get_selected_task_name() @@ -163,14 +311,6 @@ class CreateWidgetTasksWidget(TasksWidget): # Force a task changed emit. self.task_changed.emit() - def select_task_name(self, task_name): - super(CreateWidgetTasksWidget, self).select_task_name(task_name) - if not self._enabled: - current = self.get_selected_task_name() - if current: - self._last_selected_task_name = current - self._clear_selection() - def set_enabled(self, enabled): self._enabled = enabled if not enabled: @@ -181,3 +321,6 @@ class CreateWidgetTasksWidget(TasksWidget): elif self._last_selected_task_name is not None: self.select_task_name(self._last_selected_task_name) + + def _on_task_change(self): + self.task_changed.emit() diff --git a/client/ayon_core/tools/utils/tasks_widget.py b/client/ayon_core/tools/utils/tasks_widget.py deleted file mode 100644 index 12e074f910..0000000000 --- a/client/ayon_core/tools/utils/tasks_widget.py +++ /dev/null @@ -1,303 +0,0 @@ -from qtpy import QtWidgets, QtCore, QtGui -import qtawesome - -from ayon_core.client import ( - get_project, - get_asset_by_id, -) -from ayon_core.style import get_disabled_entity_icon_color -from ayon_core.tools.utils.lib import get_task_icon - -from .views import DeselectableTreeView - - -TASK_NAME_ROLE = QtCore.Qt.UserRole + 1 -TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2 -TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3 -TASK_ASSIGNEE_ROLE = QtCore.Qt.UserRole + 4 - - -class _TasksModel(QtGui.QStandardItemModel): - """A model listing the tasks combined for a list of assets""" - - def __init__(self, dbcon, parent=None): - super(_TasksModel, self).__init__(parent=parent) - self.dbcon = dbcon - self.setHeaderData( - 0, QtCore.Qt.Horizontal, "Tasks", QtCore.Qt.DisplayRole - ) - - self._no_tasks_icon = qtawesome.icon( - "fa.exclamation-circle", - color=get_disabled_entity_icon_color() - ) - self._cached_icons = {} - self._project_doc = {} - - self._empty_tasks_item = None - self._last_asset_id = None - self._loaded_project_name = None - - def _context_is_valid(self): - if self._get_current_project(): - return True - return False - - def refresh(self): - self._refresh_project_doc() - self.set_asset_id(self._last_asset_id) - - def _refresh_project_doc(self): - # Get the project configured icons from database - project_doc = {} - if self._context_is_valid(): - project_name = self.dbcon.active_project() - project_doc = get_project(project_name) - - self._loaded_project_name = self._get_current_project() - self._project_doc = project_doc - - def headerData(self, section, orientation, role=None): - if role is None: - role = QtCore.Qt.EditRole - # Show nice labels in the header - if section == 0: - if ( - role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole) - and orientation == QtCore.Qt.Horizontal - ): - return "Tasks" - - return super(_TasksModel, self).headerData(section, orientation, role) - - def _get_current_project(self): - return self.dbcon.Session.get("AVALON_PROJECT") - - def set_asset_id(self, asset_id): - asset_doc = None - if asset_id and self._context_is_valid(): - project_name = self._get_current_project() - asset_doc = get_asset_by_id( - project_name, asset_id, fields=["data.tasks"] - ) - self._set_asset(asset_doc) - - def _get_empty_task_item(self): - if self._empty_tasks_item is None: - item = QtGui.QStandardItem("No task") - item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.NoItemFlags) - self._empty_tasks_item = item - return self._empty_tasks_item - - def _set_asset(self, asset_doc): - """Set assets to track by their database id - - Arguments: - asset_doc (dict): Asset document from MongoDB. - """ - if self._loaded_project_name != self._get_current_project(): - self._refresh_project_doc() - - asset_tasks = {} - self._last_asset_id = None - if asset_doc: - asset_tasks = asset_doc.get("data", {}).get("tasks") or {} - self._last_asset_id = asset_doc["_id"] - - root_item = self.invisibleRootItem() - root_item.removeRows(0, root_item.rowCount()) - - items = [] - - for task_name, task_info in asset_tasks.items(): - task_type = task_info.get("type") - task_order = task_info.get("order") - icon = get_task_icon(self._project_doc, asset_doc, task_name) - - task_assignees = set() - assignees_data = task_info.get("assignees") or [] - for assignee in assignees_data: - username = assignee.get("username") - if username: - task_assignees.add(username) - - label = "{} ({})".format(task_name, task_type or "type N/A") - item = QtGui.QStandardItem(label) - item.setData(task_name, TASK_NAME_ROLE) - item.setData(task_type, TASK_TYPE_ROLE) - item.setData(task_order, TASK_ORDER_ROLE) - item.setData(task_assignees, TASK_ASSIGNEE_ROLE) - item.setData(icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - items.append(item) - - if not items: - item = QtGui.QStandardItem("No task") - item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.NoItemFlags) - items.append(item) - - root_item.appendRows(items) - - -class _TasksProxyModel(QtCore.QSortFilterProxyModel): - def lessThan(self, x_index, y_index): - x_order = x_index.data(TASK_ORDER_ROLE) - y_order = y_index.data(TASK_ORDER_ROLE) - if x_order is not None and y_order is not None: - if x_order < y_order: - return True - if x_order > y_order: - return False - - elif x_order is None and y_order is not None: - return True - - elif y_order is None and x_order is not None: - return False - - x_name = x_index.data(QtCore.Qt.DisplayRole) - y_name = y_index.data(QtCore.Qt.DisplayRole) - if x_name == y_name: - return True - - if x_name == tuple(sorted((x_name, y_name)))[0]: - return True - return False - - -class TasksWidget(QtWidgets.QWidget): - """Widget showing active Tasks - - Deprecated: - This widget will be removed soon. Please do not use it in new code. - """ - - task_changed = QtCore.Signal() - - def __init__(self, dbcon, parent=None): - self._dbcon = dbcon - - super(TasksWidget, self).__init__(parent) - - tasks_view = DeselectableTreeView(self) - tasks_view.setIndentation(0) - tasks_view.setSortingEnabled(True) - tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - - header_view = tasks_view.header() - header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder) - - tasks_model = self._create_source_model() - tasks_proxy = self._create_proxy_model(tasks_model) - tasks_view.setModel(tasks_proxy) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(tasks_view) - - selection_model = tasks_view.selectionModel() - selection_model.selectionChanged.connect(self._on_task_change) - - self._tasks_model = tasks_model - self._tasks_proxy = tasks_proxy - self._tasks_view = tasks_view - - self._last_selected_task_name = None - - def _create_source_model(self): - """Create source model of tasks widget. - - Model must have available 'refresh' method and 'set_asset_id' to change - context of asset. - """ - return _TasksModel(self._dbcon) - - def _create_proxy_model(self, source_model): - proxy = _TasksProxyModel() - proxy.setSourceModel(source_model) - return proxy - - def refresh(self): - self._tasks_model.refresh() - - def set_asset_id(self, asset_id): - # Try and preserve the last selected task and reselect it - # after switching assets. If there's no currently selected - # asset keep whatever the "last selected" was prior to it. - current = self.get_selected_task_name() - if current: - self._last_selected_task_name = current - - self._tasks_model.set_asset_id(asset_id) - - if self._last_selected_task_name: - self.select_task_name(self._last_selected_task_name) - - # Force a task changed emit. - self.task_changed.emit() - - def _clear_selection(self): - selection_model = self._tasks_view.selectionModel() - selection_model.clearSelection() - - def select_task_name(self, task_name): - """Select a task by name. - - If the task does not exist in the current model then selection is only - cleared. - - Args: - task (str): Name of the task to select. - - """ - task_view_model = self._tasks_view.model() - if not task_view_model: - return - - # Clear selection - selection_model = self._tasks_view.selectionModel() - selection_model.clearSelection() - - # Select the task - mode = ( - QtCore.QItemSelectionModel.Select - | QtCore.QItemSelectionModel.Rows - ) - for row in range(task_view_model.rowCount()): - index = task_view_model.index(row, 0) - name = index.data(TASK_NAME_ROLE) - if name == task_name: - selection_model.select(index, mode) - - # Set the currently active index - self._tasks_view.setCurrentIndex(index) - break - - last_selected_task_name = self.get_selected_task_name() - if last_selected_task_name: - self._last_selected_task_name = last_selected_task_name - - def get_selected_task_name(self): - """Return name of task at current index (selected) - - Returns: - str: Name of the current task. - - """ - index = self._tasks_view.currentIndex() - selection_model = self._tasks_view.selectionModel() - if index.isValid() and selection_model.isSelected(index): - return index.data(TASK_NAME_ROLE) - return None - - def get_selected_task_type(self): - index = self._tasks_view.currentIndex() - selection_model = self._tasks_view.selectionModel() - if index.isValid() and selection_model.isSelected(index): - return index.data(TASK_TYPE_ROLE) - return None - - def _on_task_change(self): - self.task_changed.emit() From 2e63f282c1b624897857421986e091673018137a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:25 +0100 Subject: [PATCH 06/29] disable validation of AVALON_PROJECT environment variable --- client/ayon_core/pipeline/context_tools.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 64d8e1f6d6..fdf4c85660 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -119,10 +119,12 @@ def install_host(host): addons_manager = _get_addons_manager() project_name = os.getenv("AVALON_PROJECT") - if not project_name: - raise ValueError( - "AVALON_PROJECT is missing in environment variables." - ) + # WARNING: This might be an issue + # - commented out because 'traypublisher' does not have set project + # if not project_name: + # raise ValueError( + # "AVALON_PROJECT is missing in environment variables." + # ) log.info("Activating {}..".format(project_name)) From 4c3f6a5645c68fc091289067e6b66d6f12c164f9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:47 +0100 Subject: [PATCH 07/29] use correct function --- client/ayon_core/pipeline/context_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index fdf4c85660..6986a062d7 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -159,7 +159,7 @@ def install_host(host): for addon in addons_manager.get_enabled_addons(): addon.on_host_install(host, host_name, project_name) - install_openpype_plugins(project_name, host_name) + install_ayon_plugins(project_name, host_name) def install_ayon_plugins(project_name=None, host_name=None): From e02883dcd41eddc73027aadaa1927c67617efc6c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:54 +0100 Subject: [PATCH 08/29] removed unused import --- client/ayon_core/pipeline/context_tools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 6986a062d7..339ef9187f 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -1,7 +1,6 @@ """Core pipeline functionality""" import os -import json import types import logging import platform From eedf7368670efb2a9cee3f0fbc9841ee0b144393 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:10:49 +0100 Subject: [PATCH 09/29] removed content of legacy_io --- client/ayon_core/pipeline/legacy_io.py | 97 ++++---------------------- 1 file changed, 12 insertions(+), 85 deletions(-) diff --git a/client/ayon_core/pipeline/legacy_io.py b/client/ayon_core/pipeline/legacy_io.py index cd09da2917..d5b555845b 100644 --- a/client/ayon_core/pipeline/legacy_io.py +++ b/client/ayon_core/pipeline/legacy_io.py @@ -1,109 +1,36 @@ -"""Wrapper around interactions with the database""" - -import os -import sys import logging -import functools - -from . import schema - -module = sys.modules[__name__] +from ayon_core.pipeline import get_current_project_name Session = {} -_is_installed = False log = logging.getLogger(__name__) - -SESSION_CONTEXT_KEYS = ( - # Name of current Project - "AVALON_PROJECT", - # Name of current Asset - "AVALON_ASSET", - # Name of current task - "AVALON_TASK", - # Name of current app - "AVALON_APP", - # Path to working directory - "AVALON_WORKDIR", - # Optional path to scenes directory (see Work Files API) - "AVALON_SCENEDIR" +log.warning( + "DEPRECATION WARNING: 'legacy_io' is deprecated and will be removed in" + " future versions of ayon-core addon." + "\nReading from Session won't give you updated information and changing" + " values won't affect global state of a process." ) def session_data_from_environment(context_keys=False): - session_data = {} - if context_keys: - for key in SESSION_CONTEXT_KEYS: - value = os.environ.get(key) - session_data[key] = value or "" - else: - for key in SESSION_CONTEXT_KEYS: - session_data[key] = None - - for key, default_value in ( - # Name of Avalon in graphical user interfaces - # Use this to customise the visual appearance of Avalon - # to better integrate with your surrounding pipeline - ("AVALON_LABEL", "Avalon"), - - # Used during any connections to the outside world - ("AVALON_TIMEOUT", "1000"), - - # Name of database used in MongoDB - ("AVALON_DB", "avalon"), - ): - value = os.environ.get(key) or default_value - if value is not None: - session_data[key] = value - - return session_data + return {} def is_installed(): - return module._is_installed + return False def install(): - """Establish a persistent connection to the database""" - if is_installed(): - return - - session = session_data_from_environment(context_keys=True) - - session["schema"] = "openpype:session-4.0" - try: - schema.validate(session) - except schema.ValidationError as e: - # TODO(marcus): Make this mandatory - log.warning(e) - - Session.update(session) - - module._is_installed = True + pass def uninstall(): - """Close any connection to the database. - - Deprecated: - This function does nothing should be removed. - """ - module._is_installed = False + pass -def requires_install(func): - @functools.wraps(func) - def decorated(*args, **kwargs): - if not is_installed(): - install() - return func(*args, **kwargs) - return decorated - - -@requires_install def active_project(*args, **kwargs): - return Session["AVALON_PROJECT"] + return get_current_project_name() def current_project(*args, **kwargs): - return Session.get("AVALON_PROJECT") + return get_current_project_name() From 509f2b677e65750fea65ecf8f87df9d06685fe18 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 9 Feb 2024 11:50:35 +0800 Subject: [PATCH 10/29] ported OP PR #6200 to ayon_core --- client/ayon_core/hosts/max/api/pipeline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/hosts/max/api/pipeline.py b/client/ayon_core/hosts/max/api/pipeline.py index ff5ef0640b..ff0267b39a 100644 --- a/client/ayon_core/hosts/max/api/pipeline.py +++ b/client/ayon_core/hosts/max/api/pipeline.py @@ -60,6 +60,9 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): rt.callbacks.addScript(rt.Name('filePostOpen'), lib.check_colorspace) + rt.callbacks.addScript(rt.Name('postWorkspaceChange'), + self._deferred_menu_creation) + def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? return True From 1a9c8f61535046b4966d7e4c6396b210a70201e0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 08:39:13 +0000 Subject: [PATCH 11/29] Add submodule --- client/ayon_core/hosts/unreal/integration | 1 + 1 file changed, 1 insertion(+) create mode 160000 client/ayon_core/hosts/unreal/integration diff --git a/client/ayon_core/hosts/unreal/integration b/client/ayon_core/hosts/unreal/integration new file mode 160000 index 0000000000..6d2793170e --- /dev/null +++ b/client/ayon_core/hosts/unreal/integration @@ -0,0 +1 @@ +Subproject commit 6d2793170ed57187842f683a943593973abcc337 From aabe18ea04de15e0d303a21c305cc8067ce70d6b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 09:00:39 +0000 Subject: [PATCH 12/29] Increment version --- client/ayon_core/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index 914e415b8c..a173569ef3 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.2.1-dev.1" +__version__ = "0.2.2" From 4da6f25b47f09ee0ef85dbabcd46b960c1d78823 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 9 Feb 2024 11:02:59 +0200 Subject: [PATCH 13/29] rearrange deadline settings --- .../server/settings/publish_plugins.py | 160 +++++++++--------- server_addon/deadline/server/version.py | 2 +- 2 files changed, 82 insertions(+), 80 deletions(-) diff --git a/server_addon/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py index 8abe59674b..3f5ac3108d 100644 --- a/server_addon/deadline/server/settings/publish_plugins.py +++ b/server_addon/deadline/server/settings/publish_plugins.py @@ -306,36 +306,38 @@ class PublishPluginsModel(BaseSettingsModel): default_factory=ValidateExpectedFilesModel, title="Validate Expected Files" ) - MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField( - default_factory=MayaSubmitDeadlineModel, - title="Maya Submit to deadline") - MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField( - default_factory=MaxSubmitDeadlineModel, - title="Max Submit to deadline") - FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField( - default_factory=FusionSubmitDeadlineModel, - title="Fusion submit to Deadline") - NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField( - default_factory=NukeSubmitDeadlineModel, - title="Nuke Submit to deadline") - HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField( - default_factory=HarmonySubmitDeadlineModel, - title="Harmony Submit to deadline") AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = ( SettingsField( default_factory=AfterEffectsSubmitDeadlineModel, - title="After Effects to deadline" + title="After Effects to deadline", + section="Hosts" ) ) - CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField( - default_factory=CelactionSubmitDeadlineModel, - title="Celaction Submit Deadline") BlenderSubmitDeadline: BlenderSubmitDeadlineModel = SettingsField( default_factory=BlenderSubmitDeadlineModel, title="Blender Submit Deadline") + CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField( + default_factory=CelactionSubmitDeadlineModel, + title="Celaction Submit Deadline") + FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField( + default_factory=FusionSubmitDeadlineModel, + title="Fusion submit to Deadline") + HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField( + default_factory=HarmonySubmitDeadlineModel, + title="Harmony Submit to deadline") + MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField( + default_factory=MaxSubmitDeadlineModel, + title="Max Submit to deadline") + MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField( + default_factory=MayaSubmitDeadlineModel, + title="Maya Submit to deadline") + NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField( + default_factory=NukeSubmitDeadlineModel, + title="Nuke Submit to deadline") ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = SettingsField( default_factory=ProcessCacheJobFarmModel, - title="Process submitted cache Job on farm.") + title="Process submitted cache Job on farm.", + section="Publish Jobs") ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = SettingsField( default_factory=ProcessSubmittedJobOnFarmModel, title="Process submitted job on farm.") @@ -357,6 +359,65 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "deadline" ] }, + "AfterEffectsSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10000, + "group": "", + "department": "", + "multiprocess": True + }, + "BlenderSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10, + "group": "none", + "job_delay": "00:00:00:00" + }, + "CelactionSubmitDeadline": { + "enabled": True, + "deadline_department": "", + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_group": "", + "deadline_chunk_size": 10, + "deadline_job_delay": "00:00:00:00" + }, + "FusionSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "priority": 50, + "chunk_size": 10, + "concurrent_tasks": 1, + "group": "" + }, + "HarmonySubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10000, + "group": "", + "department": "" + }, + "MaxSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10, + "group": "none" + }, "MayaSubmitDeadline": { "enabled": True, "optional": False, @@ -376,24 +437,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "pluginInfo": "", "scene_patches": [] }, - "MaxSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10, - "group": "none" - }, - "FusionSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "priority": 50, - "chunk_size": 10, - "concurrent_tasks": 1, - "group": "" - }, "NukeSubmitDeadline": { "enabled": True, "optional": False, @@ -410,47 +453,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "env_search_replace_values": [], "limit_groups": [] }, - "HarmonySubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10000, - "group": "", - "department": "" - }, - "AfterEffectsSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10000, - "group": "", - "department": "", - "multiprocess": True - }, - "CelactionSubmitDeadline": { - "enabled": True, - "deadline_department": "", - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_group": "", - "deadline_chunk_size": 10, - "deadline_job_delay": "00:00:00:00" - }, - "BlenderSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10, - "group": "none", - "job_delay": "00:00:00:00" - }, "ProcessSubmittedCacheJobOnFarm": { "enabled": True, "deadline_department": "", diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py index 9cb17e7976..c11f861afb 100644 --- a/server_addon/deadline/server/version.py +++ b/server_addon/deadline/server/version.py @@ -1 +1 @@ -__version__ = "0.1.8" +__version__ = "0.1.9" From b245941f158389bebb76522b692816fc3f4a1c9e Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:30 +0000 Subject: [PATCH 14/29] Update client/ayon_core/version.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index a173569ef3..914e415b8c 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.2.2" +__version__ = "0.2.1-dev.1" From c79151e5d7fa8d0d7ecf7e345e377e5612d70c4c Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:35 +0000 Subject: [PATCH 15/29] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index 9fbf97b275..f63dbe7f58 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -113,7 +113,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): return True return False - product_names = self.subsets + self.product_names + product_names = self.product_names if product_names: result = validate_string_against_patterns( instance.data["subset"], product_names From 17dd2d1e2780085980f8cb0fe1fef4438c685a0f Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:41 +0000 Subject: [PATCH 16/29] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index f63dbe7f58..f3dd8369f3 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -50,7 +50,6 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # attribute presets from settings oiiotool_defaults = None ffmpeg_args = None - subsets = [] product_names = [] def process(self, instance): From 53b27915d5ff34924da7e8b6b71c12b9ce131aac Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 15:03:46 +0000 Subject: [PATCH 17/29] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index f3dd8369f3..1471a5fb78 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -119,7 +119,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): ) if not result: self.log.debug( - "Subset \"{}\" did not match any valid subsets: {}".format( + "Product name \"{}\" did not match settings filters: {}".format( instance.data["subset"], product_names ) ) From bae63d5e015df8d09f59354899accd58d35d6512 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:49:54 +0100 Subject: [PATCH 18/29] fix houdini lib --- client/ayon_core/hosts/houdini/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py index 7163aebdec..bf66890285 100644 --- a/client/ayon_core/hosts/houdini/api/lib.py +++ b/client/ayon_core/hosts/houdini/api/lib.py @@ -6,6 +6,7 @@ import re import uuid import logging import json +from contextlib import contextmanager import six From cafbff361bfa4de76fe345d9b7e1839d2d2e13ed Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:51:15 +0100 Subject: [PATCH 19/29] use 'SetCurrentProcessExplicitAppUserModelID' only when running from code --- client/ayon_core/tools/traypublisher/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index dad314e510..4335b9e92b 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -12,7 +12,7 @@ from qtpy import QtWidgets, QtCore import qtawesome import appdirs -from ayon_core.lib import JSONSettingRegistry +from ayon_core.lib import JSONSettingRegistry, is_running_from_build from ayon_core.pipeline import install_host from ayon_core.hosts.traypublisher.api import TrayPublisherHost from ayon_core.tools.publisher.control_qt import QtPublisherController @@ -265,7 +265,7 @@ def main(): app_instance = get_ayon_qt_app() - if platform.system().lower() == "windows": + if not is_running_from_build() and platform.system().lower() == "windows": import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( u"traypublisher" From 7f462c73246bf1390f83c5abc315fda78b200165 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:55:01 +0100 Subject: [PATCH 20/29] Use AYON in docstrings and labels --- client/ayon_core/hosts/resolve/startup.py | 6 +++--- client/ayon_core/lib/local_settings.py | 4 ++-- client/ayon_core/modules/job_queue/module.py | 4 ++-- client/ayon_core/modules/timers_manager/widget_user_idle.py | 2 +- client/ayon_core/modules/webserver/webserver_module.py | 2 +- client/ayon_core/style/__init__.py | 4 ++-- client/ayon_core/tools/traypublisher/window.py | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/resolve/startup.py b/client/ayon_core/hosts/resolve/startup.py index 174a2878c5..b3c1a024d9 100644 --- a/client/ayon_core/hosts/resolve/startup.py +++ b/client/ayon_core/hosts/resolve/startup.py @@ -33,7 +33,7 @@ def ensure_installed_host(): def launch_menu(): - print("Launching Resolve OpenPype menu..") + print("Launching Resolve AYON menu..") ensure_installed_host() ayon_core.hosts.resolve.api.launch_pype_menu() @@ -54,7 +54,7 @@ def main(): else: log.info("No last workfile set to open. Skipping..") - # Launch OpenPype menu + # Launch AYON menu from ayon_core.settings import get_project_settings from ayon_core.pipeline.context_tools import get_current_project_name project_name = get_current_project_name() @@ -62,7 +62,7 @@ def main(): settings = get_project_settings(project_name) if settings.get("resolve", {}).get("launch_openpype_menu_on_start", True): - log.info("Launching OpenPype menu..") + log.info("Launching AYON menu..") launch_menu() diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index 33b3232128..022f63a618 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -38,8 +38,8 @@ class AYONSecureRegistry: Registry should be used for private data that should be available only for user. - All passed registry names will have added prefix `OpenPype/` to easier - identify which data were created by OpenPype. + All passed registry names will have added prefix `AYON/` to easier + identify which data were created by AYON. Args: name(str): Name of registry used as identifier for data. diff --git a/client/ayon_core/modules/job_queue/module.py b/client/ayon_core/modules/job_queue/module.py index 1cecd62de5..f2b022069b 100644 --- a/client/ayon_core/modules/job_queue/module.py +++ b/client/ayon_core/modules/job_queue/module.py @@ -1,4 +1,4 @@ -"""Job queue OpenPype module was created for remote execution of commands. +"""Job queue AYON addon was created for remote execution of commands. ## Why is needed Primarily created for hosts which are not easilly controlled from command line @@ -30,7 +30,7 @@ workstations know where to send or receive jobs. ### start_worker - start worker which will process jobs -- has required possitional argument which is application name from OpenPype +- has required possitional argument which is application name from AYON settings e.g. 'tvpaint/11-5' ('tvpaint' is group '11-5' is variant) - it is possible to specify server url but url from settings is used when not passed (this is added mainly for developing purposes) diff --git a/client/ayon_core/modules/timers_manager/widget_user_idle.py b/client/ayon_core/modules/timers_manager/widget_user_idle.py index 94d7a606ed..c59ab15b38 100644 --- a/client/ayon_core/modules/timers_manager/widget_user_idle.py +++ b/client/ayon_core/modules/timers_manager/widget_user_idle.py @@ -9,7 +9,7 @@ class WidgetUserIdle(QtWidgets.QWidget): def __init__(self, module): super(WidgetUserIdle, self).__init__() - self.setWindowTitle("OpenPype - Stop timers") + self.setWindowTitle("AYON - Stop timers") icon = QtGui.QIcon(resources.get_ayon_icon_filepath()) self.setWindowIcon(icon) diff --git a/client/ayon_core/modules/webserver/webserver_module.py b/client/ayon_core/modules/webserver/webserver_module.py index ec143d0866..c324e0dd18 100644 --- a/client/ayon_core/modules/webserver/webserver_module.py +++ b/client/ayon_core/modules/webserver/webserver_module.py @@ -1,6 +1,6 @@ """WebServerAddon spawns aiohttp server in asyncio loop. -Main usage of the module is in OpenPype tray where make sense to add ability +Main usage of the module is in AYON tray where make sense to add ability of other modules to add theirs routes. Module which would want use that option must have implemented method `webserver_initialization` which must expect `WebServerManager` object where is possible to add routes or paths diff --git a/client/ayon_core/style/__init__.py b/client/ayon_core/style/__init__.py index 8b2dfa1bcb..8d3089ef86 100644 --- a/client/ayon_core/style/__init__.py +++ b/client/ayon_core/style/__init__.py @@ -198,7 +198,7 @@ def _load_font(): def load_stylesheet(): - """Load and return OpenPype Qt stylesheet.""" + """Load and return AYON Qt stylesheet.""" if _Cache.stylesheet is None: _Cache.stylesheet = _load_stylesheet() @@ -207,7 +207,7 @@ def load_stylesheet(): def get_app_icon_path(): - """Path to OpenPype icon.""" + """Path to AYON icon.""" return resources.get_ayon_icon_filepath() diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index 4335b9e92b..79386d7ea0 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -35,7 +35,7 @@ class TrayPublisherController(QtPublisherController): class TrayPublisherRegistry(JSONSettingRegistry): - """Class handling OpenPype general settings registry. + """Class handling AYON general settings registry. Attributes: vendor (str): Name used for path construction. From 01ac49c8b315e8013ddaf649686751797e5e67ad Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:55:21 +0100 Subject: [PATCH 21/29] fix docstring argument name --- client/ayon_core/pipeline/farm/patterning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/farm/patterning.py b/client/ayon_core/pipeline/farm/patterning.py index 1e4b5bf37d..d7b046113b 100644 --- a/client/ayon_core/pipeline/farm/patterning.py +++ b/client/ayon_core/pipeline/farm/patterning.py @@ -11,7 +11,7 @@ def match_aov_pattern(host_name, aov_patterns, render_file_name): that we have grabbed from `exp_files`. Args: - app (str): Host name. + host_name (str): Host name. aov_patterns (dict): AOV patterns from AOV filters. render_file_name (str): Incoming file name to match against. From 3365919d966b7ddfd687d12e53153e9d3a9205fd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:31:54 +0100 Subject: [PATCH 22/29] host addons inherit from AYONAddon --- client/ayon_core/hosts/aftereffects/addon.py | 7 ++----- client/ayon_core/hosts/blender/addon.py | 7 ++----- client/ayon_core/hosts/celaction/addon.py | 7 ++----- client/ayon_core/hosts/flame/addon.py | 7 ++----- client/ayon_core/hosts/fusion/addon.py | 7 ++----- client/ayon_core/hosts/harmony/addon.py | 7 ++----- client/ayon_core/hosts/hiero/addon.py | 7 ++----- client/ayon_core/hosts/houdini/addon.py | 7 ++----- client/ayon_core/hosts/max/addon.py | 7 ++----- client/ayon_core/hosts/maya/addon.py | 7 ++----- client/ayon_core/hosts/nuke/addon.py | 7 ++----- client/ayon_core/hosts/photoshop/addon.py | 7 ++----- client/ayon_core/hosts/resolve/addon.py | 7 ++----- client/ayon_core/hosts/substancepainter/addon.py | 7 ++----- client/ayon_core/hosts/traypublisher/addon.py | 11 +++++------ client/ayon_core/hosts/tvpaint/addon.py | 7 ++----- client/ayon_core/hosts/unreal/addon.py | 7 ++----- 17 files changed, 37 insertions(+), 86 deletions(-) diff --git a/client/ayon_core/hosts/aftereffects/addon.py b/client/ayon_core/hosts/aftereffects/addon.py index 278f836a72..46d0818247 100644 --- a/client/ayon_core/hosts/aftereffects/addon.py +++ b/client/ayon_core/hosts/aftereffects/addon.py @@ -1,13 +1,10 @@ -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon -class AfterEffectsAddon(OpenPypeModule, IHostAddon): +class AfterEffectsAddon(AYONAddon, IHostAddon): name = "aftereffects" host_name = "aftereffects" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" defaults = { diff --git a/client/ayon_core/hosts/blender/addon.py b/client/ayon_core/hosts/blender/addon.py index c3804382e5..b7484de243 100644 --- a/client/ayon_core/hosts/blender/addon.py +++ b/client/ayon_core/hosts/blender/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon BLENDER_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class BlenderAddon(OpenPypeModule, IHostAddon): +class BlenderAddon(AYONAddon, IHostAddon): name = "blender" host_name = "blender" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" # Prepare path to implementation script diff --git a/client/ayon_core/hosts/celaction/addon.py b/client/ayon_core/hosts/celaction/addon.py index 4573ee7e56..d00401a2e0 100644 --- a/client/ayon_core/hosts/celaction/addon.py +++ b/client/ayon_core/hosts/celaction/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon CELACTION_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class CelactionAddon(OpenPypeModule, IHostAddon): +class CelactionAddon(AYONAddon, IHostAddon): name = "celaction" host_name = "celaction" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/flame/addon.py b/client/ayon_core/hosts/flame/addon.py index e30d7cab08..f5560cde7a 100644 --- a/client/ayon_core/hosts/flame/addon.py +++ b/client/ayon_core/hosts/flame/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class FlameAddon(OpenPypeModule, IHostAddon): +class FlameAddon(AYONAddon, IHostAddon): name = "flame" host_name = "flame" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to DL_PYTHON_HOOK_PATH env["DL_PYTHON_HOOK_PATH"] = os.path.join(HOST_DIR, "startup") diff --git a/client/ayon_core/hosts/fusion/addon.py b/client/ayon_core/hosts/fusion/addon.py index 7eff2d93c8..391ee770c4 100644 --- a/client/ayon_core/hosts/fusion/addon.py +++ b/client/ayon_core/hosts/fusion/addon.py @@ -1,6 +1,6 @@ import os import re -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon from ayon_core.lib import Logger FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -48,13 +48,10 @@ def get_fusion_version(app_name): ) -class FusionAddon(OpenPypeModule, IHostAddon): +class FusionAddon(AYONAddon, IHostAddon): name = "fusion" host_name = "fusion" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/harmony/addon.py b/client/ayon_core/hosts/harmony/addon.py index 172a1f104f..476d569415 100644 --- a/client/ayon_core/hosts/harmony/addon.py +++ b/client/ayon_core/hosts/harmony/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HARMONY_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class HarmonyAddon(OpenPypeModule, IHostAddon): +class HarmonyAddon(AYONAddon, IHostAddon): name = "harmony" host_name = "harmony" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" openharmony_path = os.path.join( diff --git a/client/ayon_core/hosts/hiero/addon.py b/client/ayon_core/hosts/hiero/addon.py index 447700e2e1..f612493ca1 100644 --- a/client/ayon_core/hosts/hiero/addon.py +++ b/client/ayon_core/hosts/hiero/addon.py @@ -1,17 +1,14 @@ import os import platform -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HIERO_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class HieroAddon(OpenPypeModule, IHostAddon): +class HieroAddon(AYONAddon, IHostAddon): name = "hiero" host_name = "hiero" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to HIERO_PLUGIN_PATH new_hiero_paths = [ diff --git a/client/ayon_core/hosts/houdini/addon.py b/client/ayon_core/hosts/houdini/addon.py index 34d140db3c..95d714aea1 100644 --- a/client/ayon_core/hosts/houdini/addon.py +++ b/client/ayon_core/hosts/houdini/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HOUDINI_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class HoudiniAddon(OpenPypeModule, IHostAddon): +class HoudiniAddon(AYONAddon, IHostAddon): name = "houdini" host_name = "houdini" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to HOUDINI_PATH and HOUDINI_MENU_PATH startup_path = os.path.join(HOUDINI_HOST_DIR, "startup") diff --git a/client/ayon_core/hosts/max/addon.py b/client/ayon_core/hosts/max/addon.py index 416014025c..12f5f7eca0 100644 --- a/client/ayon_core/hosts/max/addon.py +++ b/client/ayon_core/hosts/max/addon.py @@ -1,17 +1,14 @@ # -*- coding: utf-8 -*- import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon MAX_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class MaxAddon(OpenPypeModule, IHostAddon): +class MaxAddon(AYONAddon, IHostAddon): name = "max" host_name = "max" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Remove auto screen scale factor for Qt # - let 3dsmax decide it's value diff --git a/client/ayon_core/hosts/maya/addon.py b/client/ayon_core/hosts/maya/addon.py index 745850f6a8..c68aa4c911 100644 --- a/client/ayon_core/hosts/maya/addon.py +++ b/client/ayon_core/hosts/maya/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon MAYA_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class MayaAddon(OpenPypeModule, IHostAddon): +class MayaAddon(AYONAddon, IHostAddon): name = "maya" host_name = "maya" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to PYTHONPATH new_python_paths = [ diff --git a/client/ayon_core/hosts/nuke/addon.py b/client/ayon_core/hosts/nuke/addon.py index 4ca4408271..8e640624f0 100644 --- a/client/ayon_core/hosts/nuke/addon.py +++ b/client/ayon_core/hosts/nuke/addon.py @@ -1,17 +1,14 @@ import os import platform -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon NUKE_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class NukeAddon(OpenPypeModule, IHostAddon): +class NukeAddon(AYONAddon, IHostAddon): name = "nuke" host_name = "nuke" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to NUKE_PATH new_nuke_paths = [ diff --git a/client/ayon_core/hosts/photoshop/addon.py b/client/ayon_core/hosts/photoshop/addon.py index 0c7efdb317..3016912960 100644 --- a/client/ayon_core/hosts/photoshop/addon.py +++ b/client/ayon_core/hosts/photoshop/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon PHOTOSHOP_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class PhotoshopAddon(OpenPypeModule, IHostAddon): +class PhotoshopAddon(AYONAddon, IHostAddon): name = "photoshop" host_name = "photoshop" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" defaults = { diff --git a/client/ayon_core/hosts/resolve/addon.py b/client/ayon_core/hosts/resolve/addon.py index 9c9932826b..1354caabb2 100644 --- a/client/ayon_core/hosts/resolve/addon.py +++ b/client/ayon_core/hosts/resolve/addon.py @@ -1,17 +1,14 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon from .utils import RESOLVE_ROOT_DIR -class ResolveAddon(OpenPypeModule, IHostAddon): +class ResolveAddon(AYONAddon, IHostAddon): name = "resolve" host_name = "resolve" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/substancepainter/addon.py b/client/ayon_core/hosts/substancepainter/addon.py index a7f21c2288..26829d3153 100644 --- a/client/ayon_core/hosts/substancepainter/addon.py +++ b/client/ayon_core/hosts/substancepainter/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon SUBSTANCE_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class SubstanceAddon(OpenPypeModule, IHostAddon): +class SubstanceAddon(AYONAddon, IHostAddon): name = "substancepainter" host_name = "substancepainter" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to SUBSTANCE_PAINTER_PLUGINS_PATH plugin_path = os.path.join(SUBSTANCE_HOST_DIR, "deploy") diff --git a/client/ayon_core/hosts/traypublisher/addon.py b/client/ayon_core/hosts/traypublisher/addon.py index d8fc5ed105..70bdfe9a64 100644 --- a/client/ayon_core/hosts/traypublisher/addon.py +++ b/client/ayon_core/hosts/traypublisher/addon.py @@ -2,9 +2,9 @@ import os from ayon_core.lib import get_ayon_launcher_args from ayon_core.lib.execute import run_detached_process -from ayon_core.modules import ( +from ayon_core.addon import ( click_wrap, - OpenPypeModule, + AYONAddon, ITrayAction, IHostAddon, ) @@ -12,13 +12,12 @@ from ayon_core.modules import ( TRAYPUBLISH_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction): +class TrayPublishAddon(AYONAddon, IHostAddon, ITrayAction): label = "Publisher" name = "traypublisher" host_name = "traypublisher" - def initialize(self, modules_settings): - self.enabled = True + def initialize(self, settings): self.publish_paths = [ os.path.join(TRAYPUBLISH_ROOT_DIR, "plugins", "publish") ] @@ -36,7 +35,7 @@ class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction): def run_traypublisher(self): args = get_ayon_launcher_args( - "module", self.name, "launch" + "addon", self.name, "launch" ) run_detached_process(args) diff --git a/client/ayon_core/hosts/tvpaint/addon.py b/client/ayon_core/hosts/tvpaint/addon.py index 375f7266ae..6756b274f9 100644 --- a/client/ayon_core/hosts/tvpaint/addon.py +++ b/client/ayon_core/hosts/tvpaint/addon.py @@ -1,5 +1,5 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon TVPAINT_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -12,13 +12,10 @@ def get_launch_script_path(): ) -class TVPaintAddon(OpenPypeModule, IHostAddon): +class TVPaintAddon(AYONAddon, IHostAddon): name = "tvpaint" host_name = "tvpaint" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" diff --git a/client/ayon_core/hosts/unreal/addon.py b/client/ayon_core/hosts/unreal/addon.py index 745df951c1..c65490bd8c 100644 --- a/client/ayon_core/hosts/unreal/addon.py +++ b/client/ayon_core/hosts/unreal/addon.py @@ -1,17 +1,14 @@ import os import re -from ayon_core.modules import IHostAddon, OpenPypeModule +from ayon_core.addon import AYONAddon, IHostAddon UNREAL_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class UnrealAddon(OpenPypeModule, IHostAddon): +class UnrealAddon(AYONAddon, IHostAddon): name = "unreal" host_name = "unreal" - def initialize(self, module_settings): - self.enabled = True - def get_global_environments(self): return { "AYON_UNREAL_ROOT": UNREAL_ROOT_DIR, From 4e3fd869875a30347740f405a85efce14447654c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:32:27 +0100 Subject: [PATCH 23/29] console interpreter inherits from AYONaddon --- .../modules/python_console_interpreter/__init__.py | 2 +- .../python_console_interpreter/{module.py => addon.py} | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) rename client/ayon_core/modules/python_console_interpreter/{module.py => addon.py} (77%) diff --git a/client/ayon_core/modules/python_console_interpreter/__init__.py b/client/ayon_core/modules/python_console_interpreter/__init__.py index 5f54ac497b..8d5c23bdba 100644 --- a/client/ayon_core/modules/python_console_interpreter/__init__.py +++ b/client/ayon_core/modules/python_console_interpreter/__init__.py @@ -1,4 +1,4 @@ -from .module import ( +from .addon import ( PythonInterpreterAction ) diff --git a/client/ayon_core/modules/python_console_interpreter/module.py b/client/ayon_core/modules/python_console_interpreter/addon.py similarity index 77% rename from client/ayon_core/modules/python_console_interpreter/module.py rename to client/ayon_core/modules/python_console_interpreter/addon.py index 7819c9cbf3..ffad3ce707 100644 --- a/client/ayon_core/modules/python_console_interpreter/module.py +++ b/client/ayon_core/modules/python_console_interpreter/addon.py @@ -1,13 +1,12 @@ -from ayon_core.modules import OpenPypeModule, ITrayAction +from ayon_core.addon import AYONAddon, ITrayAction -class PythonInterpreterAction(OpenPypeModule, ITrayAction): +class PythonInterpreterAction(AYONAddon, ITrayAction): label = "Console" name = "python_interpreter" admin_action = True - def initialize(self, modules_settings): - self.enabled = True + def initialize(self, settings): self._interpreter_window = None def tray_init(self): @@ -22,7 +21,7 @@ class PythonInterpreterAction(OpenPypeModule, ITrayAction): if self._interpreter_window: return - from openpype_modules.python_console_interpreter.window import ( + from ayon_core.modules.python_console_interpreter.window import ( PythonInterpreterWidget ) From 5c294300246b0379e68ed38603fffd7a2e33986b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:32:39 +0100 Subject: [PATCH 24/29] launcher action addon inherits from AYONaddon --- client/ayon_core/modules/launcher_action.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/modules/launcher_action.py b/client/ayon_core/modules/launcher_action.py index c0266e3a57..1faf6ef4b1 100644 --- a/client/ayon_core/modules/launcher_action.py +++ b/client/ayon_core/modules/launcher_action.py @@ -1,19 +1,14 @@ import os from ayon_core import AYON_CORE_ROOT -from ayon_core.modules import ( - OpenPypeModule, - ITrayAction, -) +from ayon_core.addon import AYONAddon, ITrayAction -class LauncherAction(OpenPypeModule, ITrayAction): +class LauncherAction(AYONAddon, ITrayAction): label = "Launcher" name = "launcher_tool" - def initialize(self, _modules_settings): - # This module is always enabled - self.enabled = True + def initialize(self, settings): # Tray attributes self._window = None From b7d86bee3fb67ee4321de3ef5807fdbaa5949d12 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:34:42 +0100 Subject: [PATCH 25/29] renamed libray loader action to loader action --- .../modules/library_loader_action.py | 67 ------------------- client/ayon_core/modules/loader_action.py | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 67 deletions(-) delete mode 100644 client/ayon_core/modules/library_loader_action.py create mode 100644 client/ayon_core/modules/loader_action.py diff --git a/client/ayon_core/modules/library_loader_action.py b/client/ayon_core/modules/library_loader_action.py deleted file mode 100644 index 524c4f7144..0000000000 --- a/client/ayon_core/modules/library_loader_action.py +++ /dev/null @@ -1,67 +0,0 @@ -from ayon_core.modules import AYONAddon, ITrayModule - - -class LibraryLoaderAddon(AYONAddon, ITrayModule): - name = "library_tool" - - def initialize(self, modules_settings): - # Tray attributes - self._library_loader_imported = None - self._library_loader_window = None - - def tray_init(self): - # Add library tool - self._library_loader_imported = False - try: - from ayon_core.tools.loader.ui import LoaderWindow - - self._library_loader_imported = True - except Exception: - self.log.warning( - "Couldn't load Library loader tool for tray.", - exc_info=True - ) - - # Definition of Tray menu - def tray_menu(self, tray_menu): - if not self._library_loader_imported: - return - - from qtpy import QtWidgets - # Actions - action_library_loader = QtWidgets.QAction( - "Loader", tray_menu - ) - - action_library_loader.triggered.connect(self.show_library_loader) - - tray_menu.addAction(action_library_loader) - - def tray_start(self, *_a, **_kw): - return - - def tray_exit(self, *_a, **_kw): - return - - def show_library_loader(self): - if self._library_loader_window is None: - from ayon_core.pipeline import install_ayon_plugins - - self._init_library_loader() - - install_ayon_plugins() - - self._library_loader_window.show() - - # Raise and activate the window - # for MacOS - self._library_loader_window.raise_() - # for Windows - self._library_loader_window.activateWindow() - - def _init_library_loader(self): - from ayon_core.tools.loader.ui import LoaderWindow - - libraryloader = LoaderWindow() - - self._library_loader_window = libraryloader diff --git a/client/ayon_core/modules/loader_action.py b/client/ayon_core/modules/loader_action.py new file mode 100644 index 0000000000..a0cc417b66 --- /dev/null +++ b/client/ayon_core/modules/loader_action.py @@ -0,0 +1,67 @@ +from ayon_core.addon import AYONAddon, ITrayAddon + + +class LoaderAddon(AYONAddon, ITrayAddon): + name = "loader_tool" + + def initialize(self, settings): + # Tray attributes + self._loader_imported = None + self._loader_window = None + + def tray_init(self): + # Add library tool + self._loader_imported = False + try: + from ayon_core.tools.loader.ui import LoaderWindow + + self._loader_imported = True + except Exception: + self.log.warning( + "Couldn't load Loader tool for tray.", + exc_info=True + ) + + # Definition of Tray menu + def tray_menu(self, tray_menu): + if not self._loader_imported: + return + + from qtpy import QtWidgets + # Actions + action_loader = QtWidgets.QAction( + "Loader", tray_menu + ) + + action_loader.triggered.connect(self.show_loader) + + tray_menu.addAction(action_loader) + + def tray_start(self, *_a, **_kw): + return + + def tray_exit(self, *_a, **_kw): + return + + def show_loader(self): + if self._loader_window is None: + from ayon_core.pipeline import install_ayon_plugins + + self._init_loader() + + install_ayon_plugins() + + self._loader_window.show() + + # Raise and activate the window + # for MacOS + self._loader_window.raise_() + # for Windows + self._loader_window.activateWindow() + + def _init_loader(self): + from ayon_core.tools.loader.ui import LoaderWindow + + libraryloader = LoaderWindow() + + self._loader_window = libraryloader From 3484a3d79b2b8966f78fd7c49c2aa4a72d8978d8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:35:49 +0100 Subject: [PATCH 26/29] modified click_wrap examples and readme --- client/ayon_core/addon/README.md | 8 ++++---- client/ayon_core/addon/click_wrap.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/addon/README.md b/client/ayon_core/addon/README.md index b793b0ffb4..a15e8bdc69 100644 --- a/client/ayon_core/addon/README.md +++ b/client/ayon_core/addon/README.md @@ -31,7 +31,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - addon must implement `get_plugin_paths` which must return dictionary with possible keys `"publish"`, `"load"`, `"create"` or `"actions"` - each key may contain list or string with a path to directory with plugins -## ITrayModule +## ITrayAddon - addon has more logic when used in a tray - it is possible that addon can be used only in the tray - abstract methods @@ -46,7 +46,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - if addon has logic only in tray or for both then should be checking for `tray_initialized` attribute to decide how should handle situations ### ITrayService -- inherits from `ITrayModule` and implements `tray_menu` method for you +- inherits from `ITrayAddon` and implements `tray_menu` method for you - adds action to submenu "Services" in tray widget menu with icon and label - abstract attribute `label` - label shown in menu @@ -57,7 +57,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - these states must be set by addon itself `set_service_running` is default state on initialization ### ITrayAction -- inherits from `ITrayModule` and implements `tray_menu` method for you +- inherits from `ITrayAddon` and implements `tray_menu` method for you - adds action to tray widget menu with label - abstract attribute `label` - label shown in menu @@ -89,4 +89,4 @@ AYON addons should contain separated logic of specific kind of implementation, s ### TrayAddonsManager - inherits from `AddonsManager` -- has specific implementation for Pype Tray tool and handle `ITrayModule` methods +- has specific implementation for Pype Tray tool and handle `ITrayAddon` methods diff --git a/client/ayon_core/addon/click_wrap.py b/client/ayon_core/addon/click_wrap.py index d49188312d..911a5a5707 100644 --- a/client/ayon_core/addon/click_wrap.py +++ b/client/ayon_core/addon/click_wrap.py @@ -15,7 +15,7 @@ method to convert 'click_wrap' object to 'click' object. Before ```python import click -from ayon_core.modules import AYONAddon +from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): @@ -40,7 +40,7 @@ def mycommand(arg1, arg2): Now ``` from ayon_core import click_wrap -from ayon_core.modules import AYONAddon +from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): @@ -72,7 +72,7 @@ Added small enhancements: Example: ```python from ayon_core import click_wrap - from ayon_core.modules import AYONAddon + from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): From df9cb75799ed6ef43ba23ec10b81aa5de03aa422 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:43:29 +0100 Subject: [PATCH 27/29] added 'USE_AYON_ENTITIES' for forwards compatibility possibilities --- client/ayon_core/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/__init__.py b/client/ayon_core/__init__.py index c9c0dfc614..5f9eb6cea3 100644 --- a/client/ayon_core/__init__.py +++ b/client/ayon_core/__init__.py @@ -7,3 +7,6 @@ AYON_CORE_ROOT = os.path.dirname(os.path.abspath(__file__)) PACKAGE_DIR = AYON_CORE_ROOT PLUGINS_DIR = os.path.join(AYON_CORE_ROOT, "plugins") AYON_SERVER_ENABLED = True + +# Indicate if AYON entities should be used instead of OpenPype entities +USE_AYON_ENTITIES = False From 2e925ea64b32848097a34abbf9e13f89ec0e805a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 9 Feb 2024 21:50:30 +0100 Subject: [PATCH 28/29] fix variable check --- client/ayon_core/plugins/publish/collect_rendered_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 714d790269..1442111a31 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -144,7 +144,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): os.environ.get("AYON_PUBLISH_DATA") or os.environ.get("OPENPYPE_PUBLISH_DATA") ) - if publish_data_paths: + if not publish_data_paths: raise KnownPublishError("Missing `AYON_PUBLISH_DATA`") # QUESTION From 9d807f28f069ffff23c7306d88c756526246379d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 9 Feb 2024 22:16:43 +0100 Subject: [PATCH 29/29] session is not required key --- client/ayon_core/plugins/publish/collect_rendered_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 1442111a31..a7b6064b7a 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -72,7 +72,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): # validate basic necessary data data_err = "invalid json file - missing data" required = ["asset", "user", "comment", - "job", "instances", "session", "version"] + "job", "instances", "version"] assert all(elem in data.keys() for elem in required), data_err # set context by first json file