Merge branch '2.x/develop' into feature/239-resolve_tagging_for_publish
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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:]))
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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("\\", "/")
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 247 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
|
@ -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'):
|
||||
|
|
|
|||