Skip to content

Commit

Permalink
Merge pull request #4 from TheFoundryVisionmongers/feature/shotgun_re…
Browse files Browse the repository at this point in the history
…nder_script

Adding publish script to run at end of render jobs
  • Loading branch information
JamesPedFoundry authored May 7, 2019
2 parents 25662ce + da951b8 commit 76ef3c4
Show file tree
Hide file tree
Showing 32 changed files with 1,698 additions and 1,065 deletions.
142 changes: 93 additions & 49 deletions engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,34 @@ def context_change_allowed(self):
def init_engine(self):
self.katana_log = logging.getLogger("Shotgun Katana Engine")
self.log_debug("%s: Initializing..." % self)
self._dialog_parent = None
self.menu_name = "Shotgun"
self._menu_generator = None
self._dialogParent = None
self.menuName = "Shotgun"
self._menuGenerator = None
if self.get_setting("use_sgtk_as_menu_name", False):
self.menu_name = "Sgtk"
# import the shotgun_fields module from the framework
# tk-framework-qtwidgets = self.import_module("tk-framework-qtwidgets")
# print tk-framework-qtwidgets
# context_selector = tank.platform.import_framework(
# "tk-framework-qtwidgets", "context_selector")

# print "Imported context selector...", self.frameworks
self.menuName = "Sgtk"
if self.get_setting("automatic_context_switch", True):
# need to watch some scene events in case the engine needs
# rebuilding:
filechange_cb = lambda \
fileChangeCb = lambda \
objectHash=None, \
filename=None, \
instance_name=self.instance_name,\
prev_context=self.context, \
menu_name=self.menu_name: refresh_engine(
instance_name,
prev_context,
menu_name
instanceName=self.instance_name,\
prevContext=self.context, \
menuName=self.menuName: refresh_engine(
instanceName,
prevContext,
menuName
)
Callbacks.addCallback(Callbacks.Type.onSceneLoad, filechange_cb)
Callbacks.addCallback(Callbacks.Type.onSceneSave, filechange_cb)
Callbacks.addCallback(Callbacks.Type.onSceneLoad, fileChangeCb)
Callbacks.addCallback(Callbacks.Type.onSceneSave, fileChangeCb)

def show_dialog(self, title, bundle, widget_class, *args, **kwargs):
# This is some nastyness required because we cant import
# tk_multi_workfiles.file_save_form, as its not part of the workfiles
# module...
if self._dialog_parent:
widget = widget_class(parent=self._dialog_parent)
self._dialog_parent.layout().addWidget(widget)
if self._dialogParent:
widget = widget_class(parent=self._dialogParent)
self._dialogParent.layout().addWidget(widget)
return widget
else:
return super(KatanaEngine, self).show_dialog(
Expand All @@ -69,7 +62,7 @@ def set_dialog_parent(self, dialog_parent):
# This is some nastyness required because we cant import
# tk_multi_workfiles.file_save_form, as its not part of the workfiles
# module...
self._dialog_parent = dialog_parent
self._dialogParent = dialog_parent

def __define_qt5_base(self):
return self._define_qt_base()
Expand All @@ -94,6 +87,9 @@ def __getattr__(self, name):
try:
from PyQt5 import QtCore, QtGui, QtWidgets
import PyQt5
# Katana uses PyQt for its widgets, whereas shotgun widgets are
# tested for use with PySide. Therefore we have to implement a few
# patches where PySide is a little more forgiving than PyQt.

class QPyTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
# PyQt5 does not provide QPyTextObject as it is not necessary
Expand All @@ -102,7 +98,6 @@ class QPyTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
# it uses.
# https://docs.huihoo.com/pyqt/PyQt5/pyqt4_differences.html#qpytextobject
pass

QtCore, QtGui = PySide2Patcher.patch(
QtCore,
QtGui,
Expand Down Expand Up @@ -220,21 +215,21 @@ def add_katana_menu(self, objectHash=None):
tk_katana = self.import_module("tk_katana")
self.log_info("Start creating shotgun menu.")
try:
self._menu_generator = tk_katana.MenuGenerator(
self._menuGenerator = tk_katana.MenuGenerator(
self,
self.menu_name
self.menuName
)
self._menu_generator.create_menu()
self._menuGenerator.create_menu()
except:
traceback.print_exc()

def refresh_katana_menu(self):
'''
Refresh the Katana menu for the current context.
'''
if self._menu_generator:
if self._menuGenerator:
self.log_info("Updating shotgun menu.")
self._menu_generator.populate_menu()
self._menuGenerator.populate_menu()

def post_app_init(self):
# Add the katana menu once the apps have loaded.
Expand Down Expand Up @@ -266,42 +261,91 @@ def log_warning(self, msg):
def has_qt5(self):
return True

def getTemplateFromContext(
self,
context,
isFolder=None,
isPublish=None,
isScene=None
):
""" Based on our configuration setup, we can get the relevant katana
based templates from a context and then whether we want the folder,
scene, work or publish, template.
"""
tkCore = self.sgtk
templateKeys = tkCore.templates.keys()
allTemplateNames = [k for k in templateKeys if "katana" in k]
template_context_name = ""
templatePrefix = "katana_"
templateSuffix = "_work"
if isFolder:
templatePrefix = templatePrefix+"folder_"
if isScene:
templatePrefix = templatePrefix+"scene_"
if isPublish:
templateSuffix = "_publish"
if context.entity is None:
return self.get_template_by_name("katana_project_work")
elif context.entity:
templateEntityName = context.entity["type"].lower()
if context.step:
templateContextStep = context.step["type"].lower()
template = self.get_template_by_name(
"{0}{1}_{2}{3}".format(
templatePrefix,
templateEntityName,
templateContextStep,
templateSuffix
)
)
if template:
return template
return self.get_template_by_name(
"{0}{1}{2}".format(
templatePrefix,
templateEntityName,
templateSuffix
)
)


def refresh_engine(engine_name, prev_context, menu_name):
def refresh_engine(engineName, prevContext, menuName):
"""
refresh the current engine
Refresh the current engine, this will also set a new context based on the
current Katana scene path. If the current Katana scene path does not
belong to Shotgun, we set to the context to the base project level from
the previous context.
"""
current_engine = tank.platform.current_engine()
currentEngine = tank.platform.current_engine()
logger = logging.getLogger("Shotgun Katana Engine")

if not current_engine:
if not currentEngine:
return
new_path = NodegraphAPI.GetSourceFile()
tk = current_engine.sgtk
newPath = NodegraphAPI.GetSourceFile()
tk = currentEngine.sgtk
ctx = None
if not new_path:
if prev_context:
project_entity = prev_context.project
if not newPath:
if prevContext:
projectEntity = prevContext.project
ctx = tk.context_from_entity(
project_entity["type"],
project_entity["id"]
projectEntity["type"],
projectEntity["id"]
)
else:
return
else:
try:
tk = tank.tank_from_path(new_path)
tk = tank.tank_from_path(newPath)
except tank.TankError, e:
current_engine.log_warning(
currentEngine.log_warning(
"Unable to instantiate shotgun toolkit "
"from path {0}".format(new_path)
"from path {0}".format(newPath)
)
return
ctx = tk.context_from_path(new_path, prev_context)
ctx = tk.context_from_path(newPath, prevContext)

if ctx and ctx != tank.platform.current_engine().context:
current_engine.log_info("Changing context to: {0}".format(ctx))
current_engine.change_context(ctx)

current_engine.refresh_katana_menu()
currentEngine.log_info("Changing context to: {0}".format(ctx))
currentEngine.change_context(ctx)

currentEngine.refresh_katana_menu()
60 changes: 27 additions & 33 deletions hooks/tk-multi-loader2/basic/actions.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,59 @@


import shotgun_asset.utils as utils
from Katana import Plugins
import sgtk
import NodegraphAPI

HookBaseClass = sgtk.get_hook_baseclass()
import shotgun_asset.utils as utils

from Katana import Plugins

class KatanaActions(HookBaseClass):

def generate_actions(self, sg_publish_data, actions, ui_area):

action_instances = []
actionInstances = []
if "open_project" in actions:
action_instances.append( {
actionInstances.append({
"name": "open_project",
"params": None,
"caption": "Open Project",
"description": "This will open the Katana project file."
}
)
})

if "import_look_file" in actions:
action_instances.append( {
actionInstances.append({
"name": "import_look_file",
"params": None,
"caption": "Import Look File",
"description": "Creates a LookBakeMaterialsIn node"
}
)
})

if "alembic_in" in actions:
action_instances.append( {
actionInstances.append({
"name": "alembic_in",
"params": None,
"caption": "Import Alembic",
"description": "This will create an Alembic_In node"
}
)
})

if "importomatic" in actions:
action_instances.append( {
actionInstances.append({
"name": "importomatic",
"params": None,
"caption": "Import via Importomatic",
"description": "This creates an importomatic node"
}
)
})
nodes = NodegraphAPI.GetAllSelectedNodes()
if len(nodes) == 1 and nodes[0].getType() == "Importomatic":
action_instances.append( {
actionInstances.append({
"name": "importomatic_to_selected_node",
"params": {"node_name" : nodes[0].getName()},
"params": {"node_name": nodes[0].getName()},
"caption": "Import Into Selected Importomatic",
"description": "Imports the objects into the selected "
"importomatic node"
}
)
return action_instances
"importomatic node"
})
return actionInstances

def execute_multiple_actions(self, actions):
for action in actions:
Expand All @@ -67,21 +62,20 @@ def execute_multiple_actions(self, actions):
params = action["params"]
self.execute_action(name, params, sgPubData)


def execute_action(self, name, params, sgPubData):
assetId = utils.getShotgunAssetIdFromShotgunPublishData(sgPubData)
publishFileType = sgPubData.get("published_file_type",{})
publish_type = str(publishFileType.get("name",""))
publishFileType = sgPubData.get("published_file_type", {})
publishType = str(publishFileType.get("name", ""))
rootNode = NodegraphAPI.GetRootNode()

if name == "importomatic":
node = NodegraphAPI.CreateNode("Importomatic", rootNode)
self._execute_importomatic(assetId, node, publish_type)
self._execute_importomatic(assetId, node, publishType)
elif name == "importomatic_to_selected_node":
node_name = params.get("node_name")
if node_name:
node = NodegraphAPI.GetNode(node_name)
self._execute_importomatic(assetId, node, publish_type)
nodeName = params.get("node_name")
if nodeName:
node = NodegraphAPI.GetNode(nodeName)
self._execute_importomatic(assetId, node, publishType)
elif name == "import_look_file":
node = NodegraphAPI.CreateNode("LookFileMaterialsIn", rootNode)
inputParam = node.getParameter("lookfile")
Expand All @@ -91,15 +85,15 @@ def execute_action(self, name, params, sgPubData):
inputParam = node.getParameter("abcAsset")
inputParam.setValue(assetId, 0)

def _execute_importomatic(self, assetId, node, publish_type):
if publish_type == "Alembic Cache":
def _execute_importomatic(self, assetId, node, publishType):
if publishType == "Alembic Cache":
ImportomaticAPI = Plugins.ImportomaticAPI
handler = ImportomaticAPI.AssetModule.GetHandlerForNode(node)
new_node = handler.TriggerBatchCreateCallback(
newNode = handler.TriggerBatchCreateCallback(
filetype="Alembic",
node=node,
assetId=assetId,
locationExpression=None
)
node.insertNodeIntoOutputMerge(new_node, "default")
node.insertNodeIntoOutputMerge(newNode, "default")

Loading

0 comments on commit 76ef3c4

Please sign in to comment.