diff --git a/.github/pr-glob-labeler.yml b/.github/pr-glob-labeler.yml
new file mode 100644
index 0000000000..286e7768b5
--- /dev/null
+++ b/.github/pr-glob-labeler.yml
@@ -0,0 +1,102 @@
+# Add type: unittest label if any changes in tests folders
+'type: unittest':
+- '*/*tests*/**/*'
+
+# any changes in documentation structure
+'type: documentation':
+- '*/**/*website*/**/*'
+- '*/**/*docs*/**/*'
+
+# hosts triage
+'host: Nuke':
+- '*/**/*nuke*'
+- '*/**/*nuke*/**/*'
+
+'host: Photoshop':
+- '*/**/*photoshop*'
+- '*/**/*photoshop*/**/*'
+
+'host: Harmony':
+- '*/**/*harmony*'
+- '*/**/*harmony*/**/*'
+
+'host: UE':
+- '*/**/*unreal*'
+- '*/**/*unreal*/**/*'
+
+'host: Houdini':
+- '*/**/*houdini*'
+- '*/**/*houdini*/**/*'
+
+'host: Maya':
+- '*/**/*maya*'
+- '*/**/*maya*/**/*'
+
+'host: Resolve':
+- '*/**/*resolve*'
+- '*/**/*resolve*/**/*'
+
+'host: Blender':
+- '*/**/*blender*'
+- '*/**/*blender*/**/*'
+
+'host: Hiero':
+- '*/**/*hiero*'
+- '*/**/*hiero*/**/*'
+
+'host: Fusion':
+- '*/**/*fusion*'
+- '*/**/*fusion*/**/*'
+
+'host: Flame':
+- '*/**/*flame*'
+- '*/**/*flame*/**/*'
+
+'host: TrayPublisher':
+- '*/**/*traypublisher*'
+- '*/**/*traypublisher*/**/*'
+
+'host: 3dsmax':
+- '*/**/*max*'
+- '*/**/*max*/**/*'
+
+'host: TV Paint':
+- '*/**/*tvpaint*'
+- '*/**/*tvpaint*/**/*'
+
+'host: CelAction':
+- '*/**/*celaction*'
+- '*/**/*celaction*/**/*'
+
+'host: After Effects':
+- '*/**/*aftereffects*'
+- '*/**/*aftereffects*/**/*'
+
+'host: Substance Painter':
+- '*/**/*substancepainter*'
+- '*/**/*substancepainter*/**/*'
+
+# modules triage
+'module: Deadline':
+- '*/**/*deadline*'
+- '*/**/*deadline*/**/*'
+
+'module: RoyalRender':
+- '*/**/*royalrender*'
+- '*/**/*royalrender*/**/*'
+
+'module: Sitesync':
+- '*/**/*sync_server*'
+- '*/**/*sync_server*/**/*'
+
+'module: Ftrack':
+- '*/**/*ftrack*'
+- '*/**/*ftrack*/**/*'
+
+'module: Shotgrid':
+- '*/**/*shotgrid*'
+- '*/**/*shotgrid*/**/*'
+
+'module: Kitsu':
+- '*/**/*kitsu*'
+- '*/**/*kitsu*/**/*'
diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py
index a3920c4acb..3b35476aed 100644
--- a/client/ayon_core/addon/base.py
+++ b/client/ayon_core/addon/base.py
@@ -788,6 +788,7 @@ class AddonsManager:
addon_classes.append(modules_item)
+ aliased_names = []
for addon_cls in addon_classes:
name = addon_cls.__name__
if issubclass(addon_cls, OpenPypeModule):
@@ -807,6 +808,13 @@ class AddonsManager:
self._addons.append(addon)
self._addons_by_id[addon.id] = addon
self._addons_by_name[addon.name] = addon
+ # NOTE This will be removed with release 1.0.0 of ayon-core
+ # please use carefully.
+ # Gives option to use alias name for addon for cases when
+ # name in OpenPype was not the same as in AYON.
+ name_alias = getattr(addon, "openpype_alias", None)
+ if name_alias:
+ aliased_names.append((name_alias, addon))
enabled_str = "X"
if not addon.enabled:
enabled_str = " "
@@ -822,6 +830,17 @@ class AddonsManager:
exc_info=True
)
+ for item in aliased_names:
+ name_alias, addon = item
+ if name_alias not in self._addons_by_name:
+ self._addons_by_name[name_alias] = addon
+ continue
+ self.log.warning(
+ "Alias name '{}' of addon '{}' is already assigned.".format(
+ name_alias, addon.name
+ )
+ )
+
if self._report is not None:
report[self._report_total_key] = time.time() - time_start
self._report["Initialization"] = report
diff --git a/client/ayon_core/host/dirmap.py b/client/ayon_core/host/dirmap.py
index cecd689a4c..9756657386 100644
--- a/client/ayon_core/host/dirmap.py
+++ b/client/ayon_core/host/dirmap.py
@@ -92,8 +92,8 @@ class HostDirmap(object):
self.on_enable_dirmap()
- for k, sp in enumerate(mapping["source-path"]):
- dst = mapping["destination-path"][k]
+ for k, sp in enumerate(mapping["source_path"]):
+ dst = mapping["destination_path"][k]
try:
# add trailing slash if missing
sp = os.path.join(sp, '')
@@ -116,7 +116,7 @@ class HostDirmap(object):
continue
def get_mappings(self):
- """Get translation from source-path to destination-path.
+ """Get translation from source_path to destination_path.
It checks if Site Sync is enabled and user chose to use local
site, in that case configuration in Local Settings takes precedence
@@ -138,8 +138,8 @@ class HostDirmap(object):
if (
not mapping
- or not mapping.get("destination-path")
- or not mapping.get("source-path")
+ or not mapping.get("destination_path")
+ or not mapping.get("source_path")
):
return {}
self.log.info("Processing directory mapping ...")
@@ -154,7 +154,7 @@ class HostDirmap(object):
in Local Settings.
Returns:
- dict : { "source-path": [XXX], "destination-path": [YYYY]}
+ dict : { "source_path": [XXX], "destination_path": [YYYY]}
"""
project_name = self.project_name
@@ -210,13 +210,13 @@ class HostDirmap(object):
continue
if os.path.isdir(active_site_dir):
- if "destination-path" not in mapping:
- mapping["destination-path"] = []
- mapping["destination-path"].append(active_site_dir)
+ if "destination_path" not in mapping:
+ mapping["destination_path"] = []
+ mapping["destination_path"].append(active_site_dir)
- if "source-path" not in mapping:
- mapping["source-path"] = []
- mapping["source-path"].append(remote_site_dir)
+ if "source_path" not in mapping:
+ mapping["source_path"] = []
+ mapping["source_path"].append(remote_site_dir)
self.log.debug("local sync mapping:: {}".format(mapping))
return mapping
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..4ffed8cecf 100644
--- a/client/ayon_core/hosts/aftereffects/api/launch_logic.py
+++ b/client/ayon_core/hosts/aftereffects/api/launch_logic.py
@@ -15,9 +15,8 @@ from wsrpc_aiohttp import (
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.lib import Logger, is_in_tests
+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 +297,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/blender/plugins/publish/extract_playblast.py b/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py
index 83e6b26fbe..04fc2c5c39 100644
--- a/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py
+++ b/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py
@@ -1,9 +1,11 @@
import os
+import json
+
import clique
+import pyblish.api
import bpy
-import pyblish.api
from ayon_core.pipeline import publish
from ayon_core.hosts.blender.api import capture
from ayon_core.hosts.blender.api.lib import maintained_time
@@ -23,6 +25,8 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin):
optional = True
order = pyblish.api.ExtractorOrder + 0.01
+ presets = "{}"
+
def process(self, instance):
if not self.is_active(instance.data):
return
@@ -59,8 +63,7 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin):
self.log.debug(f"Outputting images to {path}")
- project_settings = instance.context.data["project_settings"]["blender"]
- presets = project_settings["publish"]["ExtractPlayblast"]["presets"]
+ presets = json.loads(self.presets)
preset = presets.get("default")
preset.update({
"camera": camera,
diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py b/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py
index 7b445a0113..ec701610ce 100644
--- a/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py
+++ b/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py
@@ -1,5 +1,6 @@
import os
import glob
+import json
import pyblish.api
from ayon_core.pipeline import publish
@@ -21,7 +22,7 @@ class ExtractThumbnail(publish.Extractor):
hosts = ["blender"]
families = ["review"]
order = pyblish.api.ExtractorOrder + 0.01
- presets = {}
+ presets = "{}"
def process(self, instance):
self.log.debug("Extracting capture..")
@@ -44,7 +45,8 @@ class ExtractThumbnail(publish.Extractor):
family = instance.data.get("family")
isolate = instance.data("isolate", None)
- preset = self.presets.get(family, {})
+ presets = json.loads(self.presets)
+ preset = presets.get(family, {})
preset.update({
"camera": camera,
diff --git a/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py b/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py
index a66bf53622..57797e5a44 100644
--- a/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py
+++ b/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py
@@ -50,17 +50,28 @@ class LoadClipBatch(opfapi.ClipLoader):
version_name = version.get("name", None)
colorspace = self.get_colorspace(context)
+ # TODO remove '{folder[name]}' and '{product[name]}' replacement
+ clip_name_template = (
+ self.clip_name_template
+ .replace("{folder[name]}", "{asset}")
+ .replace("{product[name]}", "{subset}")
+ )
+ layer_rename_template = (
+ self.layer_rename_template
+ .replace("{folder[name]}", "{asset}")
+ .replace("{product[name]}", "{subset}")
+ )
# in case output is not in context replace key to representation
if not context["representation"]["context"].get("output"):
- self.clip_name_template = self.clip_name_template.replace(
+ clip_name_template = clip_name_template.replace(
"output", "representation")
- self.layer_rename_template = self.layer_rename_template.replace(
+ layer_rename_template = layer_rename_template.replace(
"output", "representation")
formatting_data = deepcopy(context["representation"]["context"])
formatting_data["batch"] = self.batch.name.get_value()
- clip_name = StringTemplate(self.clip_name_template).format(
+ clip_name = StringTemplate(clip_name_template).format(
formatting_data)
# convert colorspace with ocio to flame mapping
@@ -86,7 +97,7 @@ class LoadClipBatch(opfapi.ClipLoader):
"path": path.replace("\\", "/"),
"colorspace": colorspace,
"version": "v{:0>3}".format(version_name),
- "layer_rename_template": self.layer_rename_template,
+ "layer_rename_template": layer_rename_template,
"layer_rename_patterns": self.layer_rename_patterns,
"context_data": formatting_data
}
diff --git a/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py b/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py
index af699fd03a..9e55dbce96 100644
--- a/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py
+++ b/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py
@@ -1,6 +1,5 @@
import os
import re
-import tempfile
from copy import deepcopy
import pyblish.api
@@ -15,12 +14,12 @@ from ayon_core.pipeline.editorial import (
import flame
-class ExtractSubsetResources(publish.Extractor):
+class ExtractProductResources(publish.Extractor):
"""
Extractor for transcoding files from Flame clip
"""
- label = "Extract subset resources"
+ label = "Extract product resources"
order = pyblish.api.ExtractorOrder
families = ["clip"]
hosts = ["flame"]
@@ -47,7 +46,7 @@ class ExtractSubsetResources(publish.Extractor):
hide_ui_on_process = True
# settings
- export_presets_mapping = {}
+ export_presets_mapping = []
def process(self, instance):
if not self.keep_original_representation:
@@ -146,15 +145,21 @@ class ExtractSubsetResources(publish.Extractor):
# append staging dir for later cleanup
instance.context.data["cleanupFullPaths"].append(staging_dir)
+ export_presets_mapping = {}
+ for preset_mapping in deepcopy(self.export_presets_mapping):
+ name = preset_mapping.pop("name")
+ export_presets_mapping[name] = preset_mapping
+
# add default preset type for thumbnail and reviewable video
# update them with settings and override in case the same
# are found in there
- _preset_keys = [k.split('_')[0] for k in self.export_presets_mapping]
+ _preset_keys = [k.split('_')[0] for k in export_presets_mapping]
export_presets = {
- k: v for k, v in deepcopy(self.default_presets).items()
+ k: v
+ for k, v in deepcopy(self.default_presets).items()
if k not in _preset_keys
}
- export_presets.update(self.export_presets_mapping)
+ export_presets.update(export_presets_mapping)
if not instance.data.get("versionData"):
instance.data["versionData"] = {}
diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py
index 12a29d2986..807bed59f7 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,
@@ -148,7 +147,16 @@ class GenericCreateSaver(Creator):
})
# build file path to render
- filepath = self.temp_rendering_path_template.format(**formatting_data)
+ # TODO make sure the keys are available in 'formatting_data'
+ temp_rendering_path_template = (
+ self.temp_rendering_path_template
+ .replace("{product[name]}", "{subset}")
+ .replace("{product[type]}", "{family}")
+ .replace("{folder[name]}", "{asset}")
+ .replace("{task[name]}", "{task}")
+ )
+
+ filepath = temp_rendering_path_template.format(**formatting_data)
comp = get_current_comp()
tool["Clip"] = comp.ReverseMapPath(os.path.normpath(filepath))
diff --git a/client/ayon_core/hosts/harmony/api/README.md b/client/ayon_core/hosts/harmony/api/README.md
index cdc17b2285..680a88c423 100644
--- a/client/ayon_core/hosts/harmony/api/README.md
+++ b/client/ayon_core/hosts/harmony/api/README.md
@@ -52,7 +52,7 @@ Because Harmony projects are directories, this integration uses `.zip` as work f
### Show Workfiles on launch
-You can show the Workfiles app when Harmony launches by setting environment variable `AVALON_HARMONY_WORKFILES_ON_LAUNCH=1`.
+You can show the Workfiles app when Harmony launches by setting environment variable `AYON_HARMONY_WORKFILES_ON_LAUNCH=1`.
## Developing
diff --git a/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js b/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js
index 1fb0d295e7..cdf60c1aa8 100644
--- a/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js
+++ b/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js
@@ -349,7 +349,7 @@ function start() {
/** hostname or ip of server - should be localhost */
var host = '127.0.0.1';
/** port of the server */
- var port = parseInt(System.getenv('AVALON_HARMONY_PORT'));
+ var port = parseInt(System.getenv('AYON_HARMONY_PORT'));
// Attach the client to the QApplication to preserve.
var app = QCoreApplication.instance();
diff --git a/client/ayon_core/hosts/harmony/api/lib.py b/client/ayon_core/hosts/harmony/api/lib.py
index 782134c343..bc73e19066 100644
--- a/client/ayon_core/hosts/harmony/api/lib.py
+++ b/client/ayon_core/hosts/harmony/api/lib.py
@@ -189,14 +189,14 @@ def launch(application_path, *args):
install_host(harmony)
ProcessContext.port = random.randrange(49152, 65535)
- os.environ["AVALON_HARMONY_PORT"] = str(ProcessContext.port)
+ os.environ["AYON_HARMONY_PORT"] = str(ProcessContext.port)
ProcessContext.application_path = application_path
# Launch Harmony.
setup_startup_scripts()
check_libs()
- if not os.environ.get("AVALON_HARMONY_WORKFILES_ON_LAUNCH", False):
+ if not os.environ.get("AYON_HARMONY_WORKFILES_ON_LAUNCH", False):
open_empty_workfile()
return
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/hosts/max/api/pipeline.py b/client/ayon_core/hosts/max/api/pipeline.py
index ff0267b39a..106c29fd26 100644
--- a/client/ayon_core/hosts/max/api/pipeline.py
+++ b/client/ayon_core/hosts/max/api/pipeline.py
@@ -63,9 +63,8 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
rt.callbacks.addScript(rt.Name('postWorkspaceChange'),
self._deferred_menu_creation)
- def has_unsaved_changes(self):
- # TODO: how to get it from 3dsmax?
- return True
+ def workfile_has_unsaved_changes(self):
+ return rt.getSaveRequired()
def get_workfile_extensions(self):
return [".max"]
@@ -243,3 +242,20 @@ def get_previous_loaded_object(container: str):
if str(obj) in sel_list:
node_list.append(obj)
return node_list
+
+
+def remove_container_data(container: str):
+ """Function to remove container data after updating, switching or deleting it.
+
+ Args:
+ container (str): container
+ """
+ if container.modifiers[0].name == "OP Data":
+ all_set_members_names = [
+ member.node for member
+ in container.modifiers[0].openPypeData.all_handles]
+ for current_set_member in all_set_members_names:
+ rt.Delete(current_set_member)
+ rt.deleteModifier(container, container.modifiers[0])
+
+ rt.Delete(container)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py
index 34b120c179..d7eebdbc3a 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py
@@ -1,6 +1,6 @@
import os
-from ayon_core.hosts.max.api import lib, maintained_selection
+from ayon_core.hosts.max.api import lib
from ayon_core.hosts.max.api.lib import (
unique_namespace,
get_namespace,
@@ -9,7 +9,8 @@ from ayon_core.hosts.max.api.lib import (
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -94,6 +95,5 @@ class FbxLoader(load.LoaderPlugin):
def remove(self, container):
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py
index 7267d7a59e..81f3af089f 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py
@@ -7,8 +7,10 @@ from ayon_core.hosts.max.api.lib import (
object_transform_set
)
from ayon_core.hosts.max.api.pipeline import (
- containerise, get_previous_loaded_object,
- update_custom_attribute_data
+ containerise,
+ get_previous_loaded_object,
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -93,6 +95,5 @@ class MaxSceneLoader(load.LoaderPlugin):
def remove(self, container):
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_model.py b/client/ayon_core/hosts/max/plugins/load/load_model.py
index 796e1b80ad..28ec7be01f 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_model.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_model.py
@@ -2,11 +2,13 @@ import os
from ayon_core.pipeline import load, get_representation_path
from ayon_core.hosts.max.api.pipeline import (
containerise,
- get_previous_loaded_object
+ get_previous_loaded_object,
+ remove_container_data
)
from ayon_core.hosts.max.api import lib
from ayon_core.hosts.max.api.lib import (
- maintained_selection, unique_namespace
+ maintained_selection,
+ unique_namespace
)
@@ -99,7 +101,7 @@ class ModelAbcLoader(load.LoaderPlugin):
from pymxs import runtime as rt
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
@staticmethod
def get_container_children(parent, type_name):
diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py
index 827cf63b39..81ad84546a 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py
@@ -1,8 +1,10 @@
import os
from ayon_core.pipeline import load, get_representation_path
from ayon_core.hosts.max.api.pipeline import (
- containerise, get_previous_loaded_object,
- update_custom_attribute_data
+ containerise,
+ get_previous_loaded_object,
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.hosts.max.api import lib
from ayon_core.hosts.max.api.lib import (
@@ -92,6 +94,5 @@ class FbxModelLoader(load.LoaderPlugin):
def remove(self, container):
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
index 22d3d4b58a..1023b67f0c 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py
@@ -11,7 +11,8 @@ from ayon_core.hosts.max.api.lib import maintained_selection
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -84,6 +85,5 @@ class ObjLoader(load.LoaderPlugin):
def remove(self, container):
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py
index 8d42219217..6a08bebf5a 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py
@@ -13,7 +13,8 @@ from ayon_core.hosts.max.api.lib import maintained_selection
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -114,4 +115,4 @@ class ModelUSDLoader(load.LoaderPlugin):
def remove(self, container):
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py
index a92fa66757..d7267afb7d 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py
@@ -10,7 +10,8 @@ from ayon_core.hosts.max.api import lib, maintained_selection
from ayon_core.hosts.max.api.lib import unique_namespace
from ayon_core.hosts.max.api.pipeline import (
containerise,
- get_previous_loaded_object
+ get_previous_loaded_object,
+ remove_container_data
)
@@ -105,7 +106,7 @@ class AbcLoader(load.LoaderPlugin):
from pymxs import runtime as rt
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
@staticmethod
def get_container_children(parent, type_name):
diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py
index 27b2e271d2..5b48e5d189 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py
@@ -4,7 +4,8 @@ from ayon_core.pipeline.load import LoadError
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.hosts.max.api.lib import (
@@ -105,4 +106,4 @@ class OxAbcLoader(load.LoaderPlugin):
def remove(self, container):
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
\ No newline at end of file
diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py
index 45e3da5621..7f4fba50b3 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py
@@ -8,7 +8,8 @@ from ayon_core.hosts.max.api.lib import (
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -63,6 +64,5 @@ class PointCloudLoader(load.LoaderPlugin):
def remove(self, container):
"""remove the container"""
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py
index 3f73210c24..3ccc5cc5e1 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py
@@ -9,7 +9,8 @@ from ayon_core.pipeline.load import LoadError
from ayon_core.hosts.max.api.pipeline import (
containerise,
update_custom_attribute_data,
- get_previous_loaded_object
+ get_previous_loaded_object,
+ remove_container_data
)
from ayon_core.hosts.max.api import lib
from ayon_core.hosts.max.api.lib import (
@@ -72,6 +73,5 @@ class RedshiftProxyLoader(load.LoaderPlugin):
def remove(self, container):
from pymxs import runtime as rt
-
node = rt.getNodeByName(container["instance_node"])
- rt.delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/load/load_tycache.py b/client/ayon_core/hosts/max/plugins/load/load_tycache.py
index 48fb5c447a..97f41026b4 100644
--- a/client/ayon_core/hosts/max/plugins/load/load_tycache.py
+++ b/client/ayon_core/hosts/max/plugins/load/load_tycache.py
@@ -1,13 +1,13 @@
import os
from ayon_core.hosts.max.api import lib, maintained_selection
from ayon_core.hosts.max.api.lib import (
- unique_namespace,
-
+ unique_namespace
)
from ayon_core.hosts.max.api.pipeline import (
containerise,
get_previous_loaded_object,
- update_custom_attribute_data
+ update_custom_attribute_data,
+ remove_container_data
)
from ayon_core.pipeline import get_representation_path, load
@@ -59,6 +59,5 @@ class TyCacheLoader(load.LoaderPlugin):
def remove(self, container):
"""remove the container"""
from pymxs import runtime as rt
-
node = rt.GetNodeByName(container["instance_node"])
- rt.Delete(node)
+ remove_container_data(node)
diff --git a/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py b/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py
index 294d63794e..67dde7f0a6 100644
--- a/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py
+++ b/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py
@@ -155,7 +155,9 @@ class ExtractPointCloud(publish.Extractor):
custom_attr_list = []
attr_settings = self.settings["attribute"]
- for key, value in attr_settings.items():
+ for attr in attr_settings:
+ key = attr["name"]
+ value = attr["value"]
custom_attr = "{0}.PRTChannels_{1}=True".format(operator,
value)
self.log.debug(
diff --git a/client/ayon_core/hosts/max/plugins/publish/save_scene.py b/client/ayon_core/hosts/max/plugins/publish/save_scene.py
index a40788ab41..1c59335ceb 100644
--- a/client/ayon_core/hosts/max/plugins/publish/save_scene.py
+++ b/client/ayon_core/hosts/max/plugins/publish/save_scene.py
@@ -1,11 +1,9 @@
import pyblish.api
-import os
+from ayon_core.pipeline import registered_host
class SaveCurrentScene(pyblish.api.ContextPlugin):
- """Save current scene
-
- """
+ """Save current scene"""
label = "Save current file"
order = pyblish.api.ExtractorOrder - 0.49
@@ -13,9 +11,13 @@ class SaveCurrentScene(pyblish.api.ContextPlugin):
families = ["maxrender", "workfile"]
def process(self, context):
- from pymxs import runtime as rt
- folder = rt.maxFilePath
- file = rt.maxFileName
- current = os.path.join(folder, file)
- assert context.data["currentFile"] == current
- rt.saveMaxFile(current)
+ host = registered_host()
+ current_file = host.get_current_workfile()
+
+ assert context.data["currentFile"] == current_file
+
+ if host.workfile_has_unsaved_changes():
+ self.log.info(f"Saving current file: {current_file}")
+ host.save_workfile(current_file)
+ else:
+ self.log.debug("No unsaved changes, skipping file save..")
\ No newline at end of file
diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py b/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py
index 444a8f0829..354539871f 100644
--- a/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py
+++ b/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
"""Validator for Attributes."""
+import json
+
from pyblish.api import ContextPlugin, ValidatorOrder
from pymxs import runtime as rt
@@ -61,9 +63,13 @@ class ValidateAttributes(OptionalPyblishPluginMixin,
@classmethod
def get_invalid(cls, context):
- attributes = (
- context.data["project_settings"]["max"]["publish"]
- ["ValidateAttributes"]["attributes"]
+ attributes = json.loads(
+ context.data
+ ["project_settings"]
+ ["max"]
+ ["publish"]
+ ["ValidateAttributes"]
+ ["attributes"]
)
if not attributes:
return
@@ -112,9 +118,13 @@ class ValidateAttributes(OptionalPyblishPluginMixin,
@classmethod
def repair(cls, context):
- attributes = (
- context.data["project_settings"]["max"]["publish"]
- ["ValidateAttributes"]["attributes"]
+ attributes = json.loads(
+ context.data
+ ["project_settings"]
+ ["max"]
+ ["publish"]
+ ["ValidateAttributes"]
+ ["attributes"]
)
invalid_attributes = cls.get_invalid(context)
for attrs in invalid_attributes:
diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py b/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py
index fe6e32b27b..bf5ac26fef 100644
--- a/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py
+++ b/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py
@@ -25,7 +25,7 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin,
optional = True
actions = [RepairAction]
- family_plugins_mapping = {}
+ family_plugins_mapping = []
@classmethod
def get_invalid(cls, instance):
@@ -34,6 +34,12 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin,
if not family_plugins_mapping:
return
+ # Backward compatibility - settings did have 'product_types'
+ if "product_types" in family_plugins_mapping:
+ family_plugins_mapping["families"] = family_plugins_mapping.pop(
+ "product_types"
+ )
+
invalid = []
# Find all plug-in requirements for current instance
instance_families = {instance.data["family"]}
@@ -47,7 +53,9 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin,
if not mapping:
return
- match_families = {fam.strip() for fam in mapping["families"]}
+ match_families = {
+ fam.strip() for fam in mapping["families"]
+ }
has_match = "*" in match_families or match_families.intersection(
instance_families)
diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py b/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py
index a025ed3992..73b18984ed 100644
--- a/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py
+++ b/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py
@@ -59,7 +59,9 @@ class ValidatePointCloud(pyblish.api.InstancePlugin):
event_name = sub_anim.name
opt = "${0}.{1}.export_particles".format(sel.name,
event_name)
- for key, value in attr_settings.items():
+ for attr in attr_settings:
+ key = attr["name"]
+ value = attr["value"]
custom_attr = "{0}.PRTChannels_{1}".format(opt,
value)
try:
diff --git a/client/ayon_core/hosts/max/startup/startup.ms b/client/ayon_core/hosts/max/startup/startup.ms
index b80ead4b74..4c597901f3 100644
--- a/client/ayon_core/hosts/max/startup/startup.ms
+++ b/client/ayon_core/hosts/max/startup/startup.ms
@@ -8,5 +8,8 @@
local pythonpath = systemTools.getEnvVariable "MAX_PYTHONPATH"
systemTools.setEnvVariable "PYTHONPATH" pythonpath
+ /*opens the create menu on startup to ensure users are presented with a useful default view.*/
+ max create mode
+
python.ExecuteFile startup
)
\ No newline at end of file
diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py
index 7b791c3d51..3a29fe433b 100644
--- a/client/ayon_core/hosts/maya/api/lib.py
+++ b/client/ayon_core/hosts/maya/api/lib.py
@@ -329,7 +329,7 @@ def generate_capture_preset(instance, camera, path,
# Update preset with current panel setting
# if override_viewport_options is turned off
- if not capture_preset["Viewport Options"]["override_viewport_options"]:
+ if not capture_preset["ViewportOptions"]["override_viewport_options"]:
panel_preset = capture.parse_view(preset["panel"])
panel_preset.pop("camera")
preset.update(panel_preset)
@@ -2937,14 +2937,15 @@ def load_capture_preset(data):
options.update(data["Generic"])
options.update(data["Resolution"])
- camera_options.update(data['Camera Options'])
+ camera_options.update(data["CameraOptions"])
viewport_options.update(data["Renderer"])
# DISPLAY OPTIONS
disp_options = {}
- for key, value in data['Display Options'].items():
- if key.startswith('background'):
+ for key, value in data["DisplayOptions"].items():
+ if key.startswith("background"):
# Convert background, backgroundTop, backgroundBottom colors
+
if len(value) == 4:
# Ignore alpha + convert RGB to float
value = [
@@ -2956,7 +2957,7 @@ def load_capture_preset(data):
elif key == "displayGradient":
disp_options[key] = value
- options['display_options'] = disp_options
+ options["display_options"] = disp_options
# Viewport Options has a mixture of Viewport2 Options and Viewport Options
# to pass along to capture. So we'll need to differentiate between the two
@@ -2981,7 +2982,7 @@ def load_capture_preset(data):
"motionBlurShutterOpenFraction",
"lineAAEnable"
}
- for key, value in data['Viewport Options'].items():
+ for key, value in data["ViewportOptions"].items():
# There are some keys we want to ignore
if key in {"override_viewport_options", "high_quality"}:
@@ -3140,119 +3141,6 @@ def fix_incompatible_containers():
"ReferenceLoader", type="string")
-def _null(*args):
- pass
-
-
-class shelf():
- '''A simple class to build shelves in maya. Since the build method is empty,
- it should be extended by the derived class to build the necessary shelf
- elements. By default it creates an empty shelf called "customShelf".'''
-
- ###########################################################################
- '''This is an example shelf.'''
- # class customShelf(_shelf):
- # def build(self):
- # self.addButon(label="button1")
- # self.addButon("button2")
- # self.addButon("popup")
- # p = cmds.popupMenu(b=1)
- # self.addMenuItem(p, "popupMenuItem1")
- # self.addMenuItem(p, "popupMenuItem2")
- # sub = self.addSubMenu(p, "subMenuLevel1")
- # self.addMenuItem(sub, "subMenuLevel1Item1")
- # sub2 = self.addSubMenu(sub, "subMenuLevel2")
- # self.addMenuItem(sub2, "subMenuLevel2Item1")
- # self.addMenuItem(sub2, "subMenuLevel2Item2")
- # self.addMenuItem(sub, "subMenuLevel1Item2")
- # self.addMenuItem(p, "popupMenuItem3")
- # self.addButon("button3")
- # customShelf()
- ###########################################################################
-
- def __init__(self, name="customShelf", iconPath="", preset={}):
- self.name = name
-
- self.iconPath = iconPath
-
- self.labelBackground = (0, 0, 0, 0)
- self.labelColour = (.9, .9, .9)
-
- self.preset = preset
-
- self._cleanOldShelf()
- cmds.setParent(self.name)
- self.build()
-
- def build(self):
- '''This method should be overwritten in derived classes to actually
- build the shelf elements. Otherwise, nothing is added to the shelf.'''
- for item in self.preset['items']:
- if not item.get('command'):
- item['command'] = self._null
- if item['type'] == 'button':
- self.addButon(item['name'],
- command=item['command'],
- icon=item['icon'])
- if item['type'] == 'menuItem':
- self.addMenuItem(item['parent'],
- item['name'],
- command=item['command'],
- icon=item['icon'])
- if item['type'] == 'subMenu':
- self.addMenuItem(item['parent'],
- item['name'],
- command=item['command'],
- icon=item['icon'])
-
- def addButon(self, label, icon="commandButton.png",
- command=_null, doubleCommand=_null):
- '''
- Adds a shelf button with the specified label, command,
- double click command and image.
- '''
- cmds.setParent(self.name)
- if icon:
- icon = os.path.join(self.iconPath, icon)
- print(icon)
- cmds.shelfButton(width=37, height=37, image=icon, label=label,
- command=command, dcc=doubleCommand,
- imageOverlayLabel=label, olb=self.labelBackground,
- olc=self.labelColour)
-
- def addMenuItem(self, parent, label, command=_null, icon=""):
- '''
- Adds a shelf button with the specified label, command,
- double click command and image.
- '''
- if icon:
- icon = os.path.join(self.iconPath, icon)
- print(icon)
- return cmds.menuItem(p=parent, label=label, c=command, i="")
-
- def addSubMenu(self, parent, label, icon=None):
- '''
- Adds a sub menu item with the specified label and icon to
- the specified parent popup menu.
- '''
- if icon:
- icon = os.path.join(self.iconPath, icon)
- print(icon)
- return cmds.menuItem(p=parent, label=label, i=icon, subMenu=1)
-
- def _cleanOldShelf(self):
- '''
- Checks if the shelf exists and empties it if it does
- or creates it if it does not.
- '''
- if cmds.shelfLayout(self.name, ex=1):
- if cmds.shelfLayout(self.name, q=1, ca=1):
- for each in cmds.shelfLayout(self.name, q=1, ca=1):
- cmds.deleteUI(each)
- else:
- cmds.shelfLayout(self.name, p="ShelfLayout")
-
-
def update_content_on_context_change():
"""
This will update scene content to match new asset on context change
@@ -4059,10 +3947,10 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log):
Args:
task_name (str): Task name.
- take_type (str): Task type.
+ task_type (str): Task type.
subset (str): Subset name.
project_settings (dict): Project settings.
- log (object): Logging object.
+ log (logging.Logger): Logging object.
"""
capture_preset = None
filtering_criteria = {
@@ -4091,8 +3979,18 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log):
"Falling back to deprecated Extract Playblast capture preset "
"because no new style playblast profiles are defined."
)
- capture_preset = plugin_settings["capture_preset"]
+ capture_preset = plugin_settings.get("capture_preset")
+ if capture_preset:
+ # Create deepcopy of preset as we'll change the values
+ capture_preset = copy.deepcopy(capture_preset)
+
+ viewport_options = capture_preset["ViewportOptions"]
+ # Change 'list' to 'dict' for 'capture.py'
+ viewport_options["pluginObjects"] = {
+ item["name"]: item["value"]
+ for item in viewport_options["pluginObjects"]
+ }
return capture_preset or {}
diff --git a/client/ayon_core/hosts/maya/api/lib_rendersettings.py b/client/ayon_core/hosts/maya/api/lib_rendersettings.py
index 54ee7888b3..b8a4d04a10 100644
--- a/client/ayon_core/hosts/maya/api/lib_rendersettings.py
+++ b/client/ayon_core/hosts/maya/api/lib_rendersettings.py
@@ -46,7 +46,7 @@ class RenderSettings(object):
project_settings = get_project_settings(
get_current_project_name()
)
- render_settings = project_settings["maya"]["RenderSettings"]
+ render_settings = project_settings["maya"]["render_settings"]
image_prefixes = {
"vray": render_settings["vray_renderer"]["image_prefix"],
"arnold": render_settings["arnold_renderer"]["image_prefix"],
@@ -82,12 +82,12 @@ class RenderSettings(object):
try:
aov_separator = self._aov_chars[(
self._project_settings["maya"]
- ["RenderSettings"]
+ ["render_settings"]
["aov_separator"]
)]
except KeyError:
aov_separator = "_"
- reset_frame = self._project_settings["maya"]["RenderSettings"]["reset_current_frame"] # noqa
+ reset_frame = self._project_settings["maya"]["render_settings"]["reset_current_frame"] # noqa
if reset_frame:
start_frame = cmds.getAttr("defaultRenderGlobals.startFrame")
@@ -131,7 +131,7 @@ class RenderSettings(object):
import maya.mel as mel # noqa: F401
createOptions()
- render_settings = self._project_settings["maya"]["RenderSettings"]
+ render_settings = self._project_settings["maya"]["render_settings"]
arnold_render_presets = render_settings["arnold_renderer"] # noqa
# Force resetting settings and AOV list to avoid having to deal with
# AOV checking logic, for now.
@@ -180,7 +180,7 @@ class RenderSettings(object):
from maya import cmds # noqa: F401
import maya.mel as mel # noqa: F401
- render_settings = self._project_settings["maya"]["RenderSettings"]
+ render_settings = self._project_settings["maya"]["render_settings"]
redshift_render_presets = render_settings["redshift_renderer"]
remove_aovs = render_settings["remove_aovs"]
@@ -239,7 +239,7 @@ class RenderSettings(object):
rman_render_presets = (
self._project_settings
["maya"]
- ["RenderSettings"]
+ ["render_settings"]
["renderman_renderer"]
)
display_filters = rman_render_presets["display_filters"]
@@ -304,7 +304,7 @@ class RenderSettings(object):
settings = cmds.ls(type="VRaySettingsNode")
node = settings[0] if settings else cmds.createNode("VRaySettingsNode")
- render_settings = self._project_settings["maya"]["RenderSettings"]
+ render_settings = self._project_settings["maya"]["render_settings"]
vray_render_presets = render_settings["vray_renderer"]
# vrayRenderElement
remove_aovs = render_settings["remove_aovs"]
@@ -390,7 +390,8 @@ class RenderSettings(object):
import maya.mel as mel # noqa: F401
for item in additional_attribs:
- attribute, value = item
+ attribute = item["attribute"]
+ value = item["value"]
attribute = str(attribute) # ensure str conversion from settings
attribute_type = cmds.getAttr(attribute, type=True)
if attribute_type in {"long", "bool"}:
diff --git a/client/ayon_core/hosts/maya/api/menu.py b/client/ayon_core/hosts/maya/api/menu.py
index 7478739496..70347e91b6 100644
--- a/client/ayon_core/hosts/maya/api/menu.py
+++ b/client/ayon_core/hosts/maya/api/menu.py
@@ -9,7 +9,8 @@ import maya.cmds as cmds
from ayon_core.pipeline import (
get_current_asset_name,
- get_current_task_name
+ get_current_task_name,
+ registered_host
)
from ayon_core.pipeline.workfile import BuildWorkfile
from ayon_core.tools.utils import host_tools
@@ -21,8 +22,10 @@ from .workfile_template_builder import (
create_placeholder,
update_placeholder,
build_workfile_template,
- update_workfile_template,
+ update_workfile_template
)
+from ayon_core.tools.workfile_template_build import open_template_ui
+from .workfile_template_builder import MayaTemplateBuilder
log = logging.getLogger(__name__)
@@ -167,16 +170,6 @@ def install(project_settings):
tearOff=True,
parent=MENU_NAME
)
- cmds.menuItem(
- "Create Placeholder",
- parent=builder_menu,
- command=create_placeholder
- )
- cmds.menuItem(
- "Update Placeholder",
- parent=builder_menu,
- command=update_placeholder
- )
cmds.menuItem(
"Build Workfile from template",
parent=builder_menu,
@@ -187,6 +180,27 @@ def install(project_settings):
parent=builder_menu,
command=update_workfile_template
)
+ cmds.menuItem(
+ divider=True,
+ parent=builder_menu
+ )
+ cmds.menuItem(
+ "Open Template",
+ parent=builder_menu,
+ command=lambda *args: open_template_ui(
+ MayaTemplateBuilder(registered_host()), get_main_window()
+ ),
+ )
+ cmds.menuItem(
+ "Create Placeholder",
+ parent=builder_menu,
+ command=create_placeholder
+ )
+ cmds.menuItem(
+ "Update Placeholder",
+ parent=builder_menu,
+ command=update_placeholder
+ )
cmds.setParent(MENU_NAME, menu=True)
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/api/plugin.py b/client/ayon_core/hosts/maya/api/plugin.py
index c5e3f42d10..aba5fd8903 100644
--- a/client/ayon_core/hosts/maya/api/plugin.py
+++ b/client/ayon_core/hosts/maya/api/plugin.py
@@ -22,6 +22,7 @@ from ayon_core.pipeline import (
LegacyCreator,
LoaderPlugin,
get_representation_path,
+ get_current_project_name,
)
from ayon_core.pipeline.load import LoadError
from ayon_core.client import get_asset_by_name
@@ -585,6 +586,39 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase):
project_name)
+def get_load_color_for_family(family, settings=None):
+ """Get color for family from settings.
+
+ Args:
+ family (str): Family name.
+ settings (Optional[dict]): Settings dictionary.
+
+ Returns:
+ Union[tuple[float, float, float], None]: RGB color.
+
+ """
+ if settings is None:
+ settings = get_project_settings(get_current_project_name())
+
+ colors = settings["maya"]["load"]["colors"]
+ color = colors.get(family)
+ if not color:
+ return None
+
+ if len(color) == 3:
+ red, green, blue = color
+ elif len(color) == 4:
+ red, green, blue, _ = color
+ else:
+ raise ValueError("Invalid color definition {}".format(str(color)))
+
+ if type(red, int):
+ red = red / 255.0
+ green = green / 255.0
+ blue = blue / 255.0
+ return red, green, blue
+
+
class Loader(LoaderPlugin):
hosts = ["maya"]
@@ -611,33 +645,38 @@ class Loader(LoaderPlugin):
options["attach_to_root"] = True
custom_naming = self.load_settings[loader_key]
- if not custom_naming['namespace']:
+ if not custom_naming["namespace"]:
raise LoadError("No namespace specified in "
"Maya ReferenceLoader settings")
- elif not custom_naming['group_name']:
+ elif not custom_naming["group_name"]:
self.log.debug("No custom group_name, no group will be created.")
options["attach_to_root"] = False
- asset = context['asset']
- subset = context['subset']
+ asset = context["asset"]
+ subset = context["subset"]
+ family = (
+ subset["data"].get("family")
+ or subset["data"]["families"][0]
+ )
formatting_data = {
- "asset_name": asset['name'],
- "asset_type": asset['type'],
+ "asset_name": asset["name"],
+ "asset_type": asset["type"],
"folder": {
"name": asset["name"],
},
- "subset": subset['name'],
- "family": (
- subset['data'].get('family') or
- subset['data']['families'][0]
- )
+ "subset": subset["name"],
+ "product": {
+ "name": subset["name"],
+ "type": family,
+ },
+ "family": family
}
- custom_namespace = custom_naming['namespace'].format(
+ custom_namespace = custom_naming["namespace"].format(
**formatting_data
)
- custom_group_name = custom_naming['group_name'].format(
+ custom_group_name = custom_naming["group_name"].format(
**formatting_data
)
@@ -937,7 +976,7 @@ class ReferenceLoader(Loader):
"""
settings = get_project_settings(project_name)
use_env_var_as_root = (settings["maya"]
- ["maya-dirmap"]
+ ["maya_dirmap"]
["use_env_var_as_root"])
if use_env_var_as_root:
anatomy = Anatomy(project_name)
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_render.py b/client/ayon_core/hosts/maya/plugins/create/create_render.py
index f537f249cd..4481836c89 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_render.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_render.py
@@ -35,7 +35,7 @@ class CreateRenderlayer(plugin.RenderlayerCreator):
@classmethod
def apply_settings(cls, project_settings):
- cls.render_settings = project_settings["maya"]["RenderSettings"]
+ cls.render_settings = project_settings["maya"]["render_settings"]
def create(self, subset_name, instance_data, pre_create_data):
# Only allow a single render instance to exist
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_review.py b/client/ayon_core/hosts/maya/plugins/create/create_review.py
index 6f7c0ca802..3e75b52556 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_review.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_review.py
@@ -75,7 +75,7 @@ class CreateReview(plugin.MayaCreator):
"review_width": preset["Resolution"]["width"],
"review_height": preset["Resolution"]["height"],
"isolate": preset["Generic"]["isolate_view"],
- "imagePlane": preset["Viewport Options"]["imagePlane"],
+ "imagePlane": preset["ViewportOptions"]["imagePlane"],
"panZoom": preset["Generic"]["pan_zoom"]
}
for key, value in mapping.items():
diff --git a/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py b/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py
index 3642f5f689..bc8110eff1 100644
--- a/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py
+++ b/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py
@@ -23,7 +23,7 @@ class CreateVRayScene(plugin.RenderlayerCreator):
@classmethod
def apply_settings(cls, project_settings):
- cls.render_settings = project_settings["maya"]["RenderSettings"]
+ cls.render_settings = project_settings["maya"]["render_settings"]
def create(self, subset_name, instance_data, pre_create_data):
# Only allow a single render instance to exist
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..16ac460cf7 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 (
@@ -16,6 +15,7 @@ from ayon_core.hosts.maya.api.lib import (
convert_to_maya_fps
)
from ayon_core.hosts.maya.api.pipeline import containerise
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
def is_sequence(files):
@@ -26,11 +26,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"""
@@ -72,11 +67,12 @@ class ArnoldStandinLoader(load.LoaderPlugin):
# Set color.
settings = get_project_settings(context["project"]["name"])
- color = settings['maya']['load']['colors'].get('ass')
+ color = get_load_color_for_family("ass", settings)
if color is not None:
+ red, green, blue = color
cmds.setAttr(root + ".useOutlinerColor", True)
cmds.setAttr(
- root + ".outlinerColor", color[0], color[1], color[2]
+ root + ".outlinerColor", red, green, blue
)
with maintained_selection():
@@ -99,7 +95,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/load/load_gpucache.py b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
index 00a76d374b..cdaaeeae6a 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py
@@ -9,6 +9,7 @@ from ayon_core.pipeline import (
get_representation_path
)
from ayon_core.settings import get_project_settings
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
class GpuCacheLoader(load.LoaderPlugin):
@@ -39,13 +40,12 @@ class GpuCacheLoader(load.LoaderPlugin):
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
- c = colors.get('model')
- if c is not None:
+ color = get_load_color_for_family("model", settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(root + ".useOutlinerColor", 1)
cmds.setAttr(
- root + ".outlinerColor",
- (float(c[0]) / 255), (float(c[1]) / 255), (float(c[2]) / 255)
+ root + ".outlinerColor", red, green, blue
)
# Create transform with shape
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py
index dd378602c9..8910d0fcd0 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py
@@ -16,6 +16,7 @@ from ayon_core.hosts.maya.api.lib import (
unique_namespace
)
from ayon_core.hosts.maya.api.pipeline import containerise
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
class RedshiftProxyLoader(load.LoaderPlugin):
@@ -59,12 +60,13 @@ class RedshiftProxyLoader(load.LoaderPlugin):
# colour the group node
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1)
- cmds.setAttr("{0}.outlinerColor".format(group_node),
- c[0], c[1], c[2])
+ cmds.setAttr(
+ "{0}.outlinerColor".format(group_node), red, green, blue
+ )
return containerise(
name=name,
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_reference.py b/client/ayon_core/hosts/maya/plugins/load/load_reference.py
index 36bd2e5969..75f42a9fe6 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_reference.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_reference.py
@@ -1,4 +1,3 @@
-import os
import difflib
import contextlib
@@ -6,7 +5,7 @@ from maya import cmds
import qargparse
from ayon_core.settings import get_project_settings
-import ayon_core.hosts.maya.api.plugin
+from ayon_core.hosts.maya.api import plugin
from ayon_core.hosts.maya.api.lib import (
maintained_selection,
get_container_members,
@@ -87,7 +86,7 @@ def preserve_modelpanel_cameras(container, log=None):
cmds.modelPanel(panel, edit=True, camera=new_camera)
-class ReferenceLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
+class ReferenceLoader(plugin.ReferenceLoader):
"""Reference file"""
families = ["model",
@@ -185,14 +184,16 @@ class ReferenceLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
"{}.displayHandle".format(group_name), display_handle
)
- colors = settings['maya']['load']['colors']
- c = colors.get(family)
- if c is not None:
+ color = plugin.get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr("{}.useOutlinerColor".format(group_name), 1)
- cmds.setAttr("{}.outlinerColor".format(group_name),
- (float(c[0]) / 255),
- (float(c[1]) / 255),
- (float(c[2]) / 255))
+ cmds.setAttr(
+ "{}.outlinerColor".format(group_name),
+ red,
+ green,
+ blue
+ )
cmds.setAttr(
"{}.displayHandle".format(group_name), display_handle
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py
index 98f98330d7..c68fddc60a 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py
@@ -5,6 +5,7 @@ from ayon_core.pipeline import (
load,
get_representation_path
)
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
# TODO aiVolume doesn't automatically set velocity fps correctly, set manual?
@@ -50,16 +51,11 @@ class LoadVDBtoArnold(load.LoaderPlugin):
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
-
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(root + ".useOutlinerColor", 1)
- cmds.setAttr(root + ".outlinerColor",
- (float(c[0]) / 255),
- (float(c[1]) / 255),
- (float(c[2]) / 255)
- )
+ cmds.setAttr(root + ".outlinerColor", red, green, blue)
# Create VRayVolumeGrid
grid_node = cmds.createNode("aiVolume",
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py
index 426e85cf7c..1bc75ae4c6 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py
@@ -5,6 +5,7 @@ from ayon_core.pipeline import (
load,
get_representation_path
)
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
class LoadVDBtoRedShift(load.LoaderPlugin):
@@ -69,16 +70,11 @@ class LoadVDBtoRedShift(load.LoaderPlugin):
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
-
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(root + ".useOutlinerColor", 1)
- cmds.setAttr(root + ".outlinerColor",
- (float(c[0])/255),
- (float(c[1])/255),
- (float(c[2])/255)
- )
+ cmds.setAttr(root + ".outlinerColor", red, green, blue)
# Create VR
volume_node = cmds.createNode("RedshiftVolumeShape",
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py
index ca0519900b..0c87162629 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py
@@ -5,6 +5,7 @@ from ayon_core.pipeline import (
load,
get_representation_path
)
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
from maya import cmds
@@ -129,15 +130,11 @@ class LoadVDBtoVRay(load.LoaderPlugin):
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
-
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(root + ".useOutlinerColor", 1)
- cmds.setAttr(root + ".outlinerColor",
- float(c[0]) / 255,
- float(c[1]) / 255,
- float(c[2]) / 255)
+ cmds.setAttr(root + ".outlinerColor", red, green, blue)
# Create VRayVolumeGrid
grid_node = cmds.createNode("VRayVolumeGrid",
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py
index 9b36303b64..50b63f4f11 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py
@@ -22,6 +22,7 @@ from ayon_core.hosts.maya.api.lib import (
unique_namespace
)
from ayon_core.hosts.maya.api.pipeline import containerise
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
class VRayProxyLoader(load.LoaderPlugin):
@@ -80,15 +81,12 @@ class VRayProxyLoader(load.LoaderPlugin):
# colour the group node
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1)
cmds.setAttr(
- "{0}.outlinerColor".format(group_node),
- (float(c[0]) / 255),
- (float(c[1]) / 255),
- (float(c[2]) / 255)
+ "{0}.outlinerColor".format(group_node), red, green, blue
)
return containerise(
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py
index 92d2b32549..7b4edb0567 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-import os
import maya.cmds as cmds # noqa
from ayon_core.settings import get_project_settings
from ayon_core.pipeline import (
@@ -12,6 +11,7 @@ from ayon_core.hosts.maya.api.lib import (
unique_namespace
)
from ayon_core.hosts.maya.api.pipeline import containerise
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
class VRaySceneLoader(load.LoaderPlugin):
@@ -58,14 +58,12 @@ class VRaySceneLoader(load.LoaderPlugin):
# colour the group node
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr("{0}.useOutlinerColor".format(root_node), 1)
- cmds.setAttr("{0}.outlinerColor".format(root_node),
- (float(c[0])/255),
- (float(c[1])/255),
- (float(c[2])/255)
+ cmds.setAttr(
+ "{0}.outlinerColor".format(root_node), red, green, blue
)
return containerise(
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py
index d2fc1c0ab0..afbb632d87 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py
@@ -13,6 +13,7 @@ from ayon_core.pipeline import (
)
from ayon_core.hosts.maya.api import lib
from ayon_core.hosts.maya.api.pipeline import containerise
+from ayon_core.hosts.maya.api.plugin import get_load_color_for_family
# Do not reset these values on update but only apply on first load
@@ -81,16 +82,11 @@ class YetiCacheLoader(load.LoaderPlugin):
project_name = context["project"]["name"]
settings = get_project_settings(project_name)
- colors = settings['maya']['load']['colors']
-
- c = colors.get(family)
- if c is not None:
+ color = get_load_color_for_family(family, settings)
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(group_node + ".useOutlinerColor", 1)
- cmds.setAttr(group_node + ".outlinerColor",
- (float(c[0])/255),
- (float(c[1])/255),
- (float(c[2])/255)
- )
+ cmds.setAttr(group_node + ".outlinerColor", red, green, blue)
nodes.append(group_node)
diff --git a/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py b/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py
index 2572e550e2..e7178be38b 100644
--- a/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py
+++ b/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py
@@ -1,11 +1,10 @@
import maya.cmds as cmds
-from ayon_core.settings import get_current_project_settings
-import ayon_core.hosts.maya.api.plugin
+from ayon_core.hosts.maya.api import plugin
from ayon_core.hosts.maya.api import lib
-class YetiRigLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
+class YetiRigLoader(plugin.ReferenceLoader):
"""This loader will load Yeti rig."""
families = ["yetiRig"]
@@ -41,14 +40,12 @@ class YetiRigLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
groupName=group_name
)
- settings = get_current_project_settings()
- colors = settings["maya"]["load"]["colors"]
- c = colors.get("yetiRig")
- if c is not None:
+ color = plugin.get_load_color_for_family("yetiRig")
+ if color is not None:
+ red, green, blue = color
cmds.setAttr(group_name + ".useOutlinerColor", 1)
cmds.setAttr(
- group_name + ".outlinerColor",
- (float(c[0]) / 255), (float(c[1]) / 255), (float(c[2]) / 255)
+ group_name + ".outlinerColor", red, green, blue
)
self[:] = nodes
diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_review.py b/client/ayon_core/hosts/maya/plugins/publish/collect_review.py
index 679a21243a..205c871c93 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/collect_review.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/collect_review.py
@@ -39,7 +39,7 @@ class CollectReview(pyblish.api.InstancePlugin):
if display_lights == "project_settings":
settings = instance.context.data["project_settings"]
settings = settings["maya"]["publish"]["ExtractPlayblast"]
- settings = settings["capture_preset"]["Viewport Options"]
+ settings = settings["capture_preset"]["ViewportOptions"]
display_lights = settings["displayLights"]
# Collect camera focal length.
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/extract_camera_alembic.py b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py
index b9561e299e..2be9cfec95 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py
@@ -1,4 +1,5 @@
import os
+import json
from maya import cmds
@@ -21,7 +22,7 @@ class ExtractCameraAlembic(publish.Extractor,
label = "Extract Camera (Alembic)"
hosts = ["maya"]
families = ["camera", "matchmove"]
- bake_attributes = []
+ bake_attributes = "[]"
def process(self, instance):
@@ -95,11 +96,12 @@ class ExtractCameraAlembic(publish.Extractor,
job_str += ' -file "{0}"'.format(path)
+ bake_attributes = json.loads(self.bake_attributes)
# bake specified attributes in preset
- assert isinstance(self.bake_attributes, (list, tuple)), (
+ assert isinstance(bake_attributes, list), (
"Attributes to bake must be specified as a list"
)
- for attr in self.bake_attributes:
+ for attr in bake_attributes:
self.log.debug("Adding {} attribute".format(attr))
job_str += " -attr {0}".format(attr)
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py
index 8ca1fd9d3a..689eed09f8 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py
@@ -112,9 +112,11 @@ class ExtractCameraMayaScene(publish.Extractor,
def process(self, instance):
"""Plugin entry point."""
# get settings
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py b/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py
index 2a43a30b8d..3fb84c8d83 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py
@@ -37,9 +37,11 @@ class ExtractImportReference(publish.Extractor,
if not self.is_active(instance.data):
return
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_look.py b/client/ayon_core/hosts/maya/plugins/publish/extract_look.py
index 7f97a7bf82..29390e2c7d 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_look.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_look.py
@@ -431,9 +431,11 @@ class ExtractLook(publish.Extractor):
project settings.
"""
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py b/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py
index 5045a8d252..cd6f3bab6a 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py
@@ -43,9 +43,11 @@ class ExtractMayaSceneRaw(publish.Extractor, AYONPyblishPluginMixin):
def process(self, instance):
"""Plugin entry point."""
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_model.py b/client/ayon_core/hosts/maya/plugins/publish/extract_model.py
index b6ae4d537a..543af59e8f 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_model.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_model.py
@@ -35,9 +35,11 @@ class ExtractModel(publish.Extractor,
if not self.is_active(instance.data):
return
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py b/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py
index 13e3d7c6b4..305f4698c6 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py
@@ -18,9 +18,11 @@ class ExtractRig(publish.Extractor):
def process(self, instance):
"""Plugin entry point."""
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py b/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py
index 7387849736..0b67117ebc 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py
@@ -100,9 +100,11 @@ class ExtractYetiRig(publish.Extractor):
def process(self, instance):
"""Plugin entry point."""
- ext_mapping = (
- instance.context.data["project_settings"]["maya"]["ext_mapping"]
- )
+ maya_settings = instance.context.data["project_settings"]["maya"]
+ ext_mapping = {
+ item["name"]: item["value"]
+ for item in maya_settings["ext_mapping"]
+ }
if ext_mapping:
self.log.debug("Looking in settings for scene type ...")
# use extension mapping for first family found
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py b/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py
index 3dfe2f4f2d..fc39756bf0 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py
@@ -1,3 +1,4 @@
+import json
from collections import defaultdict
import pyblish.api
@@ -23,19 +24,19 @@ class ValidateAttributes(pyblish.api.InstancePlugin,
"""
order = ValidateContentsOrder
- label = "Attributes"
+ label = "Validate Attributes"
hosts = ["maya"]
actions = [RepairAction]
optional = True
- attributes = None
+ attributes = "{}"
def process(self, instance):
if not self.is_active(instance.data):
return
# Check for preset existence.
- if not self.attributes:
+ if not self.get_attributes_data():
return
invalid = self.get_invalid(instance, compute=True)
@@ -44,6 +45,10 @@ class ValidateAttributes(pyblish.api.InstancePlugin,
"Found attributes with invalid values: {}".format(invalid)
)
+ @classmethod
+ def get_attributes_data(cls):
+ return json.loads(cls.attributes)
+
@classmethod
def get_invalid(cls, instance, compute=False):
if compute:
@@ -55,21 +60,22 @@ class ValidateAttributes(pyblish.api.InstancePlugin,
def get_invalid_attributes(cls, instance):
invalid_attributes = []
+ attributes_data = cls.get_attributes_data()
# Filter families.
families = [instance.data["family"]]
families += instance.data.get("families", [])
- families = set(families) & set(cls.attributes.keys())
+ families = set(families) & set(attributes_data.keys())
if not families:
return []
# Get all attributes to validate.
attributes = defaultdict(dict)
for family in families:
- if family not in cls.attributes:
+ if family not in attributes_data:
# No attributes to validate for family
continue
- for preset_attr, preset_value in cls.attributes[family].items():
+ for preset_attr, preset_value in attributes_data[family].items():
node_name, attribute_name = preset_attr.split(".", 1)
attributes[node_name][attribute_name] = preset_value
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py b/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py
index 85cc606b25..d5f99e5563 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py
@@ -39,7 +39,7 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
"yeticache"]
optional = True
actions = [RepairAction]
- exclude_families = []
+ exclude_product_types = []
def process(self, instance):
if not self.is_active(instance.data):
@@ -73,7 +73,9 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
# compare with data on instance
errors = []
- if [ef for ef in self.exclude_families
+ # QUESTION shouldn't this be just:
+ # 'if instance.data["family"] in self.exclude_product_types:'
+ if [ef for ef in self.exclude_product_types
if instance.data["family"] in ef]:
return
if (inst_start != frame_start_handle):
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_plugin_path_attributes.py b/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py
index d672be6fa0..fd71039e30 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py
@@ -30,14 +30,18 @@ class ValidatePluginPathAttributes(pyblish.api.InstancePlugin):
def get_invalid(cls, instance):
invalid = list()
- file_attrs = cls.attribute
+ file_attrs = {
+ item["name"]: item["value"]
+ for item in cls.attribute
+ }
if not file_attrs:
return invalid
# Consider only valid node types to avoid "Unknown object type" warning
all_node_types = set(cmds.allNodeTypes())
node_types = [
- key for key in file_attrs.keys()
+ key
+ for key in file_attrs.keys()
if key in all_node_types
]
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py
index 576886072d..384d99df1a 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py
@@ -55,12 +55,15 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin):
if staging_dir:
cls.log.debug(
"Staging dir found: \"{}\". Ignoring setting from "
- "`project_settings/maya/RenderSettings/"
+ "`project_settings/maya/render_settings/"
"default_render_image_folder`.".format(staging_dir)
)
return staging_dir
- return instance.context.data.get('project_settings')\
- .get('maya') \
- .get('RenderSettings') \
- .get('default_render_image_folder')
+ return (
+ instance.context.data
+ ["project_settings"]
+ ["maya"]
+ ["render_settings"]
+ ["default_render_image_folder"]
+ )
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_rendersettings.py b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py
index ed70d81b63..78a247b3f2 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py
@@ -265,7 +265,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
# load validation definitions from settings
settings_lights_flag = instance.context.data["project_settings"].get(
"maya", {}).get(
- "RenderSettings", {}).get(
+ "render_settings", {}).get(
"enable_all_lights", False)
instance_lights_flag = instance.data.get("renderSetupIncludeLights")
@@ -281,6 +281,8 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
# if so, compare its value from the one required.
for data in cls.get_nodes(instance, renderer):
for node in data["nodes"]:
+ # Why is captured 'PublishValidationError'? How it can be
+ # raised by 'cmds.getAttr(...)'?
try:
render_value = cmds.getAttr(
"{}.{}".format(node, data["attribute"])
@@ -310,11 +312,16 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
@classmethod
def get_nodes(cls, instance, renderer):
maya_settings = instance.context.data["project_settings"]["maya"]
+ renderer_key = "{}_render_attributes".format(renderer)
validation_settings = (
maya_settings["publish"]["ValidateRenderSettings"].get(
- "{}_render_attributes".format(renderer)
- ) or []
- )
+ renderer_key
+ )
+ ) or []
+ validation_settings = [
+ (item["type"], item["value"])
+ for item in validation_settings
+ ]
result = []
for attr, values in OrderedDict(validation_settings).items():
values = [convert_to_int_or_float(v) for v in values if v]
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py b/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py
index c6b9d23574..bb5ec8353e 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py
@@ -7,6 +7,7 @@ from ayon_core.hosts.maya.api import lib
from ayon_core.pipeline.publish import (
RepairAction,
ValidateContentsOrder,
+ PublishValidationError
)
@@ -38,7 +39,8 @@ class ValidateRigJointsHidden(pyblish.api.InstancePlugin):
invalid = self.get_invalid(instance)
if invalid:
- raise ValueError("Visible joints found: {0}".format(invalid))
+ raise PublishValidationError(
+ "Visible joints found: {0}".format(invalid))
@classmethod
def repair(cls, instance):
diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py b/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py
index 1f8d6b7470..e565866778 100644
--- a/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py
+++ b/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
"""Plugin for validating naming conventions."""
+import json
from maya import cmds
import pyblish.api
@@ -35,29 +36,37 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin,
"""
order = ValidateContentsOrder
- hosts = ['maya']
- families = ['model']
+ hosts = ["maya"]
+ families = ["model"]
optional = True
- label = 'Suffix Naming Conventions'
+ label = "Suffix Naming Conventions"
actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction]
- SUFFIX_NAMING_TABLE = {"mesh": ["_GEO", "_GES", "_GEP", "_OSD"],
- "nurbsCurve": ["_CRV"],
- "nurbsSurface": ["_NRB"],
- "locator": ["_LOC"],
- "group": ["_GRP"]}
+ SUFFIX_NAMING_TABLE = json.dumps({
+ "mesh": ["_GEO", "_GES", "_GEP", "_OSD"],
+ "nurbsCurve": ["_CRV"],
+ "nurbsSurface": ["_NRB"],
+ "locator": ["_LOC"],
+ "group": ["_GRP"]
+ })
ALLOW_IF_NOT_IN_SUFFIX_TABLE = True
@classmethod
def get_table_for_invalid(cls):
- ss = []
- for k, v in cls.SUFFIX_NAMING_TABLE.items():
- ss.append(" - {}: {}".format(k, ", ".join(v)))
+ suffix_naming_table = json.loads(cls.SUFFIX_NAMING_TABLE)
+ ss = [
+ " - {}: {}".format(k, ", ".join(v))
+ for k, v in suffix_naming_table.items()
+ ]
return "
".join(ss)
@staticmethod
- def is_valid_name(node_name, shape_type,
- SUFFIX_NAMING_TABLE, ALLOW_IF_NOT_IN_SUFFIX_TABLE):
+ def is_valid_name(
+ node_name,
+ shape_type,
+ suffix_naming_table,
+ allow_if_not_in_suffix_table
+ ):
"""Return whether node's name is correct.
The correctness for a transform's suffix is dependent on what
@@ -70,18 +79,18 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin,
Args:
node_name (str): Node name.
shape_type (str): Type of node.
- SUFFIX_NAMING_TABLE (dict): Mapping dict for suffixes.
- ALLOW_IF_NOT_IN_SUFFIX_TABLE (dict): Filter dict.
+ suffix_naming_table (dict): Mapping dict for suffixes.
+ allow_if_not_in_suffix_table (bool): Default output.
"""
- if shape_type not in SUFFIX_NAMING_TABLE:
- return ALLOW_IF_NOT_IN_SUFFIX_TABLE
- else:
- suffices = SUFFIX_NAMING_TABLE[shape_type]
- for suffix in suffices:
- if node_name.endswith(suffix):
- return True
- return False
+ if shape_type not in suffix_naming_table:
+ return allow_if_not_in_suffix_table
+
+ suffices = suffix_naming_table[shape_type]
+ for suffix in suffices:
+ if node_name.endswith(suffix):
+ return True
+ return False
@classmethod
def get_invalid(cls, instance):
@@ -91,9 +100,10 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin,
instance (:class:`pyblish.api.Instance`): published instance.
"""
- transforms = cmds.ls(instance, type='transform', long=True)
+ transforms = cmds.ls(instance, type="transform", long=True)
invalid = []
+ suffix_naming_table = json.loads(cls.SUFFIX_NAMING_TABLE)
for transform in transforms:
shapes = cmds.listRelatives(transform,
shapes=True,
@@ -101,9 +111,12 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin,
noIntermediate=True)
shape_type = cmds.nodeType(shapes[0]) if shapes else "group"
- if not cls.is_valid_name(transform, shape_type,
- cls.SUFFIX_NAMING_TABLE,
- cls.ALLOW_IF_NOT_IN_SUFFIX_TABLE):
+ if not cls.is_valid_name(
+ transform,
+ shape_type,
+ suffix_naming_table,
+ cls.ALLOW_IF_NOT_IN_SUFFIX_TABLE
+ ):
invalid.append(transform)
return invalid
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/maya/startup/userSetup.py b/client/ayon_core/hosts/maya/startup/userSetup.py
index 882f2df27c..a652e4d7de 100644
--- a/client/ayon_core/hosts/maya/startup/userSetup.py
+++ b/client/ayon_core/hosts/maya/startup/userSetup.py
@@ -46,24 +46,5 @@ if bool(int(os.environ.get(key, "0"))):
lowestPriority=True
)
-# Build a shelf.
-shelf_preset = settings['maya'].get('project_shelf')
-if shelf_preset:
- icon_path = os.path.join(
- os.environ['OPENPYPE_PROJECT_SCRIPTS'],
- project_name,
- "icons")
- icon_path = os.path.abspath(icon_path)
-
- for i in shelf_preset['imports']:
- import_string = "from {} import {}".format(project_name, i)
- print(import_string)
- exec(import_string)
-
- cmds.evalDeferred(
- "mlib.shelf(name=shelf_preset['name'], iconPath=icon_path,"
- " preset=shelf_preset)"
- )
-
print("Finished OpenPype usersetup.")
diff --git a/client/ayon_core/hosts/nuke/api/pipeline.py b/client/ayon_core/hosts/nuke/api/pipeline.py
index bdba0757b6..735426240e 100644
--- a/client/ayon_core/hosts/nuke/api/pipeline.py
+++ b/client/ayon_core/hosts/nuke/api/pipeline.py
@@ -21,10 +21,12 @@ from ayon_core.pipeline import (
AVALON_CONTAINER_ID,
get_current_asset_name,
get_current_task_name,
+ registered_host,
)
from ayon_core.pipeline.workfile import BuildWorkfile
from ayon_core.tools.utils import host_tools
from ayon_core.hosts.nuke import NUKE_ROOT_DIR
+from ayon_core.tools.workfile_template_build import open_template_ui
from .command import viewer_update_and_undo_stop
from .lib import (
@@ -55,6 +57,7 @@ from .workfile_template_builder import (
build_workfile_template,
create_placeholder,
update_placeholder,
+ NukeTemplateBuilder,
)
from .workio import (
open_file,
@@ -176,7 +179,7 @@ def add_nuke_callbacks():
nuke.addOnScriptLoad(WorkfileSettings().set_context_settings)
- if nuke_settings["nuke-dirmap"]["enabled"]:
+ if nuke_settings["dirmap"]["enabled"]:
log.info("Added Nuke's dir-mapping callback ...")
# Add dirmap for file paths.
nuke.addFilenameFilter(dirmap_file_name_filter)
@@ -313,7 +316,7 @@ def _install_menu():
lambda: BuildWorkfile().process()
)
- menu_template = menu.addMenu("Template Builder") # creating template menu
+ menu_template = menu.addMenu("Template Builder")
menu_template.addCommand(
"Build Workfile from template",
lambda: build_workfile_template()
@@ -321,6 +324,12 @@ def _install_menu():
if not ASSIST:
menu_template.addSeparator()
+ menu_template.addCommand(
+ "Open template",
+ lambda: open_template_ui(
+ NukeTemplateBuilder(registered_host()), get_main_window()
+ )
+ )
menu_template.addCommand(
"Create Place Holder",
lambda: create_placeholder()
diff --git a/client/ayon_core/hosts/nuke/api/workfile_template_builder.py b/client/ayon_core/hosts/nuke/api/workfile_template_builder.py
index 4c15da983e..218ba97dd5 100644
--- a/client/ayon_core/hosts/nuke/api/workfile_template_builder.py
+++ b/client/ayon_core/hosts/nuke/api/workfile_template_builder.py
@@ -7,7 +7,7 @@ from ayon_core.pipeline.workfile.workfile_template_builder import (
LoadPlaceholderItem,
CreatePlaceholderItem,
PlaceholderLoadMixin,
- PlaceholderCreateMixin
+ PlaceholderCreateMixin,
)
from ayon_core.tools.workfile_template_build import (
WorkfileBuildPlaceholderDialog,
diff --git a/client/ayon_core/hosts/photoshop/api/lib.py b/client/ayon_core/hosts/photoshop/api/lib.py
index 3111503e40..af14e6d02f 100644
--- a/client/ayon_core/hosts/photoshop/api/lib.py
+++ b/client/ayon_core/hosts/photoshop/api/lib.py
@@ -3,12 +3,11 @@ import sys
import contextlib
import traceback
-from ayon_core.lib import env_value_to_bool, Logger
+from ayon_core.lib import env_value_to_bool, Logger, is_in_tests
from ayon_core.addon import AddonsManager
from ayon_core.pipeline import install_host
from ayon_core.tools.utils import host_tools
from ayon_core.tools.utils import get_ayon_qt_app
-from ayon_core.tests.lib import is_in_tests
from .launch_logic import ProcessLauncher, stub
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..2912dbf23d 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,12 +17,11 @@ 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
)
-from ayon_core.tests.lib import is_in_tests
+from ayon_core.lib import is_in_tests
class CollectBatchData(pyblish.api.ContextPlugin):
@@ -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/photoshop/plugins/publish/collect_color_coded_instances.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py
index e309da62ba..6a09cff3c7 100644
--- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py
+++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py
@@ -3,10 +3,9 @@ import re
import pyblish.api
-from ayon_core.lib import prepare_template_data
+from ayon_core.lib import prepare_template_data, is_in_tests
from ayon_core.hosts.photoshop import api as photoshop
from ayon_core.settings import get_project_settings
-from ayon_core.tests.lib import is_in_tests
class CollectColorCodedInstances(pyblish.api.ContextPlugin):
@@ -29,9 +28,8 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin):
Identifier:
id (str): "pyblish.avalon.instance"
"""
- order = pyblish.api.CollectorOrder + 0.100
- label = "Instances"
+ label = "Collect Color-coded Instances"
order = pyblish.api.CollectorOrder
hosts = ["photoshop"]
targets = ["automated"]
@@ -42,7 +40,7 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin):
# flattened template cannot
subset_template_name = ""
create_flatten_image = "no"
- flatten_subset_template = ""
+ flatten_product_name_template = ""
def process(self, context):
self.log.info("CollectColorCodedInstances")
@@ -124,12 +122,12 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin):
if self.create_flatten_image != "no" and publishable_layers:
self.log.debug("create_flatten_image")
- if not self.flatten_subset_template:
+ if not self.flatten_product_name_template:
self.log.warning("No template for flatten image")
return
fill_pairs.pop("layer")
- subset = self.flatten_subset_template.format(
+ subset = self.flatten_product_name_template.format(
**prepare_template_data(fill_pairs))
first_layer = publishable_layers[0] # dummy layer
diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py
index e487760736..1ffbadf022 100644
--- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py
+++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py
@@ -6,24 +6,17 @@ Provides:
instance -> family ("review")
"""
-import os
-
import pyblish.api
-from ayon_core.pipeline.create import get_subset_name
-
class CollectReview(pyblish.api.ContextPlugin):
"""Adds review to families for instances marked to be reviewable.
"""
label = "Collect Review"
- label = "Review"
hosts = ["photoshop"]
order = pyblish.api.CollectorOrder + 0.1
- publish = True
-
def process(self, context):
for instance in context:
creator_attributes = instance.data["creator_attributes"]
diff --git a/client/ayon_core/hosts/substancepainter/api/pipeline.py b/client/ayon_core/hosts/substancepainter/api/pipeline.py
index 2bbcf2aded..03cb22136c 100644
--- a/client/ayon_core/hosts/substancepainter/api/pipeline.py
+++ b/client/ayon_core/hosts/substancepainter/api/pipeline.py
@@ -240,33 +240,34 @@ class SubstanceHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
def _install_shelves(self, project_settings):
- shelves = project_settings["substancepainter"].get("shelves", {})
+ shelves = project_settings["substancepainter"].get("shelves", [])
if not shelves:
return
# Prepare formatting data if we detect any path which might have
# template tokens like {asset} in there.
formatting_data = {}
- has_formatting_entries = any("{" in path for path in shelves.values())
+ has_formatting_entries = any("{" in item["value"] for item in shelves)
if has_formatting_entries:
project_name = self.get_current_project_name()
asset_name = self.get_current_asset_name()
task_name = self.get_current_asset_name()
system_settings = get_system_settings()
- formatting_data = get_template_data_with_names(project_name,
- asset_name,
- task_name,
- system_settings)
+ formatting_data = get_template_data_with_names(
+ project_name, asset_name, task_name, system_settings
+ )
anatomy = Anatomy(project_name)
formatting_data["root"] = anatomy.roots
- for name, path in shelves.items():
- shelf_name = None
+ for shelve_item in shelves:
# Allow formatting with anatomy for the paths
+ path = shelve_item["value"]
if "{" in path:
path = StringTemplate.format_template(path, formatting_data)
+ name = shelve_item["name"]
+ shelf_name = None
try:
shelf_name = lib.load_shelf(path, name=name)
except ValueError as exc:
diff --git a/client/ayon_core/hosts/traypublisher/api/editorial.py b/client/ayon_core/hosts/traypublisher/api/editorial.py
index d84a7200c8..6153bc5752 100644
--- a/client/ayon_core/hosts/traypublisher/api/editorial.py
+++ b/client/ayon_core/hosts/traypublisher/api/editorial.py
@@ -16,25 +16,31 @@ class ShotMetadataSolver:
NO_DECOR_PATERN = re.compile(r"\{([a-z]*?)\}")
- # presets
- clip_name_tokenizer = None
- shot_rename = True
- shot_hierarchy = None
- shot_add_tasks = None
+ def __init__(self, logger):
+ self.clip_name_tokenizer = []
+ self.shot_rename = {
+ "enabled": False,
+ "shot_rename_template": "",
+ }
+ self.shot_hierarchy = {
+ "enabled": False,
+ "parents": [],
+ "parents_path": "",
+ }
+ self.shot_add_tasks = []
+ self.log = logger
- def __init__(
+ def update_data(
self,
clip_name_tokenizer,
shot_rename,
shot_hierarchy,
- shot_add_tasks,
- logger
+ shot_add_tasks
):
self.clip_name_tokenizer = clip_name_tokenizer
self.shot_rename = shot_rename
self.shot_hierarchy = shot_hierarchy
self.shot_add_tasks = shot_add_tasks
- self.log = logger
def _rename_template(self, data):
"""Shot renaming function
@@ -86,7 +92,9 @@ class ShotMetadataSolver:
search_text = parent_name + clip_name
- for token_key, pattern in self.clip_name_tokenizer.items():
+ for clip_name_item in self.clip_name_tokenizer:
+ token_key = clip_name_item["name"]
+ pattern = clip_name_item["regex"]
p = re.compile(pattern)
match = p.findall(search_text)
if not match:
@@ -137,11 +145,11 @@ class ShotMetadataSolver:
))
_parent_tokens_type = {
- parent_token["name"]: parent_token["type"]
+ parent_token["name"]: parent_token["parent_type"]
for parent_token in hierarchy_parents
}
for _index, _parent in enumerate(
- shot_hierarchy["parents_path"].split("/")
+ shot_hierarchy["parents_path"].split("/")
):
# format parent token with value which is formatted
try:
@@ -262,22 +270,22 @@ class ShotMetadataSolver:
"""
tasks_to_add = {}
- project_tasks = project_doc["config"]["tasks"]
- for task_name, task_data in self.shot_add_tasks.items():
- _task_data = deepcopy(task_data)
+ project_task_types = project_doc["config"]["tasks"]
+ for task_item in self.shot_add_tasks:
+ task_name = task_item["name"]
+ task_type = task_item["task_type"]
# check if task type in project task types
- if _task_data["type"] in project_tasks.keys():
- tasks_to_add[task_name] = _task_data
- else:
+ if task_type not in project_task_types.keys():
raise KeyError(
"Missing task type `{}` for `{}` is not"
" existing in `{}``".format(
- _task_data["type"],
+ task_type,
task_name,
- list(project_tasks.keys())
+ list(project_task_types.keys())
)
)
+ tasks_to_add[task_name] = {"type": task_type}
return tasks_to_add
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/traypublisher/api/plugin.py b/client/ayon_core/hosts/traypublisher/api/plugin.py
index 77a8f23d2e..d3d7f80e89 100644
--- a/client/ayon_core/hosts/traypublisher/api/plugin.py
+++ b/client/ayon_core/hosts/traypublisher/api/plugin.py
@@ -311,7 +311,7 @@ class SettingsCreator(TrayPublishCreator):
@classmethod
def from_settings(cls, item_data):
identifier = item_data["identifier"]
- family = item_data["family"]
+ family = item_data["product_type"]
if not identifier:
identifier = "settings_{}".format(family)
return type(
diff --git a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
index 51a67a871e..d6501e65a2 100644
--- a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
+++ b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py
@@ -174,46 +174,42 @@ Supporting publishing new shots to project
or updating already created. Publishing will create OTIO file.
"""
icon = "fa.file"
+ product_type_presets = []
- def __init__(
- self, project_settings, *args, **kwargs
- ):
- super(EditorialSimpleCreator, self).__init__(
- project_settings, *args, **kwargs
- )
+ def __init__(self, *args, **kwargs):
+ self._shot_metadata_solver = ShotMetadataSolver(self.log)
+ super(EditorialSimpleCreator, self).__init__(*args, **kwargs)
+
+ def apply_settings(self, project_settings):
editorial_creators = deepcopy(
project_settings["traypublisher"]["editorial_creators"]
)
- # get this creator settings by identifier
- self._creator_settings = editorial_creators.get(self.identifier)
+ creator_settings = editorial_creators.get(self.identifier)
- clip_name_tokenizer = self._creator_settings["clip_name_tokenizer"]
- shot_rename = self._creator_settings["shot_rename"]
- shot_hierarchy = self._creator_settings["shot_hierarchy"]
- shot_add_tasks = self._creator_settings["shot_add_tasks"]
-
- self._shot_metadata_solver = ShotMetadataSolver(
- clip_name_tokenizer,
- shot_rename,
- shot_hierarchy,
- shot_add_tasks,
- self.log
+ self._shot_metadata_solver.update_data(
+ creator_settings["clip_name_tokenizer"],
+ creator_settings["shot_rename"],
+ creator_settings["shot_hierarchy"],
+ creator_settings["shot_add_tasks"]
)
-
- # try to set main attributes from settings
- if self._creator_settings.get("default_variants"):
- self.default_variants = self._creator_settings["default_variants"]
+ self.product_type_presets = creator_settings["product_type_presets"]
+ default_variants = creator_settings.get("default_variants")
+ if default_variants:
+ self.default_variants = default_variants
def create(self, subset_name, instance_data, pre_create_data):
- allowed_family_presets = self._get_allowed_family_presets(
+ allowed_product_type_presets = self._get_allowed_product_type_presets(
pre_create_data)
+ product_types = {
+ item["product_type"]
+ for item in self.product_type_presets
+ }
clip_instance_properties = {
- k: v for k, v in pre_create_data.items()
+ k: v
+ for k, v in pre_create_data.items()
if k != "sequence_filepath_data"
- if k not in [
- i["family"] for i in self._creator_settings["family_presets"]
- ]
+ if k not in product_types
}
asset_name = instance_data["folderPath"]
@@ -255,7 +251,7 @@ or updating already created. Publishing will create OTIO file.
otio_timeline,
media_path,
clip_instance_properties,
- allowed_family_presets,
+ allowed_product_type_presets,
os.path.basename(seq_path),
first_otio_timeline
)
@@ -355,7 +351,7 @@ or updating already created. Publishing will create OTIO file.
otio_timeline,
media_path,
instance_data,
- family_presets,
+ product_type_presets,
sequence_file_name,
first_otio_timeline=None
):
@@ -365,7 +361,7 @@ or updating already created. Publishing will create OTIO file.
otio_timeline (otio.Timeline): otio timeline object
media_path (str): media file path string
instance_data (dict): clip instance data
- family_presets (list): list of dict settings subset presets
+ product_type_presets (list): list of dict settings subset presets
"""
tracks = [
@@ -411,17 +407,17 @@ or updating already created. Publishing will create OTIO file.
"instance_id": None
}
- for _fpreset in family_presets:
+ for product_type_preset in product_type_presets:
# exclude audio family if no audio stream
if (
- _fpreset["family"] == "audio"
+ product_type_preset["product_type"] == "audio"
and not media_data.get("audio")
):
continue
instance = self._make_subset_instance(
otio_clip,
- _fpreset,
+ product_type_preset,
deepcopy(base_instance_data),
parenting_data
)
@@ -533,7 +529,7 @@ or updating already created. Publishing will create OTIO file.
def _make_subset_instance(
self,
otio_clip,
- preset,
+ product_type_preset,
instance_data,
parenting_data
):
@@ -541,16 +537,16 @@ or updating already created. Publishing will create OTIO file.
Args:
otio_clip (otio.Clip): otio clip object
- preset (dict): single family preset
+ product_type_preset (dict): single family preset
instance_data (dict): instance data
parenting_data (dict): shot instance parent data
Returns:
CreatedInstance: creator instance object
"""
- family = preset["family"]
+ family = product_type_preset["product_type"]
label = self._make_subset_naming(
- preset,
+ product_type_preset,
instance_data
)
instance_data["label"] = label
@@ -569,11 +565,11 @@ or updating already created. Publishing will create OTIO file.
else:
# add review family if defined
instance_data.update({
- "outputFileType": preset["output_file_type"],
+ "outputFileType": product_type_preset["output_file_type"],
"parent_instance_id": parenting_data["instance_id"],
"creator_attributes": {
"parent_instance": parenting_data["instance_label"],
- "add_review_family": preset.get("review")
+ "add_review_family": product_type_preset.get("review")
}
})
@@ -585,15 +581,11 @@ or updating already created. Publishing will create OTIO file.
return c_instance
- def _make_subset_naming(
- self,
- preset,
- instance_data
- ):
+ def _make_subset_naming(self, product_type_preset, instance_data):
""" Subset name maker
Args:
- preset (dict): single preset item
+ product_type_preset (dict): single preset item
instance_data (dict): instance data
Returns:
@@ -602,10 +594,10 @@ or updating already created. Publishing will create OTIO file.
asset_name = instance_data["creator_attributes"]["folderPath"]
variant_name = instance_data["variant"]
- family = preset["family"]
+ family = product_type_preset["product_type"]
# get variant name from preset or from inheritance
- _variant_name = preset.get("variant") or variant_name
+ _variant_name = product_type_preset.get("variant") or variant_name
# subset name
subset_name = "{}{}".format(
@@ -763,7 +755,7 @@ or updating already created. Publishing will create OTIO file.
"sourceOut": int(source_out)
}
- def _get_allowed_family_presets(self, pre_create_data):
+ def _get_allowed_product_type_presets(self, pre_create_data):
""" Filter out allowed family presets.
Args:
@@ -773,10 +765,11 @@ or updating already created. Publishing will create OTIO file.
list: lit of dict with preset items
"""
return [
- {"family": "shot"},
+ {"product_type": "shot"},
*[
- preset for preset in self._creator_settings["family_presets"]
- if pre_create_data[preset["family"]]
+ preset
+ for preset in self.product_type_presets
+ if pre_create_data[preset["product_type"]]
]
]
@@ -853,8 +846,8 @@ or updating already created. Publishing will create OTIO file.
]
# add variants swithers
attr_defs.extend(
- BoolDef(_var["family"], label=_var["family"])
- for _var in self._creator_settings["family_presets"]
+ BoolDef(item["product_type"], label=item["product_type"])
+ for item in self.product_type_presets
)
attr_defs.append(UISeparatorDef())
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/lib/__init__.py b/client/ayon_core/lib/__init__.py
index 12a5535a1c..ab6a604adc 100644
--- a/client/ayon_core/lib/__init__.py
+++ b/client/ayon_core/lib/__init__.py
@@ -158,6 +158,7 @@ from .ayon_info import (
is_running_from_build,
is_staging_enabled,
is_dev_mode_enabled,
+ is_in_tests,
)
@@ -229,6 +230,8 @@ __all__ = [
"IniSettingRegistry",
"JSONSettingRegistry",
+ "AYONSecureRegistry",
+ "AYONSettingsRegistry",
"OpenPypeSecureRegistry",
"OpenPypeSettingsRegistry",
"get_local_site_id",
@@ -271,6 +274,7 @@ __all__ = [
"terminal",
"get_datetime_data",
+ "get_timestamp",
"get_formatted_current_time",
"Logger",
@@ -278,6 +282,7 @@ __all__ = [
"is_running_from_build",
"is_staging_enabled",
"is_dev_mode_enabled",
+ "is_in_tests",
"requests_get",
"requests_post"
diff --git a/client/ayon_core/lib/applications.py b/client/ayon_core/lib/applications.py
index febdaacdd1..2b0b855c81 100644
--- a/client/ayon_core/lib/applications.py
+++ b/client/ayon_core/lib/applications.py
@@ -230,29 +230,25 @@ class ApplicationGroup:
self.manager = manager
self._data = data
- self.enabled = data.get("enabled", True)
- self.label = data.get("label") or None
- self.icon = data.get("icon") or None
- self._environment = data.get("environment") or {}
+ self.enabled = data["enabled"]
+ self.label = data["label"] or None
+ self.icon = data["icon"] or None
+ env = {}
+ try:
+ env = json.loads(data["environment"])
+ except Exception:
+ pass
+ self._environment = env
- host_name = data.get("host_name", None)
+ host_name = data["host_name"] or None
self.is_host = host_name is not None
self.host_name = host_name
- variants = data.get("variants") or {}
- key_label_mapping = variants.pop(M_DYNAMIC_KEY_LABEL, {})
- for variant_name, variant_data in variants.items():
- if variant_name in METADATA_KEYS:
- continue
-
- if "variant_label" not in variant_data:
- variant_label = key_label_mapping.get(variant_name)
- if variant_label:
- variant_data["variant_label"] = variant_label
-
- variants[variant_name] = Application(
- variant_name, variant_data, self
- )
+ settings_variants = data["variants"]
+ variants = {}
+ for variant_data in settings_variants:
+ app_variant = Application(variant_data, self)
+ variants[app_variant.name] = app_variant
self.variants = variants
@@ -274,62 +270,56 @@ class Application:
Object by itself does nothing special.
Args:
- name (str): Specific version (or variant) of application.
- e.g. "maya2020", "nuke11.3", etc.
data (dict): Data for the version containing information about
executables, variant label or if is enabled.
Only required key is `executables`.
group (ApplicationGroup): App group object that created the application
and under which application belongs.
+
"""
-
- def __init__(self, name, data, group):
- self.name = name
- self.group = group
+ def __init__(self, data, group):
self._data = data
-
+ name = data["name"]
+ label = data["label"] or name
enabled = False
if group.enabled:
enabled = data.get("enabled", True)
- self.enabled = enabled
- self.use_python_2 = data.get("use_python_2", False)
-
- self.label = data.get("variant_label") or name
- self.full_name = "/".join((group.name, name))
if group.label:
- full_label = " ".join((group.label, self.label))
+ full_label = " ".join((group.label, label))
else:
- full_label = self.label
- self.full_label = full_label
- self._environment = data.get("environment") or {}
+ full_label = label
+ env = {}
+ try:
+ env = json.loads(data["environment"])
+ except Exception:
+ pass
- arguments = data.get("arguments")
+ arguments = data["arguments"]
if isinstance(arguments, dict):
arguments = arguments.get(platform.system().lower())
if not arguments:
arguments = []
+
+ _executables = data["executables"].get(platform.system().lower(), [])
+ executables = [
+ ApplicationExecutable(executable)
+ for executable in _executables
+ ]
+
+ self.group = group
+
+ self.name = name
+ self.label = label
+ self.enabled = enabled
+ self.use_python_2 = data.get("use_python_2", False)
+
+ self.full_name = "/".join((group.name, name))
+ self.full_label = full_label
self.arguments = arguments
-
- if "executables" not in data:
- self.executables = [
- UndefinedApplicationExecutable()
- ]
- return
-
- _executables = data["executables"]
- if isinstance(_executables, dict):
- _executables = _executables.get(platform.system().lower())
-
- if not _executables:
- _executables = []
-
- executables = []
- for executable in _executables:
- executables.append(ApplicationExecutable(executable))
-
self.executables = executables
+ self._environment = env
def __repr__(self):
return "<{}> - {}".format(self.__class__.__name__, self.full_name)
@@ -384,12 +374,12 @@ class ApplicationManager:
"""Load applications and tools and store them by their full name.
Args:
- system_settings (dict): Preloaded system settings. When passed manager
+ studio_settings (dict): Preloaded studio settings. When passed manager
will always use these values. Gives ability to create manager
using different settings.
"""
- def __init__(self, system_settings=None):
+ def __init__(self, studio_settings=None):
self.log = Logger.get_logger(self.__class__.__name__)
self.app_groups = {}
@@ -397,16 +387,16 @@ class ApplicationManager:
self.tool_groups = {}
self.tools = {}
- self._system_settings = system_settings
+ self._studio_settings = studio_settings
self.refresh()
- def set_system_settings(self, system_settings):
+ def set_studio_settings(self, studio_settings):
"""Ability to change init system settings.
This will trigger refresh of manager.
"""
- self._system_settings = system_settings
+ self._studio_settings = studio_settings
self.refresh()
@@ -417,72 +407,37 @@ class ApplicationManager:
self.tool_groups.clear()
self.tools.clear()
- if self._system_settings is not None:
- settings = copy.deepcopy(self._system_settings)
+ if self._studio_settings is not None:
+ settings = copy.deepcopy(self._studio_settings)
else:
settings = get_system_settings(
clear_metadata=False, exclude_locals=False
)
- all_app_defs = {}
+ applications_addon_settings = settings["applications"]
+
# Prepare known applications
- app_defs = settings["applications"]
- additional_apps = {}
+ app_defs = applications_addon_settings["applications"]
+ additional_apps = app_defs.pop("additional_apps")
+ for additional_app in additional_apps:
+ app_name = additional_app.pop("name")
+ if app_name in app_defs:
+ self.log.warning((
+ "Additional application '{}' is already"
+ " in built-in applications."
+ ).format(app_name))
+ app_defs[app_name] = additional_app
+
for group_name, variant_defs in app_defs.items():
- if group_name in METADATA_KEYS:
- continue
-
- if group_name == "additional_apps":
- additional_apps = variant_defs
- else:
- all_app_defs[group_name] = variant_defs
-
- # Prepare additional applications
- # - First find dynamic keys that can be used as labels of group
- dynamic_keys = {}
- for group_name, variant_defs in additional_apps.items():
- if group_name == M_DYNAMIC_KEY_LABEL:
- dynamic_keys = variant_defs
- break
-
- # Add additional apps to known applications
- for group_name, variant_defs in additional_apps.items():
- if group_name in METADATA_KEYS:
- continue
-
- # Determine group label
- label = variant_defs.get("label")
- if not label:
- # Look for label set in dynamic labels
- label = dynamic_keys.get(group_name)
- if not label:
- label = group_name
- variant_defs["label"] = label
-
- all_app_defs[group_name] = variant_defs
-
- for group_name, variant_defs in all_app_defs.items():
- if group_name in METADATA_KEYS:
- continue
-
group = ApplicationGroup(group_name, variant_defs, self)
self.app_groups[group_name] = group
for app in group:
self.applications[app.full_name] = app
- tools_definitions = settings["tools"]["tool_groups"]
- tool_label_mapping = tools_definitions.pop(M_DYNAMIC_KEY_LABEL, {})
- for tool_group_name, tool_group_data in tools_definitions.items():
- if not tool_group_name or tool_group_name in METADATA_KEYS:
- continue
-
- tool_group_label = (
- tool_label_mapping.get(tool_group_name) or tool_group_name
- )
- group = EnvironmentToolGroup(
- tool_group_name, tool_group_label, tool_group_data, self
- )
- self.tool_groups[tool_group_name] = group
+ tools_definitions = applications_addon_settings["tool_groups"]
+ for tool_group_data in tools_definitions:
+ group = EnvironmentToolGroup(tool_group_data, self)
+ self.tool_groups[group.name] = group
for tool in group:
self.tools[tool.full_name] = tool
@@ -571,30 +526,31 @@ class EnvironmentToolGroup:
are same.
Args:
- name (str): Name of the tool group.
- data (dict): Group's information with it's variants.
+ data (dict): Group information with variants.
manager (ApplicationManager): Manager that creates the group.
"""
- def __init__(self, name, label, data, manager):
+ def __init__(self, data, manager):
+ name = data["name"]
+ label = data["label"]
+
self.name = name
self.label = label
self._data = data
self.manager = manager
- self._environment = data["environment"]
- variants = data.get("variants") or {}
- label_by_key = variants.pop(M_DYNAMIC_KEY_LABEL, {})
+ environment = {}
+ try:
+ environment = json.loads(data["environment"])
+ except Exception:
+ pass
+ self._environment = environment
+
+ variants = data.get("variants") or []
variants_by_name = {}
- for variant_name, variant_data in variants.items():
- if variant_name in METADATA_KEYS:
- continue
-
- variant_label = label_by_key.get(variant_name) or variant_name
- tool = EnvironmentTool(
- variant_name, variant_label, variant_data, self
- )
- variants_by_name[variant_name] = tool
+ for variant_data in variants:
+ tool = EnvironmentTool(variant_data, self)
+ variants_by_name[tool.name] = tool
self.variants = variants_by_name
def __repr__(self):
@@ -615,23 +571,25 @@ class EnvironmentTool:
Structure of tool information.
Args:
- name (str): Name of the tool.
variant_data (dict): Variant data with environments and
host and app variant filters.
- group (str): Name of group which wraps tool.
+ group (EnvironmentToolGroup): Name of group which wraps tool.
"""
- def __init__(self, name, label, variant_data, group):
+ def __init__(self, variant_data, group):
# Backwards compatibility 3.9.1 - 3.9.2
# - 'variant_data' contained only environments but contain also host
# and application variant filters
- host_names = variant_data.get("host_names", [])
- app_variants = variant_data.get("app_variants", [])
+ name = variant_data["name"]
+ label = variant_data["label"]
+ host_names = variant_data["host_names"]
+ app_variants = variant_data["app_variants"]
- if "environment" in variant_data:
- environment = variant_data["environment"]
- else:
- environment = variant_data
+ environment = {}
+ try:
+ environment = json.loads(variant_data["environment"])
+ except Exception:
+ pass
self.host_names = host_names
self.app_variants = app_variants
diff --git a/client/ayon_core/lib/ayon_info.py b/client/ayon_core/lib/ayon_info.py
index 725e10fa0e..97a35adcc6 100644
--- a/client/ayon_core/lib/ayon_info.py
+++ b/client/ayon_core/lib/ayon_info.py
@@ -38,6 +38,16 @@ def is_staging_enabled():
return os.getenv("AYON_USE_STAGING") == "1"
+def is_in_tests():
+ """Process is running in automatic tests mode.
+
+ Returns:
+ bool: True if running in tests.
+
+ """
+ return os.environ.get("AYON_IN_TESTS") == "1"
+
+
def is_dev_mode_enabled():
"""Dev mode is enabled in AYON.
diff --git a/client/ayon_core/modules/clockify/clockify_module.py b/client/ayon_core/modules/clockify/clockify_module.py
index adb7eb66af..58407bfe94 100644
--- a/client/ayon_core/modules/clockify/clockify_module.py
+++ b/client/ayon_core/modules/clockify/clockify_module.py
@@ -2,22 +2,27 @@ import os
import threading
import time
-from ayon_core.modules import OpenPypeModule, ITrayModule, IPluginPaths
+from ayon_core.modules import AYONAddon, ITrayModule, IPluginPaths
from ayon_core.client import get_asset_by_name
from .constants import CLOCKIFY_FTRACK_USER_PATH, CLOCKIFY_FTRACK_SERVER_PATH
-class ClockifyModule(OpenPypeModule, ITrayModule, IPluginPaths):
+class ClockifyModule(AYONAddon, ITrayModule, IPluginPaths):
name = "clockify"
- def initialize(self, modules_settings):
- clockify_settings = modules_settings[self.name]
- self.enabled = clockify_settings["enabled"]
- self.workspace_name = clockify_settings["workspace_name"]
+ def initialize(self, studio_settings):
+ enabled = self.name in studio_settings
+ workspace_name = None
+ if enabled:
+ clockify_settings = studio_settings[self.name]
+ workspace_name = clockify_settings["workspace_name"]
- if self.enabled and not self.workspace_name:
- raise Exception("Clockify Workspace is not set in settings.")
+ if enabled and workspace_name:
+ self.log.warning("Clockify Workspace is not set in settings.")
+ enabled = False
+ self.enabled = enabled
+ self.workspace_name = workspace_name
self.timer_manager = None
self.MessageWidgetClass = None
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..fb75f3a917 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
@@ -7,11 +7,10 @@ from datetime import datetime
from ayon_core.lib import (
env_value_to_bool,
collect_frames,
+ is_in_tests,
)
-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
@attr.s
@@ -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..07b9f6e819 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
@@ -10,11 +10,10 @@ from ayon_core.lib import (
BoolDef,
NumberDef,
TextDef,
+ is_in_tests,
)
-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
from openpype_modules.deadline import abstract_submit_deadline
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
@@ -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..c7047edd67 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,10 +10,9 @@ 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
+from ayon_core.lib import is_in_tests
class _ZipFile(ZipFile):
@@ -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..a864e15c76 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
@@ -7,12 +7,11 @@ import pyblish.api
from ayon_core.lib import (
TextDef,
NumberDef,
+ is_in_tests,
)
from ayon_core.pipeline import (
- legacy_io,
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
@@ -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 eb1708e3d8..393d85e785 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,11 +5,11 @@ from datetime import datetime
import pyblish.api
-from ayon_core.pipeline import legacy_io, AYONPyblishPluginMixin
-from ayon_core.tests.lib import is_in_tests
+from ayon_core.pipeline import AYONPyblishPluginMixin
from openpype_modules.deadline import abstract_submit_deadline
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
from ayon_core.lib import (
+ is_in_tests,
BoolDef,
NumberDef
)
@@ -210,12 +210,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..a4a5391ce1 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
@@ -18,6 +18,7 @@ Attributes:
from __future__ import print_function
import os
+import json
import getpass
import copy
import re
@@ -29,21 +30,20 @@ from collections import OrderedDict
import attr
from ayon_core.pipeline import (
- legacy_io,
AYONPyblishPluginMixin
)
from ayon_core.lib import (
BoolDef,
NumberDef,
TextDef,
- EnumDef
+ EnumDef,
+ is_in_tests,
)
from ayon_core.hosts.maya.api.lib_rendersettings import RenderSettings
from ayon_core.hosts.maya.api.lib import get_attr_in_layer
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
from ayon_core.pipeline.farm.tools import iter_expected_files
@@ -131,8 +131,15 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
cls.group = settings.get("group", cls.group)
cls.strict_error_checking = settings.get("strict_error_checking",
cls.strict_error_checking)
- cls.jobInfo = settings.get("jobInfo", cls.jobInfo)
- cls.pluginInfo = settings.get("pluginInfo", cls.pluginInfo)
+ job_info = settings.get("jobInfo")
+ if job_info:
+ job_info = json.loads(job_info)
+ plugin_info = settings.get("pluginInfo")
+ if plugin_info:
+ plugin_info = json.loads(plugin_info)
+
+ cls.jobInfo = job_info or cls.jobInfo
+ cls.pluginInfo = plugin_info or cls.pluginInfo
def get_job_info(self):
job_info = DeadlineJobInfo(Plugin="MayaBatch")
@@ -203,12 +210,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)
@@ -248,7 +259,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
default_rs_include_lights = (
instance.context.data['project_settings']
['maya']
- ['RenderSettings']
+ ['render_settings']
['enable_all_lights']
)
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..c4a7a43ce0 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,8 +2,8 @@ import os
import attr
from datetime import datetime
-from ayon_core.pipeline import legacy_io, PublishXmlValidationError
-from ayon_core.tests.lib import is_in_tests
+from ayon_core.pipeline import PublishXmlValidationError
+from ayon_core.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..0887c23165 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,12 +7,11 @@ from datetime import datetime
import requests
import pyblish.api
-from ayon_core.pipeline import legacy_io
from ayon_core.pipeline.publish import (
AYONPyblishPluginMixin
)
-from ayon_core.tests.lib import is_in_tests
from ayon_core.lib import (
+ is_in_tests,
BoolDef,
NumberDef
)
@@ -40,10 +39,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin,
concurrent_tasks = 1
group = ""
department = ""
- limit_groups = {}
+ limit_groups = []
use_gpu = False
env_allowed_keys = []
- env_search_replace_values = {}
+ env_search_replace_values = []
workfile_dependency = True
use_published_workfile = True
@@ -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"
@@ -402,8 +404,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin,
# finally search replace in values of any key
if self.env_search_replace_values:
for key, value in environment.items():
- for _k, _v in self.env_search_replace_values.items():
- environment[key] = value.replace(_k, _v)
+ for item in self.env_search_replace_values:
+ environment[key] = value.replace(
+ item["name"], item["value"]
+ )
payload["JobInfo"].update({
"EnvironmentKeyValue%d" % index: "{key}={value}".format(
@@ -539,8 +543,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin,
import nuke
captured_groups = []
- for lg_name, list_node_class in self.limit_groups.items():
- for node_class in list_node_class:
+ for limit_group in self.limit_groups:
+ lg_name = limit_group["name"]
+
+ for node_class in limit_group["value"]:
for node in nuke.allNodes(recurseGroups=True):
# ignore all nodes not member of defined class
if node.Class() not in node_class:
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..e6b49d4e58 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,9 +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.tests.lib import is_in_tests
+from ayon_core.pipeline import publish
+from ayon_core.lib import EnumDef, is_in_tests
from ayon_core.pipeline.version_start import get_versioning_start
from ayon_core.pipeline.farm.pyblish_functions import (
@@ -370,7 +369,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..3b34974576 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,9 +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.tests.lib import is_in_tests
+from ayon_core.pipeline import publish
+from ayon_core.lib import EnumDef, is_in_tests
from ayon_core.pipeline.version_start import get_versioning_start
from ayon_core.pipeline.farm.pyblish_functions import (
@@ -99,12 +98,33 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin,
"karma_rop", "vray_rop",
"redshift_rop"]
- aov_filter = {"maya": [r".*([Bb]eauty).*"],
- "blender": [r".*([Bb]eauty).*"],
- "aftereffects": [r".*"], # for everything from AE
- "harmony": [r".*"], # for everything from AE
- "celaction": [r".*"],
- "max": [r".*"]}
+ aov_filter = [
+ {
+ "name": "maya",
+ "value": [r".*([Bb]eauty).*"]
+ },
+ {
+ "name": "blender",
+ "value": [r".*([Bb]eauty).*"]
+ },
+ {
+ # for everything from AE
+ "name": "aftereffects",
+ "value": [r".*"]
+ },
+ {
+ "name": "harmony",
+ "value": [r".*"]
+ },
+ {
+ "name": "celaction",
+ "value": [r".*"]
+ },
+ {
+ "name": "max",
+ "value": [r".*"]
+ },
+ ]
environ_keys = [
"FTRACK_API_USER",
@@ -506,17 +526,23 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin,
self.log.debug("Instance has review explicitly disabled.")
do_not_add_review = True
+ aov_filter = {
+ item["name"]: item["value"]
+ for item in self.aov_filter
+ }
if isinstance(instance.data.get("expectedFiles")[0], dict):
instances = create_instances_for_aov(
instance, instance_skeleton_data,
- self.aov_filter, self.skip_integration_repre_list,
- do_not_add_review)
+ aov_filter,
+ self.skip_integration_repre_list,
+ do_not_add_review
+ )
else:
representations = prepare_representations(
instance_skeleton_data,
instance.data.get("expectedFiles"),
anatomy,
- self.aov_filter,
+ aov_filter,
self.skip_integration_repre_list,
do_not_add_review,
instance.context,
@@ -604,7 +630,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/modules/deadline/repository/custom/plugins/Ayon/Ayon.py b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
index a1f752605d..de0a2c6d7a 100644
--- a/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
+++ b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py
@@ -15,6 +15,7 @@ import re
import os
import platform
+__version__ = "1.0.0"
######################################################################
# This is the function that Deadline calls to get an instance of the
@@ -52,6 +53,9 @@ class AyonDeadlinePlugin(DeadlinePlugin):
del self.RenderArgumentCallback
def InitializeProcess(self):
+ self.LogInfo(
+ "Initializing process with AYON plugin {}".format(__version__)
+ )
self.PluginType = PluginType.Simple
self.StdoutHandling = True
diff --git a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
index 81aab00b93..459153c957 100644
--- a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
+++ b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py
@@ -14,7 +14,7 @@ from Deadline.Scripting import (
DirectoryUtils,
ProcessUtils,
)
-
+__version__ = "1.0.0"
VERSION_REGEX = re.compile(
r"(?P0|[1-9]\d*)"
r"\.(?P0|[1-9]\d*)"
@@ -593,7 +593,7 @@ def inject_render_job_id(deadlinePlugin):
def __main__(deadlinePlugin):
- print("*** GlobalJobPreload start ...")
+ print("*** GlobalJobPreload {} start ...".format(__version__))
print(">>> Getting job ...")
job = deadlinePlugin.GetJob()
diff --git a/client/ayon_core/modules/royalrender/lib.py b/client/ayon_core/modules/royalrender/lib.py
index d985a39d24..b53c5e6186 100644
--- a/client/ayon_core/modules/royalrender/lib.py
+++ b/client/ayon_core/modules/royalrender/lib.py
@@ -10,7 +10,12 @@ from datetime import datetime
import pyblish.api
-from ayon_core.lib import BoolDef, NumberDef, is_running_from_build
+from ayon_core.lib import (
+ BoolDef,
+ NumberDef,
+ is_running_from_build,
+ is_in_tests,
+)
from ayon_core.lib.execute import run_ayon_launcher_process
from ayon_core.modules.royalrender.api import Api as rrApi
from ayon_core.modules.royalrender.rr_job import (
@@ -22,7 +27,6 @@ from ayon_core.modules.royalrender.rr_job import (
from ayon_core.pipeline import AYONPyblishPluginMixin
from ayon_core.pipeline.publish import KnownPublishError
from ayon_core.pipeline.publish.lib import get_published_workfile_instance
-from ayon_core.tests.lib import is_in_tests
class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin,
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/modules/timers_manager/timers_manager.py b/client/ayon_core/modules/timers_manager/timers_manager.py
index daba0cead9..f8f0e4a526 100644
--- a/client/ayon_core/modules/timers_manager/timers_manager.py
+++ b/client/ayon_core/modules/timers_manager/timers_manager.py
@@ -3,8 +3,8 @@ import platform
from ayon_core.client import get_asset_by_name
-from ayon_core.modules import (
- OpenPypeModule,
+from ayon_core.addon import (
+ AYONAddon,
ITrayService,
IPluginPaths
)
@@ -76,7 +76,7 @@ class ExampleTimersManagerConnector:
class TimersManager(
- OpenPypeModule,
+ AYONAddon,
ITrayService,
IPluginPaths
):
@@ -99,23 +99,27 @@ class TimersManager(
"start_timer"
)
- def initialize(self, modules_settings):
- timers_settings = modules_settings[self.name]
+ def initialize(self, studio_settings):
+ timers_settings = studio_settings.get(self.name)
+ enabled = timers_settings is not None
- self.enabled = timers_settings["enabled"]
+ auto_stop = False
+ full_time = 0
+ message_time = 0
+ if enabled:
+ # When timer will stop if idle manager is running (minutes)
+ full_time = int(timers_settings["full_time"] * 60)
+ # How many minutes before the timer is stopped will popup the message
+ message_time = int(timers_settings["message_time"] * 60)
- # When timer will stop if idle manager is running (minutes)
- full_time = int(timers_settings["full_time"] * 60)
- # How many minutes before the timer is stopped will popup the message
- message_time = int(timers_settings["message_time"] * 60)
-
- auto_stop = timers_settings["auto_stop"]
- platform_name = platform.system().lower()
- # Turn of auto stop on MacOs because pynput requires root permissions
- # and on linux can cause thread locks on application close
- if full_time <= 0 or platform_name in ("darwin", "linux"):
- auto_stop = False
+ auto_stop = timers_settings["auto_stop"]
+ platform_name = platform.system().lower()
+ # Turn of auto stop on MacOs because pynput requires root permissions
+ # and on linux can cause thread locks on application close
+ if full_time <= 0 or platform_name in ("darwin", "linux"):
+ auto_stop = False
+ self.enabled = enabled
self.auto_stop = auto_stop
self.time_show_message = full_time - message_time
self.time_stop_timer = full_time
diff --git a/client/ayon_core/pipeline/colorspace.py b/client/ayon_core/pipeline/colorspace.py
index d77f301498..1b795e1c39 100644
--- a/client/ayon_core/pipeline/colorspace.py
+++ b/client/ayon_core/pipeline/colorspace.py
@@ -254,7 +254,7 @@ def get_imageio_file_rules_colorspace_from_filepath(
# match file rule from path
colorspace_name = None
- for file_rule in file_rules.values():
+ for file_rule in file_rules:
pattern = file_rule["pattern"]
extension = file_rule["ext"]
ext_match = re.match(
@@ -281,7 +281,7 @@ def get_config_file_rules_colorspace_from_filepath(config_path, filepath):
filepath (str): path leading to a file
Returns:
- Any[str, None]: matching colorspace name
+ Union[str, None]: matching colorspace name
"""
if not compatibility_check():
# python environment is not compatible with PyOpenColorIO
@@ -918,28 +918,13 @@ def get_imageio_file_rules(project_name, host_name, project_settings=None):
Defaults to None.
Returns:
- dict: file rules data
+ list[dict[str, Any]]: file rules data
"""
project_settings = project_settings or get_project_settings(project_name)
imageio_global, imageio_host = _get_imageio_settings(
project_settings, host_name)
- # get file rules from global and host_name
- frules_global = imageio_global["file_rules"]
- activate_global_rules = (
- frules_global.get("activate_global_file_rules", False)
- # TODO: remove this in future - backward compatibility
- or frules_global.get("enabled")
- )
- global_rules = frules_global["rules"]
-
- if not activate_global_rules:
- log.info(
- "Colorspace global file rules are disabled."
- )
- global_rules = {}
-
# host is optional, some might not have any settings
frules_host = imageio_host.get("file_rules", {})
@@ -949,8 +934,24 @@ def get_imageio_file_rules(project_name, host_name, project_settings=None):
# TODO: remove this in future - backward compatibility
activate_host_rules = frules_host.get("enabled", False)
- # return host rules if activated or global rules
- return frules_host["rules"] if activate_host_rules else global_rules
+ if activate_host_rules:
+ return frules_host["rules"]
+
+ # get file rules from global and host_name
+ frules_global = imageio_global["file_rules"]
+ activate_global_rules = (
+ frules_global.get("activate_global_file_rules", False)
+ # TODO: remove this in future - backward compatibility
+ or frules_global.get("enabled")
+ )
+
+ if not activate_global_rules:
+ log.info(
+ "Colorspace global file rules are disabled."
+ )
+ return []
+
+ return frules_global["rules"]
def get_remapped_colorspace_to_native(
diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py
index 197b1eb6e6..445e27604d 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
@@ -20,20 +19,20 @@ from ayon_core.client import (
get_asset_name_identifier,
get_ayon_server_api_connection,
)
+from ayon_core.lib import is_in_tests
from ayon_core.lib.events import emit_event
from ayon_core.addon import load_addons, AddonsManager
from ayon_core.settings import get_project_settings
-from ayon_core.tests.lib import is_in_tests
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 +115,17 @@ 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")
+ # 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."
+ # )
- 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,14 +152,13 @@ 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
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):
@@ -256,8 +249,6 @@ def uninstall_host():
deregister_host()
- legacy_io.uninstall()
-
log.info("Successfully uninstalled Avalon!")
@@ -482,13 +473,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 +524,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 +553,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 +601,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/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()
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/pipeline/template_data.py b/client/ayon_core/pipeline/template_data.py
index a1b944a431..a5ca84c754 100644
--- a/client/ayon_core/pipeline/template_data.py
+++ b/client/ayon_core/pipeline/template_data.py
@@ -17,12 +17,11 @@ def get_general_template_data(system_settings=None):
if not system_settings:
system_settings = get_system_settings()
- studio_name = system_settings["general"]["studio_name"]
- studio_code = system_settings["general"]["studio_code"]
+ core_settings = system_settings["core"]
return {
"studio": {
- "name": studio_name,
- "code": studio_code
+ "name": core_settings["studio_name"],
+ "code": core_settings["studio_code"]
},
"user": get_ayon_username()
}
diff --git a/client/ayon_core/pipeline/workfile/build_workfile.py b/client/ayon_core/pipeline/workfile/build_workfile.py
index c62facaaa9..8df3830d6e 100644
--- a/client/ayon_core/pipeline/workfile/build_workfile.py
+++ b/client/ayon_core/pipeline/workfile/build_workfile.py
@@ -321,7 +321,7 @@ class BuildWorkfile:
continue
# Check families
- profile_families = profile.get("families")
+ profile_families = profile.get("product_types")
if not profile_families:
self.log.warning((
"Build profile is missing families configuration: {0}"
@@ -338,7 +338,7 @@ class BuildWorkfile:
continue
# Prepare lowered families and representation names
- profile["families_lowered"] = [
+ profile["product_types_lowered"] = [
fam.lower() for fam in profile_families
]
profile["repre_names_lowered"] = [
@@ -375,11 +375,11 @@ class BuildWorkfile:
family_low = family.lower()
for profile in profiles:
# Skip profile if does not contain family
- if family_low not in profile["families_lowered"]:
+ if family_low not in profile["product_types_lowered"]:
continue
# Precompile name filters as regexes
- profile_regexes = profile.get("subset_name_filters")
+ profile_regexes = profile.get("product_name_filters")
if profile_regexes:
_profile_regexes = []
for regex in profile_regexes:
@@ -538,7 +538,7 @@ class BuildWorkfile:
build_presets += self.build_presets.get("linked_assets", [])
subset_ids_ordered = []
for preset in build_presets:
- for preset_family in preset["families"]:
+ for preset_family in preset["product_types"]:
for id, subset in subsets_by_id.items():
if preset_family not in subset["data"].get("families", []):
continue
diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py
index 1afe26813f..3b42b6ec0a 100644
--- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py
+++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py
@@ -553,6 +553,12 @@ class AbstractTemplateBuilder(object):
self.clear_shared_populate_data()
+ def open_template(self):
+ """Open template file with registered host."""
+ template_preset = self.get_template_preset()
+ template_path = template_preset["path"]
+ self.host.open_file(template_path)
+
@abstractmethod
def import_template(self, template_path):
"""
diff --git a/client/ayon_core/plugins/publish/cleanup.py b/client/ayon_core/plugins/publish/cleanup.py
index 7bed3269c2..df68af7e57 100644
--- a/client/ayon_core/plugins/publish/cleanup.py
+++ b/client/ayon_core/plugins/publish/cleanup.py
@@ -5,7 +5,7 @@ import shutil
import pyblish.api
import re
-from ayon_core.tests.lib import is_in_tests
+from ayon_core.lib import is_in_tests
class CleanUp(pyblish.api.InstancePlugin):
diff --git a/client/ayon_core/plugins/publish/collect_audio.py b/client/ayon_core/plugins/publish/collect_audio.py
index 94477e5578..6da3fd0685 100644
--- a/client/ayon_core/plugins/publish/collect_audio.py
+++ b/client/ayon_core/plugins/publish/collect_audio.py
@@ -43,7 +43,7 @@ class CollectAudio(pyblish.api.ContextPlugin):
"unreal"
]
- audio_subset_name = "audioMain"
+ audio_product_name = "audioMain"
def process(self, context):
# Fake filtering by family inside context plugin
@@ -71,9 +71,9 @@ class CollectAudio(pyblish.api.ContextPlugin):
asset_names = set(instances_by_asset_name.keys())
self.log.debug((
- "Searching for audio subset '{subset}' in assets {assets}"
+ "Searching for audio product '{subset}' in assets {assets}"
).format(
- subset=self.audio_subset_name,
+ subset=self.audio_product_name,
assets=", ".join([
'"{}"'.format(asset_name)
for asset_name in asset_names
@@ -130,11 +130,11 @@ class CollectAudio(pyblish.api.ContextPlugin):
}
asset_ids = set(asset_id_by_name.values())
- # Query subsets with name define by 'audio_subset_name' attr
+ # Query subsets with name define by 'audio_product_name' attr
# - one or none subsets with the name should be available on an asset
subset_docs = get_subsets(
project_name,
- subset_names=[self.audio_subset_name],
+ subset_names=[self.audio_product_name],
asset_ids=asset_ids,
fields=["_id", "parent"]
)
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..7adacbc463 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,8 +61,10 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin):
("AVALON_ASSET", asset_name),
("AVALON_TASK", task_name)
):
- legacy_io.Session[key] = value
- os.environ[key] = value
+ if value is None:
+ os.environ.pop(key, None)
+ else:
+ os.environ[key] = value
def create_instance(
self,
diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py
index 5ffcd669a0..a7b6064b7a 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
@@ -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
@@ -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
@@ -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
diff --git a/client/ayon_core/plugins/publish/collect_scene_version.py b/client/ayon_core/plugins/publish/collect_scene_version.py
index 254d3c913d..b04900c74e 100644
--- a/client/ayon_core/plugins/publish/collect_scene_version.py
+++ b/client/ayon_core/plugins/publish/collect_scene_version.py
@@ -1,8 +1,7 @@
import os
import pyblish.api
-from ayon_core.lib import get_version_from_path
-from ayon_core.tests.lib import is_in_tests
+from ayon_core.lib import get_version_from_path, is_in_tests
from ayon_core.pipeline import KnownPublishError
diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py
index 91d39882ae..b0bc94c317 100644
--- a/client/ayon_core/plugins/publish/extract_review.py
+++ b/client/ayon_core/plugins/publish/extract_review.py
@@ -74,7 +74,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
alpha_exts = ["exr", "png", "dpx"]
# Preset attributes
- profiles = None
+ profiles = []
def process(self, instance):
self.log.debug(str(instance.data["representations"]))
@@ -112,7 +112,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
self.profiles,
{
"hosts": host_name,
- "families": family,
+ "product_types": family,
},
logger=self.log)
if not profile:
@@ -719,12 +719,12 @@ class ExtractReview(pyblish.api.InstancePlugin):
lut_filters = self.lut_filters(new_repre, instance, ffmpeg_input_args)
ffmpeg_video_filters.extend(lut_filters)
- bg_alpha = 0
+ bg_alpha = 0.0
bg_color = output_def.get("bg_color")
if bg_color:
bg_red, bg_green, bg_blue, bg_alpha = bg_color
- if bg_alpha > 0:
+ if bg_alpha > 0.0:
if not temp_data["input_allow_bg"]:
self.log.info((
"Output definition has defined BG color input was"
@@ -734,8 +734,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
bg_color_hex = "#{0:0>2X}{1:0>2X}{2:0>2X}".format(
bg_red, bg_green, bg_blue
)
- bg_color_alpha = float(bg_alpha) / 255
- bg_color_str = "{}@{}".format(bg_color_hex, bg_color_alpha)
+ bg_color_str = "{}@{}".format(bg_color_hex, bg_alpha)
self.log.info("Applying BG color {}".format(bg_color_str))
color_args = [
@@ -1079,7 +1078,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
fill_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format(
f_red, f_green, f_blue
)
- fill_color_alpha = float(f_alpha) / 255
+ fill_color_alpha = f_alpha
line_thickness = letter_box_def["line_thickness"]
line_color = letter_box_def["line_color"]
@@ -1087,7 +1086,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
line_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format(
l_red, l_green, l_blue
)
- line_color_alpha = float(l_alpha) / 255
+ line_color_alpha = l_alpha
# test ratios and define if pillar or letter boxes
output_ratio = float(output_width) / float(output_height)
@@ -1283,8 +1282,12 @@ class ExtractReview(pyblish.api.InstancePlugin):
# NOTE Setting only one of `width` or `heigth` is not allowed
# - settings value can't have None but has value of 0
- output_width = output_def.get("width") or output_width or None
- output_height = output_def.get("height") or output_height or None
+ output_width = (
+ output_def.get("output_width") or output_width or None
+ )
+ output_height = (
+ output_def.get("output_height") or output_height or None
+ )
# Force to use input resolution if output resolution was not defined
# in settings. Resolution from instance is not used when
# 'use_input_res' is set to 'True'.
@@ -1294,7 +1297,12 @@ class ExtractReview(pyblish.api.InstancePlugin):
overscan_color_value = "black"
overscan_color = output_def.get("overscan_color")
if overscan_color:
- bg_red, bg_green, bg_blue, _ = overscan_color
+ if len(overscan_color) == 3:
+ bg_red, bg_green, bg_blue = overscan_color
+ else:
+ # Backwards compatibility
+ bg_red, bg_green, bg_blue, _ = overscan_color
+
overscan_color_value = "#{0:0>2X}{1:0>2X}{2:0>2X}".format(
bg_red, bg_green, bg_blue
)
@@ -1503,14 +1511,16 @@ class ExtractReview(pyblish.api.InstancePlugin):
subset_name (str): name of subset
Returns:
- list: Containg all output definitions matching entered families.
+ dict[str, Any]: Containing all output definitions matching entered
+ families.
"""
- outputs = profile.get("outputs") or {}
- if not outputs:
- return outputs
-
filtered_outputs = {}
- for filename_suffix, output_def in outputs.items():
+ outputs = profile.get("outputs")
+ if not outputs:
+ return filtered_outputs
+
+ for output_def in outputs:
+ filename_suffix = output_def["name"]
output_filters = output_def.get("filter")
# If no filter on output preset, skip filtering and add output
# profile for farther processing
@@ -1523,16 +1533,16 @@ class ExtractReview(pyblish.api.InstancePlugin):
continue
# Subsets name filters
- subset_filters = [
- subset_filter
- for subset_filter in output_filters.get("subsets", [])
+ product_name_filters = [
+ name_filter
+ for name_filter in output_filters.get("product_names", [])
# Skip empty strings
- if subset_filter
+ if name_filter
]
- if subset_name and subset_filters:
+ if subset_name and product_name_filters:
match = False
- for subset_filter in subset_filters:
- compiled = re.compile(subset_filter)
+ for product_name_filter in product_name_filters:
+ compiled = re.compile(product_name_filter)
if compiled.search(subset_name):
match = True
break
diff --git a/client/ayon_core/settings/__init__.py b/client/ayon_core/settings/__init__.py
index 51019ca570..ed3aaef7d4 100644
--- a/client/ayon_core/settings/__init__.py
+++ b/client/ayon_core/settings/__init__.py
@@ -4,7 +4,6 @@ from .constants import (
)
from .lib import (
get_general_environments,
- get_global_settings,
get_system_settings,
get_project_settings,
get_current_project_settings,
@@ -17,7 +16,6 @@ __all__ = (
"PROJECT_SETTINGS_KEY",
"get_general_environments",
- "get_global_settings",
"get_system_settings",
"get_project_settings",
"get_current_project_settings",
diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py
index ed1199d517..2577a3af06 100644
--- a/client/ayon_core/settings/ayon_settings.py
+++ b/client/ayon_core/settings/ayon_settings.py
@@ -52,117 +52,22 @@ def _convert_color(color_value):
return color_value
-def _convert_host_imageio(host_settings):
- if "imageio" not in host_settings:
- return
-
- # --- imageio ---
- ayon_imageio = host_settings["imageio"]
- # TODO remove when fixed on server
- if "ocio_config" in ayon_imageio["ocio_config"]:
- ayon_imageio["ocio_config"]["filepath"] = (
- ayon_imageio["ocio_config"].pop("ocio_config")
- )
- # Convert file rules
- imageio_file_rules = ayon_imageio["file_rules"]
- new_rules = {}
- for rule in imageio_file_rules["rules"]:
- name = rule.pop("name")
- new_rules[name] = rule
- imageio_file_rules["rules"] = new_rules
-
-
-def _convert_applications_groups(groups, clear_metadata):
- environment_key = "environment"
- if isinstance(groups, dict):
- new_groups = []
- for name, item in groups.items():
- item["name"] = name
- new_groups.append(item)
- groups = new_groups
-
- output = {}
- group_dynamic_labels = {}
- for group in groups:
- group_name = group.pop("name")
- if "label" in group:
- group_dynamic_labels[group_name] = group["label"]
-
- tool_group_envs = group[environment_key]
- if isinstance(tool_group_envs, six.string_types):
- group[environment_key] = json.loads(tool_group_envs)
-
- variants = {}
- variant_dynamic_labels = {}
- for variant in group.pop("variants"):
- variant_name = variant.pop("name")
- label = variant.get("label")
- if label and label != variant_name:
- variant_dynamic_labels[variant_name] = label
- variant_envs = variant[environment_key]
- if isinstance(variant_envs, six.string_types):
- variant[environment_key] = json.loads(variant_envs)
- variants[variant_name] = variant
- group["variants"] = variants
-
- if not clear_metadata:
- variants["__dynamic_keys_labels__"] = variant_dynamic_labels
- output[group_name] = group
-
- if not clear_metadata:
- output["__dynamic_keys_labels__"] = group_dynamic_labels
- return output
-
-
-def _convert_applications_system_settings(
- ayon_settings, output, clear_metadata
-):
- # Addon settings
- addon_settings = ayon_settings["applications"]
-
- # Remove project settings
- addon_settings.pop("only_available", None)
-
- # Applications settings
- ayon_apps = addon_settings["applications"]
-
- additional_apps = ayon_apps.pop("additional_apps")
- applications = _convert_applications_groups(
- ayon_apps, clear_metadata
- )
- applications["additional_apps"] = _convert_applications_groups(
- additional_apps, clear_metadata
- )
-
- # Tools settings
- tools = _convert_applications_groups(
- addon_settings["tool_groups"], clear_metadata
- )
-
- output["applications"] = applications
- output["tools"] = {"tool_groups": tools}
-
-
def _convert_general(ayon_settings, output, default_settings):
- # TODO get studio name/code
- core_settings = ayon_settings["core"]
- environments = core_settings["environments"]
- if isinstance(environments, six.string_types):
- environments = json.loads(environments)
-
- general = default_settings["general"]
- general.update({
- "log_to_server": False,
- "studio_name": core_settings["studio_name"],
- "studio_code": core_settings["studio_code"],
- "environment": environments
- })
- output["general"] = general
+ output["core"] = ayon_settings["core"]
+ version_check_interval = (
+ default_settings["general"]["version_check_interval"]
+ )
+ output["general"] = {
+ "version_check_interval": version_check_interval
+ }
def _convert_kitsu_system_settings(
ayon_settings, output, addon_versions, default_settings
):
+ if "kitsu" in ayon_settings:
+ output["kitsu"] = ayon_settings["kitsu"]
+
enabled = addon_versions.get("kitsu") is not None
kitsu_settings = default_settings["modules"]["kitsu"]
kitsu_settings["enabled"] = enabled
@@ -171,39 +76,6 @@ def _convert_kitsu_system_settings(
output["modules"]["kitsu"] = kitsu_settings
-def _convert_timers_manager_system_settings(
- ayon_settings, output, addon_versions, default_settings
-):
- enabled = addon_versions.get("timers_manager") is not None
- manager_settings = default_settings["modules"]["timers_manager"]
- manager_settings["enabled"] = enabled
- if enabled:
- ayon_manager = ayon_settings["timers_manager"]
- manager_settings.update({
- key: ayon_manager[key]
- for key in {
- "auto_stop",
- "full_time",
- "message_time",
- "disregard_publishing"
- }
- })
- output["modules"]["timers_manager"] = manager_settings
-
-
-def _convert_clockify_system_settings(
- ayon_settings, output, addon_versions, default_settings
-):
- enabled = addon_versions.get("clockify") is not None
- clockify_settings = default_settings["modules"]["clockify"]
- clockify_settings["enabled"] = enabled
- if enabled:
- clockify_settings["workspace_name"] = (
- ayon_settings["clockify"]["workspace_name"]
- )
- output["modules"]["clockify"] = clockify_settings
-
-
def _convert_deadline_system_settings(
ayon_settings, output, addon_versions, default_settings
):
@@ -242,21 +114,24 @@ def _convert_modules_system(
# TODO add 'enabled' values
for func in (
_convert_kitsu_system_settings,
- _convert_timers_manager_system_settings,
- _convert_clockify_system_settings,
_convert_deadline_system_settings,
_convert_royalrender_system_settings,
):
func(ayon_settings, output, addon_versions, default_settings)
+ for key in {
+ "timers_manager",
+ "clockify",
+ }:
+ if addon_versions.get(key):
+ output[key] = ayon_settings
+ else:
+ output.pop(key, None)
+
modules_settings = output["modules"]
for module_name in (
"sync_server",
- "log_viewer",
- "standalonepublish_tool",
- "project_manager",
"job_queue",
- "avalon",
"addon_paths",
):
settings = default_settings["modules"][module_name]
@@ -290,7 +165,7 @@ def convert_system_settings(ayon_settings, default_settings, addon_versions):
"modules": {}
}
if "applications" in ayon_settings:
- _convert_applications_system_settings(ayon_settings, output, False)
+ output["applications"] = ayon_settings["applications"]
if "core" in ayon_settings:
_convert_general(ayon_settings, output, default_settings)
@@ -313,26 +188,10 @@ def convert_system_settings(ayon_settings, default_settings, addon_versions):
# --------- Project settings ---------
-def _convert_applications_project_settings(ayon_settings, output):
- if "applications" not in ayon_settings:
- return
-
- output["applications"] = {
- "only_available": ayon_settings["applications"]["only_available"]
- }
-
-
def _convert_blender_project_settings(ayon_settings, output):
if "blender" not in ayon_settings:
return
ayon_blender = ayon_settings["blender"]
- _convert_host_imageio(ayon_blender)
-
- ayon_publish = ayon_blender["publish"]
-
- for plugin in ("ExtractThumbnail", "ExtractPlayblast"):
- plugin_settings = ayon_publish[plugin]
- plugin_settings["presets"] = json.loads(plugin_settings["presets"])
output["blender"] = ayon_blender
@@ -342,7 +201,6 @@ def _convert_celaction_project_settings(ayon_settings, output):
return
ayon_celaction = ayon_settings["celaction"]
- _convert_host_imageio(ayon_celaction)
output["celaction"] = ayon_celaction
@@ -353,53 +211,6 @@ def _convert_flame_project_settings(ayon_settings, output):
ayon_flame = ayon_settings["flame"]
- ayon_publish_flame = ayon_flame["publish"]
- # Plugin 'ExtractSubsetResources' renamed to 'ExtractProductResources'
- if "ExtractSubsetResources" in ayon_publish_flame:
- ayon_product_resources = ayon_publish_flame["ExtractSubsetResources"]
- else:
- ayon_product_resources = (
- ayon_publish_flame.pop("ExtractProductResources"))
- ayon_publish_flame["ExtractSubsetResources"] = ayon_product_resources
-
- # 'ExtractSubsetResources' changed model of 'export_presets_mapping'
- # - some keys were moved under 'other_parameters'
- new_subset_resources = {}
- for item in ayon_product_resources.pop("export_presets_mapping"):
- name = item.pop("name")
- if "other_parameters" in item:
- other_parameters = item.pop("other_parameters")
- item.update(other_parameters)
- new_subset_resources[name] = item
-
- ayon_product_resources["export_presets_mapping"] = new_subset_resources
-
- # 'imageio' changed model
- # - missing subkey 'project' which is in root of 'imageio' model
- _convert_host_imageio(ayon_flame)
- ayon_imageio_flame = ayon_flame["imageio"]
- if "project" not in ayon_imageio_flame:
- profile_mapping = ayon_imageio_flame.pop("profilesMapping")
- ayon_flame["imageio"] = {
- "project": ayon_imageio_flame,
- "profilesMapping": profile_mapping
- }
-
- ayon_load_flame = ayon_flame["load"]
- for plugin_name in ("LoadClip", "LoadClipBatch"):
- plugin_settings = ayon_load_flame[plugin_name]
- plugin_settings["families"] = plugin_settings.pop("product_types")
- plugin_settings["clip_name_template"] = (
- plugin_settings["clip_name_template"]
- .replace("{folder[name]}", "{asset}")
- .replace("{product[name]}", "{subset}")
- )
- plugin_settings["layer_rename_template"] = (
- plugin_settings["layer_rename_template"]
- .replace("{folder[name]}", "{asset}")
- .replace("{product[name]}", "{subset}")
- )
-
output["flame"] = ayon_flame
@@ -408,40 +219,6 @@ def _convert_fusion_project_settings(ayon_settings, output):
return
ayon_fusion = ayon_settings["fusion"]
- _convert_host_imageio(ayon_fusion)
-
- ayon_imageio_fusion = ayon_fusion["imageio"]
-
- if "ocioSettings" in ayon_imageio_fusion:
- ayon_ocio_setting = ayon_imageio_fusion.pop("ocioSettings")
- paths = ayon_ocio_setting.pop("ocioPathModel")
- for key, value in tuple(paths.items()):
- new_value = []
- if value:
- new_value.append(value)
- paths[key] = new_value
-
- ayon_ocio_setting["configFilePath"] = paths
- ayon_imageio_fusion["ocio"] = ayon_ocio_setting
- elif "ocio" in ayon_imageio_fusion:
- paths = ayon_imageio_fusion["ocio"].pop("configFilePath")
- for key, value in tuple(paths.items()):
- new_value = []
- if value:
- new_value.append(value)
- paths[key] = new_value
- ayon_imageio_fusion["ocio"]["configFilePath"] = paths
-
- _convert_host_imageio(ayon_imageio_fusion)
-
- ayon_create_saver = ayon_fusion["create"]["CreateSaver"]
- ayon_create_saver["temp_rendering_path_template"] = (
- ayon_create_saver["temp_rendering_path_template"]
- .replace("{product[name]}", "{subset}")
- .replace("{product[type]}", "{family}")
- .replace("{folder[name]}", "{asset}")
- .replace("{task[name]}", "{task}")
- )
output["fusion"] = ayon_fusion
@@ -452,173 +229,6 @@ def _convert_maya_project_settings(ayon_settings, output):
ayon_maya = ayon_settings["maya"]
- # Change key of render settings
- ayon_maya["RenderSettings"] = ayon_maya.pop("render_settings")
-
- # Convert extensions mapping
- ayon_maya["ext_mapping"] = {
- item["name"]: item["value"]
- for item in ayon_maya["ext_mapping"]
- }
-
- # Maya dirmap
- ayon_maya_dirmap = ayon_maya.pop("maya_dirmap")
- ayon_maya_dirmap_path = ayon_maya_dirmap["paths"]
- ayon_maya_dirmap_path["source-path"] = (
- ayon_maya_dirmap_path.pop("source_path")
- )
- ayon_maya_dirmap_path["destination-path"] = (
- ayon_maya_dirmap_path.pop("destination_path")
- )
- ayon_maya["maya-dirmap"] = ayon_maya_dirmap
-
- # Create plugins
- ayon_create = ayon_maya["create"]
- ayon_create_static_mesh = ayon_create["CreateUnrealStaticMesh"]
- if "static_mesh_prefixes" in ayon_create_static_mesh:
- ayon_create_static_mesh["static_mesh_prefix"] = (
- ayon_create_static_mesh.pop("static_mesh_prefixes")
- )
-
- # --- Publish (START) ---
- ayon_publish = ayon_maya["publish"]
- try:
- attributes = json.loads(
- ayon_publish["ValidateAttributes"]["attributes"]
- )
- except ValueError:
- attributes = {}
- ayon_publish["ValidateAttributes"]["attributes"] = attributes
-
- try:
- SUFFIX_NAMING_TABLE = json.loads(
- ayon_publish
- ["ValidateTransformNamingSuffix"]
- ["SUFFIX_NAMING_TABLE"]
- )
- except ValueError:
- SUFFIX_NAMING_TABLE = {}
- ayon_publish["ValidateTransformNamingSuffix"]["SUFFIX_NAMING_TABLE"] = (
- SUFFIX_NAMING_TABLE
- )
-
- validate_frame_range = ayon_publish["ValidateFrameRange"]
- if "exclude_product_types" in validate_frame_range:
- validate_frame_range["exclude_families"] = (
- validate_frame_range.pop("exclude_product_types"))
-
- # Extract playblast capture settings
- validate_rendern_settings = ayon_publish["ValidateRenderSettings"]
- for key in (
- "arnold_render_attributes",
- "vray_render_attributes",
- "redshift_render_attributes",
- "renderman_render_attributes",
- ):
- if key not in validate_rendern_settings:
- continue
- validate_rendern_settings[key] = [
- [item["type"], item["value"]]
- for item in validate_rendern_settings[key]
- ]
-
- plugin_path_attributes = ayon_publish["ValidatePluginPathAttributes"]
- plugin_path_attributes["attribute"] = {
- item["name"]: item["value"]
- for item in plugin_path_attributes["attribute"]
- }
-
- ayon_capture_preset = ayon_publish["ExtractPlayblast"]["capture_preset"]
- display_options = ayon_capture_preset["DisplayOptions"]
- for key in ("background", "backgroundBottom", "backgroundTop"):
- display_options[key] = _convert_color(display_options[key])
-
- for src_key, dst_key in (
- ("DisplayOptions", "Display Options"),
- ("ViewportOptions", "Viewport Options"),
- ("CameraOptions", "Camera Options"),
- ):
- ayon_capture_preset[dst_key] = ayon_capture_preset.pop(src_key)
-
- viewport_options = ayon_capture_preset["Viewport Options"]
- viewport_options["pluginObjects"] = {
- item["name"]: item["value"]
- for item in viewport_options["pluginObjects"]
- }
-
- ayon_playblast_settings = ayon_publish["ExtractPlayblast"]["profiles"]
- if ayon_playblast_settings:
- for setting in ayon_playblast_settings:
- capture_preset = setting["capture_preset"]
- display_options = capture_preset["DisplayOptions"]
- for key in ("background", "backgroundBottom", "backgroundTop"):
- display_options[key] = _convert_color(display_options[key])
-
- for src_key, dst_key in (
- ("DisplayOptions", "Display Options"),
- ("ViewportOptions", "Viewport Options"),
- ("CameraOptions", "Camera Options"),
- ):
- capture_preset[dst_key] = capture_preset.pop(src_key)
-
- viewport_options = capture_preset["Viewport Options"]
- viewport_options["pluginObjects"] = {
- item["name"]: item["value"]
- for item in viewport_options["pluginObjects"]
- }
-
- # Extract Camera Alembic bake attributes
- try:
- bake_attributes = json.loads(
- ayon_publish["ExtractCameraAlembic"]["bake_attributes"]
- )
- except ValueError:
- bake_attributes = []
- ayon_publish["ExtractCameraAlembic"]["bake_attributes"] = bake_attributes
-
- # --- Publish (END) ---
- for renderer_settings in ayon_maya["RenderSettings"].values():
- if (
- not isinstance(renderer_settings, dict)
- or "additional_options" not in renderer_settings
- ):
- continue
- renderer_settings["additional_options"] = [
- [item["attribute"], item["value"]]
- for item in renderer_settings["additional_options"]
- ]
-
- # Workfile build
- ayon_workfile_build = ayon_maya["workfile_build"]
- for item in ayon_workfile_build["profiles"]:
- for key in ("current_context", "linked_assets"):
- for subitem in item[key]:
- if "families" in subitem:
- break
- subitem["families"] = subitem.pop("product_types")
- subitem["subset_name_filters"] = subitem.pop(
- "product_name_filters")
-
- _convert_host_imageio(ayon_maya)
-
- ayon_maya_load = ayon_maya["load"]
- load_colors = ayon_maya_load["colors"]
- for key, color in tuple(load_colors.items()):
- load_colors[key] = _convert_color(color)
-
- reference_loader = ayon_maya_load["reference_loader"]
- reference_loader["namespace"] = (
- reference_loader["namespace"]
- .replace("{product[name]}", "{subset}")
- )
-
- if ayon_maya_load.get("import_loader"):
- import_loader = ayon_maya_load["import_loader"]
- import_loader["namespace"] = (
- import_loader["namespace"]
- .replace("{product[name]}", "{subset}")
- )
-
output["maya"] = ayon_maya
@@ -627,31 +237,6 @@ def _convert_3dsmax_project_settings(ayon_settings, output):
return
ayon_max = ayon_settings["max"]
- _convert_host_imageio(ayon_max)
- if "PointCloud" in ayon_max:
- point_cloud_attribute = ayon_max["PointCloud"]["attribute"]
- new_point_cloud_attribute = {
- item["name"]: item["value"]
- for item in point_cloud_attribute
- }
- ayon_max["PointCloud"]["attribute"] = new_point_cloud_attribute
- # --- Publish (START) ---
- ayon_publish = ayon_max["publish"]
- if "ValidateAttributes" in ayon_publish:
- try:
- attributes = json.loads(
- ayon_publish["ValidateAttributes"]["attributes"]
- )
- except ValueError:
- attributes = {}
- ayon_publish["ValidateAttributes"]["attributes"] = attributes
-
- if "ValidateLoadedPlugin" in ayon_publish:
- loaded_plugin = (
- ayon_publish["ValidateLoadedPlugin"]["family_plugins_mapping"]
- )
- for item in loaded_plugin:
- item["families"] = item.pop("product_types")
output["max"] = ayon_max
@@ -708,15 +293,6 @@ def _convert_nuke_project_settings(ayon_settings, output):
ayon_nuke = ayon_settings["nuke"]
- # --- Dirmap ---
- dirmap = ayon_nuke.pop("dirmap")
- for src_key, dst_key in (
- ("source_path", "source-path"),
- ("destination_path", "destination-path"),
- ):
- dirmap["paths"][dst_key] = dirmap["paths"].pop(src_key)
- ayon_nuke["nuke-dirmap"] = dirmap
-
# --- Load ---
ayon_load = ayon_nuke["load"]
ayon_load["LoadClip"]["_representations"] = (
@@ -808,7 +384,6 @@ def _convert_nuke_project_settings(ayon_settings, output):
# --- ImageIO ---
# NOTE 'monitorOutLut' is maybe not yet in v3 (ut should be)
- _convert_host_imageio(ayon_nuke)
ayon_imageio = ayon_nuke["imageio"]
# workfile
@@ -857,7 +432,6 @@ def _convert_hiero_project_settings(ayon_settings, output):
return
ayon_hiero = ayon_settings["hiero"]
- _convert_host_imageio(ayon_hiero)
new_gui_filters = {}
for item in ayon_hiero.pop("filters", []):
@@ -887,19 +461,6 @@ def _convert_photoshop_project_settings(ayon_settings, output):
return
ayon_photoshop = ayon_settings["photoshop"]
- _convert_host_imageio(ayon_photoshop)
-
- ayon_publish_photoshop = ayon_photoshop["publish"]
-
- ayon_colorcoded = ayon_publish_photoshop["CollectColorCodedInstances"]
- if "flatten_product_type_template" in ayon_colorcoded:
- ayon_colorcoded["flatten_subset_template"] = (
- ayon_colorcoded.pop("flatten_product_type_template"))
-
- collect_review = ayon_publish_photoshop["CollectReview"]
- if "active" in collect_review:
- collect_review["publish"] = collect_review.pop("active")
-
output["photoshop"] = ayon_photoshop
@@ -908,45 +469,14 @@ def _convert_substancepainter_project_settings(ayon_settings, output):
return
ayon_substance_painter = ayon_settings["substancepainter"]
- _convert_host_imageio(ayon_substance_painter)
- if "shelves" in ayon_substance_painter:
- shelves_items = ayon_substance_painter["shelves"]
- new_shelves_items = {
- item["name"]: item["value"]
- for item in shelves_items
- }
- ayon_substance_painter["shelves"] = new_shelves_items
-
output["substancepainter"] = ayon_substance_painter
def _convert_tvpaint_project_settings(ayon_settings, output):
if "tvpaint" not in ayon_settings:
return
+
ayon_tvpaint = ayon_settings["tvpaint"]
-
- _convert_host_imageio(ayon_tvpaint)
-
- ayon_publish_settings = ayon_tvpaint["publish"]
- for plugin_name in (
- "ValidateProjectSettings",
- "ValidateMarks",
- "ValidateStartFrame",
- "ValidateAssetName",
- ):
- ayon_value = ayon_publish_settings[plugin_name]
- for src_key, dst_key in (
- ("action_enabled", "optional"),
- ("action_enable", "active"),
- ):
- if src_key in ayon_value:
- ayon_value[dst_key] = ayon_value.pop(src_key)
-
- extract_sequence_setting = ayon_publish_settings["ExtractSequence"]
- extract_sequence_setting["review_bg"] = _convert_color(
- extract_sequence_setting["review_bg"]
- )
-
output["tvpaint"] = ayon_tvpaint
@@ -956,60 +486,6 @@ def _convert_traypublisher_project_settings(ayon_settings, output):
ayon_traypublisher = ayon_settings["traypublisher"]
- _convert_host_imageio(ayon_traypublisher)
-
- ayon_editorial_simple = (
- ayon_traypublisher["editorial_creators"]["editorial_simple"]
- )
- # Subset -> Product type conversion
- if "product_type_presets" in ayon_editorial_simple:
- family_presets = ayon_editorial_simple.pop("product_type_presets")
- for item in family_presets:
- item["family"] = item.pop("product_type")
- ayon_editorial_simple["family_presets"] = family_presets
-
- if "shot_metadata_creator" in ayon_editorial_simple:
- shot_metadata_creator = ayon_editorial_simple.pop(
- "shot_metadata_creator"
- )
- if isinstance(shot_metadata_creator["clip_name_tokenizer"], dict):
- shot_metadata_creator["clip_name_tokenizer"] = [
- {"name": "_sequence_", "regex": "(sc\\d{3})"},
- {"name": "_shot_", "regex": "(sh\\d{3})"},
- ]
- ayon_editorial_simple.update(shot_metadata_creator)
-
- ayon_editorial_simple["clip_name_tokenizer"] = {
- item["name"]: item["regex"]
- for item in ayon_editorial_simple["clip_name_tokenizer"]
- }
-
- if "shot_subset_creator" in ayon_editorial_simple:
- ayon_editorial_simple.update(
- ayon_editorial_simple.pop("shot_subset_creator"))
- for item in ayon_editorial_simple["shot_hierarchy"]["parents"]:
- item["type"] = item.pop("parent_type")
-
- # Simple creators
- ayon_simple_creators = ayon_traypublisher["simple_creators"]
- for item in ayon_simple_creators:
- if "product_type" not in item:
- break
- item["family"] = item.pop("product_type")
-
- shot_add_tasks = ayon_editorial_simple["shot_add_tasks"]
-
- # TODO: backward compatibility and remove in future
- if isinstance(shot_add_tasks, dict):
- shot_add_tasks = []
-
- # aggregate shot_add_tasks items
- new_shot_add_tasks = {
- item["name"]: {"type": item["task_type"]}
- for item in shot_add_tasks
- }
- ayon_editorial_simple["shot_add_tasks"] = new_shot_add_tasks
-
output["traypublisher"] = ayon_traypublisher
@@ -1018,7 +494,6 @@ def _convert_webpublisher_project_settings(ayon_settings, output):
return
ayon_webpublisher = ayon_settings["webpublisher"]
- _convert_host_imageio(ayon_webpublisher)
ayon_publish = ayon_webpublisher["publish"]
@@ -1031,49 +506,6 @@ def _convert_webpublisher_project_settings(ayon_settings, output):
output["webpublisher"] = ayon_webpublisher
-def _convert_deadline_project_settings(ayon_settings, output):
- if "deadline" not in ayon_settings:
- return
-
- ayon_deadline = ayon_settings["deadline"]
-
- for key in ("deadline_urls",):
- ayon_deadline.pop(key)
-
- ayon_deadline_publish = ayon_deadline["publish"]
- limit_groups = {
- item["name"]: item["value"]
- for item in ayon_deadline_publish["NukeSubmitDeadline"]["limit_groups"]
- }
- ayon_deadline_publish["NukeSubmitDeadline"]["limit_groups"] = limit_groups
-
- maya_submit = ayon_deadline_publish["MayaSubmitDeadline"]
- for json_key in ("jobInfo", "pluginInfo"):
- src_text = maya_submit.pop(json_key)
- try:
- value = json.loads(src_text)
- except ValueError:
- value = {}
- maya_submit[json_key] = value
-
- nuke_submit = ayon_deadline_publish["NukeSubmitDeadline"]
- nuke_submit["env_search_replace_values"] = {
- item["name"]: item["value"]
- for item in nuke_submit.pop("env_search_replace_values")
- }
- nuke_submit["limit_groups"] = {
- item["name"]: item["value"] for item in nuke_submit.pop("limit_groups")
- }
-
- process_subsetted_job = ayon_deadline_publish["ProcessSubmittedJobOnFarm"]
- process_subsetted_job["aov_filter"] = {
- item["name"]: item["value"]
- for item in process_subsetted_job.pop("aov_filter")
- }
-
- output["deadline"] = ayon_deadline
-
-
def _convert_royalrender_project_settings(ayon_settings, output):
if "royalrender" not in ayon_settings:
return
@@ -1148,51 +580,9 @@ def _convert_global_project_settings(ayon_settings, output, default_settings):
ayon_core = ayon_settings["core"]
- _convert_host_imageio(ayon_core)
-
- for key in (
- "environments",
- "studio_name",
- "studio_code",
- ):
- ayon_core.pop(key, None)
-
# Publish conversion
ayon_publish = ayon_core["publish"]
- ayon_collect_audio = ayon_publish["CollectAudio"]
- if "audio_product_name" in ayon_collect_audio:
- ayon_collect_audio["audio_subset_name"] = (
- ayon_collect_audio.pop("audio_product_name"))
-
- for profile in ayon_publish["ExtractReview"]["profiles"]:
- if "product_types" in profile:
- profile["families"] = profile.pop("product_types")
- new_outputs = {}
- for output_def in profile.pop("outputs"):
- name = output_def.pop("name")
- new_outputs[name] = output_def
-
- output_def_filter = output_def["filter"]
- if "product_names" in output_def_filter:
- output_def_filter["subsets"] = (
- output_def_filter.pop("product_names"))
-
- for color_key in ("overscan_color", "bg_color"):
- output_def[color_key] = _convert_color(output_def[color_key])
-
- letter_box = output_def["letter_box"]
- for color_key in ("fill_color", "line_color"):
- letter_box[color_key] = _convert_color(letter_box[color_key])
-
- if "output_width" in output_def:
- output_def["width"] = output_def.pop("output_width")
-
- if "output_height" in output_def:
- output_def["height"] = output_def.pop("output_height")
-
- profile["outputs"] = new_outputs
-
# ExtractThumbnail plugin
ayon_extract_thumbnail = ayon_publish["ExtractThumbnail"]
# fix display and view at oiio defaults
@@ -1367,13 +757,13 @@ def convert_project_settings(ayon_settings, default_settings):
"houdini",
"resolve",
"unreal",
+ "applications",
+ "deadline",
}
for key in exact_match:
if key in ayon_settings:
output[key] = ayon_settings[key]
- _convert_host_imageio(output[key])
- _convert_applications_project_settings(ayon_settings, output)
_convert_blender_project_settings(ayon_settings, output)
_convert_celaction_project_settings(ayon_settings, output)
_convert_flame_project_settings(ayon_settings, output)
@@ -1388,7 +778,6 @@ def convert_project_settings(ayon_settings, default_settings):
_convert_traypublisher_project_settings(ayon_settings, output)
_convert_webpublisher_project_settings(ayon_settings, output)
- _convert_deadline_project_settings(ayon_settings, output)
_convert_royalrender_project_settings(ayon_settings, output)
_convert_kitsu_project_settings(ayon_settings, output)
_convert_shotgrid_project_settings(ayon_settings, output)
diff --git a/client/ayon_core/settings/defaults/system_settings/applications.json b/client/ayon_core/settings/defaults/system_settings/applications.json
index a5283751e9..2610c15315 100644
--- a/client/ayon_core/settings/defaults/system_settings/applications.json
+++ b/client/ayon_core/settings/defaults/system_settings/applications.json
@@ -1271,7 +1271,7 @@
"icon": "{}/app_icons/harmony.png",
"host_name": "harmony",
"environment": {
- "AVALON_HARMONY_WORKFILES_ON_LAUNCH": "1"
+ "AYON_HARMONY_WORKFILES_ON_LAUNCH": "1"
},
"variants": {
"21": {
diff --git a/client/ayon_core/settings/lib.py b/client/ayon_core/settings/lib.py
index beae376b7c..ee453956d2 100644
--- a/client/ayon_core/settings/lib.py
+++ b/client/ayon_core/settings/lib.py
@@ -15,7 +15,8 @@ from .constants import (
from .ayon_settings import (
get_ayon_project_settings,
- get_ayon_system_settings
+ get_ayon_system_settings,
+ get_ayon_settings,
)
log = logging.getLogger(__name__)
@@ -253,14 +254,9 @@ def get_current_project_settings():
return get_project_settings(project_name)
-def get_global_settings():
- default_settings = load_openpype_default_settings()
- return default_settings["system_settings"]["general"]
-
-
def get_general_environments():
- value = get_system_settings()
- return value["general"]["environment"]
+ settings = get_ayon_settings()
+ return json.loads(settings["core"]["environments"])
def get_system_settings(*args, **kwargs):
diff --git a/client/ayon_core/tests/README.md b/client/ayon_core/tests/README.md
deleted file mode 100644
index c05166767c..0000000000
--- a/client/ayon_core/tests/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Tests for Pype
---------------
-Trigger by:
- `pype test --pype`
\ No newline at end of file
diff --git a/client/ayon_core/tests/__init__.py b/client/ayon_core/tests/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/client/ayon_core/tests/lib.py b/client/ayon_core/tests/lib.py
deleted file mode 100644
index c7d4423aba..0000000000
--- a/client/ayon_core/tests/lib.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import os
-import sys
-import shutil
-import tempfile
-import contextlib
-
-import pyblish
-import pyblish.plugin
-from pyblish.vendor import six
-
-
-# Setup
-HOST = 'python'
-FAMILY = 'test.family'
-
-REGISTERED = pyblish.plugin.registered_paths()
-PACKAGEPATH = pyblish.lib.main_package_path()
-ENVIRONMENT = os.environ.get("PYBLISHPLUGINPATH", "")
-PLUGINPATH = os.path.join(PACKAGEPATH, '..', 'tests', 'plugins')
-
-
-def setup():
- pyblish.plugin.deregister_all_paths()
-
-
-def setup_empty():
- """Disable all plug-ins"""
- setup()
- pyblish.plugin.deregister_all_plugins()
- pyblish.plugin.deregister_all_paths()
- pyblish.plugin.deregister_all_hosts()
- pyblish.plugin.deregister_all_callbacks()
- pyblish.plugin.deregister_all_targets()
- pyblish.api.deregister_all_discovery_filters()
-
-
-def teardown():
- """Restore previously REGISTERED paths"""
-
- pyblish.plugin.deregister_all_paths()
- for path in REGISTERED:
- pyblish.plugin.register_plugin_path(path)
-
- os.environ["PYBLISHPLUGINPATH"] = ENVIRONMENT
- pyblish.api.deregister_all_plugins()
- pyblish.api.deregister_all_hosts()
- pyblish.api.deregister_all_discovery_filters()
- pyblish.api.deregister_test()
- pyblish.api.__init__()
-
-
-@contextlib.contextmanager
-def captured_stdout():
- """Temporarily reassign stdout to a local variable"""
- try:
- sys.stdout = six.StringIO()
- yield sys.stdout
- finally:
- sys.stdout = sys.__stdout__
-
-
-@contextlib.contextmanager
-def captured_stderr():
- """Temporarily reassign stderr to a local variable"""
- try:
- sys.stderr = six.StringIO()
- yield sys.stderr
- finally:
- sys.stderr = sys.__stderr__
-
-
-@contextlib.contextmanager
-def tempdir():
- """Provide path to temporary directory"""
- try:
- tempdir = tempfile.mkdtemp()
- yield tempdir
- finally:
- shutil.rmtree(tempdir)
-
-
-def is_in_tests():
- """Returns if process is running in automatic tests mode.
-
- In tests mode different source DB is used, some plugins might be disabled
- etc.
- """
- return os.environ.get("IS_TEST") == '1'
diff --git a/client/ayon_core/tests/mongo_performance.py b/client/ayon_core/tests/mongo_performance.py
deleted file mode 100644
index 2df3363f4b..0000000000
--- a/client/ayon_core/tests/mongo_performance.py
+++ /dev/null
@@ -1,288 +0,0 @@
-import pymongo
-import bson
-import random
-from datetime import datetime
-import os
-
-
-class TestPerformance():
- '''
- Class for testing performance of representation and their 'files'
- parts.
- Discussion is if embedded array:
- 'files' : [ {'_id': '1111', 'path':'....},
- {'_id'...}]
- OR documents:
- 'files' : {
- '1111': {'path':'....'},
- '2222': {'path':'...'}
- }
- is faster.
-
- Current results:
- without additional partial index documents is 3x faster
- With index is array 50x faster then document
-
- Partial index something like:
- db.getCollection('performance_test').createIndex
- ({'files._id': 1},
- {partialFilterExpresion: {'files': {'$exists': true}}})
- !DIDNT work for me, had to create manually in Compass
-
- '''
-
- MONGO_URL = 'mongodb://localhost:27017'
- MONGO_DB = 'performance_test'
- MONGO_COLLECTION = 'performance_test'
-
- MAX_FILE_SIZE_B = 5000
- MAX_NUMBER_OF_SITES = 50
- ROOT_DIR = "C:/projects"
-
- inserted_ids = []
-
- def __init__(self, version='array'):
- '''
- It creates and fills collection, based on value of 'version'.
-
- :param version: 'array' - files as embedded array,
- 'doc' - as document
- '''
- self.client = pymongo.MongoClient(self.MONGO_URL)
- self.db = self.client[self.MONGO_DB]
- self.collection_name = self.MONGO_COLLECTION
-
- self.version = version
-
- if self.version != 'array':
- self.collection_name = self.MONGO_COLLECTION + '_doc'
-
- self.collection = self.db[self.collection_name]
-
- self.ids = [] # for testing
- self.inserted_ids = []
-
- def prepare(self, no_of_records=100000, create_files=False):
- '''
- Produce 'no_of_records' of representations with 'files' segment.
- It depends on 'version' value in constructor, 'arrray' or 'doc'
- :return:
- '''
- print('Purging {} collection'.format(self.collection_name))
- self.collection.delete_many({})
-
- id = bson.objectid.ObjectId()
-
- insert_recs = []
- for i in range(no_of_records):
- file_id = bson.objectid.ObjectId()
- file_id2 = bson.objectid.ObjectId()
- file_id3 = bson.objectid.ObjectId()
-
- self.inserted_ids.extend([file_id, file_id2, file_id3])
- version_str = "v{:03d}".format(i + 1)
- file_name = "test_Cylinder_workfileLookdev_{}.mb".\
- format(version_str)
-
- document = {"files": self.get_files(self.version, i + 1,
- file_id, file_id2, file_id3,
- create_files)
- ,
- "context": {
- "subset": "workfileLookdev",
- "username": "petrk",
- "task": "lookdev",
- "family": "workfile",
- "hierarchy": "Assets",
- "project": {"code": "test", "name": "Test"},
- "version": i + 1,
- "asset": "Cylinder",
- "representation": "mb",
- "root": self.ROOT_DIR
- },
- "dependencies": [],
- "name": "mb",
- "parent": {"oid": '{}'.format(id)},
- "data": {
- "path": "C:\\projects\\test_performance\\Assets\\Cylinder\\publish\\workfile\\workfileLookdev\\{}\\{}".format(version_str, file_name), # noqa: E501
- "template": "{root[work]}\\{project[name]}\\{hierarchy}\\{asset}\\publish\\{family}\\{subset}\\v{version:0>3}\\{project[code]}_{asset}_{subset}_v{version:0>3}<_{output}><.{frame:0>4}>.{representation}" # noqa: E501
- },
- "type": "representation",
- "schema": "openpype:representation-2.0"
- }
-
- insert_recs.append(document)
-
- print('Prepared {} records in {} collection'.
- format(no_of_records, self.collection_name))
-
- self.collection.insert_many(insert_recs)
- # TODO refactore to produce real array and not needeing ugly regex
- self.collection.insert_one({"inserted_id": self.inserted_ids})
- print('-' * 50)
-
- def run(self, queries=1000, loops=3):
- '''
- Run X'queries' that are searching collection Y'loops' times
- :param queries: how many times do ..find(...)
- :param loops: loop of testing X queries
- :return: None
- '''
- print('Testing version {} on {}'.format(self.version,
- self.collection_name))
- print('Queries rung {} in {} loops'.format(queries, loops))
-
- inserted_ids = list(self.collection.
- find({"inserted_id": {"$exists": True}}))
- import re
- self.ids = re.findall("'[0-9a-z]*'", str(inserted_ids))
-
- import time
-
- found_cnt = 0
- for _ in range(loops):
- print('Starting loop {}'.format(_))
- start = time.time()
- for _ in range(queries):
- # val = random.choice(self.ids)
- # val = val.replace("'", '')
- val = random.randint(0, 50)
- print(val)
-
- if (self.version == 'array'):
- # prepared for partial index, without 'files': exists
- # wont engage
- found = self.collection.\
- find({'files': {"$exists": True},
- 'files.sites.name': "local_{}".format(val)}).\
- count()
- else:
- key = "files.{}".format(val)
- found = self.collection.find_one({key: {"$exists": True}})
- print("found {} records".format(found))
- # if found:
- # found_cnt += len(list(found))
-
- end = time.time()
- print('duration per loop {}'.format(end - start))
- print("found_cnt {}".format(found_cnt))
-
- def get_files(self, mode, i, file_id, file_id2, file_id3,
- create_files=False):
- '''
- Wrapper to decide if 'array' or document version should be used
- :param mode: 'array'|'doc'
- :param i: step number
- :param file_id: ObjectId of first dummy file
- :param file_id2: ..
- :param file_id3: ..
- :return:
- '''
- if mode == 'array':
- return self.get_files_array(i, file_id, file_id2, file_id3,
- create_files)
- else:
- return self.get_files_doc(i, file_id, file_id2, file_id3)
-
- def get_files_array(self, i, file_id, file_id2, file_id3,
- create_files=False):
- ret = [
- {
- "path": "{root[work]}" + "{root[work]}/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_A_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
- "_id": '{}'.format(file_id),
- "hash": "temphash",
- "sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
- "size": random.randint(0, self.MAX_FILE_SIZE_B)
- },
- {
- "path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_B_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
- "_id": '{}'.format(file_id2),
- "hash": "temphash",
- "sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
- "size": random.randint(0, self.MAX_FILE_SIZE_B)
- },
- {
- "path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_C_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
- "_id": '{}'.format(file_id3),
- "hash": "temphash",
- "sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
- "size": random.randint(0, self.MAX_FILE_SIZE_B)
- }
-
- ]
- if create_files:
- for f in ret:
- path = f.get("path").replace("{root[work]}", self.ROOT_DIR)
- os.makedirs(os.path.dirname(path), exist_ok=True)
- with open(path, 'wb') as fp:
- fp.write(os.urandom(f.get("size")))
-
- return ret
-
- def get_files_doc(self, i, file_id, file_id2, file_id3):
- ret = {}
- ret['{}'.format(file_id)] = {
- "path": "{root[work]}" +
- "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
- "v{:03d}/test_CylinderA_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
- "hash": "temphash",
- "sites": ["studio"],
- "size": 87236
- }
-
- ret['{}'.format(file_id2)] = {
- "path": "{root[work]}" +
- "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
- "v{:03d}/test_CylinderB_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
- "hash": "temphash",
- "sites": ["studio"],
- "size": 87236
- }
- ret['{}'.format(file_id3)] = {
- "path": "{root[work]}" +
- "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
- "v{:03d}/test_CylinderC_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
- "hash": "temphash",
- "sites": ["studio"],
- "size": 87236
- }
-
- return ret
-
- def get_sites(self, number_of_sites=50):
- """
- Return array of sites declaration.
- Currently on 1st site has "created_dt" fillled, which should
- trigger upload to 'gdrive' site.
- 'gdrive' site is appended, its destination for syncing for
- Sync Server
- Args:
- number_of_sites:
-
- Returns:
-
- """
- sites = []
- for i in range(number_of_sites):
- site = {'name': "local_{}".format(i)}
- # do not create null 'created_dt' field, Mongo doesnt like it
- if i == 0:
- site['created_dt'] = datetime.now()
-
- sites.append(site)
-
- sites.append({'name': "gdrive"})
-
- return sites
-
-
-if __name__ == '__main__':
- tp = TestPerformance('array')
- tp.prepare(no_of_records=10000, create_files=True)
- # tp.run(10, 3)
-
- # print('-'*50)
- #
- # tp = TestPerformance('doc')
- # tp.prepare() # enable to prepare data
- # tp.run(1000, 3)
diff --git a/client/ayon_core/tests/test_avalon_plugin_presets.py b/client/ayon_core/tests/test_avalon_plugin_presets.py
deleted file mode 100644
index 4926286ca3..0000000000
--- a/client/ayon_core/tests/test_avalon_plugin_presets.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from ayon_core.pipeline import (
- install_host,
- LegacyCreator,
- register_creator_plugin,
- discover_creator_plugins,
-)
-
-
-class MyTestCreator(LegacyCreator):
-
- my_test_property = "A"
-
- def __init__(self, name, asset, options=None, data=None):
- super(MyTestCreator, self).__init__(self, name, asset,
- options=None, data=None)
-
-
-# this is hack like no other - we need to inject our own avalon host
-# and bypass all its validation. Avalon hosts are modules that needs
-# `ls` callable as attribute. Voila:
-class Test:
- __name__ = "test"
- ls = len
-
- @staticmethod
- def install():
- register_creator_plugin(MyTestCreator)
-
-
-def test_avalon_plugin_presets(monkeypatch, printer):
- install_host(Test)
-
- plugins = discover_creator_plugins()
- printer("Test if we got our test plugin")
- assert MyTestCreator in plugins
- for p in plugins:
- if p.__name__ == "MyTestCreator":
- printer("Test if we have overridden existing property")
- assert p.my_test_property == "B"
- printer("Test if we have overridden superclass property")
- assert p.active is False
- printer("Test if we have added new property")
- assert p.new_property == "new"
diff --git a/client/ayon_core/tests/test_lib_restructuralization.py b/client/ayon_core/tests/test_lib_restructuralization.py
deleted file mode 100644
index ffbd62b045..0000000000
--- a/client/ayon_core/tests/test_lib_restructuralization.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Test for backward compatibility of restructure of lib.py into lib library
-# Contains simple imports that should still work
-
-
-def test_backward_compatibility(printer):
- printer("Test if imports still work")
- try:
- from ayon_core.lib import execute_hook
- from ayon_core.lib import PypeHook
-
- from ayon_core.lib import ApplicationLaunchFailed
-
- from ayon_core.lib import get_ffmpeg_tool_path
- from ayon_core.lib import get_last_version_from_path
- from ayon_core.lib import get_paths_from_environ
- from ayon_core.lib import get_version_from_path
- from ayon_core.lib import version_up
-
- from ayon_core.lib import get_ffprobe_streams
-
- from ayon_core.lib import source_hash
- from ayon_core.lib import run_subprocess
-
- except ImportError as e:
- raise
diff --git a/client/ayon_core/tests/test_pyblish_filter.py b/client/ayon_core/tests/test_pyblish_filter.py
deleted file mode 100644
index bc20f863c9..0000000000
--- a/client/ayon_core/tests/test_pyblish_filter.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import os
-import pyblish.api
-import pyblish.util
-import pyblish.plugin
-from ayon_core.pipeline.publish.lib import filter_pyblish_plugins
-from . import lib
-
-
-def test_pyblish_plugin_filter_modifier(printer, monkeypatch):
- """
- Test if pyblish filter can filter and modify plugins on-the-fly.
- """
-
- lib.setup_empty()
- monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '')
- plugins = pyblish.api.registered_plugins()
- printer("Test if we have no registered plugins")
- assert len(plugins) == 0
- paths = pyblish.api.registered_paths()
- printer("Test if we have no registered plugin paths")
- assert len(paths) == 0
-
- class MyTestPlugin(pyblish.api.InstancePlugin):
- my_test_property = 1
- label = "Collect Renderable Camera(s)"
- hosts = ["test"]
- families = ["default"]
-
- pyblish.api.register_host("test")
- pyblish.api.register_plugin(MyTestPlugin)
- pyblish.api.register_discovery_filter(filter_pyblish_plugins)
- plugins = pyblish.api.discover()
-
- printer("Test if only one plugin was discovered")
- assert len(plugins) == 1
- printer("Test if properties are modified correctly")
- assert plugins[0].label == "loaded from preset"
- assert plugins[0].families == ["changed", "by", "preset"]
- assert plugins[0].optional is True
-
- lib.teardown()
-
-
-def test_pyblish_plugin_filter_removal(monkeypatch):
- """ Test that plugin can be removed by filter """
- lib.setup_empty()
- monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '')
- plugins = pyblish.api.registered_plugins()
-
- class MyTestRemovedPlugin(pyblish.api.InstancePlugin):
- my_test_property = 1
- label = "Collect Renderable Camera(s)"
- hosts = ["test"]
- families = ["default"]
-
- pyblish.api.register_host("test")
- pyblish.api.register_plugin(MyTestRemovedPlugin)
- pyblish.api.register_discovery_filter(filter_pyblish_plugins)
- plugins = pyblish.api.discover()
- assert len(plugins) == 0
diff --git a/client/ayon_core/tools/publisher/widgets/assets_widget.py b/client/ayon_core/tools/publisher/widgets/assets_widget.py
index 8a72c03e8b..1c5016de99 100644
--- a/client/ayon_core/tools/publisher/widgets/assets_widget.py
+++ b/client/ayon_core/tools/publisher/widgets/assets_widget.py
@@ -5,13 +5,13 @@ from qtpy import QtWidgets, QtCore, QtGui
from ayon_core.tools.utils import (
PlaceholderLineEdit,
RecursiveSortFilterProxyModel,
- get_asset_icon,
)
from ayon_core.tools.utils.assets_widget import (
SingleSelectAssetsWidget,
ASSET_ID_ROLE,
ASSET_NAME_ROLE,
ASSET_PATH_ROLE,
+ get_asset_icon,
)
@@ -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/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/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/utils/__init__.py b/client/ayon_core/tools/utils/__init__.py
index 7be0ea5e9f..445b4d9b97 100644
--- a/client/ayon_core/tools/utils/__init__.py
+++ b/client/ayon_core/tools/utils/__init__.py
@@ -37,10 +37,6 @@ from .lib import (
get_qt_app,
get_ayon_qt_app,
get_openpype_qt_app,
- get_asset_icon,
- get_asset_icon_by_name,
- get_asset_icon_name_from_doc,
- get_asset_icon_color_from_doc,
)
from .models import (
@@ -100,10 +96,6 @@ __all__ = (
"get_qt_app",
"get_ayon_qt_app",
"get_openpype_qt_app",
- "get_asset_icon",
- "get_asset_icon_by_name",
- "get_asset_icon_name_from_doc",
- "get_asset_icon_color_from_doc",
"RecursiveSortFilterProxyModel",
diff --git a/client/ayon_core/tools/utils/assets_widget.py b/client/ayon_core/tools/utils/assets_widget.py
index c05f3de850..7c3fd8d97c 100644
--- a/client/ayon_core/tools/utils/assets_widget.py
+++ b/client/ayon_core/tools/utils/assets_widget.py
@@ -10,6 +10,7 @@ from ayon_core.client import (
)
from ayon_core.style import (
get_default_tools_icon_color,
+ get_default_entity_icon_color,
)
from ayon_core.tools.flickcharm import FlickCharm
@@ -21,7 +22,7 @@ from .widgets import PlaceholderLineEdit
from .models import RecursiveSortFilterProxyModel
from .lib import (
DynamicQThread,
- get_asset_icon
+ get_qta_icon_by_name_and_color
)
ASSET_ID_ROLE = QtCore.Qt.UserRole + 1
@@ -31,6 +32,59 @@ ASSET_UNDERLINE_COLORS_ROLE = QtCore.Qt.UserRole + 4
ASSET_PATH_ROLE = QtCore.Qt.UserRole + 5
+def _get_default_asset_icon_name(has_children):
+ if has_children:
+ return "fa.folder"
+ return "fa.folder-o"
+
+
+def _get_asset_icon_color_from_doc(asset_doc):
+ if asset_doc:
+ return asset_doc["data"].get("color")
+ return None
+
+
+def _get_asset_icon_name_from_doc(asset_doc):
+ if asset_doc:
+ return asset_doc["data"].get("icon")
+ return None
+
+
+def _get_asset_icon_color(asset_doc):
+ icon_color = _get_asset_icon_color_from_doc(asset_doc)
+ if icon_color:
+ return icon_color
+ return get_default_entity_icon_color()
+
+
+def _get_asset_icon_name(asset_doc, has_children=True):
+ icon_name = _get_asset_icon_name_from_doc(asset_doc)
+ if icon_name:
+ return icon_name
+ return _get_default_asset_icon_name(has_children)
+
+
+def get_asset_icon(asset_doc, has_children=False):
+ """Get asset icon.
+
+ Deprecated:
+ This function will be removed in future releases. Use on your own
+ risk.
+
+ Args:
+ asset_doc (dict): Asset document.
+ has_children (Optional[bool]): Asset has children assets.
+
+ Returns:
+ QIcon: Asset icon.
+
+ """
+ icon_name = _get_asset_icon_name(asset_doc, has_children)
+ icon_color = _get_asset_icon_color(asset_doc)
+
+ return get_qta_icon_by_name_and_color(icon_name, icon_color)
+
+
class _AssetsView(TreeViewSpinner, DeselectableTreeView):
"""Asset items view.
@@ -111,7 +165,6 @@ class _AssetModel(QtGui.QStandardItemModel):
'refreshed' signal.
Args:
- dbcon (AvalonMongoDB): Ready to use connection to mongo with.
parent (QObject): Parent Qt object.
"""
@@ -128,9 +181,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 +194,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 +238,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 +260,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 +279,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 +403,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 +438,6 @@ class _AssetsWidget(QtWidgets.QWidget):
inheritance changes.
Args:
- dbcon (AvalonMongoDB): Connection to avalon mongo db.
parent (QWidget): Parent Qt widget.
"""
@@ -404,11 +449,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 +520,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 +562,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 +571,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)
diff --git a/client/ayon_core/tools/utils/lib.py b/client/ayon_core/tools/utils/lib.py
index b7edd6be71..e785cec390 100644
--- a/client/ayon_core/tools/utils/lib.py
+++ b/client/ayon_core/tools/utils/lib.py
@@ -234,62 +234,6 @@ def get_qta_icon_by_name_and_color(icon_name, icon_color):
return icon
-def get_asset_icon_name(asset_doc, has_children=True):
- icon_name = get_asset_icon_name_from_doc(asset_doc)
- if icon_name:
- return icon_name
- return get_default_asset_icon_name(has_children)
-
-
-def get_asset_icon_color(asset_doc):
- icon_color = get_asset_icon_color_from_doc(asset_doc)
- if icon_color:
- return icon_color
- return get_default_entity_icon_color()
-
-
-def get_default_asset_icon_name(has_children):
- if has_children:
- return "fa.folder"
- return "fa.folder-o"
-
-
-def get_asset_icon_name_from_doc(asset_doc):
- if asset_doc:
- return asset_doc["data"].get("icon")
- return None
-
-
-def get_asset_icon_color_from_doc(asset_doc):
- if asset_doc:
- return asset_doc["data"].get("color")
- return None
-
-
-def get_asset_icon_by_name(icon_name, icon_color, has_children=False):
- if not icon_name:
- icon_name = get_default_asset_icon_name(has_children)
-
- if icon_color:
- icon_color = QtGui.QColor(icon_color)
- else:
- icon_color = get_default_entity_icon_color()
- icon = get_qta_icon_by_name_and_color(icon_name, icon_color)
- if icon is not None:
- return icon
- return get_qta_icon_by_name_and_color(
- get_default_asset_icon_name(has_children),
- icon_color
- )
-
-
-def get_asset_icon(asset_doc, has_children=False):
- icon_name = get_asset_icon_name(asset_doc, has_children)
- icon_color = get_asset_icon_color(asset_doc)
-
- return get_qta_icon_by_name_and_color(icon_name, icon_color)
-
-
def get_default_task_icon(color=None):
if color is None:
color = get_default_entity_icon_color()
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()
diff --git a/client/ayon_core/tools/workfile_template_build/__init__.py b/client/ayon_core/tools/workfile_template_build/__init__.py
index 82a22aea50..ad94ebcf79 100644
--- a/client/ayon_core/tools/workfile_template_build/__init__.py
+++ b/client/ayon_core/tools/workfile_template_build/__init__.py
@@ -1,5 +1,8 @@
from .window import WorkfileBuildPlaceholderDialog
+from .lib import open_template_ui
__all__ = (
"WorkfileBuildPlaceholderDialog",
+
+ "open_template_ui"
)
diff --git a/client/ayon_core/tools/workfile_template_build/lib.py b/client/ayon_core/tools/workfile_template_build/lib.py
new file mode 100644
index 0000000000..de3a0d0084
--- /dev/null
+++ b/client/ayon_core/tools/workfile_template_build/lib.py
@@ -0,0 +1,28 @@
+import traceback
+
+from qtpy import QtWidgets
+
+from ayon_core.tools.utils.dialogs import show_message_dialog
+
+
+def open_template_ui(builder, main_window):
+ """Open template from `builder`
+
+ Asks user about overwriting current scene and feedsback exceptions.
+ """
+ result = QtWidgets.QMessageBox.question(
+ main_window,
+ "Opening template",
+ "Caution! You will loose unsaved changes.\nDo you want to continue?",
+ QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
+ )
+ if result == QtWidgets.QMessageBox.Yes:
+ try:
+ builder.open_template()
+ except Exception:
+ show_message_dialog(
+ title="Template Load Failed",
+ message="".join(traceback.format_exc()),
+ parent=main_window,
+ level="critical"
+ )
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)
diff --git a/client/pyproject.toml b/client/pyproject.toml
index c21ca305a7..7b4329a31a 100644
--- a/client/pyproject.toml
+++ b/client/pyproject.toml
@@ -10,8 +10,6 @@ wsrpc_aiohttp = "^3.1.1" # websocket server
Click = "^8"
clique = "1.6.*"
jsonschema = "^2.6.0"
-pymongo = "^3.11.2"
-log4mongo = "^1.7"
pyblish-base = "^1.8.11"
pynput = "^1.7.2" # Timers manager - TODO remove
speedcopy = "^2.1"
diff --git a/package.py b/package.py
index d7266d852b..3b451e0078 100644
--- a/package.py
+++ b/package.py
@@ -5,4 +5,7 @@ version = "0.2.1-dev.1"
client_dir = "ayon_core"
plugin_for = ["ayon_server"]
-ayon_version = ">=1.0.3,<2.0.0"
+requires = [
+ "~ayon_server-1.0.3+<2.0.0",
+]
+
diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py
index 8506801e7e..c01fb92b9c 100644
--- a/server/settings/publish_plugins.py
+++ b/server/settings/publish_plugins.py
@@ -9,7 +9,7 @@ from ayon_server.settings import (
task_types_enum,
)
-from ayon_server.types import ColorRGBA_uint8
+from ayon_server.types import ColorRGB_uint8, ColorRGBA_uint8
class ValidateBaseModel(BaseSettingsModel):
@@ -387,8 +387,8 @@ class ExtractReviewOutputDefModel(BaseSettingsModel):
"Crop input overscan. See the documentation for more information."
)
)
- overscan_color: ColorRGBA_uint8 = SettingsField(
- (0, 0, 0, 0.0),
+ overscan_color: ColorRGB_uint8 = SettingsField(
+ (0, 0, 0),
title="Overscan color",
description=(
"Overscan color is used when input aspect ratio is not"
@@ -901,7 +901,7 @@ DEFAULT_PUBLISH_VALUES = {
"single_frame_filter": "single_frame"
},
"overscan_crop": "",
- "overscan_color": [0, 0, 0, 1.0],
+ "overscan_color": [0, 0, 0],
"width": 1920,
"height": 1080,
"scale_pixel_aspect": True,
@@ -946,7 +946,7 @@ DEFAULT_PUBLISH_VALUES = {
"single_frame_filter": "multi_frame"
},
"overscan_crop": "",
- "overscan_color": [0, 0, 0, 1.0],
+ "overscan_color": [0, 0, 0],
"width": 0,
"height": 0,
"scale_pixel_aspect": True,
diff --git a/server_addon/applications/server/__init__.py b/server_addon/applications/server/__init__.py
index e782e8a591..d5c2de3df3 100644
--- a/server_addon/applications/server/__init__.py
+++ b/server_addon/applications/server/__init__.py
@@ -92,8 +92,9 @@ class ApplicationsAddon(BaseServerAddon):
settings_model = ApplicationsAddonSettings
async def get_default_settings(self):
- applications_path = os.path.join(self.addon_dir, "applications.json")
- tools_path = os.path.join(self.addon_dir, "tools.json")
+ server_dir = os.path.join(self.addon_dir, "server")
+ applications_path = os.path.join(server_dir, "applications.json")
+ tools_path = os.path.join(server_dir, "tools.json")
default_values = copy.deepcopy(DEFAULT_VALUES)
with open(applications_path, "r") as stream:
default_values.update(json.load(stream))
diff --git a/server_addon/create_ayon_addons.py b/server_addon/create_ayon_addons.py
index 08443d6588..5e06d8ee8a 100644
--- a/server_addon/create_ayon_addons.py
+++ b/server_addon/create_ayon_addons.py
@@ -40,6 +40,11 @@ IGNORED_HOSTS = [
IGNORED_MODULES = []
+PACKAGE_PY_TEMPLATE = """name = "{addon_name}"
+version = "{addon_version}"
+plugin_for = ["ayon_server"]
+"""
+
class ZipFileLongPaths(zipfile.ZipFile):
"""Allows longer paths in zip files.
@@ -144,18 +149,12 @@ def create_addon_zip(
output_dir: Path,
addon_name: str,
addon_version: str,
- keep_source: bool
+ keep_source: bool,
):
zip_filepath = output_dir / f"{addon_name}-{addon_version}.zip"
+
addon_output_dir = output_dir / addon_name / addon_version
with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
- zipf.writestr(
- "manifest.json",
- json.dumps({
- "addon_name": addon_name,
- "addon_version": addon_version
- })
- )
# Add client code content to zip
src_root = os.path.normpath(str(addon_output_dir.absolute()))
src_root_offset = len(src_root) + 1
@@ -167,9 +166,10 @@ def create_addon_zip(
for filename in filenames:
src_path = os.path.join(root, filename)
if rel_root:
- dst_path = os.path.join("addon", rel_root, filename)
+ dst_path = os.path.join(rel_root, filename)
else:
- dst_path = os.path.join("addon", filename)
+ dst_path = filename
+
zipf.write(src_path, dst_path)
if not keep_source:
@@ -180,9 +180,8 @@ def create_addon_package(
addon_dir: Path,
output_dir: Path,
create_zip: bool,
- keep_source: bool
+ keep_source: bool,
):
- server_dir = addon_dir / "server"
addon_version = get_addon_version(addon_dir)
addon_output_dir = output_dir / addon_dir.name / addon_version
@@ -191,18 +190,18 @@ def create_addon_package(
addon_output_dir.mkdir(parents=True)
# Copy server content
- src_root = os.path.normpath(str(server_dir.absolute()))
- src_root_offset = len(src_root) + 1
- for root, _, filenames in os.walk(str(server_dir)):
- dst_root = addon_output_dir
- if root != src_root:
- rel_root = root[src_root_offset:]
- dst_root = dst_root / rel_root
+ package_py = addon_output_dir / "package.py"
+ package_py_content = PACKAGE_PY_TEMPLATE.format(
+ addon_name=addon_dir.name, addon_version=addon_version
+ )
- dst_root.mkdir(parents=True, exist_ok=True)
- for filename in filenames:
- src_path = os.path.join(root, filename)
- shutil.copy(src_path, str(dst_root))
+ with open(package_py, "w+") as pkg_py:
+ pkg_py.write(package_py_content)
+
+ server_dir = addon_dir / "server"
+ shutil.copytree(
+ server_dir, addon_output_dir / "server", dirs_exist_ok=True
+ )
if create_zip:
create_addon_zip(
diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py
index da782cb494..e8a48ec3d1 100644
--- a/server_addon/max/server/settings/publishers.py
+++ b/server_addon/max/server/settings/publishers.py
@@ -28,9 +28,9 @@ class ValidateAttributesModel(BaseSettingsModel):
class FamilyMappingItemModel(BaseSettingsModel):
- product_types: list[str] = SettingsField(
+ families: list[str] = SettingsField(
default_factory=list,
- title="Product Types"
+ title="Families"
)
plugins: list[str] = SettingsField(
default_factory=list,
diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py
index bbab0242f6..1276d0254f 100644
--- a/server_addon/max/server/version.py
+++ b/server_addon/max/server/version.py
@@ -1 +1 @@
-__version__ = "0.1.4"
+__version__ = "0.1.5"
diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py
index 15d4275b80..b8264a56ef 100644
--- a/server_addon/maya/server/settings/loaders.py
+++ b/server_addon/maya/server/settings/loaders.py
@@ -1,40 +1,72 @@
from ayon_server.settings import BaseSettingsModel, SettingsField
-from ayon_server.types import ColorRGBA_uint8
+from ayon_server.types import ColorRGB_float
class ColorsSetting(BaseSettingsModel):
- model: ColorRGBA_uint8 = SettingsField(
- (209, 132, 30, 1.0), title="Model:")
- rig: ColorRGBA_uint8 = SettingsField(
- (59, 226, 235, 1.0), title="Rig:")
- pointcache: ColorRGBA_uint8 = SettingsField(
- (94, 209, 30, 1.0), title="Pointcache:")
- animation: ColorRGBA_uint8 = SettingsField(
- (94, 209, 30, 1.0), title="Animation:")
- ass: ColorRGBA_uint8 = SettingsField(
- (249, 135, 53, 1.0), title="Arnold StandIn:")
- camera: ColorRGBA_uint8 = SettingsField(
- (136, 114, 244, 1.0), title="Camera:")
- fbx: ColorRGBA_uint8 = SettingsField(
- (215, 166, 255, 1.0), title="FBX:")
- mayaAscii: ColorRGBA_uint8 = SettingsField(
- (67, 174, 255, 1.0), title="Maya Ascii:")
- mayaScene: ColorRGBA_uint8 = SettingsField(
- (67, 174, 255, 1.0), title="Maya Scene:")
- setdress: ColorRGBA_uint8 = SettingsField(
- (255, 250, 90, 1.0), title="Set Dress:")
- layout: ColorRGBA_uint8 = SettingsField((
- 255, 250, 90, 1.0), title="Layout:")
- vdbcache: ColorRGBA_uint8 = SettingsField(
- (249, 54, 0, 1.0), title="VDB Cache:")
- vrayproxy: ColorRGBA_uint8 = SettingsField(
- (255, 150, 12, 1.0), title="VRay Proxy:")
- vrayscene_layer: ColorRGBA_uint8 = SettingsField(
- (255, 150, 12, 1.0), title="VRay Scene:")
- yeticache: ColorRGBA_uint8 = SettingsField(
- (99, 206, 220, 1.0), title="Yeti Cache:")
- yetiRig: ColorRGBA_uint8 = SettingsField(
- (0, 205, 125, 1.0), title="Yeti Rig:")
+ model: ColorRGB_float = SettingsField(
+ (0.82, 0.52, 0.12),
+ title="Model:"
+ )
+ rig: ColorRGB_float = SettingsField(
+ (0.23, 0.89, 0.92),
+ title="Rig:"
+ )
+ pointcache: ColorRGB_float = SettingsField(
+ (0.37, 0.82, 0.12),
+ title="Pointcache:"
+ )
+ animation: ColorRGB_float = SettingsField(
+ (0.37, 0.82, 0.12),
+ title="Animation:"
+ )
+ ass: ColorRGB_float = SettingsField(
+ (0.98, 0.53, 0.21),
+ title="Arnold StandIn:"
+ )
+ camera: ColorRGB_float = SettingsField(
+ (0.53, 0.45, 0.96),
+ title="Camera:"
+ )
+ fbx: ColorRGB_float = SettingsField(
+ (0.84, 0.65, 1.0),
+ title="FBX:"
+ )
+ mayaAscii: ColorRGB_float = SettingsField(
+ (0.26, 0.68, 1.0),
+ title="Maya Ascii:"
+ )
+ mayaScene: ColorRGB_float = SettingsField(
+ (0.26, 0.68, 1.0),
+ title="Maya Scene:"
+ )
+ setdress: ColorRGB_float = SettingsField(
+ (1.0, 0.98, 0.35),
+ title="Set Dress:"
+ )
+ layout: ColorRGB_float = SettingsField(
+ (1.0, 0.98, 0.35),
+ title="Layout:"
+ )
+ vdbcache: ColorRGB_float = SettingsField(
+ (0.98, 0.21, 0.0),
+ title="VDB Cache:"
+ )
+ vrayproxy: ColorRGB_float = SettingsField(
+ (1.0, 0.59, 0.05),
+ title="VRay Proxy:"
+ )
+ vrayscene_layer: ColorRGB_float = SettingsField(
+ (1.0, 0.59, 0.05),
+ title="VRay Scene:"
+ )
+ yeticache: ColorRGB_float = SettingsField(
+ (0.39, 0.81, 0.86),
+ title="Yeti Cache:"
+ )
+ yetiRig: ColorRGB_float = SettingsField(
+ (0.0, 0.80, 0.49),
+ title="Yeti Rig:"
+ )
class ReferenceLoaderModel(BaseSettingsModel):
@@ -67,54 +99,22 @@ class LoadersModel(BaseSettingsModel):
DEFAULT_LOADERS_SETTING = {
"colors": {
- "model": [
- 209, 132, 30, 1.0
- ],
- "rig": [
- 59, 226, 235, 1.0
- ],
- "pointcache": [
- 94, 209, 30, 1.0
- ],
- "animation": [
- 94, 209, 30, 1.0
- ],
- "ass": [
- 249, 135, 53, 1.0
- ],
- "camera": [
- 136, 114, 244, 1.0
- ],
- "fbx": [
- 215, 166, 255, 1.0
- ],
- "mayaAscii": [
- 67, 174, 255, 1.0
- ],
- "mayaScene": [
- 67, 174, 255, 1.0
- ],
- "setdress": [
- 255, 250, 90, 1.0
- ],
- "layout": [
- 255, 250, 90, 1.0
- ],
- "vdbcache": [
- 249, 54, 0, 1.0
- ],
- "vrayproxy": [
- 255, 150, 12, 1.0
- ],
- "vrayscene_layer": [
- 255, 150, 12, 1.0
- ],
- "yeticache": [
- 99, 206, 220, 1.0
- ],
- "yetiRig": [
- 0, 205, 125, 1.0
- ]
+ "model": [0.82, 0.52, 0.12],
+ "rig": [0.23, 0.89, 0.92],
+ "pointcache": [0.37, 0.82, 0.12],
+ "animation": [0.37, 0.82, 0.12],
+ "ass": [0.98, 0.53, 0.21],
+ "camera":[0.53, 0.45, 0.96],
+ "fbx": [0.84, 0.65, 1.0],
+ "mayaAscii": [0.26, 0.68, 1.0],
+ "mayaScene": [0.26, 0.68, 1.0],
+ "setdress": [1.0, 0.98, 0.35],
+ "layout": [1.0, 0.98, 0.35],
+ "vdbcache": [0.98, 0.21, 0.0],
+ "vrayproxy": [1.0, 0.59, 0.05],
+ "vrayscene_layer": [1.0, 0.59, 0.05],
+ "yeticache": [0.39, 0.81, 0.86],
+ "yetiRig": [0.0, 0.80, 0.49],
},
"reference_loader": {
"namespace": "{folder[name]}_{product[name]}_##_",
diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py
index 0461a18cc8..dcedf3ccc9 100644
--- a/server_addon/maya/server/settings/publish_playblast.py
+++ b/server_addon/maya/server/settings/publish_playblast.py
@@ -6,7 +6,7 @@ from ayon_server.settings import (
ensure_unique_names,
task_types_enum,
)
-from ayon_server.types import ColorRGBA_uint8
+from ayon_server.types import ColorRGB_float
def hardware_falloff_enum():
@@ -54,17 +54,17 @@ class DisplayOptionsSetting(BaseSettingsModel):
override_display: bool = SettingsField(
True, title="Override display options"
)
- background: ColorRGBA_uint8 = SettingsField(
- (125, 125, 125, 1.0), title="Background Color"
+ background: ColorRGB_float = SettingsField(
+ (0.5, 0.5, 0.5), title="Background Color"
)
displayGradient: bool = SettingsField(
True, title="Display background gradient"
)
- backgroundTop: ColorRGBA_uint8 = SettingsField(
- (125, 125, 125, 1.0), title="Background Top"
+ backgroundTop: ColorRGB_float = SettingsField(
+ (0.5, 0.5, 0.5), title="Background Top"
)
- backgroundBottom: ColorRGBA_uint8 = SettingsField(
- (125, 125, 125, 1.0), title="Background Bottom"
+ backgroundBottom: ColorRGB_float = SettingsField(
+ (0.5, 0.5, 0.5), title="Background Bottom"
)
@@ -283,22 +283,19 @@ DEFAULT_PLAYBLAST_SETTING = {
"DisplayOptions": {
"override_display": True,
"background": [
- 125,
- 125,
- 125,
- 1.0
+ 0.5,
+ 0.5,
+ 0.5
],
"backgroundBottom": [
- 125,
- 125,
- 125,
- 1.0
+ 0.5,
+ 0.5,
+ 0.5
],
"backgroundTop": [
- 125,
- 125,
- 125,
- 1.0
+ 0.5,
+ 0.5,
+ 0.5
],
"displayGradient": True
},
diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py
index 684d830189..8202425a2d 100644
--- a/server_addon/maya/server/version.py
+++ b/server_addon/maya/server/version.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring addon version."""
-__version__ = "0.1.8"
+__version__ = "0.1.9"
diff --git a/server_addon/photoshop/server/settings/publish_plugins.py b/server_addon/photoshop/server/settings/publish_plugins.py
index c4a392d490..d04faaf53a 100644
--- a/server_addon/photoshop/server/settings/publish_plugins.py
+++ b/server_addon/photoshop/server/settings/publish_plugins.py
@@ -62,9 +62,9 @@ class CollectColorCodedInstancesPlugin(BaseSettingsModel):
enum_resolver=lambda: create_flatten_image_enum,
)
- flatten_product_type_template: str = SettingsField(
+ flatten_product_name_template: str = SettingsField(
"",
- title="Subset template for flatten image"
+ title="Product name template for flatten image"
)
color_code_mapping: list[ColorCodeMappings] = SettingsField(
@@ -178,7 +178,7 @@ class PhotoshopPublishPlugins(BaseSettingsModel):
DEFAULT_PUBLISH_SETTINGS = {
"CollectColorCodedInstances": {
"create_flatten_image": "no",
- "flatten_product_type_template": "",
+ "flatten_product_name_template": "",
"color_code_mapping": []
},
"CollectReview": {
diff --git a/server_addon/photoshop/server/version.py b/server_addon/photoshop/server/version.py
index a242f0e757..df0c92f1e2 100644
--- a/server_addon/photoshop/server/version.py
+++ b/server_addon/photoshop/server/version.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring addon version."""
-__version__ = "0.1.1"
+__version__ = "0.1.2"
diff --git a/server_addon/tvpaint/server/settings/publish_plugins.py b/server_addon/tvpaint/server/settings/publish_plugins.py
index 0623524c92..37ad3e0e70 100644
--- a/server_addon/tvpaint/server/settings/publish_plugins.py
+++ b/server_addon/tvpaint/server/settings/publish_plugins.py
@@ -1,5 +1,5 @@
from ayon_server.settings import BaseSettingsModel, SettingsField
-from ayon_server.types import ColorRGBA_uint8
+from ayon_server.types import ColorRGB_uint8
class CollectRenderInstancesModel(BaseSettingsModel):
@@ -11,8 +11,8 @@ class CollectRenderInstancesModel(BaseSettingsModel):
class ExtractSequenceModel(BaseSettingsModel):
"""Review BG color is used for whole scene review and for thumbnails."""
# TODO Use alpha color
- review_bg: ColorRGBA_uint8 = SettingsField(
- (255, 255, 255, 1.0),
+ review_bg: ColorRGB_uint8 = SettingsField(
+ (255, 255, 255),
title="Review BG color")
@@ -100,7 +100,7 @@ DEFAULT_PUBLISH_SETTINGS = {
"ignore_render_pass_transparency": False
},
"ExtractSequence": {
- "review_bg": [255, 255, 255, 1.0]
+ "review_bg": [255, 255, 255]
},
"ValidateProjectSettings": {
"enabled": True,
diff --git a/server_addon/tvpaint/server/version.py b/server_addon/tvpaint/server/version.py
index 485f44ac21..b3f4756216 100644
--- a/server_addon/tvpaint/server/version.py
+++ b/server_addon/tvpaint/server/version.py
@@ -1 +1 @@
-__version__ = "0.1.1"
+__version__ = "0.1.2"