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/__init__.py b/client/ayon_core/__init__.py
index c9c0dfc614..5f9eb6cea3 100644
--- a/client/ayon_core/__init__.py
+++ b/client/ayon_core/__init__.py
@@ -7,3 +7,6 @@ AYON_CORE_ROOT = os.path.dirname(os.path.abspath(__file__))
PACKAGE_DIR = AYON_CORE_ROOT
PLUGINS_DIR = os.path.join(AYON_CORE_ROOT, "plugins")
AYON_SERVER_ENABLED = True
+
+# Indicate if AYON entities should be used instead of OpenPype entities
+USE_AYON_ENTITIES = False
diff --git a/client/ayon_core/addon/README.md b/client/ayon_core/addon/README.md
index b793b0ffb4..a15e8bdc69 100644
--- a/client/ayon_core/addon/README.md
+++ b/client/ayon_core/addon/README.md
@@ -31,7 +31,7 @@ AYON addons should contain separated logic of specific kind of implementation, s
- addon must implement `get_plugin_paths` which must return dictionary with possible keys `"publish"`, `"load"`, `"create"` or `"actions"`
- each key may contain list or string with a path to directory with plugins
-## ITrayModule
+## ITrayAddon
- addon has more logic when used in a tray
- it is possible that addon can be used only in the tray
- abstract methods
@@ -46,7 +46,7 @@ AYON addons should contain separated logic of specific kind of implementation, s
- if addon has logic only in tray or for both then should be checking for `tray_initialized` attribute to decide how should handle situations
### ITrayService
-- inherits from `ITrayModule` and implements `tray_menu` method for you
+- inherits from `ITrayAddon` and implements `tray_menu` method for you
- adds action to submenu "Services" in tray widget menu with icon and label
- abstract attribute `label`
- label shown in menu
@@ -57,7 +57,7 @@ AYON addons should contain separated logic of specific kind of implementation, s
- these states must be set by addon itself `set_service_running` is default state on initialization
### ITrayAction
-- inherits from `ITrayModule` and implements `tray_menu` method for you
+- inherits from `ITrayAddon` and implements `tray_menu` method for you
- adds action to tray widget menu with label
- abstract attribute `label`
- label shown in menu
@@ -89,4 +89,4 @@ AYON addons should contain separated logic of specific kind of implementation, s
### TrayAddonsManager
- inherits from `AddonsManager`
-- has specific implementation for Pype Tray tool and handle `ITrayModule` methods
+- has specific implementation for Pype Tray tool and handle `ITrayAddon` methods
diff --git a/client/ayon_core/addon/click_wrap.py b/client/ayon_core/addon/click_wrap.py
index d49188312d..911a5a5707 100644
--- a/client/ayon_core/addon/click_wrap.py
+++ b/client/ayon_core/addon/click_wrap.py
@@ -15,7 +15,7 @@ method to convert 'click_wrap' object to 'click' object.
Before
```python
import click
-from ayon_core.modules import AYONAddon
+from ayon_core.addon import AYONAddon
class ExampleAddon(AYONAddon):
@@ -40,7 +40,7 @@ def mycommand(arg1, arg2):
Now
```
from ayon_core import click_wrap
-from ayon_core.modules import AYONAddon
+from ayon_core.addon import AYONAddon
class ExampleAddon(AYONAddon):
@@ -72,7 +72,7 @@ Added small enhancements:
Example:
```python
from ayon_core import click_wrap
- from ayon_core.modules import AYONAddon
+ from ayon_core.addon import AYONAddon
class ExampleAddon(AYONAddon):
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/addon.py b/client/ayon_core/hosts/aftereffects/addon.py
index 278f836a72..46d0818247 100644
--- a/client/ayon_core/hosts/aftereffects/addon.py
+++ b/client/ayon_core/hosts/aftereffects/addon.py
@@ -1,13 +1,10 @@
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
-class AfterEffectsAddon(OpenPypeModule, IHostAddon):
+class AfterEffectsAddon(AYONAddon, IHostAddon):
name = "aftereffects"
host_name = "aftereffects"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
"""Modify environments to contain all required for implementation."""
defaults = {
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/blender/addon.py
index c3804382e5..b7484de243 100644
--- a/client/ayon_core/hosts/blender/addon.py
+++ b/client/ayon_core/hosts/blender/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
BLENDER_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class BlenderAddon(OpenPypeModule, IHostAddon):
+class BlenderAddon(AYONAddon, IHostAddon):
name = "blender"
host_name = "blender"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
"""Modify environments to contain all required for implementation."""
# Prepare path to implementation script
diff --git a/client/ayon_core/hosts/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/celaction/addon.py b/client/ayon_core/hosts/celaction/addon.py
index 4573ee7e56..d00401a2e0 100644
--- a/client/ayon_core/hosts/celaction/addon.py
+++ b/client/ayon_core/hosts/celaction/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
CELACTION_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class CelactionAddon(OpenPypeModule, IHostAddon):
+class CelactionAddon(AYONAddon, IHostAddon):
name = "celaction"
host_name = "celaction"
- def initialize(self, module_settings):
- self.enabled = True
-
def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
diff --git a/client/ayon_core/hosts/flame/addon.py b/client/ayon_core/hosts/flame/addon.py
index e30d7cab08..f5560cde7a 100644
--- a/client/ayon_core/hosts/flame/addon.py
+++ b/client/ayon_core/hosts/flame/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class FlameAddon(OpenPypeModule, IHostAddon):
+class FlameAddon(AYONAddon, IHostAddon):
name = "flame"
host_name = "flame"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to DL_PYTHON_HOOK_PATH
env["DL_PYTHON_HOOK_PATH"] = os.path.join(HOST_DIR, "startup")
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/fusion/addon.py
index 7eff2d93c8..391ee770c4 100644
--- a/client/ayon_core/hosts/fusion/addon.py
+++ b/client/ayon_core/hosts/fusion/addon.py
@@ -1,6 +1,6 @@
import os
import re
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
from ayon_core.lib import Logger
FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -48,13 +48,10 @@ def get_fusion_version(app_name):
)
-class FusionAddon(OpenPypeModule, IHostAddon):
+class FusionAddon(AYONAddon, IHostAddon):
name = "fusion"
host_name = "fusion"
- def initialize(self, module_settings):
- self.enabled = True
-
def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/harmony/addon.py
index 172a1f104f..476d569415 100644
--- a/client/ayon_core/hosts/harmony/addon.py
+++ b/client/ayon_core/hosts/harmony/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
HARMONY_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class HarmonyAddon(OpenPypeModule, IHostAddon):
+class HarmonyAddon(AYONAddon, IHostAddon):
name = "harmony"
host_name = "harmony"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
"""Modify environments to contain all required for implementation."""
openharmony_path = os.path.join(
diff --git a/client/ayon_core/hosts/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/hiero/addon.py b/client/ayon_core/hosts/hiero/addon.py
index 447700e2e1..f612493ca1 100644
--- a/client/ayon_core/hosts/hiero/addon.py
+++ b/client/ayon_core/hosts/hiero/addon.py
@@ -1,17 +1,14 @@
import os
import platform
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
HIERO_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class HieroAddon(OpenPypeModule, IHostAddon):
+class HieroAddon(AYONAddon, IHostAddon):
name = "hiero"
host_name = "hiero"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to HIERO_PLUGIN_PATH
new_hiero_paths = [
diff --git a/client/ayon_core/hosts/houdini/addon.py b/client/ayon_core/hosts/houdini/addon.py
index 34d140db3c..95d714aea1 100644
--- a/client/ayon_core/hosts/houdini/addon.py
+++ b/client/ayon_core/hosts/houdini/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
HOUDINI_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class HoudiniAddon(OpenPypeModule, IHostAddon):
+class HoudiniAddon(AYONAddon, IHostAddon):
name = "houdini"
host_name = "houdini"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to HOUDINI_PATH and HOUDINI_MENU_PATH
startup_path = os.path.join(HOUDINI_HOST_DIR, "startup")
diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py
index 7163aebdec..bf66890285 100644
--- a/client/ayon_core/hosts/houdini/api/lib.py
+++ b/client/ayon_core/hosts/houdini/api/lib.py
@@ -6,6 +6,7 @@ import re
import uuid
import logging
import json
+from contextlib import contextmanager
import six
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/addon.py b/client/ayon_core/hosts/max/addon.py
index 416014025c..12f5f7eca0 100644
--- a/client/ayon_core/hosts/max/addon.py
+++ b/client/ayon_core/hosts/max/addon.py
@@ -1,17 +1,14 @@
# -*- coding: utf-8 -*-
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
MAX_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class MaxAddon(OpenPypeModule, IHostAddon):
+class MaxAddon(AYONAddon, IHostAddon):
name = "max"
host_name = "max"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Remove auto screen scale factor for Qt
# - let 3dsmax decide it's value
diff --git a/client/ayon_core/hosts/max/api/pipeline.py b/client/ayon_core/hosts/max/api/pipeline.py
index 2dc3eb6da8..c9b74cea9e 100644
--- a/client/ayon_core/hosts/max/api/pipeline.py
+++ b/client/ayon_core/hosts/max/api/pipeline.py
@@ -59,6 +59,9 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
rt.callbacks.addScript(rt.Name('filePostOpen'),
lib.check_colorspace)
+
+ rt.callbacks.addScript(rt.Name('postWorkspaceChange'),
+ self._deferred_menu_creation)
def workfile_has_unsaved_changes(self):
return rt.getSaveRequired()
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/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/maya/addon.py b/client/ayon_core/hosts/maya/addon.py
index 745850f6a8..c68aa4c911 100644
--- a/client/ayon_core/hosts/maya/addon.py
+++ b/client/ayon_core/hosts/maya/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
MAYA_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class MayaAddon(OpenPypeModule, IHostAddon):
+class MayaAddon(AYONAddon, IHostAddon):
name = "maya"
host_name = "maya"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to PYTHONPATH
new_python_paths = [
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/nuke/addon.py
index 4ca4408271..8e640624f0 100644
--- a/client/ayon_core/hosts/nuke/addon.py
+++ b/client/ayon_core/hosts/nuke/addon.py
@@ -1,17 +1,14 @@
import os
import platform
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
NUKE_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class NukeAddon(OpenPypeModule, IHostAddon):
+class NukeAddon(AYONAddon, IHostAddon):
name = "nuke"
host_name = "nuke"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to NUKE_PATH
new_nuke_paths = [
diff --git a/client/ayon_core/hosts/nuke/api/pipeline.py b/client/ayon_core/hosts/nuke/api/pipeline.py
index bdba0757b6..7483d404ec 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["nuke_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/addon.py b/client/ayon_core/hosts/photoshop/addon.py
index 0c7efdb317..3016912960 100644
--- a/client/ayon_core/hosts/photoshop/addon.py
+++ b/client/ayon_core/hosts/photoshop/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
PHOTOSHOP_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class PhotoshopAddon(OpenPypeModule, IHostAddon):
+class PhotoshopAddon(AYONAddon, IHostAddon):
name = "photoshop"
host_name = "photoshop"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
"""Modify environments to contain all required for implementation."""
defaults = {
diff --git a/client/ayon_core/hosts/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/resolve/addon.py b/client/ayon_core/hosts/resolve/addon.py
index 9c9932826b..1354caabb2 100644
--- a/client/ayon_core/hosts/resolve/addon.py
+++ b/client/ayon_core/hosts/resolve/addon.py
@@ -1,17 +1,14 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
from .utils import RESOLVE_ROOT_DIR
-class ResolveAddon(OpenPypeModule, IHostAddon):
+class ResolveAddon(AYONAddon, IHostAddon):
name = "resolve"
host_name = "resolve"
- def initialize(self, module_settings):
- self.enabled = True
-
def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
diff --git a/client/ayon_core/hosts/resolve/startup.py b/client/ayon_core/hosts/resolve/startup.py
index 174a2878c5..b3c1a024d9 100644
--- a/client/ayon_core/hosts/resolve/startup.py
+++ b/client/ayon_core/hosts/resolve/startup.py
@@ -33,7 +33,7 @@ def ensure_installed_host():
def launch_menu():
- print("Launching Resolve OpenPype menu..")
+ print("Launching Resolve AYON menu..")
ensure_installed_host()
ayon_core.hosts.resolve.api.launch_pype_menu()
@@ -54,7 +54,7 @@ def main():
else:
log.info("No last workfile set to open. Skipping..")
- # Launch OpenPype menu
+ # Launch AYON menu
from ayon_core.settings import get_project_settings
from ayon_core.pipeline.context_tools import get_current_project_name
project_name = get_current_project_name()
@@ -62,7 +62,7 @@ def main():
settings = get_project_settings(project_name)
if settings.get("resolve", {}).get("launch_openpype_menu_on_start", True):
- log.info("Launching OpenPype menu..")
+ log.info("Launching AYON menu..")
launch_menu()
diff --git a/client/ayon_core/hosts/substancepainter/addon.py b/client/ayon_core/hosts/substancepainter/addon.py
index a7f21c2288..26829d3153 100644
--- a/client/ayon_core/hosts/substancepainter/addon.py
+++ b/client/ayon_core/hosts/substancepainter/addon.py
@@ -1,16 +1,13 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
SUBSTANCE_HOST_DIR = os.path.dirname(os.path.abspath(__file__))
-class SubstanceAddon(OpenPypeModule, IHostAddon):
+class SubstanceAddon(AYONAddon, IHostAddon):
name = "substancepainter"
host_name = "substancepainter"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
# Add requirements to SUBSTANCE_PAINTER_PLUGINS_PATH
plugin_path = os.path.join(SUBSTANCE_HOST_DIR, "deploy")
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/traypublisher/addon.py
index d8fc5ed105..70bdfe9a64 100644
--- a/client/ayon_core/hosts/traypublisher/addon.py
+++ b/client/ayon_core/hosts/traypublisher/addon.py
@@ -2,9 +2,9 @@ import os
from ayon_core.lib import get_ayon_launcher_args
from ayon_core.lib.execute import run_detached_process
-from ayon_core.modules import (
+from ayon_core.addon import (
click_wrap,
- OpenPypeModule,
+ AYONAddon,
ITrayAction,
IHostAddon,
)
@@ -12,13 +12,12 @@ from ayon_core.modules import (
TRAYPUBLISH_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction):
+class TrayPublishAddon(AYONAddon, IHostAddon, ITrayAction):
label = "Publisher"
name = "traypublisher"
host_name = "traypublisher"
- def initialize(self, modules_settings):
- self.enabled = True
+ def initialize(self, settings):
self.publish_paths = [
os.path.join(TRAYPUBLISH_ROOT_DIR, "plugins", "publish")
]
@@ -36,7 +35,7 @@ class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction):
def run_traypublisher(self):
args = get_ayon_launcher_args(
- "module", self.name, "launch"
+ "addon", self.name, "launch"
)
run_detached_process(args)
diff --git a/client/ayon_core/hosts/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/addon.py b/client/ayon_core/hosts/tvpaint/addon.py
index 375f7266ae..6756b274f9 100644
--- a/client/ayon_core/hosts/tvpaint/addon.py
+++ b/client/ayon_core/hosts/tvpaint/addon.py
@@ -1,5 +1,5 @@
import os
-from ayon_core.modules import OpenPypeModule, IHostAddon
+from ayon_core.addon import AYONAddon, IHostAddon
TVPAINT_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -12,13 +12,10 @@ def get_launch_script_path():
)
-class TVPaintAddon(OpenPypeModule, IHostAddon):
+class TVPaintAddon(AYONAddon, IHostAddon):
name = "tvpaint"
host_name = "tvpaint"
- def initialize(self, module_settings):
- self.enabled = True
-
def add_implementation_envs(self, env, _app):
"""Modify environments to contain all required for implementation."""
diff --git a/client/ayon_core/hosts/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/hosts/unreal/addon.py b/client/ayon_core/hosts/unreal/addon.py
index 745df951c1..c65490bd8c 100644
--- a/client/ayon_core/hosts/unreal/addon.py
+++ b/client/ayon_core/hosts/unreal/addon.py
@@ -1,17 +1,14 @@
import os
import re
-from ayon_core.modules import IHostAddon, OpenPypeModule
+from ayon_core.addon import AYONAddon, IHostAddon
UNREAL_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-class UnrealAddon(OpenPypeModule, IHostAddon):
+class UnrealAddon(AYONAddon, IHostAddon):
name = "unreal"
host_name = "unreal"
- def initialize(self, module_settings):
- self.enabled = True
-
def get_global_environments(self):
return {
"AYON_UNREAL_ROOT": UNREAL_ROOT_DIR,
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..70aa9811c7 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,30 @@ 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")
+ app_defs.update(additional_apps)
+
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 +519,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 +564,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/lib/local_settings.py b/client/ayon_core/lib/local_settings.py
index 33b3232128..022f63a618 100644
--- a/client/ayon_core/lib/local_settings.py
+++ b/client/ayon_core/lib/local_settings.py
@@ -38,8 +38,8 @@ class AYONSecureRegistry:
Registry should be used for private data that should be available only for
user.
- All passed registry names will have added prefix `OpenPype/` to easier
- identify which data were created by OpenPype.
+ All passed registry names will have added prefix `AYON/` to easier
+ identify which data were created by AYON.
Args:
name(str): Name of registry used as identifier for data.
diff --git a/client/ayon_core/modules/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 9988248957..dbc000a163 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
)
@@ -207,12 +207,16 @@ class HoudiniSubmitDeadline(
"AVALON_PROJECT",
"AVALON_ASSET",
"AVALON_TASK",
+ "AVALON_WORKDIR",
"AVALON_APP_NAME",
"AYON_LOG_NO_COLORS",
]
- environment = dict({key: os.environ[key] for key in keys
- if key in os.environ}, **legacy_io.Session)
+ environment = {
+ key: os.environ[key]
+ for key in keys
+ if key in os.environ
+ }
for key in keys:
value = environment.get(key)
diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py
index 0a7c96008e..8908283164 100644
--- a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py
+++ b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py
@@ -9,7 +9,6 @@ from ayon_core.lib import (
NumberDef,
)
from ayon_core.pipeline import (
- legacy_io,
AYONPyblishPluginMixin
)
from ayon_core.pipeline.publish.lib import (
@@ -110,12 +109,16 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
"AVALON_PROJECT",
"AVALON_ASSET",
"AVALON_TASK",
+ "AVALON_WORKDIR",
"AVALON_APP_NAME",
"IS_TEST"
]
- environment = dict({key: os.environ[key] for key in keys
- if key in os.environ}, **legacy_io.Session)
+ environment = {
+ key: os.environ[key]
+ for key in keys
+ if key in os.environ
+ }
for key in keys:
value = environment.get(key)
diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py
index 84e6e93e6a..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/job_queue/module.py b/client/ayon_core/modules/job_queue/module.py
index 1cecd62de5..f2b022069b 100644
--- a/client/ayon_core/modules/job_queue/module.py
+++ b/client/ayon_core/modules/job_queue/module.py
@@ -1,4 +1,4 @@
-"""Job queue OpenPype module was created for remote execution of commands.
+"""Job queue AYON addon was created for remote execution of commands.
## Why is needed
Primarily created for hosts which are not easilly controlled from command line
@@ -30,7 +30,7 @@ workstations know where to send or receive jobs.
### start_worker
- start worker which will process jobs
-- has required possitional argument which is application name from OpenPype
+- has required possitional argument which is application name from AYON
settings e.g. 'tvpaint/11-5' ('tvpaint' is group '11-5' is variant)
- it is possible to specify server url but url from settings is used when not
passed (this is added mainly for developing purposes)
diff --git a/client/ayon_core/modules/launcher_action.py b/client/ayon_core/modules/launcher_action.py
index c0266e3a57..1faf6ef4b1 100644
--- a/client/ayon_core/modules/launcher_action.py
+++ b/client/ayon_core/modules/launcher_action.py
@@ -1,19 +1,14 @@
import os
from ayon_core import AYON_CORE_ROOT
-from ayon_core.modules import (
- OpenPypeModule,
- ITrayAction,
-)
+from ayon_core.addon import AYONAddon, ITrayAction
-class LauncherAction(OpenPypeModule, ITrayAction):
+class LauncherAction(AYONAddon, ITrayAction):
label = "Launcher"
name = "launcher_tool"
- def initialize(self, _modules_settings):
- # This module is always enabled
- self.enabled = True
+ def initialize(self, settings):
# Tray attributes
self._window = None
diff --git a/client/ayon_core/modules/library_loader_action.py b/client/ayon_core/modules/library_loader_action.py
deleted file mode 100644
index 524c4f7144..0000000000
--- a/client/ayon_core/modules/library_loader_action.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from ayon_core.modules import AYONAddon, ITrayModule
-
-
-class LibraryLoaderAddon(AYONAddon, ITrayModule):
- name = "library_tool"
-
- def initialize(self, modules_settings):
- # Tray attributes
- self._library_loader_imported = None
- self._library_loader_window = None
-
- def tray_init(self):
- # Add library tool
- self._library_loader_imported = False
- try:
- from ayon_core.tools.loader.ui import LoaderWindow
-
- self._library_loader_imported = True
- except Exception:
- self.log.warning(
- "Couldn't load Library loader tool for tray.",
- exc_info=True
- )
-
- # Definition of Tray menu
- def tray_menu(self, tray_menu):
- if not self._library_loader_imported:
- return
-
- from qtpy import QtWidgets
- # Actions
- action_library_loader = QtWidgets.QAction(
- "Loader", tray_menu
- )
-
- action_library_loader.triggered.connect(self.show_library_loader)
-
- tray_menu.addAction(action_library_loader)
-
- def tray_start(self, *_a, **_kw):
- return
-
- def tray_exit(self, *_a, **_kw):
- return
-
- def show_library_loader(self):
- if self._library_loader_window is None:
- from ayon_core.pipeline import install_ayon_plugins
-
- self._init_library_loader()
-
- install_ayon_plugins()
-
- self._library_loader_window.show()
-
- # Raise and activate the window
- # for MacOS
- self._library_loader_window.raise_()
- # for Windows
- self._library_loader_window.activateWindow()
-
- def _init_library_loader(self):
- from ayon_core.tools.loader.ui import LoaderWindow
-
- libraryloader = LoaderWindow()
-
- self._library_loader_window = libraryloader
diff --git a/client/ayon_core/modules/loader_action.py b/client/ayon_core/modules/loader_action.py
new file mode 100644
index 0000000000..a0cc417b66
--- /dev/null
+++ b/client/ayon_core/modules/loader_action.py
@@ -0,0 +1,67 @@
+from ayon_core.addon import AYONAddon, ITrayAddon
+
+
+class LoaderAddon(AYONAddon, ITrayAddon):
+ name = "loader_tool"
+
+ def initialize(self, settings):
+ # Tray attributes
+ self._loader_imported = None
+ self._loader_window = None
+
+ def tray_init(self):
+ # Add library tool
+ self._loader_imported = False
+ try:
+ from ayon_core.tools.loader.ui import LoaderWindow
+
+ self._loader_imported = True
+ except Exception:
+ self.log.warning(
+ "Couldn't load Loader tool for tray.",
+ exc_info=True
+ )
+
+ # Definition of Tray menu
+ def tray_menu(self, tray_menu):
+ if not self._loader_imported:
+ return
+
+ from qtpy import QtWidgets
+ # Actions
+ action_loader = QtWidgets.QAction(
+ "Loader", tray_menu
+ )
+
+ action_loader.triggered.connect(self.show_loader)
+
+ tray_menu.addAction(action_loader)
+
+ def tray_start(self, *_a, **_kw):
+ return
+
+ def tray_exit(self, *_a, **_kw):
+ return
+
+ def show_loader(self):
+ if self._loader_window is None:
+ from ayon_core.pipeline import install_ayon_plugins
+
+ self._init_loader()
+
+ install_ayon_plugins()
+
+ self._loader_window.show()
+
+ # Raise and activate the window
+ # for MacOS
+ self._loader_window.raise_()
+ # for Windows
+ self._loader_window.activateWindow()
+
+ def _init_loader(self):
+ from ayon_core.tools.loader.ui import LoaderWindow
+
+ libraryloader = LoaderWindow()
+
+ self._loader_window = libraryloader
diff --git a/client/ayon_core/modules/python_console_interpreter/__init__.py b/client/ayon_core/modules/python_console_interpreter/__init__.py
index 5f54ac497b..8d5c23bdba 100644
--- a/client/ayon_core/modules/python_console_interpreter/__init__.py
+++ b/client/ayon_core/modules/python_console_interpreter/__init__.py
@@ -1,4 +1,4 @@
-from .module import (
+from .addon import (
PythonInterpreterAction
)
diff --git a/client/ayon_core/modules/python_console_interpreter/module.py b/client/ayon_core/modules/python_console_interpreter/addon.py
similarity index 77%
rename from client/ayon_core/modules/python_console_interpreter/module.py
rename to client/ayon_core/modules/python_console_interpreter/addon.py
index 7819c9cbf3..ffad3ce707 100644
--- a/client/ayon_core/modules/python_console_interpreter/module.py
+++ b/client/ayon_core/modules/python_console_interpreter/addon.py
@@ -1,13 +1,12 @@
-from ayon_core.modules import OpenPypeModule, ITrayAction
+from ayon_core.addon import AYONAddon, ITrayAction
-class PythonInterpreterAction(OpenPypeModule, ITrayAction):
+class PythonInterpreterAction(AYONAddon, ITrayAction):
label = "Console"
name = "python_interpreter"
admin_action = True
- def initialize(self, modules_settings):
- self.enabled = True
+ def initialize(self, settings):
self._interpreter_window = None
def tray_init(self):
@@ -22,7 +21,7 @@ class PythonInterpreterAction(OpenPypeModule, ITrayAction):
if self._interpreter_window:
return
- from openpype_modules.python_console_interpreter.window import (
+ from ayon_core.modules.python_console_interpreter.window import (
PythonInterpreterWidget
)
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/widget_user_idle.py b/client/ayon_core/modules/timers_manager/widget_user_idle.py
index 94d7a606ed..c59ab15b38 100644
--- a/client/ayon_core/modules/timers_manager/widget_user_idle.py
+++ b/client/ayon_core/modules/timers_manager/widget_user_idle.py
@@ -9,7 +9,7 @@ class WidgetUserIdle(QtWidgets.QWidget):
def __init__(self, module):
super(WidgetUserIdle, self).__init__()
- self.setWindowTitle("OpenPype - Stop timers")
+ self.setWindowTitle("AYON - Stop timers")
icon = QtGui.QIcon(resources.get_ayon_icon_filepath())
self.setWindowIcon(icon)
diff --git a/client/ayon_core/modules/webserver/webserver_module.py b/client/ayon_core/modules/webserver/webserver_module.py
index ec143d0866..c324e0dd18 100644
--- a/client/ayon_core/modules/webserver/webserver_module.py
+++ b/client/ayon_core/modules/webserver/webserver_module.py
@@ -1,6 +1,6 @@
"""WebServerAddon spawns aiohttp server in asyncio loop.
-Main usage of the module is in OpenPype tray where make sense to add ability
+Main usage of the module is in AYON tray where make sense to add ability
of other modules to add theirs routes. Module which would want use that
option must have implemented method `webserver_initialization` which must
expect `WebServerManager` object where is possible to add routes or paths
diff --git a/client/ayon_core/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/farm/patterning.py b/client/ayon_core/pipeline/farm/patterning.py
index 1e4b5bf37d..d7b046113b 100644
--- a/client/ayon_core/pipeline/farm/patterning.py
+++ b/client/ayon_core/pipeline/farm/patterning.py
@@ -11,7 +11,7 @@ def match_aov_pattern(host_name, aov_patterns, render_file_name):
that we have grabbed from `exp_files`.
Args:
- app (str): Host name.
+ host_name (str): Host name.
aov_patterns (dict): AOV patterns from AOV filters.
render_file_name (str): Incoming file name to match against.
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/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py
index 90e0ef7431..3874ddc13c 100644
--- a/client/ayon_core/plugins/publish/extract_thumbnail.py
+++ b/client/ayon_core/plugins/publish/extract_thumbnail.py
@@ -2,6 +2,7 @@ import copy
import os
import subprocess
import tempfile
+import re
import pyblish.api
from ayon_core.lib import (
@@ -35,6 +36,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
"traypublisher",
"substancepainter",
"nuke",
+ "aftereffects"
]
enabled = False
@@ -49,6 +51,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
# attribute presets from settings
oiiotool_defaults = None
ffmpeg_args = None
+ product_names = []
def process(self, instance):
# run main process
@@ -103,6 +106,26 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
self.log.debug("Skipping crypto passes.")
return
+ # We only want to process the subsets needed from settings.
+ def validate_string_against_patterns(input_str, patterns):
+ for pattern in patterns:
+ if re.match(pattern, input_str):
+ return True
+ return False
+
+ product_names = self.product_names
+ if product_names:
+ result = validate_string_against_patterns(
+ instance.data["subset"], product_names
+ )
+ if not result:
+ self.log.debug(
+ "Product name \"{}\" did not match settings filters: {}".format(
+ instance.data["subset"], product_names
+ )
+ )
+ return
+
# first check for any explicitly marked representations for thumbnail
explicit_repres = self._get_explicit_repres_for_thumbnail(instance)
if explicit_repres:
diff --git a/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..fe54714f75 100644
--- a/client/ayon_core/settings/ayon_settings.py
+++ b/client/ayon_core/settings/ayon_settings.py
@@ -72,97 +72,22 @@ def _convert_host_imageio(host_settings):
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
@@ -290,7 +215,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,27 +238,12 @@ 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
@@ -353,53 +263,7 @@ 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
@@ -410,39 +274,6 @@ def _convert_fusion_project_settings(ayon_settings, output):
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 +283,8 @@ 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 +293,8 @@ 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")
+ _convert_host_imageio(ayon_max)
output["max"] = ayon_max
@@ -708,15 +351,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"] = (
@@ -888,18 +522,6 @@ def _convert_photoshop_project_settings(ayon_settings, output):
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
@@ -909,44 +531,15 @@ def _convert_substancepainter_project_settings(ayon_settings, output):
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
@@ -958,58 +551,6 @@ def _convert_traypublisher_project_settings(ayon_settings, output):
_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
@@ -1031,49 +572,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
@@ -1149,50 +647,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 +824,14 @@ 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 +846,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/project_settings/global.json b/client/ayon_core/settings/defaults/project_settings/global.json
index bb7e3266bd..782fff1052 100644
--- a/client/ayon_core/settings/defaults/project_settings/global.json
+++ b/client/ayon_core/settings/defaults/project_settings/global.json
@@ -70,6 +70,7 @@
},
"ExtractThumbnail": {
"enabled": true,
+ "subsets": [],
"integrate_thumbnail": false,
"background_color": [
0,
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/style/__init__.py b/client/ayon_core/style/__init__.py
index 8b2dfa1bcb..8d3089ef86 100644
--- a/client/ayon_core/style/__init__.py
+++ b/client/ayon_core/style/__init__.py
@@ -198,7 +198,7 @@ def _load_font():
def load_stylesheet():
- """Load and return OpenPype Qt stylesheet."""
+ """Load and return AYON Qt stylesheet."""
if _Cache.stylesheet is None:
_Cache.stylesheet = _load_stylesheet()
@@ -207,7 +207,7 @@ def load_stylesheet():
def get_app_icon_path():
- """Path to OpenPype icon."""
+ """Path to AYON icon."""
return resources.get_ayon_icon_filepath()
diff --git a/client/ayon_core/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..faad37104d 100644
--- a/client/ayon_core/tools/publisher/widgets/assets_widget.py
+++ b/client/ayon_core/tools/publisher/widgets/assets_widget.py
@@ -21,7 +21,7 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
def __init__(self, controller, parent):
self._controller = controller
- super(CreateWidgetAssetsWidget, self).__init__(None, parent)
+ super(CreateWidgetAssetsWidget, self).__init__(parent)
self.set_refresh_btn_visibility(False)
self.set_current_asset_btn_visibility(False)
@@ -31,6 +31,9 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
self._last_filter_height = None
+ def get_project_name(self):
+ return self._controller.project_name
+
def get_selected_asset_name(self):
selection_model = self._view.selectionModel()
indexes = selection_model.selectedRows()
@@ -79,10 +82,10 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
def update_current_asset(self):
# Hide set current asset if there is no one
- asset_name = self._get_current_session_asset()
+ asset_name = self._get_current_asset_name()
self.set_current_asset_btn_visibility(bool(asset_name))
- def _get_current_session_asset(self):
+ def _get_current_asset_name(self):
return self._controller.current_asset_name
def _create_source_model(self):
diff --git a/client/ayon_core/tools/publisher/widgets/create_widget.py b/client/ayon_core/tools/publisher/widgets/create_widget.py
index 12135c6891..8eae205882 100644
--- a/client/ayon_core/tools/publisher/widgets/create_widget.py
+++ b/client/ayon_core/tools/publisher/widgets/create_widget.py
@@ -565,7 +565,7 @@ class CreateWidget(QtWidgets.QWidget):
self._last_thumbnail_path = None
def _on_current_session_context_request(self):
- self._assets_widget.set_current_session_asset()
+ self._assets_widget.select_current_asset()
task_name = self.current_task_name
if task_name:
self._tasks_widget.select_task_name(task_name)
diff --git a/client/ayon_core/tools/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/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py
index dad314e510..79386d7ea0 100644
--- a/client/ayon_core/tools/traypublisher/window.py
+++ b/client/ayon_core/tools/traypublisher/window.py
@@ -12,7 +12,7 @@ from qtpy import QtWidgets, QtCore
import qtawesome
import appdirs
-from ayon_core.lib import JSONSettingRegistry
+from ayon_core.lib import JSONSettingRegistry, is_running_from_build
from ayon_core.pipeline import install_host
from ayon_core.hosts.traypublisher.api import TrayPublisherHost
from ayon_core.tools.publisher.control_qt import QtPublisherController
@@ -35,7 +35,7 @@ class TrayPublisherController(QtPublisherController):
class TrayPublisherRegistry(JSONSettingRegistry):
- """Class handling OpenPype general settings registry.
+ """Class handling AYON general settings registry.
Attributes:
vendor (str): Name used for path construction.
@@ -265,7 +265,7 @@ def main():
app_instance = get_ayon_qt_app()
- if platform.system().lower() == "windows":
+ if not is_running_from_build() and platform.system().lower() == "windows":
import ctypes
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
u"traypublisher"
diff --git a/client/ayon_core/tools/utils/assets_widget.py b/client/ayon_core/tools/utils/assets_widget.py
index c05f3de850..7bacf3291d 100644
--- a/client/ayon_core/tools/utils/assets_widget.py
+++ b/client/ayon_core/tools/utils/assets_widget.py
@@ -111,7 +111,6 @@ class _AssetModel(QtGui.QStandardItemModel):
'refreshed' signal.
Args:
- dbcon (AvalonMongoDB): Ready to use connection to mongo with.
parent (QObject): Parent Qt object.
"""
@@ -128,9 +127,8 @@ class _AssetModel(QtGui.QStandardItemModel):
"data.color": 1
}
- def __init__(self, dbcon, parent=None):
+ def __init__(self, parent=None):
super(_AssetModel, self).__init__(parent=parent)
- self.dbcon = dbcon
self._refreshing = False
self._doc_fetching_thread = None
@@ -142,6 +140,7 @@ class _AssetModel(QtGui.QStandardItemModel):
self._item_ids_with_color = set()
self._items_by_asset_id = {}
+ self._project_name = None
self._last_project_name = None
@property
@@ -185,6 +184,16 @@ class _AssetModel(QtGui.QStandardItemModel):
return self.get_indexes_by_asset_ids(asset_ids)
+ def get_project_name(self):
+ return self._project_name
+
+ def set_project_name(self, project_name, refresh):
+ if self._project_name == project_name:
+ return
+ self._project_name = project_name
+ if refresh:
+ self.refresh()
+
def refresh(self, force=False):
"""Refresh the data for the model.
@@ -197,7 +206,7 @@ class _AssetModel(QtGui.QStandardItemModel):
return
self.stop_refresh()
- project_name = self.dbcon.Session.get("AVALON_PROJECT")
+ project_name = self._project_name
clear_model = False
if project_name != self._last_project_name:
clear_model = True
@@ -216,23 +225,6 @@ class _AssetModel(QtGui.QStandardItemModel):
def stop_refresh(self):
self._stop_fetch_thread()
- def clear_underlines(self):
- for asset_id in set(self._item_ids_with_color):
- self._item_ids_with_color.remove(asset_id)
- item = self._items_by_asset_id.get(asset_id)
- if item is not None:
- item.setData(None, ASSET_UNDERLINE_COLORS_ROLE)
-
- def set_underline_colors(self, colors_by_asset_id):
- self.clear_underlines()
-
- for asset_id, colors in colors_by_asset_id.items():
- item = self._items_by_asset_id.get(asset_id)
- if item is None:
- continue
- item.setData(colors, ASSET_UNDERLINE_COLORS_ROLE)
- self._item_ids_with_color.add(asset_id)
-
def _clear_items(self):
root_item = self.invisibleRootItem()
root_item.removeRows(0, root_item.rowCount())
@@ -357,7 +349,7 @@ class _AssetModel(QtGui.QStandardItemModel):
self._doc_fetched.emit()
def _fetch_asset_docs(self):
- project_name = self.dbcon.current_project()
+ project_name = self.get_project_name()
if not project_name:
return []
@@ -392,7 +384,6 @@ class _AssetsWidget(QtWidgets.QWidget):
inheritance changes.
Args:
- dbcon (AvalonMongoDB): Connection to avalon mongo db.
parent (QWidget): Parent Qt widget.
"""
@@ -404,11 +395,9 @@ class _AssetsWidget(QtWidgets.QWidget):
# It was double clicked on view
double_clicked = QtCore.Signal()
- def __init__(self, dbcon, parent=None):
+ def __init__(self, parent=None):
super(_AssetsWidget, self).__init__(parent=parent)
- self.dbcon = dbcon
-
# Tree View
model = self._create_source_model()
proxy = self._create_proxy_model(model)
@@ -477,18 +466,28 @@ class _AssetsWidget(QtWidgets.QWidget):
self._model = model
self._proxy = proxy
self._view = view
- self._last_project_name = None
self._last_btns_height = None
+ self._current_asset_name = None
+
self.model_selection = {}
@property
def header_widget(self):
return self._header_widget
+ def get_project_name(self):
+ self._model.get_project_name()
+
+ def set_project_name(self, project_name, refresh=True):
+ self._model.set_project_name(project_name, refresh)
+
+ def set_current_asset_name(self, asset_name):
+ self._current_asset_name = asset_name
+
def _create_source_model(self):
- model = _AssetModel(dbcon=self.dbcon, parent=self)
+ model = _AssetModel(parent=self)
model.refreshed.connect(self._on_model_refresh)
return model
@@ -509,8 +508,8 @@ class _AssetsWidget(QtWidgets.QWidget):
def stop_refresh(self):
self._model.stop_refresh()
- def _get_current_session_asset(self):
- return self.dbcon.Session.get("AVALON_ASSET")
+ def _get_current_asset_name(self):
+ return self._current_asset_name
def _on_current_asset_click(self):
"""Trigger change of asset to current context asset.
@@ -518,10 +517,10 @@ class _AssetsWidget(QtWidgets.QWidget):
in differnt way.
"""
- self.set_current_session_asset()
+ self.select_current_asset()
- def set_current_session_asset(self):
- asset_name = self._get_current_session_asset()
+ def select_current_asset(self):
+ asset_name = self._get_current_asset_name()
if asset_name:
self.select_asset_by_name(asset_name)
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/server/settings/publish_plugins.py b/server/settings/publish_plugins.py
index 7aa86aafa6..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):
@@ -176,6 +176,10 @@ class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel):
class ExtractThumbnailModel(BaseSettingsModel):
_isGroup = True
enabled: bool = SettingsField(True)
+ product_names: list[str] = SettingsField(
+ default_factory=list,
+ title="Product names"
+ )
integrate_thumbnail: bool = SettingsField(
True,
title="Integrate Thumbnail Representation"
@@ -383,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"
@@ -844,6 +848,7 @@ DEFAULT_PUBLISH_VALUES = {
},
"ExtractThumbnail": {
"enabled": True,
+ "product_names": [],
"integrate_thumbnail": True,
"target_size": {
"type": "source"
@@ -896,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,
@@ -941,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/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py
index 8abe59674b..3f5ac3108d 100644
--- a/server_addon/deadline/server/settings/publish_plugins.py
+++ b/server_addon/deadline/server/settings/publish_plugins.py
@@ -306,36 +306,38 @@ class PublishPluginsModel(BaseSettingsModel):
default_factory=ValidateExpectedFilesModel,
title="Validate Expected Files"
)
- MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField(
- default_factory=MayaSubmitDeadlineModel,
- title="Maya Submit to deadline")
- MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField(
- default_factory=MaxSubmitDeadlineModel,
- title="Max Submit to deadline")
- FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField(
- default_factory=FusionSubmitDeadlineModel,
- title="Fusion submit to Deadline")
- NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField(
- default_factory=NukeSubmitDeadlineModel,
- title="Nuke Submit to deadline")
- HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField(
- default_factory=HarmonySubmitDeadlineModel,
- title="Harmony Submit to deadline")
AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = (
SettingsField(
default_factory=AfterEffectsSubmitDeadlineModel,
- title="After Effects to deadline"
+ title="After Effects to deadline",
+ section="Hosts"
)
)
- CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField(
- default_factory=CelactionSubmitDeadlineModel,
- title="Celaction Submit Deadline")
BlenderSubmitDeadline: BlenderSubmitDeadlineModel = SettingsField(
default_factory=BlenderSubmitDeadlineModel,
title="Blender Submit Deadline")
+ CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField(
+ default_factory=CelactionSubmitDeadlineModel,
+ title="Celaction Submit Deadline")
+ FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField(
+ default_factory=FusionSubmitDeadlineModel,
+ title="Fusion submit to Deadline")
+ HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField(
+ default_factory=HarmonySubmitDeadlineModel,
+ title="Harmony Submit to deadline")
+ MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField(
+ default_factory=MaxSubmitDeadlineModel,
+ title="Max Submit to deadline")
+ MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField(
+ default_factory=MayaSubmitDeadlineModel,
+ title="Maya Submit to deadline")
+ NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField(
+ default_factory=NukeSubmitDeadlineModel,
+ title="Nuke Submit to deadline")
ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = SettingsField(
default_factory=ProcessCacheJobFarmModel,
- title="Process submitted cache Job on farm.")
+ title="Process submitted cache Job on farm.",
+ section="Publish Jobs")
ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = SettingsField(
default_factory=ProcessSubmittedJobOnFarmModel,
title="Process submitted job on farm.")
@@ -357,6 +359,65 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = {
"deadline"
]
},
+ "AfterEffectsSubmitDeadline": {
+ "enabled": True,
+ "optional": False,
+ "active": True,
+ "use_published": True,
+ "priority": 50,
+ "chunk_size": 10000,
+ "group": "",
+ "department": "",
+ "multiprocess": True
+ },
+ "BlenderSubmitDeadline": {
+ "enabled": True,
+ "optional": False,
+ "active": True,
+ "use_published": True,
+ "priority": 50,
+ "chunk_size": 10,
+ "group": "none",
+ "job_delay": "00:00:00:00"
+ },
+ "CelactionSubmitDeadline": {
+ "enabled": True,
+ "deadline_department": "",
+ "deadline_priority": 50,
+ "deadline_pool": "",
+ "deadline_pool_secondary": "",
+ "deadline_group": "",
+ "deadline_chunk_size": 10,
+ "deadline_job_delay": "00:00:00:00"
+ },
+ "FusionSubmitDeadline": {
+ "enabled": True,
+ "optional": False,
+ "active": True,
+ "priority": 50,
+ "chunk_size": 10,
+ "concurrent_tasks": 1,
+ "group": ""
+ },
+ "HarmonySubmitDeadline": {
+ "enabled": True,
+ "optional": False,
+ "active": True,
+ "use_published": True,
+ "priority": 50,
+ "chunk_size": 10000,
+ "group": "",
+ "department": ""
+ },
+ "MaxSubmitDeadline": {
+ "enabled": True,
+ "optional": False,
+ "active": True,
+ "use_published": True,
+ "priority": 50,
+ "chunk_size": 10,
+ "group": "none"
+ },
"MayaSubmitDeadline": {
"enabled": True,
"optional": False,
@@ -376,24 +437,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = {
"pluginInfo": "",
"scene_patches": []
},
- "MaxSubmitDeadline": {
- "enabled": True,
- "optional": False,
- "active": True,
- "use_published": True,
- "priority": 50,
- "chunk_size": 10,
- "group": "none"
- },
- "FusionSubmitDeadline": {
- "enabled": True,
- "optional": False,
- "active": True,
- "priority": 50,
- "chunk_size": 10,
- "concurrent_tasks": 1,
- "group": ""
- },
"NukeSubmitDeadline": {
"enabled": True,
"optional": False,
@@ -410,47 +453,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = {
"env_search_replace_values": [],
"limit_groups": []
},
- "HarmonySubmitDeadline": {
- "enabled": True,
- "optional": False,
- "active": True,
- "use_published": True,
- "priority": 50,
- "chunk_size": 10000,
- "group": "",
- "department": ""
- },
- "AfterEffectsSubmitDeadline": {
- "enabled": True,
- "optional": False,
- "active": True,
- "use_published": True,
- "priority": 50,
- "chunk_size": 10000,
- "group": "",
- "department": "",
- "multiprocess": True
- },
- "CelactionSubmitDeadline": {
- "enabled": True,
- "deadline_department": "",
- "deadline_priority": 50,
- "deadline_pool": "",
- "deadline_pool_secondary": "",
- "deadline_group": "",
- "deadline_chunk_size": 10,
- "deadline_job_delay": "00:00:00:00"
- },
- "BlenderSubmitDeadline": {
- "enabled": True,
- "optional": False,
- "active": True,
- "use_published": True,
- "priority": 50,
- "chunk_size": 10,
- "group": "none",
- "job_delay": "00:00:00:00"
- },
"ProcessSubmittedCacheJobOnFarm": {
"enabled": True,
"deadline_department": "",
diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py
index 9cb17e7976..c11f861afb 100644
--- a/server_addon/deadline/server/version.py
+++ b/server_addon/deadline/server/version.py
@@ -1 +1 @@
-__version__ = "0.1.8"
+__version__ = "0.1.9"
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"