Merge branch 'develop' into enhancement/OP-4152_refactor-folder-colors

This commit is contained in:
Ondřej Samohel 2022-12-15 14:53:32 +01:00 committed by GitHub
commit 966b72c7bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 428 additions and 402 deletions

View file

@ -29,8 +29,14 @@ def main(ctx):
It wraps different commands together.
"""
if ctx.invoked_subcommand is None:
ctx.invoke(tray)
# Print help if headless mode is used
if os.environ.get("OPENPYPE_HEADLESS_MODE") == "1":
print(ctx.get_help())
sys.exit(0)
else:
ctx.invoke(tray)
@main.command()

View file

@ -32,11 +32,6 @@ class CreateCamera(plugin.Creator):
subset = self.data["subset"]
name = plugin.asset_name(asset, subset)
camera = bpy.data.cameras.new(subset)
camera_obj = bpy.data.objects.new(subset, camera)
instances.objects.link(camera_obj)
asset_group = bpy.data.objects.new(name=name, object_data=None)
asset_group.empty_display_type = 'SINGLE_ARROW'
instances.objects.link(asset_group)
@ -53,6 +48,11 @@ class CreateCamera(plugin.Creator):
bpy.ops.object.parent_set(keep_transform=True)
else:
plugin.deselect_all()
camera = bpy.data.cameras.new(subset)
camera_obj = bpy.data.objects.new(subset, camera)
instances.objects.link(camera_obj)
camera_obj.select_set(True)
asset_group.select_set(True)
bpy.context.view_layer.objects.active = asset_group

View file

@ -7,7 +7,7 @@ import contextlib
import hou # noqa
from openpype.host import HostBase, IWorkfileHost, ILoadHost, INewPublisher
from openpype.host import HostBase, IWorkfileHost, ILoadHost, IPublishHost
import pyblish.api
@ -40,7 +40,7 @@ CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher):
class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
name = "houdini"
def __init__(self):

View file

@ -3441,3 +3441,8 @@ def iter_visible_nodes_in_range(nodes, start, end):
# If no more nodes to process break the frame iterations..
if not node_dependencies:
break
def get_attribute_input(attr):
connections = cmds.listConnections(attr, plugs=True, destination=False)
return connections[0] if connections else None

View file

@ -95,21 +95,25 @@ class RenderSettings(object):
if renderer == "redshift":
self._set_redshift_settings(width, height)
mel.eval("redshiftUpdateActiveAovList")
def _set_arnold_settings(self, width, height):
"""Sets settings for Arnold."""
from mtoa.core import createOptions # noqa
from mtoa.aovs import AOVInterface # noqa
createOptions()
arnold_render_presets = self._project_settings["maya"]["RenderSettings"]["arnold_renderer"] # noqa
render_settings = self._project_settings["maya"]["RenderSettings"]
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.
# This is a work around because the standard
# function to revert render settings does not reset AOVs list in MtoA
# Fetch current aovs in case there's any.
current_aovs = AOVInterface().getAOVs()
remove_aovs = render_settings["remove_aovs"]
if remove_aovs:
# Remove fetched AOVs
AOVInterface().removeAOVs(current_aovs)
AOVInterface().removeAOVs(current_aovs)
mel.eval("unifiedRenderGlobalsRevertToDefault")
img_ext = arnold_render_presets["image_format"]
img_prefix = arnold_render_presets["image_prefix"]
@ -118,6 +122,8 @@ class RenderSettings(object):
multi_exr = arnold_render_presets["multilayer_exr"]
additional_options = arnold_render_presets["additional_options"]
for aov in aovs:
if aov in current_aovs and not remove_aovs:
continue
AOVInterface('defaultArnoldRenderOptions').addAOV(aov)
cmds.setAttr("defaultResolution.width", width)
@ -141,12 +147,50 @@ class RenderSettings(object):
def _set_redshift_settings(self, width, height):
"""Sets settings for Redshift."""
redshift_render_presets = (
self._project_settings
["maya"]
["RenderSettings"]
["redshift_renderer"]
)
render_settings = self._project_settings["maya"]["RenderSettings"]
redshift_render_presets = render_settings["redshift_renderer"]
remove_aovs = render_settings["remove_aovs"]
all_rs_aovs = cmds.ls(type='RedshiftAOV')
if remove_aovs:
for aov in all_rs_aovs:
enabled = cmds.getAttr("{}.enabled".format(aov))
if enabled:
cmds.delete(aov)
redshift_aovs = redshift_render_presets["aov_list"]
# list all the aovs
all_rs_aovs = cmds.ls(type='RedshiftAOV')
for rs_aov in redshift_aovs:
rs_layername = rs_aov
if " " in rs_aov:
rs_renderlayer = rs_aov.replace(" ", "")
rs_layername = "rsAov_{}".format(rs_renderlayer)
else:
rs_layername = "rsAov_{}".format(rs_aov)
if rs_layername in all_rs_aovs:
continue
cmds.rsCreateAov(type=rs_aov)
# update the AOV list
mel.eval("redshiftUpdateActiveAovList")
rs_p_engine = redshift_render_presets["primary_gi_engine"]
rs_s_engine = redshift_render_presets["secondary_gi_engine"]
if int(rs_p_engine) or int(rs_s_engine) != 0:
cmds.setAttr("redshiftOptions.GIEnabled", 1)
if int(rs_p_engine) == 0:
# reset the primary GI Engine as default
cmds.setAttr("redshiftOptions.primaryGIEngine", 4)
if int(rs_s_engine) == 0:
# reset the secondary GI Engine as default
cmds.setAttr("redshiftOptions.secondaryGIEngine", 2)
else:
cmds.setAttr("redshiftOptions.GIEnabled", 0)
cmds.setAttr("redshiftOptions.primaryGIEngine", int(rs_p_engine))
cmds.setAttr("redshiftOptions.secondaryGIEngine", int(rs_s_engine))
additional_options = redshift_render_presets["additional_options"]
ext = redshift_render_presets["image_format"]
img_exts = ["iff", "exr", "tif", "png", "tga", "jpg"]
@ -163,12 +207,31 @@ class RenderSettings(object):
"""Sets important settings for Vray."""
settings = cmds.ls(type="VRaySettingsNode")
node = settings[0] if settings else cmds.createNode("VRaySettingsNode")
vray_render_presets = (
self._project_settings
["maya"]
["RenderSettings"]
["vray_renderer"]
)
render_settings = self._project_settings["maya"]["RenderSettings"]
vray_render_presets = render_settings["vray_renderer"]
# vrayRenderElement
remove_aovs = render_settings["remove_aovs"]
all_vray_aovs = cmds.ls(type='VRayRenderElement')
lightSelect_aovs = cmds.ls(type='VRayRenderElementSet')
if remove_aovs:
for aov in all_vray_aovs:
# remove all aovs except LightSelect
enabled = cmds.getAttr("{}.enabled".format(aov))
if enabled:
cmds.delete(aov)
# remove LightSelect
for light_aovs in lightSelect_aovs:
light_enabled = cmds.getAttr("{}.enabled".format(light_aovs))
if light_enabled:
cmds.delete(lightSelect_aovs)
vray_aovs = vray_render_presets["aov_list"]
for renderlayer in vray_aovs:
renderElement = "vrayAddRenderElement {}".format(renderlayer)
RE_name = mel.eval(renderElement)
# if there is more than one same render element
if RE_name.endswith("1"):
cmds.delete(RE_name)
# Set aov separator
# First we need to explicitly set the UI items in Render Settings
# because that is also what V-Ray updates to when that Render Settings

View file

@ -217,7 +217,7 @@ class ReferenceLoader(Loader):
# Need to save alembic settings and reapply, cause referencing resets
# them to incoming data.
alembic_attrs = ["speed", "offset", "cycleType"]
alembic_attrs = ["speed", "offset", "cycleType", "time"]
alembic_data = {}
if representation["name"] == "abc":
alembic_nodes = cmds.ls(
@ -226,7 +226,12 @@ class ReferenceLoader(Loader):
if alembic_nodes:
for attr in alembic_attrs:
node_attr = "{}.{}".format(alembic_nodes[0], attr)
alembic_data[attr] = cmds.getAttr(node_attr)
data = {
"input": lib.get_attribute_input(node_attr),
"value": cmds.getAttr(node_attr)
}
alembic_data[attr] = data
else:
self.log.debug("No alembic nodes found in {}".format(members))
@ -263,8 +268,19 @@ class ReferenceLoader(Loader):
"{}:*".format(namespace), type="AlembicNode"
)
if alembic_nodes:
for attr, value in alembic_data.items():
cmds.setAttr("{}.{}".format(alembic_nodes[0], attr), value)
alembic_node = alembic_nodes[0] # assume single AlembicNode
for attr, data in alembic_data.items():
node_attr = "{}.{}".format(alembic_node, attr)
input = lib.get_attribute_input(node_attr)
if data["input"]:
if data["input"] != input:
cmds.connectAttr(
data["input"], node_attr, force=True
)
else:
if input:
cmds.disconnectAttr(input, node_attr)
cmds.setAttr(node_attr, data["value"])
# Fix PLN-40 for older containers created with Avalon that had the
# `.verticesOnlySet` set to True.

View file

@ -105,6 +105,11 @@ class ExtractThumbnail(publish.Extractor):
pm.currentTime(refreshFrameInt - 1, edit=True)
pm.currentTime(refreshFrameInt, edit=True)
# Override transparency if requested.
transparency = instance.data.get("transparency", 0)
if transparency != 0:
preset["viewport2_options"]["transparencyAlgorithm"] = transparency
# Isolate view is requested by having objects in the set besides a
# camera.
if preset.pop("isolate_view", False) and instance.data.get("isolate"):

View file

@ -2,6 +2,7 @@
import os
import logging
from typing import List
import semver
import pyblish.api
@ -21,6 +22,9 @@ import unreal # noqa
logger = logging.getLogger("openpype.hosts.unreal")
OPENPYPE_CONTAINERS = "OpenPypeContainers"
UNREAL_VERSION = semver.VersionInfo(
*os.getenv("OPENPYPE_UNREAL_VERSION").split(".")
)
HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.unreal.__file__))
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
@ -111,7 +115,9 @@ def ls():
"""
ar = unreal.AssetRegistryHelpers.get_asset_registry()
openpype_containers = ar.get_assets_by_class("AssetContainer", True)
# UE 5.1 changed how class name is specified
class_name = ["/Script/OpenPype", "AssetContainer"] if UNREAL_VERSION.major == 5 and UNREAL_VERSION.minor > 0 else "AssetContainer" # noqa
openpype_containers = ar.get_assets_by_class(class_name, True)
# get_asset_by_class returns AssetData. To get all metadata we need to
# load asset. get_tag_values() work only on metadata registered in

View file

@ -150,6 +150,7 @@ class UnrealPrelaunchHook(PreLaunchHook):
engine_path=Path(engine_path)
)
self.launch_context.env["OPENPYPE_UNREAL_VERSION"] = engine_version
# Append project file to launch arguments
self.launch_context.launch_args.append(
f"\"{project_file.as_posix()}\"")

View file

@ -6,7 +6,11 @@ public class OpenPype : ModuleRules
{
public OpenPype(ReadOnlyTargetRules Target) : base(Target)
{
DefaultBuildSettings = BuildSettingsVersion.V2;
bLegacyPublicIncludePaths = false;
ShadowVariableWarningLevel = WarningLevel.Error;
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_0;
PublicIncludePaths.AddRange(
new string[] {

View file

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AssetContainer.h"
#include "AssetRegistryModule.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Misc/PackageName.h"
#include "Engine.h"
#include "Containers/UnrealString.h"
@ -30,8 +30,8 @@ void UAssetContainer::OnAssetAdded(const FAssetData& AssetData)
// get asset path and class
FString assetPath = AssetData.GetFullName();
FString assetFName = AssetData.AssetClass.ToString();
FString assetFName = AssetData.AssetClassPath.ToString();
UE_LOG(LogTemp, Log, TEXT("asset name %s"), *assetFName);
// split path
assetPath.ParseIntoArray(split, TEXT(" "), true);
@ -60,7 +60,7 @@ void UAssetContainer::OnAssetRemoved(const FAssetData& AssetData)
// get asset path and class
FString assetPath = AssetData.GetFullName();
FString assetFName = AssetData.AssetClass.ToString();
FString assetFName = AssetData.AssetClassPath.ToString();
// split path
assetPath.ParseIntoArray(split, TEXT(" "), true);
@ -93,7 +93,7 @@ void UAssetContainer::OnAssetRenamed(const FAssetData& AssetData, const FString&
// get asset path and class
FString assetPath = AssetData.GetFullName();
FString assetFName = AssetData.AssetClass.ToString();
FString assetFName = AssetData.AssetClassPath.ToString();
// split path
assetPath.ParseIntoArray(split, TEXT(" "), true);

View file

@ -1,11 +1,13 @@
#pragma once
#include "OpenPypePublishInstance.h"
#include "AssetRegistryModule.h"
#include "NotificationManager.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetToolsModule.h"
#include "Framework/Notifications/NotificationManager.h"
#include "OpenPypeLib.h"
#include "OpenPypeSettings.h"
#include "SNotificationList.h"
#include "Widgets/Notifications/SNotificationList.h"
//Moves all the invalid pointers to the end to prepare them for the shrinking
#define REMOVE_INVALID_ENTRIES(VAR) VAR.CompactStable(); \
@ -53,7 +55,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData)
if (!IsValid(Asset))
{
UE_LOG(LogAssetData, Warning, TEXT("Asset \"%s\" is not valid! Skipping the addition."),
*InAssetData.ObjectPath.ToString());
*InAssetData.GetObjectPathString());
return;
}

View file

@ -5,7 +5,7 @@
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Engine/AssetUserData.h"
#include "AssetData.h"
#include "AssetRegistry/AssetData.h"
#include "AssetContainer.generated.h"
/**

View file

@ -50,7 +50,10 @@ def get_engine_versions(env=None):
# environment variable not set
pass
except OSError:
# specified directory doesn't exists
# specified directory doesn't exist
pass
except StopIteration:
# specified directory doesn't exist
pass
# if we've got something, terminate auto-detection process

View file

@ -3,6 +3,8 @@
import ast
import unreal # noqa
import pyblish.api
from openpype.hosts.unreal.api.pipeline import UNREAL_VERSION
from openpype.pipeline.publish import KnownPublishError
class CollectInstances(pyblish.api.ContextPlugin):
@ -23,8 +25,10 @@ class CollectInstances(pyblish.api.ContextPlugin):
def process(self, context):
ar = unreal.AssetRegistryHelpers.get_asset_registry()
instance_containers = ar.get_assets_by_class(
"OpenPypePublishInstance", True)
class_name = ["/Script/OpenPype",
"AssetContainer"] if UNREAL_VERSION.major == 5 and \
UNREAL_VERSION.minor > 0 else "OpenPypePublishInstance" # noqa
instance_containers = ar.get_assets_by_class(class_name, True)
for container_data in instance_containers:
asset = container_data.get_asset()
@ -32,9 +36,8 @@ class CollectInstances(pyblish.api.ContextPlugin):
data["objectName"] = container_data.asset_name
# convert to strings
data = {str(key): str(value) for (key, value) in data.items()}
assert data.get("family"), (
"instance has no family"
)
if not data.get("family"):
raise KnownPublishError("instance has no family")
# content of container
members = ast.literal_eval(data.get("members"))

View file

@ -126,22 +126,16 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"harmony": [r".*"], # for everything from AE
"celaction": [r".*"]}
enviro_filter = [
environ_job_filter = [
"OPENPYPE_METADATA_FILE"
]
environ_keys = [
"FTRACK_API_USER",
"FTRACK_API_KEY",
"FTRACK_SERVER",
"OPENPYPE_METADATA_FILE",
"AVALON_PROJECT",
"AVALON_ASSET",
"AVALON_TASK",
"AVALON_APP_NAME",
"OPENPYPE_PUBLISH_JOB"
"OPENPYPE_LOG_NO_COLORS",
"OPENPYPE_USERNAME",
"OPENPYPE_RENDER_JOB",
"OPENPYPE_PUBLISH_JOB",
"OPENPYPE_MONGO",
"OPENPYPE_VERSION"
]
@ -223,29 +217,42 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
instance_version = instance.data.get("version") # take this if exists
if instance_version != 1:
override_version = instance_version
output_dir = self._get_publish_folder(instance.context.data['anatomy'],
deepcopy(
instance.data["anatomyData"]),
instance.data.get("asset"),
instances[0]["subset"],
'render',
override_version)
output_dir = self._get_publish_folder(
instance.context.data['anatomy'],
deepcopy(instance.data["anatomyData"]),
instance.data.get("asset"),
instances[0]["subset"],
'render',
override_version
)
# Transfer the environment from the original job to this dependent
# job so they use the same environment
metadata_path, roothless_metadata_path = \
self._create_metadata_path(instance)
environment = job["Props"].get("Env", {})
environment["AVALON_PROJECT"] = legacy_io.Session["AVALON_PROJECT"]
environment["AVALON_ASSET"] = legacy_io.Session["AVALON_ASSET"]
environment["AVALON_TASK"] = legacy_io.Session["AVALON_TASK"]
environment["AVALON_APP_NAME"] = os.environ.get("AVALON_APP_NAME")
environment["OPENPYPE_VERSION"] = os.environ.get("OPENPYPE_VERSION")
environment["OPENPYPE_LOG_NO_COLORS"] = "1"
environment["OPENPYPE_USERNAME"] = instance.context.data["user"]
environment["OPENPYPE_PUBLISH_JOB"] = "1"
environment["OPENPYPE_RENDER_JOB"] = "0"
environment = {
"AVALON_PROJECT": legacy_io.Session["AVALON_PROJECT"],
"AVALON_ASSET": legacy_io.Session["AVALON_ASSET"],
"AVALON_TASK": legacy_io.Session["AVALON_TASK"],
"OPENPYPE_USERNAME": instance.context.data["user"],
"OPENPYPE_PUBLISH_JOB": "1",
"OPENPYPE_RENDER_JOB": "0",
"OPENPYPE_REMOTE_JOB": "0",
"OPENPYPE_LOG_NO_COLORS": "1"
}
# add environments from self.environ_keys
for env_key in self.environ_keys:
if os.getenv(env_key):
environment[env_key] = os.environ[env_key]
# pass environment keys from self.environ_job_filter
job_environ = job["Props"].get("Env", {})
for env_j_key in self.environ_job_filter:
if job_environ.get(env_j_key):
environment[env_j_key] = job_environ[env_j_key]
# Add mongo url if it's enabled
if instance.context.data.get("deadlinePassMongoUrl"):
mongo_url = os.environ.get("OPENPYPE_MONGO")
@ -309,19 +316,15 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
if instance.data.get("suspend_publish"):
payload["JobInfo"]["InitialStatus"] = "Suspended"
index = 0
for key in environment:
if key.upper() in self.enviro_filter:
payload["JobInfo"].update(
{
"EnvironmentKeyValue%d"
% index: "{key}={value}".format(
key=key, value=environment[key]
)
}
)
index += 1
for index, (key_, value_) in enumerate(environment.items()):
payload["JobInfo"].update(
{
"EnvironmentKeyValue%d"
% index: "{key}={value}".format(
key=key_, value=value_
)
}
)
# remove secondary pool
payload["JobInfo"].pop("SecondaryPool", None)

View file

@ -1,5 +1,4 @@
import os
import re
import json
import copy
import tempfile
@ -21,6 +20,7 @@ from openpype.lib import (
CREATE_NO_WINDOW
)
from openpype.lib.profiles_filtering import filter_profiles
class ExtractBurnin(publish.Extractor):
@ -34,6 +34,7 @@ class ExtractBurnin(publish.Extractor):
label = "Extract burnins"
order = pyblish.api.ExtractorOrder + 0.03
families = ["review", "burnin"]
hosts = [
"nuke",
@ -53,6 +54,7 @@ class ExtractBurnin(publish.Extractor):
"flame"
# "resolve"
]
optional = True
positions = [
@ -69,11 +71,15 @@ class ExtractBurnin(publish.Extractor):
"y_offset": 5
}
# Preset attributes
# Configurable by Settings
profiles = None
options = None
def process(self, instance):
if not self.profiles:
self.log.warning("No profiles present for create burnin")
return
# QUESTION what is this for and should we raise an exception?
if "representations" not in instance.data:
raise RuntimeError("Burnin needs already created mov to work on.")
@ -137,18 +143,29 @@ class ExtractBurnin(publish.Extractor):
return filtered_repres
def main_process(self, instance):
# TODO get these data from context
host_name = instance.context.data["hostName"]
task_name = os.environ["AVALON_TASK"]
family = self.main_family_from_instance(instance)
family = instance.data["family"]
task_data = instance.data["anatomyData"].get("task", {})
task_name = task_data.get("name")
task_type = task_data.get("type")
subset = instance.data["subset"]
filtering_criteria = {
"hosts": host_name,
"families": family,
"task_names": task_name,
"task_types": task_type,
"subset": subset
}
profile = filter_profiles(self.profiles, filtering_criteria,
logger=self.log)
# Find profile most matching current host, task and instance family
profile = self.find_matching_profile(host_name, task_name, family)
if not profile:
self.log.info((
"Skipped instance. None of profiles in presets are for"
" Host: \"{}\" | Family: \"{}\" | Task \"{}\""
).format(host_name, family, task_name))
" Host: \"{}\" | Families: \"{}\" | Task \"{}\""
" | Task type \"{}\" | Subset \"{}\" "
).format(host_name, family, task_name, task_type, subset))
return
self.log.debug("profile: {}".format(profile))
@ -158,7 +175,8 @@ class ExtractBurnin(publish.Extractor):
if not burnin_defs:
self.log.info((
"Skipped instance. Burnin definitions are not set for profile"
" Host: \"{}\" | Family: \"{}\" | Task \"{}\" | Profile \"{}\""
" Host: \"{}\" | Families: \"{}\" | Task \"{}\""
" | Profile \"{}\""
).format(host_name, family, task_name, profile))
return
@ -693,130 +711,6 @@ class ExtractBurnin(publish.Extractor):
)
})
def find_matching_profile(self, host_name, task_name, family):
""" Filter profiles by Host name, Task name and main Family.
Filtering keys are "hosts" (list), "tasks" (list), "families" (list).
If key is not find or is empty than it's expected to match.
Args:
profiles (list): Profiles definition from presets.
host_name (str): Current running host name.
task_name (str): Current context task name.
family (str): Main family of current Instance.
Returns:
dict/None: Return most matching profile or None if none of profiles
match at least one criteria.
"""
matching_profiles = None
highest_points = -1
for profile in self.profiles or tuple():
profile_points = 0
profile_value = []
# Host filtering
host_names = profile.get("hosts")
match = self.validate_value_by_regexes(host_name, host_names)
if match == -1:
continue
profile_points += match
profile_value.append(bool(match))
# Task filtering
task_names = profile.get("tasks")
match = self.validate_value_by_regexes(task_name, task_names)
if match == -1:
continue
profile_points += match
profile_value.append(bool(match))
# Family filtering
families = profile.get("families")
match = self.validate_value_by_regexes(family, families)
if match == -1:
continue
profile_points += match
profile_value.append(bool(match))
if profile_points > highest_points:
matching_profiles = []
highest_points = profile_points
if profile_points == highest_points:
profile["__value__"] = profile_value
matching_profiles.append(profile)
if not matching_profiles:
return
if len(matching_profiles) == 1:
return matching_profiles[0]
return self.profile_exclusion(matching_profiles)
def profile_exclusion(self, matching_profiles):
"""Find out most matching profile by host, task and family match.
Profiles are selectivelly filtered. Each profile should have
"__value__" key with list of booleans. Each boolean represents
existence of filter for specific key (host, taks, family).
Profiles are looped in sequence. In each sequence are split into
true_list and false_list. For next sequence loop are used profiles in
true_list if there are any profiles else false_list is used.
Filtering ends when only one profile left in true_list. Or when all
existence booleans loops passed, in that case first profile from left
profiles is returned.
Args:
matching_profiles (list): Profiles with same values.
Returns:
dict: Most matching profile.
"""
self.log.info(
"Search for first most matching profile in match order:"
" Host name -> Task name -> Family."
)
# Filter all profiles with highest points value. First filter profiles
# with matching host if there are any then filter profiles by task
# name if there are any and lastly filter by family. Else use first in
# list.
idx = 0
final_profile = None
while True:
profiles_true = []
profiles_false = []
for profile in matching_profiles:
value = profile["__value__"]
# Just use first profile when idx is greater than values.
if not idx < len(value):
final_profile = profile
break
if value[idx]:
profiles_true.append(profile)
else:
profiles_false.append(profile)
if final_profile is not None:
break
if profiles_true:
matching_profiles = profiles_true
else:
matching_profiles = profiles_false
if len(matching_profiles) == 1:
final_profile = matching_profiles[0]
break
idx += 1
final_profile.pop("__value__")
return final_profile
def filter_burnins_defs(self, profile, instance):
"""Filter outputs by their values from settings.
@ -909,56 +803,6 @@ class ExtractBurnin(publish.Extractor):
return True
return False
def compile_list_of_regexes(self, in_list):
"""Convert strings in entered list to compiled regex objects."""
regexes = []
if not in_list:
return regexes
for item in in_list:
if not item:
continue
try:
regexes.append(re.compile(item))
except TypeError:
self.log.warning((
"Invalid type \"{}\" value \"{}\"."
" Expected string based object. Skipping."
).format(str(type(item)), str(item)))
return regexes
def validate_value_by_regexes(self, value, in_list):
"""Validate in any regexe from list match entered value.
Args:
in_list (list): List with regexes.
value (str): String where regexes is checked.
Returns:
int: Returns `0` when list is not set or is empty. Returns `1` when
any regex match value and returns `-1` when none of regexes
match value entered.
"""
if not in_list:
return 0
output = -1
regexes = self.compile_list_of_regexes(in_list)
for regex in regexes:
if re.match(regex, value):
output = 1
break
return output
def main_family_from_instance(self, instance):
"""Return main family of entered instance."""
family = instance.data.get("family")
if not family:
family = instance.data["families"][0]
return family
def families_from_instance(self, instance):
"""Return all families of entered instance."""
families = []

View file

@ -209,6 +209,9 @@
{
"families": [],
"hosts": [],
"task_types": [],
"task_names": [],
"subsets": [],
"burnins": {
"burnin": {
"TOP_LEFT": "{yy}-{mm}-{dd}",

View file

@ -59,6 +59,7 @@
"default_render_image_folder": "renders/maya",
"enable_all_lights": true,
"aov_separator": "underscore",
"remove_aovs": false,
"reset_current_frame": false,
"arnold_renderer": {
"image_prefix": "<Scene>/<RenderLayer>/<RenderLayer>_<RenderPass>",

View file

@ -526,11 +526,28 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"label": "Host names",
"type": "hosts-enum",
"multiselection": true
},
{
"key": "task_types",
"label": "Task types",
"type": "task-types-enum"
},
{
"key": "task_names",
"label": "Task names",
"type": "list",
"object_type": "text"
},
{
"key": "subsets",
"label": "Subset names",
"type": "list",
"object_type": "text"
},
{
"type": "splitter"
},

View file

@ -31,6 +31,11 @@
{"dot": ". (dot)"}
]
},
{
"key": "remove_aovs",
"label": "Remove existing AOVs",
"type": "boolean"
},
{
"key": "reset_current_frame",
"label": "Reset Current Frame",
@ -204,74 +209,76 @@
"defaults": "empty",
"enum_items": [
{"empty": "< empty >"},
{"atmosphereChannel": "atmosphere"},
{"backgroundChannel": "background"},
{"bumpNormalsChannel": "bumpnormals"},
{"causticsChannel": "caustics"},
{"coatFilterChannel": "coat_filter"},
{"coatGlossinessChannel": "coatGloss"},
{"coatReflectionChannel": "coat_reflection"},
{"vrayCoatChannel": "coat_specular"},
{"CoverageChannel": "coverage"},
{"cryptomatteChannel": "cryptomatte"},
{"customColor": "custom_color"},
{"drBucketChannel": "DR"},
{"denoiserChannel": "denoiser"},
{"diffuseChannel": "diffuse"},
{"ExtraTexElement": "extraTex"},
{"giChannel": "GI"},
{"LightMixElement": "None"},
{"lightingChannel": "lighting"},
{"LightingAnalysisChannel": "LightingAnalysis"},
{"materialIDChannel": "materialID"},
{"MaterialSelectElement": "materialSelect"},
{"matteShadowChannel": "matteShadow"},
{"MultiMatteElement": "multimatte"},
{"multimatteIDChannel": "multimatteID"},
{"normalsChannel": "normals"},
{"nodeIDChannel": "objectId"},
{"objectSelectChannel": "objectSelect"},
{"rawCoatFilterChannel": "raw_coat_filter"},
{"rawCoatReflectionChannel": "raw_coat_reflection"},
{"rawDiffuseFilterChannel": "rawDiffuseFilter"},
{"rawGiChannel": "rawGI"},
{"rawLightChannel": "rawLight"},
{"rawReflectionChannel": "rawReflection"},
{"rawReflectionFilterChannel": "rawReflectionFilter"},
{"rawRefractionChannel": "rawRefraction"},
{"rawRefractionFilterChannel": "rawRefractionFilter"},
{"rawShadowChannel": "rawShadow"},
{"rawSheenFilterChannel": "raw_sheen_filter"},
{"rawSheenReflectionChannel": "raw_sheen_reflection"},
{"rawTotalLightChannel": "rawTotalLight"},
{"reflectIORChannel": "reflIOR"},
{"reflectChannel": "reflect"},
{"reflectionFilterChannel": "reflectionFilter"},
{"reflectGlossinessChannel": "reflGloss"},
{"refractChannel": "refract"},
{"refractionFilterChannel": "refractionFilter"},
{"refractGlossinessChannel": "refrGloss"},
{"renderIDChannel": "renderId"},
{"FastSSS2Channel": "SSS"},
{"sampleRateChannel": "sampleRate"},
{"atmosphereChannel": "atmosphereChannel"},
{"backgroundChannel": "backgroundChannel"},
{"bumpNormalsChannel": "bumpNormalsChannel"},
{"causticsChannel": "causticsChannel"},
{"coatFilterChannel": "coatFilterChannel"},
{"coatGlossinessChannel": "coatGlossinessChannel"},
{"coatReflectionChannel": "coatReflectionChannel"},
{"vrayCoatChannel": "vrayCoatChannel"},
{"CoverageChannel": "CoverageChannel"},
{"cryptomatteChannel": "cryptomatteChannel"},
{"customColor": "customColor"},
{"drBucketChannel": "drBucketChannel"},
{"denoiserChannel": "denoiserChannel"},
{"diffuseChannel": "diffuseChannel"},
{"ExtraTexElement": "ExtraTexElement"},
{"giChannel": "giChannel"},
{"LightMixElement": "LightMixElement"},
{"LightSelectElement": "LightSelectElement"},
{"lightingChannel": "lightingChannel"},
{"LightingAnalysisChannel": "LightingAnalysisChannel"},
{"materialIDChannel": "materialIDChannel"},
{"MaterialSelectElement": "MaterialSelectElement"},
{"matteShadowChannel": "matteShadowChannel"},
{"metalnessChannel": "metalnessChannel"},
{"MultiMatteElement": "MultiMatteElement"},
{"multimatteIDChannel": "multimatteIDChannel"},
{"noiseLevelChannel": "noiseLevelChannel"},
{"normalsChannel": "normalsChannel"},
{"nodeIDChannel": "nodeIDChannel"},
{"objectSelectChannel": "objectSelectChannel"},
{"rawCoatFilterChannel": "rawCoatFilterChannel"},
{"rawCoatReflectionChannel": "rawCoatReflectionChannel"},
{"rawDiffuseFilterChannel": "rawDiffuseFilterChannel"},
{"rawGiChannel": "rawGiChannel"},
{"rawLightChannel": "rawLightChannel"},
{"rawReflectionChannel": "rawReflectionChannel"},
{"rawReflectionFilterChannel": "rawReflectionFilterChannel"},
{"rawRefractionChannel": "rawRefractionChannel"},
{"rawRefractionFilterChannel": "rawRefractionFilterChannel"},
{"rawShadowChannel": "rawShadowChannel"},
{"rawSheenFilterChannel": "rawSheenFilterChannel"},
{"rawSheenReflectionChannel": "rawSheenReflectionChannel"},
{"rawTotalLightChannel": "rawTotalLightChannel"},
{"reflectIORChannel": "reflectIORChannel"},
{"reflectChannel": "reflectChannel"},
{"reflectionFilterChannel": "reflectionFilterChannel"},
{"reflectGlossinessChannel": "reflectGlossinessChannel"},
{"refractChannel": "refractChannel"},
{"refractionFilterChannel": "refractionFilterChannel"},
{"refractGlossinessChannel": "refractGlossinessChannel"},
{"renderIDChannel": "renderIDChannel"},
{"FastSSS2Channel": "FastSSS2Channel"},
{"sampleRateChannel": "sampleRateChannel"},
{"samplerInfo": "samplerInfo"},
{"selfIllumChannel": "selfIllum"},
{"shadowChannel": "shadow"},
{"sheenFilterChannel": "sheen_filter"},
{"sheenGlossinessChannel": "sheenGloss"},
{"sheenReflectionChannel": "sheen_reflection"},
{"vraySheenChannel": "sheen_specular"},
{"specularChannel": "specular"},
{"selfIllumChannel": "selfIllumChannel"},
{"shadowChannel": "shadowChannel"},
{"sheenFilterChannel": "sheenFilterChannel"},
{"sheenGlossinessChannel": "sheenGlossinessChannel"},
{"sheenReflectionChannel": "sheenReflectionChannel"},
{"vraySheenChannel": "vraySheenChannel"},
{"specularChannel": "specularChannel"},
{"Toon": "Toon"},
{"toonLightingChannel": "toonLighting"},
{"toonSpecularChannel": "toonSpecular"},
{"totalLightChannel": "totalLight"},
{"unclampedColorChannel": "unclampedColor"},
{"VRScansPaintMaskChannel": "VRScansPaintMask"},
{"VRScansZoneMaskChannel": "VRScansZoneMask"},
{"velocityChannel": "velocity"},
{"zdepthChannel": "zDepth"},
{"LightSelectElement": "lightselect"}
{"toonLightingChannel": "toonLightingChannel"},
{"toonSpecularChannel": "toonSpecularChannel"},
{"totalLightChannel": "totalLightChannel"},
{"unclampedColorChannel": "unclampedColorChannel"},
{"VRScansPaintMaskChannel": "VRScansPaintMaskChannel"},
{"VRScansZoneMaskChannel": "VRScansZoneMaskChannel"},
{"velocityChannel": "velocityChannel"},
{"zdepthChannel": "zdepthChannel"}
]
},
{
@ -310,9 +317,8 @@
"defaults": "0",
"enum_items": [
{"0": "None"},
{"1": "Photon Map"},
{"2": "Irradiance Cache"},
{"3": "Brute Force"}
{"3": "Irradiance Cache"},
{"4": "Brute Force"}
]
},
{
@ -323,9 +329,8 @@
"defaults": "0",
"enum_items": [
{"0": "None"},
{"1": "Photon Map"},
{"2": "Irradiance Cache"},
{"3": "Brute Force"}
{"2": "Irradiance Point Cloud"},
{"4": "Brute Force"}
]
},
{
@ -361,46 +366,46 @@
"defaults": "empty",
"enum_items": [
{"empty": "< none >"},
{"AO": "Ambient Occlusion"},
{"Ambient Occlusion": "Ambient Occlusion"},
{"Background": "Background"},
{"Beauty": "Beauty"},
{"BumpNormals": "Bump Normals"},
{"Bump Normals": "Bump Normals"},
{"Caustics": "Caustics"},
{"CausticsRaw": "Caustics Raw"},
{"Caustics Raw": "Caustics Raw"},
{"Cryptomatte": "Cryptomatte"},
{"Custom": "Custom"},
{"Z": "Depth"},
{"DiffuseFilter": "Diffuse Filter"},
{"DiffuseLighting": "Diffuse Lighting"},
{"DiffuseLightingRaw": "Diffuse Lighting Raw"},
{"Depth": "Depth"},
{"Diffuse Filter": "Diffuse Filter"},
{"Diffuse Lighting": "Diffuse Lighting"},
{"Diffuse Lighting Raw": "Diffuse Lighting Raw"},
{"Emission": "Emission"},
{"GI": "Global Illumination"},
{"GIRaw": "Global Illumination Raw"},
{"Global Illumination": "Global Illumination"},
{"Global Illumination Raw": "Global Illumination Raw"},
{"Matte": "Matte"},
{"MotionVectors": "Ambient Occlusion"},
{"N": "Normals"},
{"ID": "ObjectID"},
{"ObjectBumpNormal": "Object-Space Bump Normals"},
{"ObjectPosition": "Object-Space Positions"},
{"PuzzleMatte": "Puzzle Matte"},
{"Motion Vectors": "Motion Vectors"},
{"Normals": "Normals"},
{"ObjectID": "ObjectID"},
{"Object-Space Bump Normals": "Object-Space Bump Normals"},
{"Object-Space Positions": "Object-Space Positions"},
{"Puzzle Matte": "Puzzle Matte"},
{"Reflections": "Reflections"},
{"ReflectionsFilter": "Reflections Filter"},
{"ReflectionsRaw": "Reflections Raw"},
{"Reflections Filter": "Reflections Filter"},
{"Reflections Raw": "Reflections Raw"},
{"Refractions": "Refractions"},
{"RefractionsFilter": "Refractions Filter"},
{"RefractionsRaw": "Refractions Filter"},
{"Refractions Filter": "Refractions Filter"},
{"Refractions Raw": "Refractions Filter"},
{"Shadows": "Shadows"},
{"SpecularLighting": "Specular Lighting"},
{"SSS": "Sub Surface Scatter"},
{"SSSRaw": "Sub Surface Scatter Raw"},
{"TotalDiffuseLightingRaw": "Total Diffuse Lighting Raw"},
{"TotalTransLightingRaw": "Total Translucency Filter"},
{"TransTint": "Translucency Filter"},
{"TransGIRaw": "Translucency Lighting Raw"},
{"VolumeFogEmission": "Volume Fog Emission"},
{"VolumeFogTint": "Volume Fog Tint"},
{"VolumeLighting": "Volume Lighting"},
{"P": "World Position"}
{"Sub Surface Scatter": "Sub Surface Scatter"},
{"Sub Surface Scatter Raw": "Sub Surface Scatter Raw"},
{"Total Diffuse Lighting Raw": "Total Diffuse Lighting Raw"},
{"Total Translucency Filter": "Total Translucency Filter"},
{"Translucency Filter": "Translucency Filter"},
{"Translucency Lighting Raw": "Translucency Lighting Raw"},
{"Volume Fog Emission": "Volume Fog Emission"},
{"Volume Fog Tint": "Volume Fog Tint"},
{"Volume Lighting": "Volume Lighting"},
{"World Position": "World Position"}
]
},
{

View file

@ -155,7 +155,7 @@ class DropEmpty(QtWidgets.QWidget):
extensions_label = " or ".join(allowed_items)
else:
last_item = allowed_items.pop(-1)
new_last_item = " or ".join(last_item, allowed_items.pop(-1))
new_last_item = " or ".join([last_item, allowed_items.pop(-1)])
allowed_items.append(new_last_item)
extensions_label = ", ".join(allowed_items)

View file

@ -1,5 +1,5 @@
import sys
from Qt import QtWidgets, QtGui
from qtpy import QtWidgets, QtGui
from openpype import style
from .lib import (

View file

@ -1,5 +1,5 @@
import platform
from Qt import QtWidgets
from qtpy import QtWidgets
from .widgets import (
Separator,
ExpandingWidget

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets
from qtpy import QtWidgets
from openpype.tools.utils import PlaceholderLineEdit

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets
from qtpy import QtWidgets
from openpype.tools.experimental_tools import (
ExperimentalTools,
LOCAL_EXPERIMENTAL_KEY

View file

@ -1,6 +1,6 @@
import getpass
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
from openpype.lib import is_admin_password_required
from openpype.widgets import PasswordDialog
from openpype.tools.utils import PlaceholderLineEdit

View file

@ -2,7 +2,7 @@ import os
import sys
import traceback
from Qt import QtWidgets
from qtpy import QtWidgets
from pymongo.errors import ServerSelectionTimeoutError
from openpype.lib import change_openpype_mongo_url

View file

@ -1,6 +1,6 @@
import platform
import copy
from Qt import QtWidgets, QtCore, QtGui
from qtpy import QtWidgets, QtCore, QtGui
from openpype.tools.settings.settings import ProjectListWidget
from openpype.tools.utils import PlaceholderLineEdit
from openpype.settings.constants import (

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
from openpype.tools.settings.settings.widgets import (
ExpandingWidget
)

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtGui
from qtpy import QtWidgets, QtGui
from openpype import style

View file

@ -5,7 +5,7 @@ import traceback
import functools
import datetime
from Qt import QtWidgets, QtGui, QtCore
from qtpy import QtWidgets, QtGui, QtCore
from openpype.settings.entities import ProjectSettings
from openpype.tools.settings import CHILD_OFFSET

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtGui, QtCore
from qtpy import QtWidgets, QtGui, QtCore
PREFIX_ROLE = QtCore.Qt.UserRole + 1
LAST_SEGMENT_ROLE = QtCore.Qt.UserRole + 2

View file

@ -2,7 +2,7 @@ import sys
import traceback
import contextlib
from enum import Enum
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
import qtawesome
from openpype.lib import get_openpype_version

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore, QtGui
from qtpy import QtWidgets, QtCore, QtGui
from .item_widgets import InputWidget

View file

@ -1,4 +1,4 @@
from Qt import QtCore
from qtpy import QtCore
DEFAULT_PROJECT_LABEL = "< Default >"

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
from openpype.tools.utils.delegates import pretty_date

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets
from qtpy import QtWidgets
from .widgets import (
ExpandingWidget,

View file

@ -1,6 +1,6 @@
from uuid import uuid4
from Qt import QtWidgets, QtCore, QtGui
from qtpy import QtWidgets, QtCore
from .base import BaseWidget
from .lib import (

View file

@ -1,5 +1,5 @@
import os
from Qt import QtGui
from qtpy import QtGui
def get_image_path(image_filename):

View file

@ -1,6 +1,6 @@
import json
from Qt import QtWidgets, QtCore, QtGui
from qtpy import QtWidgets, QtCore, QtGui
from openpype.widgets.sliders import NiceSlider
from openpype.tools.settings import CHILD_OFFSET

View file

@ -1,4 +1,4 @@
from Qt import QtCore
from qtpy import QtCore
from .widgets import SettingsToolBtn

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
from openpype.tools.settings import (
CHILD_OFFSET

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
from .widgets import (
GridLabelWidget,

View file

@ -1,4 +1,4 @@
from Qt import QtCore, QtGui, QtWidgets
from qtpy import QtCore, QtGui, QtWidgets
class ComboItemDelegate(QtWidgets.QStyledItemDelegate):

View file

@ -1,7 +1,7 @@
import re
import collections
from Qt import QtCore, QtWidgets, QtGui
from qtpy import QtCore, QtWidgets, QtGui
ENTITY_LABEL_ROLE = QtCore.Qt.UserRole + 1
ENTITY_PATH_ROLE = QtCore.Qt.UserRole + 2

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtCore
from qtpy import QtWidgets, QtCore
def indented_print(data, indent=0):

View file

@ -1,6 +1,6 @@
import copy
import uuid
from Qt import QtWidgets, QtCore, QtGui
from qtpy import QtWidgets, QtCore, QtGui
import qtawesome
from openpype.client import get_projects

View file

@ -1,4 +1,4 @@
from Qt import QtWidgets, QtGui, QtCore
from qtpy import QtWidgets, QtGui, QtCore
from openpype import style

View file

@ -1,5 +1,5 @@
from uuid import uuid4
from Qt import QtWidgets
from qtpy import QtWidgets
from .widgets import (
ExpandingWidget,

View file

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring Pype version."""
__version__ = "3.14.9-nightly.3"
__version__ = "3.14.9-nightly.4"

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -0,0 +1,38 @@
---
id: dev_deadline
title: Deadline integration
sidebar_label: Deadline integration
toc_max_heading_level: 4
---
Deadline is not host as usual, it is missing most of the host features, but it does have
its own set of publishing plugins.
## How to test OpenPype on Deadline
### Versions
Since 3.14 job submitted from OpenPype is bound to OpenPype version used to submit it. So
if you submit job with 3.14.8, Deadline will try to find that particular version and use it
for rendering. This is handled by `OPENPYPE_VERSION` variable on job - you can delete it from
there and then the version set in studio Settings will be used.
![Deadline Job Version](assets/deadline_job_version.png)
Deadline needs to bootstrap this version so it will try to look the closest compatible
build. So to use version 3.14.8 on Deadline it is enough to have build 3.14.0 or similar - important
are the first two version numbers - major and minor. If they match, the version
is considered compatible.
### Testing
So to test various changes you don't need to build again an again OpenPype and putting
it to directory where Deadline is looking for versions - this needs to be done only on
minor version change. That build will then be used to bootstrap whatever is set on the
job or in the studio Settings.
So you can either use zip version if it suits you, or better set your sources directory
so it will be find as a version - for example with symlink.
That way you can only modify `OPENPYPE_VERSION` variable on job to point it to version
you would like to test.

View file

@ -157,6 +157,7 @@ module.exports = {
"dev_host_implementation",
"dev_publishing"
]
}
},
"dev_deadline"
]
};