mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 22:02:15 +01:00
Merge branch 'develop' into feature/next_task_update_with_settings
This commit is contained in:
commit
a794043b7c
61 changed files with 707 additions and 378 deletions
|
|
@ -32,6 +32,9 @@ Attributes:
|
|||
ImagePrefixes (dict): Mapping between renderers and their respective
|
||||
image prefix atrribute names.
|
||||
|
||||
Todo:
|
||||
Determine `multipart` from render instance.
|
||||
|
||||
"""
|
||||
|
||||
import types
|
||||
|
|
@ -94,6 +97,10 @@ class ExpectedFiles:
|
|||
|
||||
multipart = False
|
||||
|
||||
def __init__(self, render_instance):
|
||||
"""Constructor."""
|
||||
self._render_instance = render_instance
|
||||
|
||||
def get(self, renderer, layer):
|
||||
"""Get expected files for given renderer and render layer.
|
||||
|
||||
|
|
@ -114,15 +121,20 @@ class ExpectedFiles:
|
|||
renderSetup.instance().switchToLayerUsingLegacyName(layer)
|
||||
|
||||
if renderer.lower() == "arnold":
|
||||
return self._get_files(ExpectedFilesArnold(layer))
|
||||
return self._get_files(ExpectedFilesArnold(layer,
|
||||
self._render_instance))
|
||||
elif renderer.lower() == "vray":
|
||||
return self._get_files(ExpectedFilesVray(layer))
|
||||
return self._get_files(ExpectedFilesVray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "redshift":
|
||||
return self._get_files(ExpectedFilesRedshift(layer))
|
||||
return self._get_files(ExpectedFilesRedshift(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "mentalray":
|
||||
return self._get_files(ExpectedFilesMentalray(layer))
|
||||
return self._get_files(ExpectedFilesMentalray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "renderman":
|
||||
return self._get_files(ExpectedFilesRenderman(layer))
|
||||
return self._get_files(ExpectedFilesRenderman(
|
||||
layer, self._render_instance))
|
||||
else:
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
|
|
@ -149,9 +161,10 @@ class AExpectedFiles:
|
|||
layer = None
|
||||
multipart = False
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
self.layer = layer
|
||||
self.render_instance = render_instance
|
||||
|
||||
@abstractmethod
|
||||
def get_aovs(self):
|
||||
|
|
@ -460,9 +473,9 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
"maya": "",
|
||||
}
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesArnold, self).__init__(layer)
|
||||
super(ExpectedFilesArnold, self).__init__(layer, render_instance)
|
||||
self.renderer = "arnold"
|
||||
|
||||
def get_aovs(self):
|
||||
|
|
@ -531,9 +544,9 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
class ExpectedFilesVray(AExpectedFiles):
|
||||
"""Expected files for V-Ray renderer."""
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesVray, self).__init__(layer)
|
||||
super(ExpectedFilesVray, self).__init__(layer, render_instance)
|
||||
self.renderer = "vray"
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
|
|
@ -614,24 +627,25 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
|
||||
default_ext = "exr"
|
||||
|
||||
# add beauty as default
|
||||
enabled_aovs.append(
|
||||
(u"beauty", default_ext)
|
||||
)
|
||||
|
||||
if not self.maya_is_true(
|
||||
cmds.getAttr("vraySettings.relements_enableall")
|
||||
):
|
||||
return enabled_aovs
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"vrayUseReferencedAovs", False) or False
|
||||
|
||||
# filter all namespace prefixed AOVs - they are pulled in from
|
||||
# references and are not rendered.
|
||||
vr_aovs = [
|
||||
n
|
||||
for n in cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"]
|
||||
)
|
||||
if len(n.split(":")) == 1
|
||||
]
|
||||
# this will have list of all aovs no matter if they are coming from
|
||||
# reference or not.
|
||||
vr_aovs = cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"]) or []
|
||||
if not use_ref_aovs:
|
||||
ref_aovs = cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"],
|
||||
referencedNodes=True) or []
|
||||
# get difference
|
||||
vr_aovs = list(set(vr_aovs) - set(ref_aovs))
|
||||
|
||||
for aov in vr_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
|
|
@ -703,9 +717,9 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
|
||||
ext_mapping = ["iff", "exr", "tif", "png", "tga", "jpg"]
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Construtor."""
|
||||
super(ExpectedFilesRedshift, self).__init__(layer)
|
||||
super(ExpectedFilesRedshift, self).__init__(layer, render_instance)
|
||||
self.renderer = "redshift"
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
|
|
@ -822,9 +836,9 @@ class ExpectedFilesRenderman(AExpectedFiles):
|
|||
This is very rudimentary and needs more love and testing.
|
||||
"""
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesRenderman, self).__init__(layer)
|
||||
super(ExpectedFilesRenderman, self).__init__(layer, render_instance)
|
||||
self.renderer = "renderman"
|
||||
|
||||
def get_aovs(self):
|
||||
|
|
@ -887,7 +901,7 @@ class ExpectedFilesRenderman(AExpectedFiles):
|
|||
class ExpectedFilesMentalray(AExpectedFiles):
|
||||
"""Skeleton unimplemented class for Mentalray renderer."""
|
||||
|
||||
def __init__(self, layer):
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor.
|
||||
|
||||
Raises:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,11 @@ from .plugin_tools import (
|
|||
filter_pyblish_plugins,
|
||||
source_hash,
|
||||
get_unique_layer_name,
|
||||
get_background_layers
|
||||
get_background_layers,
|
||||
oiio_supported,
|
||||
decompress,
|
||||
get_decompress_dir,
|
||||
should_decompress
|
||||
)
|
||||
|
||||
from .user_settings import (
|
||||
|
|
@ -108,6 +112,10 @@ __all__ = [
|
|||
"source_hash",
|
||||
"get_unique_layer_name",
|
||||
"get_background_layers",
|
||||
"oiio_supported",
|
||||
"decompress",
|
||||
"get_decompress_dir",
|
||||
"should_decompress",
|
||||
|
||||
"version_up",
|
||||
"get_version_from_path",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import inspect
|
|||
import logging
|
||||
import re
|
||||
import json
|
||||
import tempfile
|
||||
|
||||
from . import execute
|
||||
|
||||
from pype.settings import get_project_settings
|
||||
|
||||
|
|
@ -134,3 +137,115 @@ def get_background_layers(file_url):
|
|||
layer.get("filename")).
|
||||
replace("\\", "/"))
|
||||
return layers
|
||||
|
||||
|
||||
def oiio_supported():
|
||||
"""
|
||||
Checks if oiiotool is configured for this platform.
|
||||
|
||||
Expects full path to executable.
|
||||
|
||||
'should_decompress' will throw exception if configured,
|
||||
but not present or not working.
|
||||
Returns:
|
||||
(bool)
|
||||
"""
|
||||
oiio_path = os.getenv("PYPE_OIIO_PATH", "")
|
||||
if not oiio_path or not os.path.exists(oiio_path):
|
||||
log.debug("OIIOTool is not configured or not present at {}".
|
||||
format(oiio_path))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def decompress(target_dir, file_url,
|
||||
input_frame_start=None, input_frame_end=None, log=None):
|
||||
"""
|
||||
Decompresses DWAA 'file_url' .exr to 'target_dir'.
|
||||
|
||||
Creates uncompressed files in 'target_dir', they need to be cleaned.
|
||||
|
||||
File url could be for single file or for a sequence, in that case
|
||||
%0Xd will be as a placeholder for frame number AND input_frame* will
|
||||
be filled.
|
||||
In that case single oiio command with '--frames' will be triggered for
|
||||
all frames, this should be faster then looping and running sequentially
|
||||
|
||||
Args:
|
||||
target_dir (str): extended from stagingDir
|
||||
file_url (str): full urls to source file (with or without %0Xd)
|
||||
input_frame_start (int) (optional): first frame
|
||||
input_frame_end (int) (optional): last frame
|
||||
log (Logger) (optional): pype logger
|
||||
"""
|
||||
is_sequence = input_frame_start is not None and \
|
||||
input_frame_end is not None and \
|
||||
(int(input_frame_end) > int(input_frame_start))
|
||||
|
||||
oiio_cmd = []
|
||||
oiio_cmd.append(os.getenv("PYPE_OIIO_PATH"))
|
||||
|
||||
oiio_cmd.append("--compression none")
|
||||
|
||||
base_file_name = os.path.basename(file_url)
|
||||
oiio_cmd.append(file_url)
|
||||
|
||||
if is_sequence:
|
||||
oiio_cmd.append("--frames {}-{}".format(input_frame_start,
|
||||
input_frame_end))
|
||||
|
||||
oiio_cmd.append("-o")
|
||||
oiio_cmd.append(os.path.join(target_dir, base_file_name))
|
||||
|
||||
subprocess_exr = " ".join(oiio_cmd)
|
||||
|
||||
if not log:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
log.debug("Decompressing {}".format(subprocess_exr))
|
||||
execute.execute(
|
||||
subprocess_exr, shell=True, logger=log
|
||||
)
|
||||
|
||||
|
||||
def get_decompress_dir():
|
||||
"""
|
||||
Creates temporary folder for decompressing.
|
||||
Its local, in case of farm it is 'local' to the farm machine.
|
||||
|
||||
Should be much faster, needs to be cleaned up later.
|
||||
"""
|
||||
return os.path.normpath(
|
||||
tempfile.mkdtemp(prefix="pyblish_tmp_")
|
||||
)
|
||||
|
||||
|
||||
def should_decompress(file_url):
|
||||
"""
|
||||
Tests that 'file_url' is compressed with DWAA.
|
||||
|
||||
Uses 'oiio_supported' to check that OIIO tool is available for this
|
||||
platform.
|
||||
|
||||
Shouldn't throw exception as oiiotool is guarded by check function.
|
||||
Currently implemented this way as there is no support for Mac and Linux
|
||||
In the future, it should be more strict and throws exception on
|
||||
misconfiguration.
|
||||
|
||||
Args:
|
||||
file_url (str): path to rendered file (in sequence it would be
|
||||
first file, if that compressed it is expected that whole seq
|
||||
will be too)
|
||||
Returns:
|
||||
(bool): 'file_url' is DWAA compressed and should be decompressed
|
||||
and we can decompress (oiiotool supported)
|
||||
"""
|
||||
if oiio_supported():
|
||||
output = execute.execute([
|
||||
os.getenv("PYPE_OIIO_PATH"),
|
||||
"--info", "-v", file_url])
|
||||
return "compression: \"dwaa\"" in output or \
|
||||
"compression: \"dwab\"" in output
|
||||
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ from .ftrack import (
|
|||
IFtrackEventHandlerPaths
|
||||
)
|
||||
from .clockify import ClockifyModule
|
||||
from .logging import LoggingModule
|
||||
from .log_viewer import LogViewModule
|
||||
from .muster import MusterModule
|
||||
from .standalonepublish_action import StandAlonePublishAction
|
||||
from .websocket_server import WebsocketModule
|
||||
|
|
@ -70,7 +70,7 @@ __all__ = (
|
|||
|
||||
"ClockifyModule",
|
||||
"IdleManager",
|
||||
"LoggingModule",
|
||||
"LogViewModule",
|
||||
"MusterModule",
|
||||
"StandAlonePublishAction",
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ class AppplicationsAction(BaseAction):
|
|||
identifier = "pype_app.{}.".format(str(uuid4()))
|
||||
icon_url = os.environ.get("PYPE_STATICS_SERVER")
|
||||
|
||||
def __init__(self, session, plugins_presets=None):
|
||||
super().__init__(session, plugins_presets)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.application_manager = ApplicationManager()
|
||||
self.dbcon = AvalonMongoDB()
|
||||
|
|
@ -210,6 +210,6 @@ class AppplicationsAction(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets=None):
|
||||
def register(session):
|
||||
"""Register action. Called when used as an event plugin."""
|
||||
AppplicationsAction(session, plugins_presets).register()
|
||||
AppplicationsAction(session).register()
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ class BatchTasksAction(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets=None):
|
||||
def register(session):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
BatchTasksAction(session, plugins_presets).register()
|
||||
BatchTasksAction(session).register()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ class CleanHierarchicalAttrsAction(BaseAction):
|
|||
label = "Pype Admin"
|
||||
variant = "- Clean hierarchical custom attributes"
|
||||
description = "Unset empty hierarchical attribute values."
|
||||
role_list = ["Pypeclub", "Administrator", "Project Manager"]
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
|
||||
all_project_entities_query = (
|
||||
|
|
@ -20,12 +19,17 @@ class CleanHierarchicalAttrsAction(BaseAction):
|
|||
"select value, entity_id from CustomAttributeValue "
|
||||
"where entity_id in ({}) and configuration_id is \"{}\""
|
||||
)
|
||||
settings_key = "clean_hierarchical_attr"
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
"""Show only on project entity."""
|
||||
if len(entities) == 1 and entities[0].entity_type.lower() == "project":
|
||||
return True
|
||||
return False
|
||||
if (
|
||||
len(entities) != 1
|
||||
or entities[0].entity_type.lower() != "project"
|
||||
):
|
||||
return False
|
||||
|
||||
return self.valid_roles(session, entities, event)
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
project = entities[0]
|
||||
|
|
@ -98,7 +102,7 @@ class CleanHierarchicalAttrsAction(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
CleanHierarchicalAttrsAction(session, plugins_presets).register()
|
||||
CleanHierarchicalAttrsAction(session).register()
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class ClientReviewSort(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
ClientReviewSort(session, plugins_presets).register()
|
||||
ClientReviewSort(session).register()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class ComponentOpen(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
ComponentOpen(session, plugins_presets).register()
|
||||
ComponentOpen(session).register()
|
||||
|
|
|
|||
|
|
@ -131,9 +131,8 @@ class CustomAttributes(BaseAction):
|
|||
variant = '- Create/Update Avalon Attributes'
|
||||
#: Action description.
|
||||
description = 'Creates Avalon/Mongo ID for double check'
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
settings_key = "create_update_attributes"
|
||||
|
||||
required_keys = ("key", "label", "type")
|
||||
|
||||
|
|
@ -150,7 +149,7 @@ class CustomAttributes(BaseAction):
|
|||
Validation
|
||||
- action is only for Administrators
|
||||
'''
|
||||
return True
|
||||
return self.valid_roles(session, entities, event)
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
# JOB SETTINGS
|
||||
|
|
@ -814,7 +813,7 @@ class CustomAttributes(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
CustomAttributes(session, plugins_presets).register()
|
||||
CustomAttributes(session).register()
|
||||
|
|
|
|||
|
|
@ -243,6 +243,6 @@ class CreateFolders(BaseAction):
|
|||
return os.path.normpath(filled_template.split("{")[0])
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
"""Register plugin. Called when used as an plugin."""
|
||||
CreateFolders(session, plugins_presets).register()
|
||||
CreateFolders(session).register()
|
||||
|
|
|
|||
|
|
@ -238,5 +238,5 @@ class CreateProjectFolders(BaseAction):
|
|||
os.makedirs(path.format(project_root=project_root))
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
CreateProjectFolders(session, plugins_presets).register()
|
||||
def register(session):
|
||||
CreateProjectFolders(session).register()
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ class DeleteAssetSubset(BaseAction):
|
|||
#: Action description.
|
||||
description = "Removes from Avalon with all childs and asset from Ftrack"
|
||||
icon = statics_icon("ftrack", "action_icons", "DeleteAsset.svg")
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ["Pypeclub", "Administrator", "Project Manager"]
|
||||
|
||||
settings_key = "delete_asset_subset"
|
||||
#: Db connection
|
||||
dbcon = AvalonMongoDB()
|
||||
|
||||
|
|
@ -32,17 +32,21 @@ class DeleteAssetSubset(BaseAction):
|
|||
""" Validation """
|
||||
task_ids = []
|
||||
for ent_info in event["data"]["selection"]:
|
||||
entType = ent_info.get("entityType", "")
|
||||
if entType == "task":
|
||||
if ent_info.get("entityType") == "task":
|
||||
task_ids.append(ent_info["entityId"])
|
||||
|
||||
is_valid = False
|
||||
for entity in entities:
|
||||
ftrack_id = entity["id"]
|
||||
if ftrack_id not in task_ids:
|
||||
continue
|
||||
if entity.entity_type.lower() != "task":
|
||||
return True
|
||||
return False
|
||||
if (
|
||||
entity["id"] in task_ids
|
||||
and entity.entity_type.lower() != "task"
|
||||
):
|
||||
is_valid = True
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
is_valid = self.valid_roles(session, entities, event)
|
||||
return is_valid
|
||||
|
||||
def _launch(self, event):
|
||||
try:
|
||||
|
|
@ -662,7 +666,7 @@ class DeleteAssetSubset(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
DeleteAssetSubset(session, plugins_presets).register()
|
||||
DeleteAssetSubset(session).register()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class DeleteOldVersions(BaseAction):
|
|||
"Delete files from older publishes so project can be"
|
||||
" archived with only lates versions."
|
||||
)
|
||||
role_list = ["Pypeclub", "Project Manager", "Administrator"]
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
|
||||
dbcon = AvalonMongoDB()
|
||||
|
|
@ -31,13 +30,16 @@ class DeleteOldVersions(BaseAction):
|
|||
sequence_splitter = "__sequence_splitter__"
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
selection = event["data"].get("selection") or []
|
||||
for entity in selection:
|
||||
entity_type = (entity.get("entityType") or "").lower()
|
||||
if entity_type == "assetversion":
|
||||
return True
|
||||
return False
|
||||
""" Validation. """
|
||||
is_valid = False
|
||||
for entity in entities:
|
||||
if entity.entity_type.lower() == "assetversion":
|
||||
is_valid = True
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
is_valid = self.valid_roles(session, entities, event)
|
||||
return is_valid
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
# TODO Add roots existence validation
|
||||
|
|
@ -577,7 +579,7 @@ class DeleteOldVersions(BaseAction):
|
|||
return (os.path.normpath(path), sequence_path)
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
DeleteOldVersions(session, plugins_presets).register()
|
||||
DeleteOldVersions(session).register()
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class Delivery(BaseAction):
|
|||
description = "Deliver data to client"
|
||||
role_list = ["Pypeclub", "Administrator", "Project manager"]
|
||||
icon = statics_icon("ftrack", "action_icons", "Delivery.svg")
|
||||
settings_key = "delivery_action"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.db_con = AvalonMongoDB()
|
||||
|
|
@ -30,11 +31,15 @@ class Delivery(BaseAction):
|
|||
super(Delivery, self).__init__(*args, **kwargs)
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
is_valid = False
|
||||
for entity in entities:
|
||||
if entity.entity_type.lower() == "assetversion":
|
||||
return True
|
||||
is_valid = True
|
||||
break
|
||||
|
||||
return False
|
||||
if is_valid:
|
||||
is_valid = self.valid_roles(session, entities, event)
|
||||
return is_valid
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
if event["data"].get("values", {}):
|
||||
|
|
@ -692,7 +697,7 @@ class Delivery(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
Delivery(session, plugins_presets).register()
|
||||
Delivery(session).register()
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@ class DJVViewAction(BaseAction):
|
|||
"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)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.djv_path = self.find_djv_path()
|
||||
|
||||
|
|
@ -208,7 +207,7 @@ class DJVViewAction(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
"""Register hooks."""
|
||||
|
||||
DJVViewAction(session, plugins_presets).register()
|
||||
DJVViewAction(session).register()
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ class JobKiller(BaseAction):
|
|||
#: Action description.
|
||||
description = 'Killing selected running jobs'
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
settings_key = "job_killer"
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
return True
|
||||
return self.valid_roles(session, entities, event)
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
if not event['data'].get('values', {}):
|
||||
|
|
@ -112,7 +111,7 @@ class JobKiller(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
JobKiller(session, plugins_presets).register()
|
||||
JobKiller(session).register()
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class MultipleNotes(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
MultipleNotes(session, plugins_presets).register()
|
||||
MultipleNotes(session).register()
|
||||
|
|
|
|||
|
|
@ -16,22 +16,23 @@ class PrepareProject(BaseAction):
|
|||
#: Action description.
|
||||
description = 'Set basic attributes on the project'
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ["Pypeclub", "Administrator", "Project manager"]
|
||||
icon = statics_icon("ftrack", "action_icons", "PrepareProject.svg")
|
||||
|
||||
settings_key = "prepare_project"
|
||||
|
||||
# Key to store info about trigerring create folder structure
|
||||
create_project_structure_key = "create_folder_structure"
|
||||
item_splitter = {'type': 'label', 'value': '---'}
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
if len(entities) != 1:
|
||||
if (
|
||||
len(entities) != 1
|
||||
or entities[0].entity_type.lower() != "project"
|
||||
):
|
||||
return False
|
||||
|
||||
if entities[0].entity_type.lower() != "project":
|
||||
return False
|
||||
|
||||
return True
|
||||
return self.valid_roles(session, entities, event)
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
if event['data'].get('values', {}):
|
||||
|
|
@ -454,6 +455,6 @@ class PrepareProject(BaseAction):
|
|||
self.log.debug("*** Creating project specifig configs Finished ***")
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
PrepareProject(session, plugins_presets).register()
|
||||
PrepareProject(session).register()
|
||||
|
|
|
|||
|
|
@ -19,13 +19,8 @@ class RVAction(BaseAction):
|
|||
|
||||
allowed_types = ["img", "mov", "exr", "mp4"]
|
||||
|
||||
def __init__(self, session, plugins_presets):
|
||||
""" Constructor
|
||||
|
||||
:param session: ftrack Session
|
||||
:type session: :class:`ftrack_api.Session`
|
||||
"""
|
||||
super().__init__(session, plugins_presets)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# QUESTION load RV application data from AppplicationManager?
|
||||
rv_path = None
|
||||
|
|
@ -317,7 +312,7 @@ class RVAction(BaseAction):
|
|||
return paths
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
"""Register hooks."""
|
||||
|
||||
RVAction(session, plugins_presets).register()
|
||||
RVAction(session).register()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class SeedDebugProject(BaseAction):
|
|||
#: priority
|
||||
priority = 100
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ["Pypeclub"]
|
||||
icon = statics_icon("ftrack", "action_icons", "SeedProject.svg")
|
||||
|
||||
# Asset names which will be created in `Assets` entity
|
||||
|
|
@ -58,9 +57,12 @@ class SeedDebugProject(BaseAction):
|
|||
existing_projects = None
|
||||
new_project_item = "< New Project >"
|
||||
current_project_item = "< Current Project >"
|
||||
settings_key = "seed_project"
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
if not self.valid_roles(session, entities, event):
|
||||
return False
|
||||
return True
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
|
|
@ -428,7 +430,7 @@ class SeedDebugProject(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
SeedDebugProject(session, plugins_presets).register()
|
||||
SeedDebugProject(session).register()
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ class StoreThumbnailsToAvalon(BaseAction):
|
|||
# Action description
|
||||
description = 'Test action'
|
||||
# roles that are allowed to register this action
|
||||
role_list = ["Pypeclub", "Administrator", "Project Manager"]
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
settings_key = "store_thubmnail_to_avalon"
|
||||
|
||||
thumbnail_key = "AVALON_THUMBNAIL_ROOT"
|
||||
|
||||
|
|
@ -31,10 +31,15 @@ class StoreThumbnailsToAvalon(BaseAction):
|
|||
super(StoreThumbnailsToAvalon, self).__init__(*args, **kwargs)
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
is_valid = False
|
||||
for entity in entities:
|
||||
if entity.entity_type.lower() == "assetversion":
|
||||
return True
|
||||
return False
|
||||
is_valid = True
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
is_valid = self.valid_roles(session, entities, event)
|
||||
return is_valid
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
user = session.query(
|
||||
|
|
@ -457,5 +462,5 @@ class StoreThumbnailsToAvalon(BaseAction):
|
|||
return output
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
StoreThumbnailsToAvalon(session, plugins_presets).register()
|
||||
def register(session):
|
||||
StoreThumbnailsToAvalon(session).register()
|
||||
|
|
|
|||
|
|
@ -41,20 +41,26 @@ class SyncToAvalonLocal(BaseAction):
|
|||
#: priority
|
||||
priority = 200
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ["Pypeclub"]
|
||||
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
|
||||
|
||||
settings_key = "sync_to_avalon_local"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.entities_factory = SyncEntitiesFactory(self.log, self.session)
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
""" Validate selection. """
|
||||
is_valid = False
|
||||
for ent in event["data"]["selection"]:
|
||||
# Ignore entities that are not tasks or projects
|
||||
if ent["entityType"].lower() in ["show", "task"]:
|
||||
return True
|
||||
return False
|
||||
is_valid = True
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
is_valid = self.valid_roles(session, entities, event)
|
||||
return is_valid
|
||||
|
||||
def launch(self, session, in_entities, event):
|
||||
time_start = time.time()
|
||||
|
|
@ -187,7 +193,7 @@ class SyncToAvalonLocal(BaseAction):
|
|||
pass
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
SyncToAvalonLocal(session, plugins_presets).register()
|
||||
SyncToAvalonLocal(session).register()
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ class TestAction(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
TestAction(session, plugins_presets).register()
|
||||
def register(session):
|
||||
TestAction(session).register()
|
||||
|
|
|
|||
|
|
@ -15,11 +15,9 @@ class ThumbToChildren(BaseAction):
|
|||
icon = statics_icon("ftrack", "action_icons", "Thumbnail.svg")
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
if (len(entities) != 1 or entities[0].entity_type in ['Project']):
|
||||
"""Show only on project."""
|
||||
if (len(entities) != 1 or entities[0].entity_type in ["Project"]):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
|
@ -59,7 +57,7 @@ class ThumbToChildren(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
ThumbToChildren(session, plugins_presets).register()
|
||||
ThumbToChildren(session).register()
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class ThumbToParent(BaseAction):
|
|||
}
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
ThumbToParent(session, plugins_presets).register()
|
||||
ThumbToParent(session).register()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class ActionAskWhereIRun(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
ActionAskWhereIRun(session, plugins_presets).register()
|
||||
ActionAskWhereIRun(session).register()
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class ActionShowWhereIRun(BaseAction):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
ActionShowWhereIRun(session, plugins_presets).register()
|
||||
ActionShowWhereIRun(session).register()
|
||||
|
|
|
|||
|
|
@ -430,5 +430,5 @@ class PushHierValuesToNonHier(ServerAction):
|
|||
session.commit()
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
PushHierValuesToNonHier(session, plugins_presets).register()
|
||||
def register(session):
|
||||
PushHierValuesToNonHier(session).register()
|
||||
|
|
|
|||
|
|
@ -182,6 +182,6 @@ class SyncToAvalonServer(ServerAction):
|
|||
pass
|
||||
|
||||
|
||||
def register(session, plugins_presets={}):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
SyncToAvalonServer(session, plugins_presets).register()
|
||||
SyncToAvalonServer(session).register()
|
||||
|
|
|
|||
|
|
@ -47,6 +47,6 @@ class DelAvalonIdFromNew(BaseEvent):
|
|||
continue
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
DelAvalonIdFromNew(session, plugins_presets).register()
|
||||
DelAvalonIdFromNew(session).register()
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class FirstVersionStatus(BaseEvent):
|
|||
return filtered_ents
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
FirstVersionStatus(session, plugins_presets).register()
|
||||
FirstVersionStatus(session).register()
|
||||
|
|
|
|||
|
|
@ -260,5 +260,5 @@ class NextTaskUpdate(BaseEvent):
|
|||
return types
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
NextTaskUpdate(session, plugins_presets).register()
|
||||
def register(session):
|
||||
NextTaskUpdate(session).register()
|
||||
|
|
|
|||
|
|
@ -364,5 +364,5 @@ class PushFrameValuesToTaskEvent(BaseEvent):
|
|||
return output, hiearchical
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
PushFrameValuesToTaskEvent(session, plugins_presets).register()
|
||||
def register(session):
|
||||
PushFrameValuesToTaskEvent(session).register()
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class RadioButtons(BaseEvent):
|
|||
session.commit()
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
RadioButtons(session, plugins_presets).register()
|
||||
RadioButtons(session).register()
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
created_entities = []
|
||||
report_splitter = {"type": "label", "value": "---"}
|
||||
|
||||
def __init__(self, session, plugins_presets={}):
|
||||
def __init__(self, session):
|
||||
'''Expects a ftrack_api.Session instance'''
|
||||
# Debug settings
|
||||
# - time expiration in seconds
|
||||
|
|
@ -67,7 +67,7 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
self.dbcon = AvalonMongoDB()
|
||||
# Set processing session to not use global
|
||||
self.set_process_session(session)
|
||||
super().__init__(session, plugins_presets)
|
||||
super().__init__(session)
|
||||
|
||||
def debug_logs(self):
|
||||
"""This is debug method for printing small debugs messages. """
|
||||
|
|
@ -2513,6 +2513,6 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
return mongo_id_configuration_id
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
SyncToAvalonEvent(session, plugins_presets).register()
|
||||
SyncToAvalonEvent(session).register()
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ class TaskStatusToParent(BaseEvent):
|
|||
session, event, project_id
|
||||
)
|
||||
# Load settings
|
||||
project_settings = self.get_settings_for_project(
|
||||
session, event, project_entity=project_entity
|
||||
project_settings = self.get_project_settings_from_event(
|
||||
event, project_entity
|
||||
)
|
||||
|
||||
# Prepare loaded settings and check if can be processed
|
||||
|
|
@ -419,5 +419,5 @@ class TaskStatusToParent(BaseEvent):
|
|||
return output
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
TaskStatusToParent(session, plugins_presets).register()
|
||||
def register(session):
|
||||
TaskStatusToParent(session).register()
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ class TaskToVersionStatus(BaseEvent):
|
|||
project_entity = self.get_project_entity_from_event(
|
||||
session, event, project_id
|
||||
)
|
||||
project_settings = self.get_settings_for_project(
|
||||
session, event, project_entity=project_entity
|
||||
project_settings = self.get_project_settings_from_event(
|
||||
event, project_entity
|
||||
)
|
||||
|
||||
project_name = project_entity["full_name"]
|
||||
|
|
@ -372,5 +372,5 @@ class TaskToVersionStatus(BaseEvent):
|
|||
return last_asset_versions_by_task_id
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
TaskToVersionStatus(session, plugins_presets).register()
|
||||
def register(session):
|
||||
TaskToVersionStatus(session).register()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
import ftrack_api
|
||||
from pype.modules.ftrack import BaseEvent
|
||||
|
||||
|
||||
|
|
@ -20,7 +16,7 @@ class TestEvent(BaseEvent):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
TestEvent(session, plugins_presets).register()
|
||||
TestEvent(session).register()
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ class ThumbnailEvents(BaseEvent):
|
|||
project_entity = self.get_project_entity_from_event(
|
||||
session, event, project_id
|
||||
)
|
||||
project_settings = self.get_settings_for_project(
|
||||
session, event, project_entity=project_entity
|
||||
project_settings = self.get_project_settings_from_event(
|
||||
event, project_entity
|
||||
)
|
||||
|
||||
project_name = project_entity["full_name"]
|
||||
|
|
@ -151,5 +151,5 @@ class ThumbnailEvents(BaseEvent):
|
|||
return filtered_entities_info
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
ThumbnailEvents(session, plugins_presets).register()
|
||||
def register(session):
|
||||
ThumbnailEvents(session).register()
|
||||
|
|
|
|||
|
|
@ -250,9 +250,9 @@ class UserAssigmentEvent(BaseEvent):
|
|||
return True
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
"""
|
||||
Register plugin. Called when used as an plugin.
|
||||
"""
|
||||
|
||||
UserAssigmentEvent(session, plugins_presets).register()
|
||||
UserAssigmentEvent(session).register()
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ class VersionToTaskStatus(BaseEvent):
|
|||
project_entity = self.get_project_entity_from_event(
|
||||
session, event, project_id
|
||||
)
|
||||
project_settings = self.get_settings_for_project(
|
||||
session, event, project_entity=project_entity
|
||||
project_settings = self.get_project_settings_from_event(
|
||||
event, project_entity
|
||||
)
|
||||
|
||||
project_name = project_entity["full_name"]
|
||||
|
|
@ -241,7 +241,7 @@ class VersionToTaskStatus(BaseEvent):
|
|||
return output
|
||||
|
||||
|
||||
def register(session, plugins_presets):
|
||||
def register(session):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
VersionToTaskStatus(session, plugins_presets).register()
|
||||
VersionToTaskStatus(session).register()
|
||||
|
|
|
|||
|
|
@ -108,21 +108,10 @@ class FtrackServer:
|
|||
" in registered paths: \"{}\""
|
||||
).format("| ".join(paths)))
|
||||
|
||||
# TODO replace with settings or get rid of passing the dictionary
|
||||
plugins_presets = {}
|
||||
|
||||
function_counter = 0
|
||||
for function_dict in register_functions_dict:
|
||||
register = function_dict["register"]
|
||||
try:
|
||||
if len(inspect.signature(register).parameters) == 1:
|
||||
register(self.session)
|
||||
else:
|
||||
register(self.session, plugins_presets=plugins_presets)
|
||||
|
||||
if function_counter % 7 == 0:
|
||||
time.sleep(0.1)
|
||||
function_counter += 1
|
||||
register(self.session)
|
||||
except Exception as exc:
|
||||
msg = '"{}" - register was not successful ({})'.format(
|
||||
function_dict['name'], str(exc)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ class BaseAction(BaseHandler):
|
|||
icon = None
|
||||
type = 'Action'
|
||||
|
||||
def __init__(self, session, plugins_presets={}):
|
||||
settings_frack_subkey = "user_handlers"
|
||||
|
||||
def __init__(self, session):
|
||||
'''Expects a ftrack_api.Session instance'''
|
||||
if self.label is None:
|
||||
raise ValueError('Action missing label.')
|
||||
|
|
@ -37,7 +39,7 @@ class BaseAction(BaseHandler):
|
|||
if self.identifier is None:
|
||||
raise ValueError('Action missing identifier.')
|
||||
|
||||
super().__init__(session, plugins_presets)
|
||||
super().__init__(session)
|
||||
|
||||
def register(self):
|
||||
'''
|
||||
|
|
@ -67,6 +69,9 @@ class BaseAction(BaseHandler):
|
|||
|
||||
def _discover(self, event):
|
||||
entities = self._translate_event(event)
|
||||
if not entities:
|
||||
return
|
||||
|
||||
accepts = self.discover(self.session, entities, event)
|
||||
if not accepts:
|
||||
return
|
||||
|
|
@ -146,21 +151,18 @@ class BaseAction(BaseHandler):
|
|||
|
||||
def _launch(self, event):
|
||||
entities = self._translate_event(event)
|
||||
if not entities:
|
||||
return
|
||||
|
||||
preactions_launched = self._handle_preactions(self.session, event)
|
||||
if preactions_launched is False:
|
||||
return
|
||||
|
||||
interface = self._interface(
|
||||
self.session, entities, event
|
||||
)
|
||||
|
||||
interface = self._interface(self.session, entities, event)
|
||||
if interface:
|
||||
return interface
|
||||
|
||||
response = self.launch(
|
||||
self.session, entities, event
|
||||
)
|
||||
response = self.launch(self.session, entities, event)
|
||||
|
||||
return self._handle_result(response)
|
||||
|
||||
|
|
@ -196,50 +198,29 @@ class BaseAction(BaseHandler):
|
|||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def roles_check(settings_roles, user_roles, default=True):
|
||||
"""Compare roles from setting and user's roles.
|
||||
|
||||
class ServerAction(BaseAction):
|
||||
"""Action class meant to be used on event server.
|
||||
Args:
|
||||
settings_roles(list): List of role names from settings.
|
||||
user_roles(list): User's lowered role names.
|
||||
default(bool): If `settings_roles` is empty list.
|
||||
|
||||
Unlike the `BaseAction` roles are not checked on register but on discover.
|
||||
For the same reason register is modified to not filter topics by username.
|
||||
"""
|
||||
Returns:
|
||||
bool: `True` if user has at least one role from settings or
|
||||
default if `settings_roles` is empty.
|
||||
"""
|
||||
if not settings_roles:
|
||||
return default
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if not self.role_list:
|
||||
self.role_list = set()
|
||||
else:
|
||||
self.role_list = set(
|
||||
role_name.lower()
|
||||
for role_name in self.role_list
|
||||
)
|
||||
super(ServerAction, self).__init__(*args, **kwargs)
|
||||
|
||||
def _register_role_check(self):
|
||||
# Skip register role check.
|
||||
return
|
||||
|
||||
def _discover(self, event):
|
||||
"""Check user discover availability."""
|
||||
if not self._check_user_discover(event):
|
||||
return
|
||||
return super(ServerAction, self)._discover(event)
|
||||
|
||||
def _check_user_discover(self, event):
|
||||
"""Should be action discovered by user trying to show actions."""
|
||||
if not self.role_list:
|
||||
return True
|
||||
|
||||
user_entity = self._get_user_entity(event)
|
||||
if not user_entity:
|
||||
return False
|
||||
|
||||
for role in user_entity["user_security_roles"]:
|
||||
lowered_role = role["security_role"]["name"].lower()
|
||||
if lowered_role in self.role_list:
|
||||
for role_name in settings_roles:
|
||||
if role_name.lower() in user_roles:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_user_entity(self, event):
|
||||
@classmethod
|
||||
def get_user_entity_from_event(cls, session, event):
|
||||
"""Query user entity from event."""
|
||||
not_set = object()
|
||||
|
||||
|
|
@ -251,17 +232,88 @@ class ServerAction(BaseAction):
|
|||
user_id = user_info.get("id")
|
||||
username = user_info.get("username")
|
||||
if user_id:
|
||||
user_entity = self.session.query(
|
||||
user_entity = session.query(
|
||||
"User where id is {}".format(user_id)
|
||||
).first()
|
||||
if not user_entity and username:
|
||||
user_entity = self.session.query(
|
||||
user_entity = session.query(
|
||||
"User where username is {}".format(username)
|
||||
).first()
|
||||
event["data"]["user_entity"] = user_entity
|
||||
|
||||
return user_entity
|
||||
|
||||
@classmethod
|
||||
def get_user_roles_from_event(cls, session, event):
|
||||
"""Query user entity from event."""
|
||||
not_set = object()
|
||||
|
||||
user_roles = event["data"].get("user_roles", not_set)
|
||||
if user_roles is not_set:
|
||||
user_roles = []
|
||||
user_entity = cls.get_user_entity_from_event(session, event)
|
||||
for role in user_entity["user_security_roles"]:
|
||||
user_roles.append(role["security_role"]["name"].lower())
|
||||
event["data"]["user_roles"] = user_roles
|
||||
return user_roles
|
||||
|
||||
def get_project_entity_from_event(self, session, event, entities):
|
||||
"""Load or query and fill project entity from/to event data.
|
||||
|
||||
Project data are stored by ftrack id because in most cases it is
|
||||
easier to access project id than project name.
|
||||
|
||||
Args:
|
||||
session (ftrack_api.Session): Current session.
|
||||
event (ftrack_api.Event): Processed event by session.
|
||||
entities (list): Ftrack entities of selection.
|
||||
"""
|
||||
|
||||
# Try to get project entity from event
|
||||
project_entity = event["data"].get("project_entity")
|
||||
if not project_entity:
|
||||
project_entity = self.get_project_from_entity(
|
||||
entities[0], session
|
||||
)
|
||||
event["data"]["project_entity"] = project_entity
|
||||
return project_entity
|
||||
|
||||
def get_ftrack_settings(self, session, event, entities):
|
||||
project_entity = self.get_project_entity_from_event(
|
||||
session, event, entities
|
||||
)
|
||||
project_settings = self.get_project_settings_from_event(
|
||||
event, project_entity
|
||||
)
|
||||
return project_settings["ftrack"]
|
||||
|
||||
def valid_roles(self, session, entities, event):
|
||||
"""Validate user roles by settings.
|
||||
|
||||
Method requires to have set `settings_key` attribute.
|
||||
"""
|
||||
ftrack_settings = self.get_ftrack_settings(session, event, entities)
|
||||
settings = (
|
||||
ftrack_settings[self.settings_frack_subkey][self.settings_key]
|
||||
)
|
||||
if not settings.get("enabled", True):
|
||||
return False
|
||||
|
||||
user_role_list = self.get_user_roles_from_event(session, event)
|
||||
if not self.roles_check(settings.get("role_list"), user_role_list):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class ServerAction(BaseAction):
|
||||
"""Action class meant to be used on event server.
|
||||
|
||||
Unlike the `BaseAction` roles are not checked on register but on discover.
|
||||
For the same reason register is modified to not filter topics by username.
|
||||
"""
|
||||
|
||||
settings_frack_subkey = "events"
|
||||
|
||||
def register(self):
|
||||
"""Register subcription to Ftrack event hub."""
|
||||
self.session.event_hub.subscribe(
|
||||
|
|
|
|||
|
|
@ -37,14 +37,13 @@ class BaseHandler(object):
|
|||
type = 'No-type'
|
||||
ignore_me = False
|
||||
preactions = []
|
||||
role_list = []
|
||||
|
||||
@staticmethod
|
||||
def join_query_keys(keys):
|
||||
"""Helper to join keys to query."""
|
||||
return ",".join(["\"{}\"".format(key) for key in keys])
|
||||
|
||||
def __init__(self, session, plugins_presets=None):
|
||||
def __init__(self, session):
|
||||
'''Expects a ftrack_api.Session instance'''
|
||||
self.log = Logger().get_logger(self.__class__.__name__)
|
||||
if not(
|
||||
|
|
@ -65,31 +64,19 @@ class BaseHandler(object):
|
|||
# Using decorator
|
||||
self.register = self.register_decorator(self.register)
|
||||
self.launch = self.launch_log(self.launch)
|
||||
if plugins_presets is None:
|
||||
plugins_presets = {}
|
||||
self.plugins_presets = plugins_presets
|
||||
|
||||
# Decorator
|
||||
def register_decorator(self, func):
|
||||
@functools.wraps(func)
|
||||
def wrapper_register(*args, **kwargs):
|
||||
|
||||
presets_data = self.plugins_presets.get(self.__class__.__name__)
|
||||
if presets_data:
|
||||
for key, value in presets_data.items():
|
||||
if not hasattr(self, key):
|
||||
continue
|
||||
setattr(self, key, value)
|
||||
|
||||
if self.ignore_me:
|
||||
return
|
||||
|
||||
label = self.__class__.__name__
|
||||
if hasattr(self, 'label'):
|
||||
if self.variant is None:
|
||||
label = self.label
|
||||
else:
|
||||
label = '{} {}'.format(self.label, self.variant)
|
||||
label = getattr(self, "label", self.__class__.__name__)
|
||||
variant = getattr(self, "variant", None)
|
||||
if variant:
|
||||
label = "{} {}".format(label, variant)
|
||||
|
||||
try:
|
||||
self._preregister()
|
||||
|
||||
|
|
@ -126,12 +113,10 @@ class BaseHandler(object):
|
|||
def launch_log(self, func):
|
||||
@functools.wraps(func)
|
||||
def wrapper_launch(*args, **kwargs):
|
||||
label = self.__class__.__name__
|
||||
if hasattr(self, 'label'):
|
||||
label = self.label
|
||||
if hasattr(self, 'variant'):
|
||||
if self.variant is not None:
|
||||
label = '{} {}'.format(self.label, self.variant)
|
||||
label = getattr(self, "label", self.__class__.__name__)
|
||||
variant = getattr(self, "variant", None)
|
||||
if variant:
|
||||
label = "{} {}".format(label, variant)
|
||||
|
||||
self.log.info(('{} "{}": Launched').format(self.type, label))
|
||||
try:
|
||||
|
|
@ -156,28 +141,7 @@ class BaseHandler(object):
|
|||
def reset_session(self):
|
||||
self.session.reset()
|
||||
|
||||
def _register_role_check(self):
|
||||
if not self.role_list or not isinstance(self.role_list, (list, tuple)):
|
||||
return
|
||||
|
||||
user_entity = self.session.query(
|
||||
"User where username is \"{}\"".format(self.session.api_user)
|
||||
).one()
|
||||
available = False
|
||||
lowercase_rolelist = [
|
||||
role_name.lower()
|
||||
for role_name in self.role_list
|
||||
]
|
||||
for role in user_entity["user_security_roles"]:
|
||||
if role["security_role"]["name"].lower() in lowercase_rolelist:
|
||||
available = True
|
||||
break
|
||||
if available is False:
|
||||
raise MissingPermision
|
||||
|
||||
def _preregister(self):
|
||||
self._register_role_check()
|
||||
|
||||
# Custom validations
|
||||
result = self.preregister()
|
||||
if result is None:
|
||||
|
|
@ -564,7 +528,7 @@ class BaseHandler(object):
|
|||
"Publishing event: {}"
|
||||
).format(str(event.__dict__)))
|
||||
|
||||
def get_project_from_entity(self, entity):
|
||||
def get_project_from_entity(self, entity, session=None):
|
||||
low_entity_type = entity.entity_type.lower()
|
||||
if low_entity_type == "project":
|
||||
return entity
|
||||
|
|
@ -585,61 +549,30 @@ class BaseHandler(object):
|
|||
return parent["project"]
|
||||
|
||||
project_data = entity["link"][0]
|
||||
return self.session.query(
|
||||
|
||||
if session is None:
|
||||
session = self.session
|
||||
return session.query(
|
||||
"Project where id is {}".format(project_data["id"])
|
||||
).one()
|
||||
|
||||
def get_project_entity_from_event(self, session, event, project_id):
|
||||
"""Load or query and fill project entity from/to event data.
|
||||
|
||||
Project data are stored by ftrack id because in most cases it is
|
||||
easier to access project id than project name.
|
||||
|
||||
Args:
|
||||
session (ftrack_api.Session): Current session.
|
||||
event (ftrack_api.Event): Processed event by session.
|
||||
project_id (str): Ftrack project id.
|
||||
"""
|
||||
if not project_id:
|
||||
raise ValueError(
|
||||
"Entered `project_id` is not valid. {} ({})".format(
|
||||
str(project_id), str(type(project_id))
|
||||
)
|
||||
)
|
||||
# Try to get project entity from event
|
||||
project_entities = event["data"].get("project_entities")
|
||||
if not project_entities:
|
||||
project_entities = {}
|
||||
event["data"]["project_entities"] = project_entities
|
||||
|
||||
project_entity = project_entities.get(project_id)
|
||||
if not project_entity:
|
||||
# Get project entity from task and store to event
|
||||
project_entity = session.get("Project", project_id)
|
||||
event["data"]["project_entities"][project_id] = project_entity
|
||||
return project_entity
|
||||
|
||||
def get_settings_for_project(
|
||||
self, session, event, project_id=None, project_entity=None
|
||||
):
|
||||
def get_project_settings_from_event(self, event, project_entity):
|
||||
"""Load or fill pype's project settings from event data.
|
||||
|
||||
Project data are stored by ftrack id because in most cases it is
|
||||
easier to access project id than project name.
|
||||
|
||||
Args:
|
||||
session (ftrack_api.Session): Current session.
|
||||
event (ftrack_api.Event): Processed event by session.
|
||||
project_id (str): Ftrack project id. Must be entered if
|
||||
project_entity is not.
|
||||
project_entity (ftrack_api.Entity): Project entity. Must be entered
|
||||
if project_id is not.
|
||||
project_entity (ftrack_api.Entity): Project entity.
|
||||
"""
|
||||
if not project_entity:
|
||||
project_entity = self.get_project_entity_from_event(
|
||||
session, event, project_id
|
||||
)
|
||||
raise AssertionError((
|
||||
"Invalid arguments entered. Project entity or project id"
|
||||
"must be entered."
|
||||
))
|
||||
|
||||
project_id = project_entity["id"]
|
||||
project_name = project_entity["full_name"]
|
||||
|
||||
project_settings_by_id = event["data"].get("project_settings")
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ class BaseEvent(BaseHandler):
|
|||
|
||||
type = 'Event'
|
||||
|
||||
def __init__(self, session, plugins_presets={}):
|
||||
'''Expects a ftrack_api.Session instance'''
|
||||
super().__init__(session, plugins_presets)
|
||||
|
||||
# Decorator
|
||||
def launch_log(self, func):
|
||||
@functools.wraps(func)
|
||||
|
|
@ -50,3 +46,33 @@ class BaseEvent(BaseHandler):
|
|||
session,
|
||||
ignore=['socialfeed', 'socialnotification']
|
||||
)
|
||||
|
||||
def get_project_entity_from_event(self, session, event, project_id):
|
||||
"""Load or query and fill project entity from/to event data.
|
||||
|
||||
Project data are stored by ftrack id because in most cases it is
|
||||
easier to access project id than project name.
|
||||
|
||||
Args:
|
||||
session (ftrack_api.Session): Current session.
|
||||
event (ftrack_api.Event): Processed event by session.
|
||||
project_id (str): Ftrack project id.
|
||||
"""
|
||||
if not project_id:
|
||||
raise ValueError(
|
||||
"Entered `project_id` is not valid. {} ({})".format(
|
||||
str(project_id), str(type(project_id))
|
||||
)
|
||||
)
|
||||
# Try to get project entity from event
|
||||
project_entities = event["data"].get("project_entities")
|
||||
if not project_entities:
|
||||
project_entities = {}
|
||||
event["data"]["project_entities"] = project_entities
|
||||
|
||||
project_entity = project_entities.get(project_id)
|
||||
if not project_entity:
|
||||
# Get project entity from task and store to event
|
||||
project_entity = session.get("Project", project_id)
|
||||
event["data"]["project_entities"][project_id] = project_entity
|
||||
return project_entity
|
||||
|
|
|
|||
6
pype/modules/log_viewer/__init__.py
Normal file
6
pype/modules/log_viewer/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from .log_view_module import LogViewModule
|
||||
|
||||
|
||||
__all__ = (
|
||||
"LogViewModule",
|
||||
)
|
||||
|
|
@ -2,7 +2,7 @@ from pype.api import Logger
|
|||
from .. import PypeModule, ITrayModule
|
||||
|
||||
|
||||
class LoggingModule(PypeModule, ITrayModule):
|
||||
class LogViewModule(PypeModule, ITrayModule):
|
||||
name = "log_viewer"
|
||||
|
||||
def initialize(self, modules_settings):
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
from .logging_module import LoggingModule
|
||||
|
||||
|
||||
__all__ = (
|
||||
"LoggingModule",
|
||||
)
|
||||
|
|
@ -6,6 +6,9 @@ import tempfile
|
|||
|
||||
import pype.api
|
||||
import pyblish
|
||||
from pype.lib import should_decompress, \
|
||||
get_decompress_dir, decompress
|
||||
import shutil
|
||||
|
||||
|
||||
class ExtractBurnin(pype.api.Extractor):
|
||||
|
|
@ -28,7 +31,8 @@ class ExtractBurnin(pype.api.Extractor):
|
|||
"premiere",
|
||||
"standalonepublisher",
|
||||
"harmony",
|
||||
"fusion"
|
||||
"fusion",
|
||||
"aftereffects"
|
||||
]
|
||||
optional = True
|
||||
|
||||
|
|
@ -204,6 +208,26 @@ class ExtractBurnin(pype.api.Extractor):
|
|||
# Prepare paths and files for process.
|
||||
self.input_output_paths(new_repre, temp_data, filename_suffix)
|
||||
|
||||
decompressed_dir = ''
|
||||
full_input_path = temp_data["full_input_path"]
|
||||
do_decompress = should_decompress(full_input_path)
|
||||
if do_decompress:
|
||||
decompressed_dir = get_decompress_dir()
|
||||
|
||||
decompress(
|
||||
decompressed_dir,
|
||||
full_input_path,
|
||||
temp_data["frame_start"],
|
||||
temp_data["frame_end"],
|
||||
self.log
|
||||
)
|
||||
|
||||
# input path changed, 'decompressed' added
|
||||
input_file = os.path.basename(full_input_path)
|
||||
temp_data["full_input_path"] = os.path.join(
|
||||
decompressed_dir,
|
||||
input_file)
|
||||
|
||||
# Data for burnin script
|
||||
script_data = {
|
||||
"input": temp_data["full_input_path"],
|
||||
|
|
@ -263,6 +287,9 @@ class ExtractBurnin(pype.api.Extractor):
|
|||
os.remove(filepath)
|
||||
self.log.debug("Removed: \"{}\"".format(filepath))
|
||||
|
||||
if do_decompress and os.path.exists(decompressed_dir):
|
||||
shutil.rmtree(decompressed_dir)
|
||||
|
||||
def prepare_basic_data(self, instance):
|
||||
"""Pick data from instance for processing and for burnin strings.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import os
|
|||
import pyblish.api
|
||||
import pype.api
|
||||
import pype.lib
|
||||
from pype.lib import should_decompress, \
|
||||
get_decompress_dir, decompress
|
||||
import shutil
|
||||
|
||||
|
||||
class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
||||
|
|
@ -22,7 +25,8 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
if 'crypto' in instance.data['subset']:
|
||||
return
|
||||
|
||||
# ffmpeg doesn't support multipart exrs
|
||||
do_decompress = False
|
||||
# ffmpeg doesn't support multipart exrs, use oiiotool if available
|
||||
if instance.data.get("multipartExr") is True:
|
||||
return
|
||||
|
||||
|
|
@ -36,10 +40,6 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
# filter out mov and img sequences
|
||||
representations_new = representations[:]
|
||||
|
||||
if instance.data.get("multipartExr"):
|
||||
# ffmpeg doesn't support multipart exrs
|
||||
return
|
||||
|
||||
for repre in representations:
|
||||
tags = repre.get("tags", [])
|
||||
self.log.debug(repre)
|
||||
|
|
@ -60,6 +60,19 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
full_input_path = os.path.join(stagingdir, input_file)
|
||||
self.log.info("input {}".format(full_input_path))
|
||||
|
||||
decompressed_dir = ''
|
||||
do_decompress = should_decompress(full_input_path)
|
||||
if do_decompress:
|
||||
decompressed_dir = get_decompress_dir()
|
||||
|
||||
decompress(
|
||||
decompressed_dir,
|
||||
full_input_path)
|
||||
# input path changed, 'decompressed' added
|
||||
full_input_path = os.path.join(
|
||||
decompressed_dir,
|
||||
input_file)
|
||||
|
||||
filename = os.path.splitext(input_file)[0]
|
||||
if not filename.endswith('.'):
|
||||
filename += "."
|
||||
|
|
@ -93,7 +106,14 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
|
||||
# run subprocess
|
||||
self.log.debug("{}".format(subprocess_jpeg))
|
||||
pype.api.subprocess(subprocess_jpeg, shell=True)
|
||||
try: # temporary until oiiotool is supported cross platform
|
||||
pype.api.subprocess(subprocess_jpeg, shell=True)
|
||||
except RuntimeError as exp:
|
||||
if "Compression" in str(exp):
|
||||
self.log.debug("Unsupported compression on input files. " +
|
||||
"Skipping!!!")
|
||||
return
|
||||
raise
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
|
@ -111,4 +131,7 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
self.log.debug("Adding: {}".format(representation))
|
||||
representations_new.append(representation)
|
||||
|
||||
if do_decompress and os.path.exists(decompressed_dir):
|
||||
shutil.rmtree(decompressed_dir)
|
||||
|
||||
instance.data["representations"] = representations_new
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import pyblish.api
|
|||
import clique
|
||||
import pype.api
|
||||
import pype.lib
|
||||
from pype.lib import should_decompress, \
|
||||
get_decompress_dir, decompress
|
||||
|
||||
|
||||
class ExtractReview(pyblish.api.InstancePlugin):
|
||||
|
|
@ -14,7 +16,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
Compulsory attribute of representation is tags list with "review",
|
||||
otherwise the representation is ignored.
|
||||
|
||||
All new represetnations are created and encoded by ffmpeg following
|
||||
All new representations are created and encoded by ffmpeg following
|
||||
presets found in `pype-config/presets/plugins/global/
|
||||
publish.json:ExtractReview:outputs`.
|
||||
"""
|
||||
|
|
@ -188,9 +190,17 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
temp_data = self.prepare_temp_data(instance, repre, output_def)
|
||||
|
||||
ffmpeg_args = self._ffmpeg_arguments(
|
||||
output_def, instance, new_repre, temp_data
|
||||
)
|
||||
try: # temporary until oiiotool is supported cross platform
|
||||
ffmpeg_args = self._ffmpeg_arguments(
|
||||
output_def, instance, new_repre, temp_data
|
||||
)
|
||||
except ZeroDivisionError:
|
||||
if 'exr' in temp_data["origin_repre"]["ext"]:
|
||||
self.log.debug("Unsupported compression on input " +
|
||||
"files. Skipping!!!")
|
||||
return
|
||||
raise
|
||||
|
||||
subprcs_cmd = " ".join(ffmpeg_args)
|
||||
|
||||
# run subprocess
|
||||
|
|
@ -318,9 +328,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
Args:
|
||||
output_def (dict): Currently processed output definition.
|
||||
instance (Instance): Currently processed instance.
|
||||
new_repre (dict): Reprensetation representing output of this
|
||||
new_repre (dict): Representation representing output of this
|
||||
process.
|
||||
temp_data (dict): Base data for successfull process.
|
||||
temp_data (dict): Base data for successful process.
|
||||
"""
|
||||
|
||||
# Get FFmpeg arguments from profile presets
|
||||
|
|
@ -331,9 +341,35 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
ffmpeg_video_filters = out_def_ffmpeg_args.get("video_filters") or []
|
||||
ffmpeg_audio_filters = out_def_ffmpeg_args.get("audio_filters") or []
|
||||
|
||||
if isinstance(new_repre['files'], list):
|
||||
input_files_urls = [os.path.join(new_repre["stagingDir"], f) for f
|
||||
in new_repre['files']]
|
||||
test_path = input_files_urls[0]
|
||||
else:
|
||||
test_path = os.path.join(
|
||||
new_repre["stagingDir"], new_repre['files'])
|
||||
do_decompress = should_decompress(test_path)
|
||||
|
||||
if do_decompress:
|
||||
# change stagingDir, decompress first
|
||||
# calculate all paths with modified directory, used on too many
|
||||
# places
|
||||
# will be purged by cleanup.py automatically
|
||||
orig_staging_dir = new_repre["stagingDir"]
|
||||
new_repre["stagingDir"] = get_decompress_dir()
|
||||
|
||||
# Prepare input and output filepaths
|
||||
self.input_output_paths(new_repre, output_def, temp_data)
|
||||
|
||||
if do_decompress:
|
||||
input_file = temp_data["full_input_path"].\
|
||||
replace(new_repre["stagingDir"], orig_staging_dir)
|
||||
|
||||
decompress(new_repre["stagingDir"], input_file,
|
||||
temp_data["frame_start"],
|
||||
temp_data["frame_end"],
|
||||
self.log)
|
||||
|
||||
# Set output frames len to 1 when ouput is single image
|
||||
if (
|
||||
temp_data["output_ext_is_image"]
|
||||
|
|
@ -930,7 +966,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
return regexes
|
||||
|
||||
def validate_value_by_regexes(self, value, in_list):
|
||||
"""Validates in any regexe from list match entered value.
|
||||
"""Validates in any regex from list match entered value.
|
||||
|
||||
Args:
|
||||
in_list (list): List with regexes.
|
||||
|
|
@ -955,9 +991,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
def profile_exclusion(self, matching_profiles):
|
||||
"""Find out most matching profile byt host, task and family match.
|
||||
|
||||
Profiles are selectivelly filtered. Each profile should have
|
||||
Profiles are selectively filtered. Each profile should have
|
||||
"__value__" key with list of booleans. Each boolean represents
|
||||
existence of filter for specific key (host, taks, family).
|
||||
existence of filter for specific key (host, tasks, 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.
|
||||
|
|
@ -1036,7 +1072,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
highest_profile_points = -1
|
||||
# Each profile get 1 point for each matching filter. Profile with most
|
||||
# points is returnd. For cases when more than one profile will match
|
||||
# points is returned. For cases when more than one profile will match
|
||||
# are also stored ordered lists of matching values.
|
||||
for profile in self.profiles:
|
||||
profile_points = 0
|
||||
|
|
@ -1648,7 +1684,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
def add_video_filter_args(self, args, inserting_arg):
|
||||
"""
|
||||
Fixing video filter argumets to be one long string
|
||||
Fixing video filter arguments to be one long string
|
||||
|
||||
Args:
|
||||
args (list): list of string arguments
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from avalon import io
|
|||
from avalon.vendor import filelink
|
||||
import pype.api
|
||||
from datetime import datetime
|
||||
from pype.modules import ModulesManager
|
||||
# from pype.modules import ModulesManager
|
||||
|
||||
# this is needed until speedcopy for linux is fixed
|
||||
if sys.platform == "win32":
|
||||
|
|
@ -933,15 +933,15 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
remote_site = None
|
||||
sync_server_presets = None
|
||||
|
||||
manager = ModulesManager()
|
||||
sync_server = manager.modules_by_name["sync_server"]
|
||||
try:
|
||||
if sync_server.enabled:
|
||||
local_site, remote_site = sync_server.get_sites_for_project()
|
||||
except ValueError:
|
||||
log.debug(("There are not set presets for SyncServer."
|
||||
" No credentials provided, no synching possible").
|
||||
format(str(sync_server_presets)))
|
||||
# manager = ModulesManager()
|
||||
# sync_server = manager.modules_by_name["sync_server"]
|
||||
# try:
|
||||
# if sync_server.enabled:
|
||||
# local_site, remote_site = sync_server.get_sites_for_project()
|
||||
# except ValueError:
|
||||
# log.debug(("There are not set presets for SyncServer."
|
||||
# " No credentials provided, no synching possible").
|
||||
# format(str(sync_server_presets)))
|
||||
|
||||
rec = {
|
||||
"_id": io.ObjectId(),
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ class CreateRender(avalon.maya.Creator):
|
|||
self.data["tilesX"] = 2
|
||||
self.data["tilesY"] = 2
|
||||
self.data["convertToScanline"] = False
|
||||
self.data["vrayUseReferencedAovs"] = False
|
||||
# Disable for now as this feature is not working yet
|
||||
# self.data["assScene"] = False
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
|
||||
# return all expected files for all cameras and aovs in given
|
||||
# frame range
|
||||
ef = ExpectedFiles()
|
||||
ef = ExpectedFiles(render_instance)
|
||||
exp_files = ef.get(renderer, layer_name)
|
||||
self.log.info("multipart: {}".format(ef.multipart))
|
||||
assert exp_files, "no file names were generated, this is bug"
|
||||
|
|
@ -248,7 +248,8 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
"tilesX": render_instance.data.get("tilesX") or 2,
|
||||
"tilesY": render_instance.data.get("tilesY") or 2,
|
||||
"priority": render_instance.data.get("priority"),
|
||||
"convertToScanline": render_instance.data.get("convertToScanline") or False # noqa: E501
|
||||
"convertToScanline": render_instance.data.get("convertToScanline") or False, # noqa: E501
|
||||
"vrayUseReferencedAovs": render_instance.data.get("vrayUseReferencedAovs") or False # noqa: E501
|
||||
}
|
||||
|
||||
if self.sync_workfile_version:
|
||||
|
|
|
|||
90
pype/plugins/maya/publish/validate_vray_referenced_aovs.py
Normal file
90
pype/plugins/maya/publish/validate_vray_referenced_aovs.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Validate if there are AOVs pulled from references."""
|
||||
import pyblish.api
|
||||
import types
|
||||
from maya import cmds
|
||||
|
||||
import pype.hosts.maya.action
|
||||
|
||||
|
||||
class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin):
|
||||
"""Validate whether the V-Ray Render Elements (AOVs) include references.
|
||||
|
||||
This will check if there are AOVs pulled from references. If
|
||||
`Vray Use Referenced Aovs` is checked on render instance, u must add those
|
||||
manually to Render Elements as Pype will expect them to be rendered.
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
label = 'VRay Referenced AOVs'
|
||||
hosts = ['maya']
|
||||
families = ['renderlayer']
|
||||
actions = [pype.api.RepairContextAction]
|
||||
|
||||
def process(self, instance):
|
||||
"""Plugin main entry point."""
|
||||
if instance.data.get("renderer") != "vray":
|
||||
# If not V-Ray ignore..
|
||||
return
|
||||
|
||||
ref_aovs = cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"],
|
||||
referencedNodes=True)
|
||||
ref_aovs_enabled = ValidateVrayReferencedAOVs.maya_is_true(
|
||||
cmds.getAttr("vraySettings.relements_usereferenced"))
|
||||
|
||||
if not instance.data.get("vrayUseReferencedAovs"):
|
||||
if ref_aovs_enabled and ref_aovs:
|
||||
self.log.warning((
|
||||
"Referenced AOVs are enabled in Vray "
|
||||
"Render Settings and are detected in scene, but "
|
||||
"Pype render instance option for referenced AOVs is "
|
||||
"disabled. Those AOVs will be rendered but not published "
|
||||
"by Pype."
|
||||
))
|
||||
self.log.warning(", ".join(ref_aovs))
|
||||
else:
|
||||
if not ref_aovs:
|
||||
self.log.warning((
|
||||
"Use of referenced AOVs enabled but there are none "
|
||||
"in the scene."
|
||||
))
|
||||
if not ref_aovs_enabled:
|
||||
self.log.error((
|
||||
"'Use referenced' not enabled in Vray Render Settings."
|
||||
))
|
||||
raise AssertionError("Invalid render settings")
|
||||
|
||||
@classmethod
|
||||
def repair(cls, context):
|
||||
"""Repair action."""
|
||||
vray_settings = cmds.ls(type="VRaySettingsNode")
|
||||
if not vray_settings:
|
||||
node = cmds.createNode("VRaySettingsNode")
|
||||
else:
|
||||
node = vray_settings[0]
|
||||
|
||||
cmds.setAttr("{}.relements_usereferenced".format(node), True)
|
||||
|
||||
@staticmethod
|
||||
def maya_is_true(attr_val):
|
||||
"""Whether a Maya attr evaluates to True.
|
||||
|
||||
When querying an attribute value from an ambiguous object the
|
||||
Maya API will return a list of values, which need to be properly
|
||||
handled to evaluate properly.
|
||||
|
||||
Args:
|
||||
attr_val (mixed): Maya attribute to be evaluated as bool.
|
||||
|
||||
Returns:
|
||||
bool: cast Maya attribute to Pythons boolean value.
|
||||
|
||||
"""
|
||||
if isinstance(attr_val, types.BooleanType):
|
||||
return attr_val
|
||||
elif isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
return any(attr_val)
|
||||
else:
|
||||
return bool(attr_val)
|
||||
|
|
@ -97,13 +97,11 @@
|
|||
"ignored_statuses": [
|
||||
"In Progress",
|
||||
"Omitted",
|
||||
"On hold"
|
||||
"On hold",
|
||||
"Approved"
|
||||
],
|
||||
"status_change": {
|
||||
"In Progress": [],
|
||||
"Ready": [
|
||||
"Not Ready"
|
||||
]
|
||||
"In Progress": []
|
||||
}
|
||||
},
|
||||
"create_update_attributes": {
|
||||
|
|
@ -170,7 +168,8 @@
|
|||
"sync_to_avalon_local": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub"
|
||||
"Pypeclub",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"seed_project": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue