Merge branch '2.x/develop' into feature/239-resolve_tagging_for_publish

This commit is contained in:
Jakub Jezek 2020-07-13 10:57:57 +02:00
commit a26292bf87
No known key found for this signature in database
GPG key ID: C4B96E101D2A47F3
63 changed files with 294 additions and 221 deletions

View file

@ -1,5 +1,6 @@
import os
import traceback
import winreg
from avalon import api, io, lib
from pype.lib import PypeHook
from pype.api import Logger, Anatomy
@ -14,6 +15,12 @@ class PremierePrelaunch(PypeHook):
shell script.
"""
project_code = None
reg_string_value = [{
"path": r"Software\Adobe\CSXS.9",
"name": "PlayerDebugMode",
"type": winreg.REG_SZ,
"value": "1"
}]
def __init__(self, logger=None):
if not logger:
@ -55,6 +62,10 @@ class PremierePrelaunch(PypeHook):
# adding project code to env
env["AVALON_PROJECT_CODE"] = self.project_code
# add keys to registry
self.modify_registry()
# start avalon
try:
__import__("pype.hosts.premiere")
__import__("pyblish")
@ -69,6 +80,24 @@ class PremierePrelaunch(PypeHook):
return True
def modify_registry(self):
# adding key to registry
for key in self.reg_string_value:
winreg.CreateKey(winreg.HKEY_CURRENT_USER, key["path"])
rg_key = winreg.OpenKey(
key=winreg.HKEY_CURRENT_USER,
sub_key=key["path"],
reserved=0,
access=winreg.KEY_ALL_ACCESS)
winreg.SetValueEx(
rg_key,
key["name"],
0,
key["type"],
key["value"]
)
def get_anatomy_filled(self):
root_path = api.registered_root()
project_name = self._S["AVALON_PROJECT"]

View file

@ -11,7 +11,7 @@ import pyblish.util
from pype.api import Logger
import pype
import pype.celaction
from pype.hosts import celaction
log = Logger().get_logger("Celaction_cli_publisher")
@ -49,7 +49,7 @@ def cli():
# parser.add_argument("--programDir",
# help=("Directory with celaction program installation"))
pype.celaction.kwargs = parser.parse_args(sys.argv[1:]).__dict__
celaction.kwargs = parser.parse_args(sys.argv[1:]).__dict__
def _prepare_publish_environments():

View file

@ -536,6 +536,15 @@ class ExpectedFilesVray(AExpectedFiles):
prefix = "{}_<aov>".format(prefix)
return prefix
def _get_layer_data(self):
"""Override to get vray specific extension."""
layer_data = super(ExpectedFilesVray, self)._get_layer_data()
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
default_ext = "exr"
layer_data["defaultExt"] = default_ext
return layer_data
def get_files(self):
"""Get expected files.

View file

@ -18,7 +18,7 @@ def main(env):
# Register Host (and it's pyblish plugins)
host_name = env["AVALON_APP"]
# TODO not sure if use "pype." or "avalon." for host import
host_import_str = f"pype.{host_name}"
host_import_str = f"pype.hosts.{host_name}"
try:
host_module = importlib.import_module(host_import_str)

View file

@ -497,9 +497,8 @@ class DeleteAssetSubset(BaseAction):
for entity in entities:
ftrack_id = entity["id"]
ftrack_id_name_map[ftrack_id] = entity["name"]
if ftrack_id in ftrack_ids_to_delete:
continue
not_deleted_entities_id.append(ftrack_id)
if ftrack_id not in ftrack_ids_to_delete:
not_deleted_entities_id.append(ftrack_id)
mongo_proc_txt = "MongoProcessing: "
ftrack_proc_txt = "Ftrack processing: "
@ -534,25 +533,20 @@ class DeleteAssetSubset(BaseAction):
ftrack_proc_txt, ", ".join(ftrack_ids_to_delete)
))
joined_ids_to_delete = ", ".join(
["\"{}\"".format(id) for id in ftrack_ids_to_delete]
ftrack_ents_to_delete = (
self._filter_entities_to_delete(ftrack_ids_to_delete, session)
)
ftrack_ents_to_delete = self.session.query(
"select id, link from TypedContext where id in ({})".format(
joined_ids_to_delete
)
).all()
for entity in ftrack_ents_to_delete:
self.session.delete(entity)
session.delete(entity)
try:
self.session.commit()
session.commit()
except Exception:
ent_path = "/".join(
[ent["name"] for ent in entity["link"]]
)
msg = "Failed to delete entity"
report_messages[msg].append(ent_path)
self.session.rollback()
session.rollback()
self.log.warning(
"{} <{}>".format(msg, ent_path),
exc_info=True
@ -568,7 +562,7 @@ class DeleteAssetSubset(BaseAction):
for name in asset_names_to_delete
])
# Find assets of selected entities with names of checked subsets
assets = self.session.query((
assets = session.query((
"select id from Asset where"
" context_id in ({}) and name in ({})"
).format(joined_not_deleted, joined_asset_names)).all()
@ -578,20 +572,54 @@ class DeleteAssetSubset(BaseAction):
", ".join([asset["id"] for asset in assets])
))
for asset in assets:
self.session.delete(asset)
session.delete(asset)
try:
self.session.commit()
session.commit()
except Exception:
self.session.rollback()
session.rollback()
msg = "Failed to delete asset"
report_messages[msg].append(asset["id"])
self.log.warning(
"{} <{}>".format(asset["id"]),
"Asset: {} <{}>".format(asset["name"], asset["id"]),
exc_info=True
)
return self.report_handle(report_messages, project_name, event)
def _filter_entities_to_delete(self, ftrack_ids_to_delete, session):
"""Filter children entities to avoid CircularDependencyError."""
joined_ids_to_delete = ", ".join(
["\"{}\"".format(id) for id in ftrack_ids_to_delete]
)
to_delete_entities = session.query(
"select id, link from TypedContext where id in ({})".format(
joined_ids_to_delete
)
).all()
filtered = to_delete_entities[:]
while True:
changed = False
_filtered = filtered[:]
for entity in filtered:
entity_id = entity["id"]
for _entity in tuple(_filtered):
if entity_id == _entity["id"]:
continue
for _link in _entity["link"]:
if entity_id == _link["id"] and _entity in _filtered:
_filtered.remove(_entity)
changed = True
break
filtered = _filtered
if not changed:
break
return filtered
def report_handle(self, report_messages, project_name, event):
if not report_messages:
return {

View file

@ -1,13 +1,7 @@
import os
import sys
import logging
import subprocess
from operator import itemgetter
import ftrack_api
from pype.modules.ftrack.lib import BaseAction, statics_icon
from pype.api import Logger, config
log = Logger().get_logger(__name__)
class DJVViewAction(BaseAction):
@ -19,20 +13,18 @@ class DJVViewAction(BaseAction):
type = 'Application'
allowed_types = [
"cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg",
"mp4", "m4v", "mxf", "iff", "z", "ifl", "jpeg", "jpg", "jfif", "lut",
"1dl", "exr", "pic", "png", "ppm", "pnm", "pgm", "pbm", "rla", "rpf",
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img"
]
def __init__(self, session, plugins_presets):
'''Expects a ftrack_api.Session instance'''
super().__init__(session, plugins_presets)
self.djv_path = None
self.config_data = config.get_presets()['djv_view']['config']
self.set_djv_path()
if self.djv_path is None:
return
self.allowed_types = self.config_data.get(
'file_ext', ["img", "mov", "exr"]
)
self.djv_path = self.find_djv_path()
def preregister(self):
if self.djv_path is None:
@ -53,11 +45,10 @@ class DJVViewAction(BaseAction):
return True
return False
def set_djv_path(self):
for path in self.config_data.get("djv_paths", []):
def find_djv_path(self):
for path in (os.environ.get("DJV_PATH") or "").split(os.pathsep):
if os.path.exists(path):
self.djv_path = path
break
return path
def interface(self, session, entities, event):
if event['data'].get('values', {}):
@ -221,43 +212,3 @@ def register(session, plugins_presets={}):
"""Register hooks."""
DJVViewAction(session, plugins_presets).register()
def main(arguments=None):
'''Set up logging and register action.'''
if arguments is None:
arguments = []
import argparse
parser = argparse.ArgumentParser()
# Allow setting of logging level from arguments.
loggingLevels = {}
for level in (
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
logging.ERROR, logging.CRITICAL
):
loggingLevels[logging.getLevelName(level).lower()] = level
parser.add_argument(
'-v', '--verbosity',
help='Set the logging output verbosity.',
choices=loggingLevels.keys(),
default='info'
)
namespace = parser.parse_args(arguments)
# Set up basic logging
logging.basicConfig(level=loggingLevels[namespace.verbosity])
session = ftrack_api.Session()
register(session)
# Wait for events
logging.info(
'Registered actions and listening for events. Use Ctrl-C to abort.'
)
session.event_hub.wait()
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

View file

@ -1,16 +1,16 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib import parse
import os
import webbrowser
import functools
import pype
import inspect
from Qt import QtCore
from pype.api import resources
class LoginServerHandler(BaseHTTPRequestHandler):
'''Login server handler.'''
message_filepath = resources.get_resource("ftrack", "sign_in_message.html")
def __init__(self, login_callback, *args, **kw):
'''Initialise handler.'''
self.login_callback = login_callback
@ -28,23 +28,21 @@ class LoginServerHandler(BaseHTTPRequestHandler):
login_credentials = parse.parse_qs(query)
api_user = login_credentials['api_user'][0]
api_key = login_credentials['api_key'][0]
# get path to resources
path_items = os.path.dirname(
inspect.getfile(pype)
).split(os.path.sep)
del path_items[-1]
path_items.extend(['res', 'ftrack', 'sign_in_message.html'])
message_filepath = os.path.sep.join(path_items)
message_file = open(message_filepath, 'r')
sign_in_message = message_file.read()
message_file.close()
with open(self.message_filepath, "r") as message_file:
sign_in_message = message_file.read()
# formatting html code for python
replacement = [('{', '{{'), ('}', '}}'), ('{{}}', '{}')]
for r in (replacement):
sign_in_message = sign_in_message.replace(*r)
replacements = (
("{", "{{"),
("}", "}}"),
("{{}}", "{}")
)
for replacement in (replacements):
sign_in_message = sign_in_message.replace(*replacement)
message = sign_in_message.format(api_user)
else:
message = '<h1>Failed to sign in</h1>'
message = "<h1>Failed to sign in</h1>"
self.send_response(200)
self.end_headers()
@ -74,7 +72,6 @@ class LoginServerThread(QtCore.QThread):
def run(self):
'''Listen for events.'''
# self._server = BaseHTTPServer.HTTPServer(
self._server = HTTPServer(
('localhost', 0),
functools.partial(

View file

@ -2,6 +2,8 @@ from .rest_api import RestApiServer
from .base_class import RestApi, abort, route, register_statics
from .lib import RestMethods, CallbackResult
CLASS_DEFINIION = RestApiServer
def tray_init(tray_widget, main_widget):
return RestApiServer()

View file

@ -6,7 +6,7 @@ from socketserver import ThreadingMixIn
from http.server import HTTPServer
from .lib import RestApiFactory, Handler
from .base_class import route, register_statics
from pype.api import config, Logger
from pype.api import Logger
log = Logger().get_logger("RestApiServer")
@ -85,24 +85,22 @@ class RestApiServer:
Callback may return many types. For more information read docstring of
`_handle_callback_result` defined in handler.
"""
default_port = 8011
exclude_ports = []
def __init__(self):
self.qaction = None
self.failed_icon = None
self._is_running = False
try:
self.presets = config.get_presets()["services"]["rest_api"]
except Exception:
self.presets = {"default_port": 8011, "exclude_ports": []}
log.debug((
"There are not set presets for RestApiModule."
" Using defaults \"{}\""
).format(str(self.presets)))
port = self.find_port()
self.rest_api_thread = RestApiThread(self, port)
statics_dir = os.path.sep.join([os.environ["PYPE_MODULE_ROOT"], "res"])
statics_dir = os.path.join(
os.environ["PYPE_MODULE_ROOT"],
"pype",
"resources"
)
self.register_statics("/res", statics_dir)
os.environ["PYPE_STATICS_SERVER"] = "{}/res".format(
os.environ["PYPE_REST_API_URL"]
@ -126,8 +124,8 @@ class RestApiServer:
RestApiFactory.register_obj(obj)
def find_port(self):
start_port = self.presets["default_port"]
exclude_ports = self.presets["exclude_ports"]
start_port = self.default_port
exclude_ports = self.exclude_ports
found_port = None
# port check takes time so it's lowered to 100 ports
for port in range(start_port, start_port+100):

View file

@ -1,6 +1,8 @@
from .timers_manager import TimersManager
from .widget_user_idle import WidgetUserIdle
CLASS_DEFINIION = TimersManager
def tray_init(tray_widget, main_widget):
return TimersManager(tray_widget, main_widget)

View file

@ -22,12 +22,20 @@ class TimersManager(metaclass=Singleton):
If IdleManager is imported then is able to handle about stop timers
when user idles for a long time (set in presets).
"""
modules = []
is_running = False
last_task = None
# Presetable attributes
# - when timer will stop if idle manager is running (minutes)
full_time = 15
# - how many minutes before the timer is stopped will popup the message
message_time = 0.5
def __init__(self, tray_widget, main_widget):
self.log = Logger().get_logger(self.__class__.__name__)
self.modules = []
self.is_running = False
self.last_task = None
self.tray_widget = tray_widget
self.main_widget = main_widget
@ -37,20 +45,13 @@ class TimersManager(metaclass=Singleton):
def set_signal_times(self):
try:
timer_info = (
config.get_presets()
.get('services')
.get('timers_manager')
.get('timer')
)
full_time = int(float(timer_info['full_time'])*60)
message_time = int(float(timer_info['message_time'])*60)
full_time = int(self.full_time * 60)
message_time = int(self.message_time * 60)
self.time_show_message = full_time - message_time
self.time_stop_timer = full_time
return True
except Exception:
self.log.warning('Was not able to load presets for TimersManager')
return False
self.log.error("Couldn't set timer signals.", exc_info=True)
def add_module(self, module):
""" Adds module to context

View file

@ -1,5 +1,5 @@
import pyblish.api
import pype.celaction
from pype.hosts import celaction
class CollectCelactionCliKwargs(pyblish.api.Collector):
@ -9,7 +9,7 @@ class CollectCelactionCliKwargs(pyblish.api.Collector):
order = pyblish.api.Collector.order - 0.1
def process(self, context):
kwargs = pype.celaction.kwargs.copy()
kwargs = celaction.kwargs.copy()
self.log.info("Storing kwargs: %s" % kwargs)
context.set_data("kwargs", kwargs)

View file

@ -16,6 +16,7 @@ class CollectCelactionInstances(pyblish.api.ContextPlugin):
scene_file = os.path.basename(current_file)
version = context.data["version"]
asset_entity = context.data["assetEntity"]
project_entity = context.data["projectEntity"]
shared_instance_data = {
"asset": asset_entity["name"],
@ -24,8 +25,12 @@ class CollectCelactionInstances(pyblish.api.ContextPlugin):
"handleStart": asset_entity["data"]["handleStart"],
"handleEnd": asset_entity["data"]["handleEnd"],
"fps": asset_entity["data"]["fps"],
"resolutionWidth": asset_entity["data"]["resolutionWidth"],
"resolutionHeight": asset_entity["data"]["resolutionHeight"],
"resolutionWidth": asset_entity["data"].get(
"resolutionWidth",
project_entity["data"]["resolutionWidth"]),
"resolutionHeight": asset_entity["data"].get(
"resolutionHeight",
project_entity["data"]["resolutionHeight"]),
"pixelAspect": 1,
"step": 1,
"version": version

View file

@ -1,5 +1,6 @@
import os
import pyblish.api
import copy
class CollectRenderPath(pyblish.api.InstancePlugin):
@ -7,19 +8,21 @@ class CollectRenderPath(pyblish.api.InstancePlugin):
label = "Collect Render Path"
order = pyblish.api.CollectorOrder + 0.495
families = ["render.farm"]
def process(self, instance):
anatomy = instance.context.data["anatomy"]
current_file = instance.context.data["currentFile"]
work_dir = os.path.dirname(current_file)
anatomy_data = copy.deepcopy(instance.data["anatomyData"])
padding = anatomy.templates.get("frame_padding", 4)
render_dir = os.path.join(
work_dir, "render", "celaction"
)
render_path = os.path.join(
render_dir,
".".join([instance.data["subset"], f"%0{padding}d", "png"])
)
anatomy_data.update({
"frame": f"%0{padding}d",
"representation": "png"
})
anatomy_filled = anatomy.format(anatomy_data)
render_dir = anatomy_filled["render_tmp"]["folder"]
render_path = anatomy_filled["render_tmp"]["path"]
# create dir if it doesnt exists
os.makedirs(render_dir, exist_ok=True)

View file

@ -27,6 +27,12 @@ class ExtractCelactionDeadline(pyblish.api.InstancePlugin):
deadline_group = ""
deadline_chunk_size = 1
enviro_filter = [
"FTRACK_API_USER",
"FTRACK_API_KEY",
"FTRACK_SERVER"
]
def process(self, instance):
context = instance.context
@ -155,6 +161,19 @@ class ExtractCelactionDeadline(pyblish.api.InstancePlugin):
plugin = payload["JobInfo"]["Plugin"]
self.log.info("using render plugin : {}".format(plugin))
i = 0
for key, values in dict(os.environ).items():
if key.upper() in self.enviro_filter:
payload["JobInfo"].update(
{
"EnvironmentKeyValue%d"
% i: "{key}={value}".format(
key=key, value=values
)
}
)
i += 1
self.log.info("Submitting..")
self.log.info(json.dumps(payload, indent=4, sort_keys=True))

View file

@ -1,34 +1,27 @@
import os
import subprocess
import json
from pype.api import config
from avalon import api
def get_families():
families = []
paths = config.get_presets().get("djv_view", {}).get("config", {}).get(
"djv_paths", []
)
for path in paths:
def existing_djv_path():
djv_paths = os.environ.get("DJV_PATH") or ""
for path in djv_paths.split(os.pathsep):
if os.path.exists(path):
families.append("*")
break
return families
def get_representation():
return config.get_presets().get("djv_view", {}).get("config", {}).get(
'file_ext', []
)
return path
return None
class OpenInDJV(api.Loader):
"""Open Image Sequence with system default"""
config_data = config.get_presets().get("djv_view", {}).get("config", {})
families = get_families()
representations = get_representation()
djv_path = existing_djv_path()
families = ["*"] if djv_path else []
representations = [
"cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg",
"mp4", "m4v", "mxf", "iff", "z", "ifl", "jpeg", "jpg", "jfif", "lut",
"1dl", "exr", "pic", "png", "ppm", "pnm", "pgm", "pbm", "rla", "rpf",
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img"
]
label = "Open in DJV"
order = -10
@ -36,14 +29,6 @@ class OpenInDJV(api.Loader):
color = "orange"
def load(self, context, name, namespace, data):
self.djv_path = None
paths = config.get_presets().get("djv_view", {}).get("config", {}).get(
"djv_paths", []
)
for path in paths:
if os.path.exists(path):
self.djv_path = path
break
directory = os.path.dirname(self.fname)
from avalon.vendor import clique

View file

@ -285,6 +285,20 @@ class ExtractReview(pyblish.api.InstancePlugin):
# Prepare input and output filepaths
self.input_output_paths(new_repre, output_def, temp_data)
# Set output frames len to 1 when ouput is single image
if (
temp_data["output_ext_is_image"]
and not temp_data["output_is_sequence"]
):
output_frames_len = 1
else:
output_frames_len = (
temp_data["output_frame_end"]
- temp_data["output_frame_start"]
+ 1
)
if temp_data["input_is_sequence"]:
# Set start frame
ffmpeg_input_args.append(
@ -303,31 +317,14 @@ class ExtractReview(pyblish.api.InstancePlugin):
)
elif temp_data["without_handles"]:
# TODO use frames ubstead if `-ss`:
# `select="gte(n\,{handle_start}),setpts=PTS-STARTPTS`
# Pros:
# 1.) Python is not good at float operation
# 2.) FPS on instance may not be same as input's
start_sec = float(temp_data["handle_start"]) / temp_data["fps"]
ffmpeg_input_args.append("-ss {:0.2f}".format(start_sec))
# Set output frames len to 1 when ouput is single image
if (
temp_data["output_ext_is_image"]
and not temp_data["output_is_sequence"]
):
output_frames_len = 1
duration_sec = float(output_frames_len / temp_data["fps"])
ffmpeg_output_args.append("-t {:0.2f}".format(duration_sec))
else:
output_frames_len = (
temp_data["output_frame_end"]
- temp_data["output_frame_start"]
+ 1
)
# NOTE used `-frames` instead of `-t` - should work the same way
# NOTE this also replaced `-shortest` argument
ffmpeg_output_args.append("-frames {}".format(output_frames_len))
# Use shortest input
ffmpeg_output_args.append("-shortest")
# Add video/image input path
ffmpeg_input_args.append(

View file

@ -166,8 +166,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"FTRACK_SERVER",
"PYPE_METADATA_FILE",
"AVALON_PROJECT",
"PYPE_LOG_NO_COLORS",
"PYPE_PYTHON_EXE"
"PYPE_LOG_NO_COLORS"
]
# custom deadline atributes
@ -191,6 +190,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
# list of family names to transfer to new family if present
families_transfer = ["render3d", "render2d", "ftrack", "slate"]
plugin_python_version = "3.7"
def _submit_deadline_post_job(self, instance, job):
"""Submit publish job to Deadline.
@ -202,9 +202,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"""
data = instance.data.copy()
subset = data["subset"]
job_name = "{batch} - {subset} [publish image sequence]".format(
batch=job["Props"]["Name"], subset=subset
)
job_name = "Publish - {subset}".format(subset=subset)
output_dir = instance.data["outputDir"]
# Convert output dir to `{root}/rest/of/path/...` with Anatomy
@ -240,7 +238,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"OutputDirectory0": output_dir
},
"PluginInfo": {
"Version": "3.6",
"Version": self.plugin_python_version,
"ScriptFile": _get_script(),
"Arguments": "",
"SingleFrameOnly": "True",

View file

@ -59,7 +59,7 @@ payload_skeleton = {
}
def get_renderer_variables(renderlayer=None):
def get_renderer_variables(renderlayer, root):
"""Retrieve the extension which has been set in the VRay settings.
Will return None if the current renderer is not VRay
@ -68,6 +68,7 @@ def get_renderer_variables(renderlayer=None):
Args:
renderlayer (str): the node name of the renderlayer.
root (str): base path to render
Returns:
dict
@ -87,6 +88,7 @@ def get_renderer_variables(renderlayer=None):
filename_0 = filename_0.replace('_<RenderPass>', '_beauty')
prefix_attr = "defaultRenderGlobals.imageFilePrefix"
if renderer == "vray":
renderlayer = renderlayer.split("_")[-1]
# Maya's renderSettings function does not return V-Ray file extension
# so we get the extension from vraySettings
extension = cmds.getAttr("vraySettings.imageFormatStr")
@ -101,6 +103,16 @@ def get_renderer_variables(renderlayer=None):
extension = "exr"
prefix_attr = "vraySettings.fileNamePrefix"
filename_prefix = cmds.getAttr(prefix_attr)
# we need to determine path for vray as maya `renderSettings` query
# does not work for vray.
scene = cmds.file(query=True, sceneName=True)
scene, _ = os.path.splitext(os.path.basename(scene))
filename_0 = filename_prefix.replace('<Scene>', scene)
filename_0 = filename_0.replace('<Layer>', renderlayer)
filename_0 = "{}.{}.{}".format(
filename_0, "#" * int(padding), extension)
filename_0 = os.path.normpath(os.path.join(root, filename_0))
elif renderer == "renderman":
prefix_attr = "rmanGlobals.imageFileFormat"
elif renderer == "redshift":
@ -236,7 +248,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
jobname = "%s - %s" % (filename, instance.name)
# Get the variables depending on the renderer
render_variables = get_renderer_variables(renderlayer)
render_variables = get_renderer_variables(renderlayer, dirname)
filename_0 = render_variables["filename_0"]
if self.use_published:
new_scene = os.path.splitext(filename)[0]
@ -267,6 +279,11 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
payload_data["workspace"] = workspace
payload_data["dirname"] = dirname
self.log.info("--- Submission data:")
for k, v in payload_data.items():
self.log.info("- {}: {}".format(k, v))
self.log.info("-" * 20)
frame_pattern = payload_skeleton["JobInfo"]["Frames"]
payload_skeleton["JobInfo"]["Frames"] = frame_pattern.format(
start=int(self._instance.data["frameStartHandle"]),
@ -295,9 +312,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
dependencies = instance.context.data["fileDependencies"]
dependencies.append(filepath)
for dependency in dependencies:
self.log.info(dependency)
key = "AssetDependency" + str(dependencies.index(dependency))
self.log.info(key)
payload_skeleton["JobInfo"][key] = dependency
# Handle environments -----------------------------------------------
@ -311,8 +326,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
"AVALON_TASK",
"PYPE_USERNAME",
"PYPE_DEV",
"PYPE_LOG_NO_COLORS",
"PYPE_SETUP_PATH"
"PYPE_LOG_NO_COLORS"
]
environment = dict({key: os.environ[key] for key in keys
@ -388,7 +402,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
raise Exception(response.text)
# Store output dir for unified publisher (filesequence)
instance.data["outputDir"] = os.path.dirname(filename_0)
instance.data["outputDir"] = os.path.dirname(output_filename_0)
instance.data["deadlineSubmissionJob"] = response.json()
def _get_maya_payload(self, data):
@ -423,6 +437,13 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
def _get_vray_export_payload(self, data):
payload = copy.deepcopy(payload_skeleton)
vray_settings = cmds.ls(type="VRaySettingsNode")
node = vray_settings[0]
template = cmds.getAttr("{}.vrscene_filename".format(node))
scene, _ = os.path.splitext(data["filename"])
first_file = self.format_vray_output_filename(scene, template)
first_file = "{}/{}".format(data["workspace"], first_file)
output = os.path.dirname(first_file)
job_info_ext = {
# Job name, as seen in Monitor
"Name": "Export {} [{}-{}]".format(
@ -444,7 +465,8 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
"UsingRenderLayers": True,
"UseLegacyRenderLayers": True,
"RenderLayer": data["renderlayer"],
"ProjectPath": data["workspace"]
"ProjectPath": data["workspace"],
"OutputFilePath": output
}
payload["JobInfo"].update(job_info_ext)
@ -545,6 +567,8 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
"Width": self._instance.data["resolutionWidth"],
"Height": self._instance.data["resolutionHeight"],
"OutputFilePath": payload["JobInfo"]["OutputDirectory0"],
"OutputFileName": payload["JobInfo"]["OutputFilename0"]
}
payload["JobInfo"].update(job_info_ext)
@ -669,11 +693,13 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin):
# Ensure filename has no extension
file_name, _ = os.path.splitext(filename)
layer = self._instance.data['setMembers']
# Reformat without tokens
output_path = smart_replace(
template,
{"<Scene>": file_name,
"<Layer>": self._instance.data['setMembers']})
"<Layer>": layer})
if dir:
return output_path.replace("\\", "/")

View file

@ -56,7 +56,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
'arnold': 'maya/<Scene>/<RenderLayer>/<RenderLayer>_<RenderPass>',
'redshift': 'maya/<Scene>/<RenderLayer>/<RenderLayer>',
'vray': 'maya/<scene>/<Layer>/<Layer>',
'vray': 'maya/<Scene>/<Layer>/<Layer>',
'renderman': '<layer>_<aov>.<f4>.<ext>'
}
@ -77,7 +77,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
R_SCENE_TOKEN = re.compile(r'%s|<scene>', re.IGNORECASE)
DEFAULT_PADDING = 4
VRAY_PREFIX = "maya/<scene>/<Layer>/<Layer>"
VRAY_PREFIX = "maya/<Scene>/<Layer>/<Layer>"
DEFAULT_PREFIX = "maya/<Scene>/<RenderLayer>/<RenderLayer>_<RenderPass>"
def process(self, instance):

View file

@ -46,7 +46,7 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
invalid = True
vrscene_filename = cmds.getAttr("{}.vrscene_filename".format(node))
if vrscene_filename != "vrayscene/<Scene>/<Scene>_<Layer>/<Layer>":
if vrscene_filename != "vrayscene/<Scene>/<Layer>/<Layer>":
cls.log.error("Template for file name is wrong")
invalid = True
@ -65,5 +65,5 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
cmds.setAttr("{}.vrscene_on".format(node), True)
cmds.setAttr("{}.misc_eachFrameInFile".format(node), True)
cmds.setAttr("{}.vrscene_filename".format(node),
"vrayscene/<Scene>/<Scene>_<Layer>/<Layer>",
"vrayscene/<Scene>/<Layer>/<Layer>",
type="string")

View file

@ -120,7 +120,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
chunk_size = self.deadline_chunk_size
priority = instance.data.get("deadlinePriority")
if priority != 50:
if not priority:
priority = self.deadline_priority
payload = {

View file

@ -11,7 +11,7 @@ class CollectFrameranges(pyblish.api.InstancePlugin):
"""
label = "Collect Clip Frameranges"
order = pyblish.api.CollectorOrder
order = pyblish.api.CollectorOrder - 0.01
families = ['clip']
def process(self, instance):

View file

@ -12,7 +12,7 @@ class CollectClipRepresentations(pyblish.api.InstancePlugin):
"""
label = "Collect Clip Representations"
order = pyblish.api.CollectorOrder
order = pyblish.api.CollectorOrder + 0.1
families = ['clip']
def process(self, instance):

View file

@ -37,13 +37,7 @@ class ValidateAutoSyncOff(pyblish.api.ContextPlugin):
query = 'Project where full_name is "{}"'.format(project_name)
project = session.query(query).one()
invalid = None
if project.get('custom_attributes', {}).get(
'avalon_auto_sync', False):
invalid = project
return invalid
return project
@classmethod
def repair(cls, context):
@ -55,4 +49,4 @@ class ValidateAutoSyncOff(pyblish.api.ContextPlugin):
except Exception:
tp, value, tb = sys.exc_info()
session.rollback()
six.reraise(tp, value, tb)
raise

View file

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 257 KiB

After

Width:  |  Height:  |  Size: 257 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 247 KiB

After

Width:  |  Height:  |  Size: 247 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Before After
Before After

View file

@ -30,12 +30,15 @@ class TrayManager:
os.path.join(CURRENT_DIR, "modules_imports.json")
)
presets = config.get_presets(first_run=True)
menu_items = presets["tray"]["menu_items"]
try:
self.modules_usage = presets["tray"]["menu_items"]["item_usage"]
self.modules_usage = menu_items["item_usage"]
except Exception:
self.modules_usage = {}
self.log.critical("Couldn't find modules usage data.")
self.module_attributes = menu_items.get("attributes") or {}
self.icon_run = QtGui.QIcon(
resources.get_resource("icons", "circle_green.png")
)
@ -71,12 +74,20 @@ class TrayManager:
if item_usage is None:
item_usage = self.modules_usage.get(import_path, True)
if item_usage:
items.append(item)
else:
if not item_usage:
if not title:
title = import_path
self.log.info("{} - Module ignored".format(title))
continue
_attributes = self.module_attributes.get(title)
if _attributes is None:
_attributes = self.module_attributes.get(import_path)
if _attributes:
item["attributes"] = _attributes
items.append(item)
if items:
self.process_items(items, self.tray_widget.menu)
@ -153,11 +164,29 @@ class TrayManager:
import_path = item.get('import_path', None)
title = item.get('title', import_path)
fromlist = item.get('fromlist', [])
attributes = item.get("attributes", {})
try:
module = __import__(
"{}".format(import_path),
fromlist=fromlist
)
klass = getattr(module, "CLASS_DEFINIION", None)
if not klass and attributes:
self.log.error((
"There are defined attributes for module \"{}\" but"
"module does not have defined \"CLASS_DEFINIION\"."
).format(import_path))
elif klass and attributes:
for key, value in attributes.items():
if hasattr(klass, key):
setattr(klass, key, value)
else:
self.log.error((
"Module \"{}\" does not have attribute \"{}\"."
" Check your settings please."
).format(import_path, key))
obj = module.tray_init(self.tray_widget, self.main_window)
name = obj.__class__.__name__
if hasattr(obj, 'tray_menu'):