mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
hound cleanup 🐶🧽🧺 II.
This commit is contained in:
parent
c85bd30e1b
commit
7b2932c9a7
67 changed files with 652 additions and 542 deletions
|
|
@ -23,7 +23,7 @@ class CreateAlembicCamera(plugin.Creator):
|
|||
|
||||
parms = {
|
||||
"filename": "$HIP/pyblish/%s.abc" % self.name,
|
||||
"use_sop_path": False
|
||||
"use_sop_path": False,
|
||||
}
|
||||
|
||||
if self.nodes:
|
||||
|
|
@ -33,10 +33,7 @@ class CreateAlembicCamera(plugin.Creator):
|
|||
# Split the node path into the first root and the remainder
|
||||
# So we can set the root and objects parameters correctly
|
||||
_, root, remainder = path.split("/", 2)
|
||||
parms.update({
|
||||
"root": "/" + root,
|
||||
"objects": remainder
|
||||
})
|
||||
parms.update({"root": "/" + root, "objects": remainder})
|
||||
|
||||
instance.setParms(parms)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class CreateCompositeSequence(houdini.Creator):
|
|||
"""Composite ROP to Image Sequence"""
|
||||
|
||||
label = "Composite (Image Sequence)"
|
||||
family = "colorbleed.imagesequence"
|
||||
family = "imagesequence"
|
||||
icon = "gears"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -20,13 +20,15 @@ class CreatePointCache(plugin.Creator):
|
|||
def process(self):
|
||||
instance = super(CreatePointCache, self).process()
|
||||
|
||||
parms = {"use_sop_path": True, # Export single node from SOP Path
|
||||
"build_from_path": True, # Direct path of primitive in output
|
||||
"path_attrib": "path", # Pass path attribute for output
|
||||
"prim_to_detail_pattern": "cbId",
|
||||
"format": 2, # Set format to Ogawa
|
||||
"facesets": 0, # No face sets (by default exclude them)
|
||||
"filename": "$HIP/pyblish/%s.abc" % self.name}
|
||||
parms = {
|
||||
"use_sop_path": True, # Export single node from SOP Path
|
||||
"build_from_path": True, # Direct path of primitive in output
|
||||
"path_attrib": "path", # Pass path attribute for output
|
||||
"prim_to_detail_pattern": "cbId",
|
||||
"format": 2, # Set format to Ogawa
|
||||
"facesets": 0, # No face sets (by default exclude them)
|
||||
"filename": "$HIP/pyblish/%s.abc" % self.name,
|
||||
}
|
||||
|
||||
if self.nodes:
|
||||
node = self.nodes[0]
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@ class CreateRedshiftROP(houdini.Creator):
|
|||
instance.setName(basename + "_ROP", unique_name=True)
|
||||
|
||||
# Also create the linked Redshift IPR Rop
|
||||
ipr_rop = self.parent.createNode("Redshift_IPR",
|
||||
node_name=basename + "_IPR")
|
||||
ipr_rop = self.parent.createNode(
|
||||
"Redshift_IPR", node_name=basename + "_IPR"
|
||||
)
|
||||
|
||||
# Move it to directly under the Redshift ROP
|
||||
ipr_rop.setPosition(instance.position() + hou.Vector2(0, -1))
|
||||
|
|
@ -48,11 +49,10 @@ class CreateRedshiftROP(houdini.Creator):
|
|||
parms = {
|
||||
# Render frame range
|
||||
"trange": 1,
|
||||
|
||||
# Redshift ROP settings
|
||||
"RS_outputFileNamePrefix": prefix,
|
||||
"RS_outputMultilayerMode": 0, # no multi-layered exr
|
||||
"RS_outputBeautyAOVSuffix": "beauty"
|
||||
"RS_outputMultilayerMode": 0, # no multi-layered exr
|
||||
"RS_outputBeautyAOVSuffix": "beauty",
|
||||
}
|
||||
instance.setParms(parms)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class CreateUSD(houdini.Creator):
|
|||
"""Universal Scene Description"""
|
||||
|
||||
label = "USD"
|
||||
family = "colorbleed.usd"
|
||||
family = "usd"
|
||||
icon = "gears"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -21,7 +21,7 @@ class CreateUSD(houdini.Creator):
|
|||
|
||||
parms = {
|
||||
"lopoutput": "$HIP/pyblish/%s.usd" % self.name,
|
||||
"enableoutputprocessor_simplerelativepaths": False
|
||||
"enableoutputprocessor_simplerelativepaths": False,
|
||||
}
|
||||
|
||||
if self.nodes:
|
||||
|
|
@ -31,9 +31,12 @@ class CreateUSD(houdini.Creator):
|
|||
instance.setParms(parms)
|
||||
|
||||
# Lock any parameters in this list
|
||||
to_lock = ["fileperframe",
|
||||
# Lock some Avalon attributes
|
||||
"family", "id"]
|
||||
to_lock = [
|
||||
"fileperframe",
|
||||
# Lock some Avalon attributes
|
||||
"family",
|
||||
"id",
|
||||
]
|
||||
for name in to_lock:
|
||||
parm = instance.parm(name)
|
||||
parm.lock(True)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CreateUSDModel(api.Creator):
|
|||
|
||||
def process(self):
|
||||
|
||||
node_type = "cb::author_model:1.0"
|
||||
node_type = "op::author_model:1.0"
|
||||
|
||||
subset = self.data["subset"]
|
||||
name = "author_{}".format(subset)
|
||||
|
|
@ -24,10 +24,7 @@ class CreateUSDModel(api.Creator):
|
|||
instance = stage.createNode(node_type, node_name=name)
|
||||
instance.moveToGoodPosition(move_unconnected=True)
|
||||
|
||||
parms = {
|
||||
"asset_name": self.data["asset"],
|
||||
"variant_name": variant
|
||||
}
|
||||
parms = {"asset_name": self.data["asset"], "variant_name": variant}
|
||||
|
||||
# Set the Geo Path to the first selected node (if any)
|
||||
selection = hou.selectedNodes()
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ class _USDWorkspace(api.Creator):
|
|||
# With the Workspace HDAs there is no need to imprint the instance data
|
||||
# since this data is pre-built into it. However, we do set the right
|
||||
# asset as that can be defined by the user.
|
||||
parms = {
|
||||
"asset": self.data["asset"]
|
||||
}
|
||||
parms = {"asset": self.data["asset"]}
|
||||
instance.setParms(parms)
|
||||
|
||||
return instance
|
||||
|
|
@ -47,7 +45,7 @@ class USDCreateShadingWorkspace(_USDWorkspace):
|
|||
label = "USD Shading Workspace"
|
||||
family = "colorbleed.shade.usd"
|
||||
|
||||
node_type = "cb::shadingWorkspace::1.0"
|
||||
node_type = "op::shadingWorkspace::1.0"
|
||||
node_name = "shadingWorkspace"
|
||||
step = "Shade"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class CreateUSDRender(houdini.Creator):
|
|||
"""USD Render ROP in /stage"""
|
||||
|
||||
label = "USD Render"
|
||||
family = "colorbleed.usdrender"
|
||||
family = "usdrender"
|
||||
icon = "magic"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ class CreateVDBCache(plugin.Creator):
|
|||
def process(self):
|
||||
instance = super(CreateVDBCache, self).process()
|
||||
|
||||
parms = {"sopoutput": "$HIP/pyblish/%s.$F4.vdb" % self.name,
|
||||
"initsim": True}
|
||||
parms = {
|
||||
"sopoutput": "$HIP/pyblish/%s.$F4.vdb" % self.name,
|
||||
"initsim": True,
|
||||
}
|
||||
|
||||
if self.nodes:
|
||||
node = self.nodes[0]
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@ from avalon import api
|
|||
|
||||
|
||||
class SetFrameRangeLoader(api.Loader):
|
||||
"""Set Maya frame range"""
|
||||
"""Set Houdini frame range"""
|
||||
|
||||
families = ["colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.vdbcache",
|
||||
"colorbleed.usd"]
|
||||
families = [
|
||||
"animation",
|
||||
"camera",
|
||||
"pointcache",
|
||||
"vdbcache",
|
||||
"usd",
|
||||
]
|
||||
representations = ["abc", "vdb", "usd"]
|
||||
|
||||
label = "Set frame range"
|
||||
|
|
@ -24,15 +26,17 @@ class SetFrameRangeLoader(api.Loader):
|
|||
|
||||
import hou
|
||||
|
||||
version = context['version']
|
||||
version = context["version"]
|
||||
version_data = version.get("data", {})
|
||||
|
||||
start = version_data.get("startFrame", None)
|
||||
end = version_data.get("endFrame", None)
|
||||
|
||||
if start is None or end is None:
|
||||
print("Skipping setting frame range because start or "
|
||||
"end frame data is missing..")
|
||||
print(
|
||||
"Skipping setting frame range because start or "
|
||||
"end frame data is missing.."
|
||||
)
|
||||
return
|
||||
|
||||
hou.playbar.setFrameRange(start, end)
|
||||
|
|
@ -42,11 +46,13 @@ class SetFrameRangeLoader(api.Loader):
|
|||
class SetFrameRangeWithHandlesLoader(api.Loader):
|
||||
"""Set Maya frame range including pre- and post-handles"""
|
||||
|
||||
families = ["colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.vdbcache",
|
||||
"colorbleed.usd"]
|
||||
families = [
|
||||
"animation",
|
||||
"camera",
|
||||
"pointcache",
|
||||
"vdbcache",
|
||||
"usd",
|
||||
]
|
||||
representations = ["abc", "vdb", "usd"]
|
||||
|
||||
label = "Set frame range (with handles)"
|
||||
|
|
@ -58,15 +64,17 @@ class SetFrameRangeWithHandlesLoader(api.Loader):
|
|||
|
||||
import hou
|
||||
|
||||
version = context['version']
|
||||
version = context["version"]
|
||||
version_data = version.get("data", {})
|
||||
|
||||
start = version_data.get("startFrame", None)
|
||||
end = version_data.get("endFrame", None)
|
||||
|
||||
if start is None or end is None:
|
||||
print("Skipping setting frame range because start or "
|
||||
"end frame data is missing..")
|
||||
print(
|
||||
"Skipping setting frame range because start or "
|
||||
"end frame data is missing.."
|
||||
)
|
||||
return
|
||||
|
||||
# Include handles
|
||||
|
|
|
|||
|
|
@ -6,10 +6,7 @@ from avalon.houdini import pipeline, lib
|
|||
class AbcLoader(api.Loader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["model",
|
||||
"animation",
|
||||
"pointcache",
|
||||
"gpuCache"]
|
||||
families = ["model", "animation", "pointcache", "gpuCache"]
|
||||
label = "Load Alembic"
|
||||
representations = ["abc"]
|
||||
order = -10
|
||||
|
|
@ -80,19 +77,22 @@ class AbcLoader(api.Loader):
|
|||
|
||||
self[:] = nodes
|
||||
|
||||
return pipeline.containerise(node_name,
|
||||
namespace,
|
||||
nodes,
|
||||
context,
|
||||
self.__class__.__name__,
|
||||
suffix="")
|
||||
return pipeline.containerise(
|
||||
node_name,
|
||||
namespace,
|
||||
nodes,
|
||||
context,
|
||||
self.__class__.__name__,
|
||||
suffix="",
|
||||
)
|
||||
|
||||
def update(self, container, representation):
|
||||
|
||||
node = container["node"]
|
||||
try:
|
||||
alembic_node = next(n for n in node.children() if
|
||||
n.type().name() == "alembic")
|
||||
alembic_node = next(
|
||||
n for n in node.children() if n.type().name() == "alembic"
|
||||
)
|
||||
except StopIteration:
|
||||
self.log.error("Could not find node of type `alembic`")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -2,24 +2,25 @@ from avalon import api
|
|||
from avalon.houdini import pipeline, lib
|
||||
|
||||
|
||||
ARCHIVE_EXPRESSION = '__import__("_alembic_hom_extensions").alembicGetCameraDict'
|
||||
ARCHIVE_EXPRESSION = ('__import__("_alembic_hom_extensions")'
|
||||
'.alembicGetCameraDict')
|
||||
|
||||
|
||||
def transfer_non_default_values(src, dest, ignore=None):
|
||||
"""Copy parm from src to dest.
|
||||
|
||||
|
||||
Because the Alembic Archive rebuilds the entire node
|
||||
hierarchy on triggering "Build Hierarchy" we want to
|
||||
preserve any local tweaks made by the user on the camera
|
||||
for ease of use. That could be a background image, a
|
||||
resolution change or even Redshift camera parameters.
|
||||
|
||||
|
||||
We try to do so by finding all Parms that exist on both
|
||||
source and destination node, include only those that both
|
||||
are not at their default value, they must be visible,
|
||||
we exclude those that have the special "alembic archive"
|
||||
channel expression and ignore certain Parm types.
|
||||
|
||||
|
||||
"""
|
||||
import hou
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,15 @@ from avalon.houdini import pipeline, lib
|
|||
|
||||
import hou
|
||||
|
||||
|
||||
def get_image_avalon_container():
|
||||
"""The COP2 files must be in a COP2 network.
|
||||
|
||||
"""The COP2 files must be in a COP2 network.
|
||||
|
||||
So we maintain a single entry point within AVALON_CONTAINERS,
|
||||
just for ease of use.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
path = pipeline.AVALON_CONTAINERS
|
||||
avalon_container = hou.node(path)
|
||||
if not avalon_container:
|
||||
|
|
@ -20,18 +21,21 @@ def get_image_avalon_container():
|
|||
# but make sure the pipeline still is built the
|
||||
# way we anticipate it was built, asserting it.
|
||||
assert path == "/obj/AVALON_CONTAINERS"
|
||||
|
||||
|
||||
parent = hou.node("/obj")
|
||||
avalon_container = parent.createNode("subnet",
|
||||
node_name="AVALON_CONTAINERS")
|
||||
|
||||
avalon_container = parent.createNode(
|
||||
"subnet", node_name="AVALON_CONTAINERS"
|
||||
)
|
||||
|
||||
image_container = hou.node(path + "/IMAGES")
|
||||
if not image_container:
|
||||
image_container = avalon_container.createNode("cop2net", node_name="IMAGES")
|
||||
image_container = avalon_container.createNode(
|
||||
"cop2net", node_name="IMAGES"
|
||||
)
|
||||
image_container.moveToGoodPosition()
|
||||
|
||||
|
||||
return image_container
|
||||
|
||||
|
||||
|
||||
class ImageLoader(api.Loader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
|
@ -57,12 +61,12 @@ class ImageLoader(api.Loader):
|
|||
# Define node name
|
||||
namespace = namespace if namespace else context["asset"]["name"]
|
||||
node_name = "{}_{}".format(namespace, name) if namespace else name
|
||||
|
||||
|
||||
node = parent.createNode("file", node_name=node_name)
|
||||
node.moveToGoodPosition()
|
||||
|
||||
node.setParms({"filename1": file_path})
|
||||
|
||||
|
||||
# Imprint it manually
|
||||
data = {
|
||||
"schema": "avalon-core:container-2.0",
|
||||
|
|
@ -75,7 +79,7 @@ class ImageLoader(api.Loader):
|
|||
|
||||
# todo: add folder="Avalon"
|
||||
lib.imprint(node, data)
|
||||
|
||||
|
||||
return node
|
||||
|
||||
def update(self, container, representation):
|
||||
|
|
@ -88,32 +92,32 @@ class ImageLoader(api.Loader):
|
|||
file_path = self._get_file_sequence(file_path)
|
||||
|
||||
# Update attributes
|
||||
node.setParms({
|
||||
"filename1": file_path,
|
||||
"representation": str(representation["_id"])
|
||||
})
|
||||
node.setParms(
|
||||
{
|
||||
"filename1": file_path,
|
||||
"representation": str(representation["_id"]),
|
||||
}
|
||||
)
|
||||
|
||||
def remove(self, container):
|
||||
|
||||
node = container["node"]
|
||||
|
||||
|
||||
# Let's clean up the IMAGES COP2 network
|
||||
# if it ends up being empty and we deleted
|
||||
# the last file node. Store the parent
|
||||
# before we delete the node.
|
||||
parent = node.parent()
|
||||
|
||||
|
||||
node.destroy()
|
||||
|
||||
|
||||
if not parent.children():
|
||||
parent.destroy()
|
||||
|
||||
|
||||
|
||||
def _get_file_sequence(self, root):
|
||||
files = sorted(os.listdir(root))
|
||||
|
||||
|
||||
first_fname = files[0]
|
||||
prefix, padding, suffix = first_fname.rsplit(".", 2)
|
||||
fname = ".".join([prefix, "$F{}".format(len(padding)), suffix])
|
||||
return os.path.join(root, fname).replace("\\", "/")
|
||||
return os.path.join(root, fname).replace("\\", "/")
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ from avalon.houdini import pipeline, lib
|
|||
class USDSublayerLoader(api.Loader):
|
||||
"""Sublayer USD file in Solaris"""
|
||||
|
||||
families = ["colorbleed.usd",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"usdCamera"]
|
||||
families = [
|
||||
"colorbleed.usd",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"usdCamera",
|
||||
]
|
||||
label = "Sublayer USD"
|
||||
representations = ["usd", "usda", "usdlc", "usdnc", "abc"]
|
||||
order = 1
|
||||
|
|
@ -62,8 +64,12 @@ class USDSublayerLoader(api.Loader):
|
|||
file_path = file_path.replace("\\", "/")
|
||||
|
||||
# Update attributes
|
||||
node.setParms({"filepath1": file_path,
|
||||
"representation": str(representation["_id"])})
|
||||
node.setParms(
|
||||
{
|
||||
"filepath1": file_path,
|
||||
"representation": str(representation["_id"]),
|
||||
}
|
||||
)
|
||||
|
||||
# Reload files
|
||||
node.parm("reload").pressButton()
|
||||
|
|
@ -71,4 +77,4 @@ class USDSublayerLoader(api.Loader):
|
|||
def remove(self, container):
|
||||
|
||||
node = container["node"]
|
||||
node.destroy()
|
||||
node.destroy()
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ from avalon.houdini import pipeline, lib
|
|||
class USDReferenceLoader(api.Loader):
|
||||
"""Reference USD file in Solaris"""
|
||||
|
||||
families = ["colorbleed.usd",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"usdCamera"]
|
||||
families = [
|
||||
"colorbleed.usd",
|
||||
"colorbleed.pointcache",
|
||||
"colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"usdCamera",
|
||||
]
|
||||
label = "Reference USD"
|
||||
representations = ["usd", "usda", "usdlc", "usdnc", "abc"]
|
||||
order = -8
|
||||
|
|
@ -62,8 +64,12 @@ class USDReferenceLoader(api.Loader):
|
|||
file_path = file_path.replace("\\", "/")
|
||||
|
||||
# Update attributes
|
||||
node.setParms({"filepath1": file_path,
|
||||
"representation": str(representation["_id"])})
|
||||
node.setParms(
|
||||
{
|
||||
"filepath1": file_path,
|
||||
"representation": str(representation["_id"]),
|
||||
}
|
||||
)
|
||||
|
||||
# Reload files
|
||||
node.parm("reload").pressButton()
|
||||
|
|
|
|||
|
|
@ -45,12 +45,14 @@ class VdbLoader(api.Loader):
|
|||
nodes = [container, file_node]
|
||||
self[:] = nodes
|
||||
|
||||
return pipeline.containerise(node_name,
|
||||
namespace,
|
||||
nodes,
|
||||
context,
|
||||
self.__class__.__name__,
|
||||
suffix="")
|
||||
return pipeline.containerise(
|
||||
node_name,
|
||||
namespace,
|
||||
nodes,
|
||||
context,
|
||||
self.__class__.__name__,
|
||||
suffix="",
|
||||
)
|
||||
|
||||
def format_path(self, path):
|
||||
"""Format file path correctly for single vdb or vdb sequence"""
|
||||
|
|
@ -68,8 +70,10 @@ class VdbLoader(api.Loader):
|
|||
files = sorted(os.listdir(path))
|
||||
first = next((x for x in files if x.endswith(".vdb")), None)
|
||||
if first is None:
|
||||
raise RuntimeError("Couldn't find first .vdb file of "
|
||||
"sequence in: %s" % path)
|
||||
raise RuntimeError(
|
||||
"Couldn't find first .vdb file of "
|
||||
"sequence in: %s" % path
|
||||
)
|
||||
|
||||
# Set <frame>.vdb to $F.vdb
|
||||
first = re.sub(r"\.(\d+)\.vdb$", ".$F.vdb", first)
|
||||
|
|
@ -85,8 +89,9 @@ class VdbLoader(api.Loader):
|
|||
|
||||
node = container["node"]
|
||||
try:
|
||||
file_node = next(n for n in node.children() if
|
||||
n.type().name() == "file")
|
||||
file_node = next(
|
||||
n for n in node.children() if n.type().name() == "file"
|
||||
)
|
||||
except StopIteration:
|
||||
self.log.error("Could not find node of type `alembic`")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -40,5 +40,4 @@ class ShowInUsdview(api.Loader):
|
|||
# Force string to avoid unicode issues
|
||||
env = {str(key): str(value) for key, value in env.items()}
|
||||
|
||||
subprocess.Popen([usdview, filepath, "--renderer", "GL"],
|
||||
env=env)
|
||||
subprocess.Popen([usdview, filepath, "--renderer", "GL"], env=env)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import pyblish.api
|
||||
import openpype.api
|
||||
|
||||
|
||||
class CollectInstanceActiveState(pyblish.api.InstancePlugin):
|
||||
|
|
@ -28,9 +27,11 @@ class CollectInstanceActiveState(pyblish.api.InstancePlugin):
|
|||
active = not node.isBypassed()
|
||||
|
||||
# Set instance active state
|
||||
instance.data.update({
|
||||
"active": active,
|
||||
# temporarily translation of `active` to `publish` till issue has
|
||||
# been resolved: https://github.com/pyblish/pyblish-base/issues/307
|
||||
"publish": active
|
||||
})
|
||||
instance.data.update(
|
||||
{
|
||||
"active": active,
|
||||
# temporarily translation of `active` to `publish` till issue has
|
||||
# been resolved: https://github.com/pyblish/pyblish-base/issues/307
|
||||
"publish": active,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class CollectHoudiniCurrentFile(pyblish.api.ContextPlugin):
|
|||
|
||||
order = pyblish.api.CollectorOrder - 0.5
|
||||
label = "Houdini Current File"
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
|
||||
def process(self, context):
|
||||
"""Inject the current working file"""
|
||||
|
|
@ -27,8 +27,10 @@ class CollectHoudiniCurrentFile(pyblish.api.ContextPlugin):
|
|||
# could have existed already. We will allow it if the file exists,
|
||||
# but show a warning for this edge case to clarify the potential
|
||||
# false positive.
|
||||
self.log.warning("Current file is 'untitled.hip' and we are "
|
||||
"unable to detect whether the current scene is "
|
||||
"saved correctly.")
|
||||
self.log.warning(
|
||||
"Current file is 'untitled.hip' and we are "
|
||||
"unable to detect whether the current scene is "
|
||||
"saved correctly."
|
||||
)
|
||||
|
||||
context.data['currentFile'] = filepath
|
||||
context.data["currentFile"] = filepath
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ class CollectFrames(pyblish.api.InstancePlugin):
|
|||
|
||||
order = pyblish.api.CollectorOrder
|
||||
label = "Collect Frames"
|
||||
families = ["vdbcache",
|
||||
"imagesequence"]
|
||||
families = ["vdbcache", "imagesequence"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -39,9 +38,9 @@ class CollectFrames(pyblish.api.InstancePlugin):
|
|||
# Check if frames are bigger than 1 (file collection)
|
||||
# override the result
|
||||
if end_frame - start_frame > 1:
|
||||
result = self.create_file_list(match,
|
||||
int(start_frame),
|
||||
int(end_frame))
|
||||
result = self.create_file_list(
|
||||
match, int(start_frame), int(end_frame)
|
||||
)
|
||||
|
||||
# todo: `frames` currently conflicts with "explicit frames" for a
|
||||
# for a custom frame list. So this should be refactored.
|
||||
|
|
@ -67,12 +66,12 @@ class CollectFrames(pyblish.api.InstancePlugin):
|
|||
# Get the parts of the filename surrounding the frame number
|
||||
# so we can put our own frame numbers in.
|
||||
span = match.span(1)
|
||||
prefix = match.string[:span[0]]
|
||||
prefix = match.string[: span[0]]
|
||||
suffix = match.string[span[1]:]
|
||||
|
||||
# Generate filenames for all frames
|
||||
result = []
|
||||
for i in range(start_frame, end_frame+1):
|
||||
for i in range(start_frame, end_frame + 1):
|
||||
|
||||
# Format frame number by the padding amount
|
||||
str_frame = "{number:0{width}d}".format(number=i, width=padding)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
import hou
|
||||
|
||||
import avalon.io as io
|
||||
import avalon.api as api
|
||||
import pyblish.api
|
||||
|
||||
|
|
@ -30,7 +27,7 @@ def collect_input_containers(nodes):
|
|||
# and the contained children should be all we need. So we disregard
|
||||
# checking for .references() on the nodes.
|
||||
members = set(node.allSubChildren())
|
||||
members.add(node) # include the node itself
|
||||
members.add(node) # include the node itself
|
||||
|
||||
# If there's an intersection
|
||||
if not lookup.isdisjoint(members):
|
||||
|
|
@ -51,8 +48,9 @@ def iter_upstream(node):
|
|||
|
||||
"""
|
||||
|
||||
upstream = node.inputAncestors(include_ref_inputs=True,
|
||||
follow_subnets=True)
|
||||
upstream = node.inputAncestors(
|
||||
include_ref_inputs=True, follow_subnets=True
|
||||
)
|
||||
|
||||
# Initialize process queue with the node's ancestors itself
|
||||
queue = list(upstream)
|
||||
|
|
@ -73,8 +71,9 @@ def iter_upstream(node):
|
|||
|
||||
# Include the references' ancestors that have not been collected yet.
|
||||
for reference in references:
|
||||
ancestors = reference.inputAncestors(include_ref_inputs=True,
|
||||
follow_subnets=True)
|
||||
ancestors = reference.inputAncestors(
|
||||
include_ref_inputs=True, follow_subnets=True
|
||||
)
|
||||
ancestors = [n for n in ancestors if n not in collected]
|
||||
|
||||
queue.extend(ancestors)
|
||||
|
|
@ -103,8 +102,9 @@ class CollectUpstreamInputs(pyblish.api.InstancePlugin):
|
|||
if output is None:
|
||||
# If no valid output node is set then ignore it as validation
|
||||
# will be checking those cases.
|
||||
self.log.debug("No output node found, skipping "
|
||||
"collecting of inputs..")
|
||||
self.log.debug(
|
||||
"No output node found, skipping " "collecting of inputs.."
|
||||
)
|
||||
return
|
||||
|
||||
# Collect all upstream parents
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class CollectInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# Create nice name if the instance has a frame range.
|
||||
label = data.get("name", node.name())
|
||||
label += " (%s)" % data["asset"] # include asset in name
|
||||
label += " (%s)" % data["asset"] # include asset in name
|
||||
|
||||
if "frameStart" in data and "frameEnd" in data:
|
||||
frames = "[{frameStart} - {frameEnd}]".format(**data)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import os
|
||||
|
||||
import hou
|
||||
import pyblish.api
|
||||
from avalon import io
|
||||
from avalon.houdini import lib
|
||||
import openpype.hosts.houdini.api.usd as hou_usdlib
|
||||
import openpype.lib.usdlib as usdlib
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ class CollectOutputSOPPath(pyblish.api.InstancePlugin):
|
|||
"""Collect the out node's SOP/COP Path value."""
|
||||
|
||||
order = pyblish.api.CollectorOrder
|
||||
families = ["pointcache",
|
||||
"camera",
|
||||
"vdbcache",
|
||||
"imagesequence",
|
||||
"usd",
|
||||
"usdrender"]
|
||||
families = [
|
||||
"pointcache",
|
||||
"camera",
|
||||
"vdbcache",
|
||||
"imagesequence",
|
||||
"usd",
|
||||
"usdrender",
|
||||
]
|
||||
|
||||
hosts = ["houdini"]
|
||||
label = "Collect Output Node Path"
|
||||
|
|
@ -53,8 +55,9 @@ class CollectOutputSOPPath(pyblish.api.InstancePlugin):
|
|||
out_node = node.parm("loppath").evalAsNode()
|
||||
|
||||
else:
|
||||
raise ValueError("ROP node type '%s' is"
|
||||
" not supported." % node_type)
|
||||
raise ValueError(
|
||||
"ROP node type '%s' is" " not supported." % node_type
|
||||
)
|
||||
|
||||
if not out_node:
|
||||
self.log.warning("No output node collected.")
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import pyblish.api
|
|||
|
||||
def get_top_referenced_parm(parm):
|
||||
|
||||
processed = set() # disallow infinite loop
|
||||
processed = set() # disallow infinite loop
|
||||
while True:
|
||||
if parm.path() in processed:
|
||||
raise RuntimeError("Parameter references result in cycle.")
|
||||
|
||||
|
||||
processed.add(parm.path())
|
||||
|
||||
ref = parm.getReferencedParm()
|
||||
|
|
@ -27,7 +27,7 @@ def evalParmNoFrame(node, parm, pad_character="#"):
|
|||
|
||||
parameter = node.parm(parm)
|
||||
assert parameter, "Parameter does not exist: %s.%s" % (node, parm)
|
||||
|
||||
|
||||
# If the parameter has a parameter reference, then get that
|
||||
# parameter instead as otherwise `unexpandedString()` fails.
|
||||
parameter = get_top_referenced_parm(parameter)
|
||||
|
|
@ -38,7 +38,7 @@ def evalParmNoFrame(node, parm, pad_character="#"):
|
|||
except hou.Error as exc:
|
||||
print("Failed: %s" % parameter)
|
||||
raise RuntimeError(exc)
|
||||
|
||||
|
||||
def replace(match):
|
||||
padding = 1
|
||||
n = match.group(2)
|
||||
|
|
@ -70,31 +70,32 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
|
||||
rop = instance[0]
|
||||
|
||||
|
||||
# Collect chunkSize
|
||||
chunk_size_parm = rop.parm("chunkSize")
|
||||
if chunk_size_parm:
|
||||
chunk_size = int(chunk_size_parm.eval())
|
||||
instance.data["chunkSize"] = chunk_size
|
||||
self.log.debug("Chunk Size: %s" % chunk_size)
|
||||
|
||||
|
||||
default_prefix = evalParmNoFrame(rop, "RS_outputFileNamePrefix")
|
||||
beauty_suffix = rop.evalParm("RS_outputBeautyAOVSuffix")
|
||||
render_products = []
|
||||
|
||||
# Default beauty AOV
|
||||
beauty_product = self.get_render_product_name(prefix=default_prefix,
|
||||
suffix=beauty_suffix)
|
||||
beauty_product = self.get_render_product_name(
|
||||
prefix=default_prefix, suffix=beauty_suffix
|
||||
)
|
||||
render_products.append(beauty_product)
|
||||
|
||||
num_aovs = rop.evalParm("RS_aov")
|
||||
for index in range(num_aovs):
|
||||
i = index + 1
|
||||
|
||||
|
||||
# Skip disabled AOVs
|
||||
if not rop.evalParm("RS_aovEnable_%s" % i):
|
||||
continue
|
||||
|
||||
|
||||
aov_suffix = rop.evalParm("RS_aovSuffix_%s" % i)
|
||||
aov_prefix = evalParmNoFrame(rop, "RS_aovCustomPrefix_%s" % i)
|
||||
if not aov_prefix:
|
||||
|
|
@ -122,10 +123,7 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin):
|
|||
# there is no suffix for the current product, for example:
|
||||
# foo_%AOV% -> foo.exr
|
||||
pattern = "%AOV%" if suffix else "[._-]?%AOV%"
|
||||
product_name = re.sub(pattern,
|
||||
suffix,
|
||||
prefix,
|
||||
flags=re.IGNORECASE)
|
||||
product_name = re.sub(pattern, suffix, prefix, flags=re.IGNORECASE)
|
||||
else:
|
||||
if suffix:
|
||||
# Add ".{suffix}" before the extension
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ class CollectRemotePublishSettings(pyblish.api.ContextPlugin):
|
|||
|
||||
order = pyblish.api.CollectorOrder
|
||||
families = ["*"]
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
targets = ["deadline"]
|
||||
label = 'Remote Publish Submission Settings'
|
||||
label = "Remote Publish Submission Settings"
|
||||
actions = [openpype.api.RepairAction]
|
||||
|
||||
def process(self, context):
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ def get_var_changed(variable=None):
|
|||
cmd = "varchange -V"
|
||||
if variable:
|
||||
cmd += " {0}".format(variable)
|
||||
output, errors = hou.hscript(cmd)
|
||||
output, _ = hou.hscript(cmd)
|
||||
|
||||
changed = {}
|
||||
for line in output.split("Variable: "):
|
||||
|
|
@ -44,7 +44,7 @@ def get_var_changed(variable=None):
|
|||
|
||||
|
||||
class CollectRenderProducts(pyblish.api.InstancePlugin):
|
||||
"""Collect USD Render Products"""
|
||||
"""Collect USD Render Products."""
|
||||
|
||||
label = "Collect Render Products"
|
||||
order = pyblish.api.CollectorOrder + 0.4
|
||||
|
|
@ -56,14 +56,17 @@ class CollectRenderProducts(pyblish.api.InstancePlugin):
|
|||
node = instance.data.get("output_node")
|
||||
if not node:
|
||||
rop_path = instance[0].path()
|
||||
raise RuntimeError("No output node found. Make sure to connect an "
|
||||
"input to the USD ROP: %s" % rop_path)
|
||||
raise RuntimeError(
|
||||
"No output node found. Make sure to connect an "
|
||||
"input to the USD ROP: %s" % rop_path
|
||||
)
|
||||
|
||||
# Workaround Houdini 18.0.391 bug where $HIPNAME doesn't automatically
|
||||
# update after scene save.
|
||||
if hou.applicationVersion() == (18, 0, 391):
|
||||
self.log.debug("Checking for recook to workaround "
|
||||
"$HIPNAME refresh bug...")
|
||||
self.log.debug(
|
||||
"Checking for recook to workaround " "$HIPNAME refresh bug..."
|
||||
)
|
||||
changed = get_var_changed("HIPNAME").get("HIPNAME")
|
||||
if changed:
|
||||
self.log.debug("Recooking for $HIPNAME refresh bug...")
|
||||
|
|
@ -101,7 +104,7 @@ class CollectRenderProducts(pyblish.api.InstancePlugin):
|
|||
# TODO: Confirm this actually is allowed USD stages and HUSK
|
||||
# Substitute $F
|
||||
def replace(match):
|
||||
"""Replace $F4 with padded #"""
|
||||
"""Replace $F4 with padded #."""
|
||||
padding = int(match.group(2)) if match.group(2) else 1
|
||||
return "#" * padding
|
||||
|
||||
|
|
@ -118,8 +121,10 @@ class CollectRenderProducts(pyblish.api.InstancePlugin):
|
|||
filename = os.path.join(dirname, filename_base)
|
||||
filename = filename.replace("\\", "/")
|
||||
|
||||
assert "#" in filename, "Couldn't resolve render product name " \
|
||||
"with frame number: %s" % name
|
||||
assert "#" in filename, (
|
||||
"Couldn't resolve render product name "
|
||||
"with frame number: %s" % name
|
||||
)
|
||||
|
||||
filenames.append(filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
order = pyblish.api.CollectorOrder + 0.35
|
||||
label = "Collect USD Bootstrap"
|
||||
hosts = ["houdini"]
|
||||
families = ["colorbleed.usd",
|
||||
"colorbleed.usd.layered"]
|
||||
families = ["usd", "usd.layered"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
instance_subset = instance.data["subset"]
|
||||
for name, layers in usdlib.PIPELINE.items():
|
||||
if instance_subset in set(layers):
|
||||
return name # e.g. "asset"
|
||||
return name # e.g. "asset"
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
|
@ -54,15 +53,11 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
|
||||
self.log.debug("Add bootstrap for: %s" % bootstrap)
|
||||
|
||||
asset = io.find_one({"name": instance.data["asset"],
|
||||
"type": "asset"})
|
||||
asset = io.find_one({"name": instance.data["asset"], "type": "asset"})
|
||||
assert asset, "Asset must exist: %s" % asset
|
||||
|
||||
# Check which are not about to be created and don't exist yet
|
||||
required = {
|
||||
"shot": ["usdShot"],
|
||||
"asset": ["usdAsset"]
|
||||
}.get(bootstrap)
|
||||
required = {"shot": ["usdShot"], "asset": ["usdAsset"]}.get(bootstrap)
|
||||
|
||||
require_all_layers = instance.data.get("requireAllLayers", False)
|
||||
if require_all_layers:
|
||||
|
|
@ -78,18 +73,18 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
if self._subset_exists(instance, subset, asset):
|
||||
continue
|
||||
|
||||
self.log.debug("Creating {0} USD bootstrap: {1} {2}".format(
|
||||
bootstrap,
|
||||
asset["name"],
|
||||
subset
|
||||
))
|
||||
self.log.debug(
|
||||
"Creating {0} USD bootstrap: {1} {2}".format(
|
||||
bootstrap, asset["name"], subset
|
||||
)
|
||||
)
|
||||
|
||||
new = instance.context.create_instance(subset)
|
||||
new.data["subset"] = subset
|
||||
new.data["label"] = "{0} ({1})".format(subset, asset["name"])
|
||||
new.data["family"] = "colorbleed.usd.bootstrap"
|
||||
new.data["family"] = "usd.bootstrap"
|
||||
new.data["comment"] = "Automated bootstrap USD file."
|
||||
new.data["publishFamilies"] = ["colorbleed.usd"]
|
||||
new.data["publishFamilies"] = ["usd"]
|
||||
|
||||
# Do not allow the user to toggle this instance
|
||||
new.data["optional"] = False
|
||||
|
|
@ -100,7 +95,6 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
|
||||
def _subset_exists(self, instance, subset, asset):
|
||||
"""Return whether subset exists in current context or in database."""
|
||||
|
||||
# Allow it to be created during this publish session
|
||||
context = instance.context
|
||||
for inst in context:
|
||||
|
|
@ -112,6 +106,8 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin):
|
|||
|
||||
# Or, if they already exist in the database we can
|
||||
# skip them too.
|
||||
return bool(io.find_one({"name": subset,
|
||||
"type": "subset",
|
||||
"parent": asset["_id"]}))
|
||||
return bool(
|
||||
io.find_one(
|
||||
{"name": subset, "type": "subset", "parent": asset["_id"]}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ from avalon.houdini import lib
|
|||
import openpype.hosts.houdini.lib.usd as usdlib
|
||||
|
||||
import hou
|
||||
from pxr import Sdf
|
||||
|
||||
|
||||
class CollectUsdLayers(pyblish.api.InstancePlugin):
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import hou
|
|||
|
||||
|
||||
class CollectWorksceneFPS(pyblish.api.ContextPlugin):
|
||||
"""Get the FPS of the work scene"""
|
||||
"""Get the FPS of the work scene."""
|
||||
|
||||
label = "Workscene FPS"
|
||||
order = pyblish.api.CollectorOrder
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class ExtractUSD(openpype.api.Extractor):
|
|||
label = "Extract USD"
|
||||
hosts = ["houdini"]
|
||||
targets = ["local"]
|
||||
families = ["colorbleed.usd",
|
||||
families = ["usd",
|
||||
"usdModel",
|
||||
"usdSetDress"]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from openpype.hosts.houdini.api.lib import render_rop
|
|||
|
||||
|
||||
class ExitStack(object):
|
||||
"""Context manager for dynamic management of a stack of exit callbacks
|
||||
"""Context manager for dynamic management of a stack of exit callbacks.
|
||||
|
||||
For example:
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ class ExitStack(object):
|
|||
# in the list raise an exception
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._exit_callbacks = deque()
|
||||
|
||||
|
|
@ -35,8 +36,10 @@ class ExitStack(object):
|
|||
|
||||
def _push_cm_exit(self, cm, cm_exit):
|
||||
"""Helper to correctly register callbacks to __exit__ methods"""
|
||||
|
||||
def _exit_wrapper(*exc_details):
|
||||
return cm_exit(cm, *exc_details)
|
||||
|
||||
_exit_wrapper.__self__ = cm
|
||||
self.push(_exit_wrapper)
|
||||
|
||||
|
|
@ -58,20 +61,22 @@ class ExitStack(object):
|
|||
self._exit_callbacks.append(exit)
|
||||
else:
|
||||
self._push_cm_exit(exit, exit_method)
|
||||
return exit # Allow use as a decorator
|
||||
return exit # Allow use as a decorator
|
||||
|
||||
def callback(self, callback, *args, **kwds):
|
||||
"""Registers an arbitrary callback and arguments.
|
||||
|
||||
Cannot suppress exceptions.
|
||||
"""
|
||||
|
||||
def _exit_wrapper(exc_type, exc, tb):
|
||||
callback(*args, **kwds)
|
||||
|
||||
# We changed the signature, so using @wraps is not appropriate, but
|
||||
# setting __wrapped__ may still help with introspection
|
||||
_exit_wrapper.__wrapped__ = callback
|
||||
self.push(_exit_wrapper)
|
||||
return callback # Allow use as a decorator
|
||||
return callback # Allow use as a decorator
|
||||
|
||||
def enter_context(self, cm):
|
||||
"""Enters the supplied context manager
|
||||
|
|
@ -97,6 +102,7 @@ class ExitStack(object):
|
|||
# We manipulate the exception state so it behaves as though
|
||||
# we were actually nesting multiple with statements
|
||||
frame_exc = sys.exc_info()[1]
|
||||
|
||||
def _fix_exception_context(new_exc, old_exc):
|
||||
while 1:
|
||||
exc_context = new_exc.__context__
|
||||
|
|
@ -148,15 +154,11 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
label = "Extract Layered USD"
|
||||
hosts = ["houdini"]
|
||||
targets = ["local"]
|
||||
families = ["colorbleed.usd.layered",
|
||||
"usdShade"]
|
||||
families = ["colorbleed.usd.layered", "usdShade"]
|
||||
|
||||
# Force Output Processors so it will always save any file
|
||||
# into our unique staging directory with processed Avalon paths
|
||||
output_processors = [
|
||||
"avalon_uri_processor",
|
||||
"stagingdir_processor"
|
||||
]
|
||||
output_processors = ["avalon_uri_processor", "stagingdir_processor"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -168,8 +170,9 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
# The individual rop nodes are collected as "publishDependencies"
|
||||
dependencies = instance.data["publishDependencies"]
|
||||
ropnodes = [dependency[0] for dependency in dependencies]
|
||||
assert all(node.type().name() in {"usd", "usd_rop"}
|
||||
for node in ropnodes)
|
||||
assert all(
|
||||
node.type().name() in {"usd", "usd_rop"} for node in ropnodes
|
||||
)
|
||||
|
||||
# Main ROP node, either a USD Rop or ROP network with multiple USD ROPs
|
||||
node = instance[0]
|
||||
|
|
@ -177,9 +180,12 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
# Collect any output dependencies that have not been processed yet
|
||||
# during extraction of other instances
|
||||
outputs = [fname]
|
||||
active_dependencies = [dep for dep in dependencies if
|
||||
dep.data.get("publish", True) and
|
||||
not dep.data.get("_isExtracted", False)]
|
||||
active_dependencies = [
|
||||
dep
|
||||
for dep in dependencies
|
||||
if dep.data.get("publish", True)
|
||||
and not dep.data.get("_isExtracted", False)
|
||||
]
|
||||
for dependency in active_dependencies:
|
||||
outputs.append(dependency.data["usdFilename"])
|
||||
|
||||
|
|
@ -192,13 +198,11 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
# This sets staging directory on the processor to force our
|
||||
# output files to end up in the Staging Directory.
|
||||
"stagingdiroutputprocessor_stagingDir": staging_dir,
|
||||
|
||||
# Force the Avalon URI Output Processor to refactor paths for
|
||||
# references, payloads and layers to published paths.
|
||||
"avalonurioutputprocessor_use_publish_paths": True,
|
||||
|
||||
# Only write out specific USD files based on our outputs
|
||||
"savepattern": save_pattern
|
||||
"savepattern": save_pattern,
|
||||
}
|
||||
overrides = list()
|
||||
with ExitStack() as stack:
|
||||
|
|
@ -207,7 +211,7 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
manager = hou_usdlib.outputprocessors(
|
||||
ropnode,
|
||||
processors=self.output_processors,
|
||||
disable_all_others=True
|
||||
disable_all_others=True,
|
||||
)
|
||||
stack.enter_context(manager)
|
||||
|
||||
|
|
@ -216,8 +220,10 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
# exist when the Output Processor is added to the ROP node.
|
||||
for name, value in rop_overrides.items():
|
||||
parm = ropnode.parm(name)
|
||||
assert parm, "Parm not found: %s.%s" % (ropnode.path(),
|
||||
name)
|
||||
assert parm, "Parm not found: %s.%s" % (
|
||||
ropnode.path(),
|
||||
name,
|
||||
)
|
||||
overrides.append((parm, value))
|
||||
|
||||
stack.enter_context(parm_values(overrides))
|
||||
|
|
@ -236,12 +242,13 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
dependency_fname = dependency.data["usdFilename"]
|
||||
|
||||
filepath = os.path.join(staging_dir, dependency_fname)
|
||||
similar = self._compare_with_latest_publish(dependency,
|
||||
filepath)
|
||||
similar = self._compare_with_latest_publish(dependency, filepath)
|
||||
if similar:
|
||||
# Deactivate this dependency
|
||||
self.log.debug("Dependency matches previous publish version,"
|
||||
" deactivating %s for publish" % dependency)
|
||||
self.log.debug(
|
||||
"Dependency matches previous publish version,"
|
||||
" deactivating %s for publish" % dependency
|
||||
)
|
||||
dependency.data["publish"] = False
|
||||
else:
|
||||
self.log.debug("Extracted dependency: %s" % dependency)
|
||||
|
|
@ -265,33 +272,35 @@ class ExtractUSDLayered(openpype.api.Extractor):
|
|||
# Compare this dependency with the latest published version
|
||||
# to detect whether we should make this into a new publish
|
||||
# version. If not, skip it.
|
||||
asset = io.find_one({
|
||||
"name": dependency.data["asset"],
|
||||
"type": "asset"
|
||||
})
|
||||
subset = io.find_one({
|
||||
"name": dependency.data["subset"],
|
||||
"type": "subset",
|
||||
"parent": asset["_id"]
|
||||
})
|
||||
asset = io.find_one(
|
||||
{"name": dependency.data["asset"], "type": "asset"}
|
||||
)
|
||||
subset = io.find_one(
|
||||
{
|
||||
"name": dependency.data["subset"],
|
||||
"type": "subset",
|
||||
"parent": asset["_id"],
|
||||
}
|
||||
)
|
||||
if not subset:
|
||||
# Subset doesn't exist yet. Definitely new file
|
||||
self.log.debug("No existing subset..")
|
||||
return False
|
||||
|
||||
version = io.find_one({
|
||||
"type": "version",
|
||||
"parent": subset["_id"],
|
||||
}, sort=[("name", -1)])
|
||||
version = io.find_one(
|
||||
{"type": "version", "parent": subset["_id"], }, sort=[("name", -1)]
|
||||
)
|
||||
if not version:
|
||||
self.log.debug("No existing version..")
|
||||
return False
|
||||
|
||||
representation = io.find_one({
|
||||
"name": ext.lstrip("."),
|
||||
"type": "representation",
|
||||
"parent": version["_id"]
|
||||
})
|
||||
representation = io.find_one(
|
||||
{
|
||||
"name": ext.lstrip("."),
|
||||
"type": "representation",
|
||||
"parent": version["_id"],
|
||||
}
|
||||
)
|
||||
if not representation:
|
||||
self.log.debug("No existing representation..")
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ class ExtractVDBCache(openpype.api.Extractor):
|
|||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
'name': 'mov',
|
||||
'ext': 'mov',
|
||||
'files': output,
|
||||
"name": "mov",
|
||||
"ext": "mov",
|
||||
"files": output,
|
||||
"stagingDir": staging_dir,
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ class IncrementCurrentFile(pyblish.api.InstancePlugin):
|
|||
label = "Increment current file"
|
||||
order = pyblish.api.IntegratorOrder + 9.0
|
||||
hosts = ["houdini"]
|
||||
families = ["colorbleed.usdrender",
|
||||
"redshift_rop"]
|
||||
families = ["colorbleed.usdrender", "redshift_rop"]
|
||||
targets = ["local"]
|
||||
|
||||
def process(self, instance):
|
||||
|
|
@ -32,17 +31,21 @@ class IncrementCurrentFile(pyblish.api.InstancePlugin):
|
|||
|
||||
context = instance.context
|
||||
errored_plugins = get_errored_plugins_from_data(context)
|
||||
if any(plugin.__name__ == "HoudiniSubmitPublishDeadline"
|
||||
for plugin in errored_plugins):
|
||||
raise RuntimeError("Skipping incrementing current file because "
|
||||
"submission to deadline failed.")
|
||||
if any(
|
||||
plugin.__name__ == "HoudiniSubmitPublishDeadline"
|
||||
for plugin in errored_plugins
|
||||
):
|
||||
raise RuntimeError(
|
||||
"Skipping incrementing current file because "
|
||||
"submission to deadline failed."
|
||||
)
|
||||
|
||||
# Filename must not have changed since collecting
|
||||
host = avalon.api.registered_host()
|
||||
current_file = host.current_file()
|
||||
assert context.data['currentFile'] == current_file, (
|
||||
"Collected filename from current scene name."
|
||||
)
|
||||
assert (
|
||||
context.data["currentFile"] == current_file
|
||||
), "Collected filename from current scene name."
|
||||
|
||||
new_filepath = version_up(current_file)
|
||||
host.save(new_filepath)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import pyblish.api
|
||||
|
||||
import os
|
||||
import hou
|
||||
from openpype.api import version_up
|
||||
from openpype.action import get_errored_plugins_from_data
|
||||
|
|
@ -21,14 +20,16 @@ class IncrementCurrentFileDeadline(pyblish.api.ContextPlugin):
|
|||
def process(self, context):
|
||||
|
||||
errored_plugins = get_errored_plugins_from_data(context)
|
||||
if any(plugin.__name__ == "HoudiniSubmitPublishDeadline"
|
||||
for plugin in errored_plugins):
|
||||
raise RuntimeError("Skipping incrementing current file because "
|
||||
"submission to deadline failed.")
|
||||
if any(
|
||||
plugin.__name__ == "HoudiniSubmitPublishDeadline"
|
||||
for plugin in errored_plugins
|
||||
):
|
||||
raise RuntimeError(
|
||||
"Skipping incrementing current file because "
|
||||
"submission to deadline failed."
|
||||
)
|
||||
|
||||
current_filepath = context.data["currentFile"]
|
||||
new_filepath = version_up(current_filepath)
|
||||
|
||||
hou.hipFile.save(file_name=new_filepath,
|
||||
save_to_recent_files=True)
|
||||
|
||||
hou.hipFile.save(file_name=new_filepath, save_to_recent_files=True)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class SaveCurrentScene(pyblish.api.InstancePlugin):
|
|||
label = "Save current file"
|
||||
order = pyblish.api.IntegratorOrder - 0.49
|
||||
hosts = ["houdini"]
|
||||
families = ["colorbleed.usdrender",
|
||||
families = ["usdrender",
|
||||
"redshift_rop"]
|
||||
targets = ["local"]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ class SaveCurrentSceneDeadline(pyblish.api.ContextPlugin):
|
|||
def process(self, context):
|
||||
import hou
|
||||
|
||||
assert context.data['currentFile'] == hou.hipFile.path(), (
|
||||
"Collected filename from current scene name."
|
||||
)
|
||||
assert (
|
||||
context.data["currentFile"] == hou.hipFile.path()
|
||||
), "Collected filename from current scene name."
|
||||
|
||||
if hou.hipFile.hasUnsavedChanges():
|
||||
self.log.info("Saving current file..")
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import hou
|
|||
|
||||
|
||||
class HoudiniSubmitRenderDeadline(pyblish.api.InstancePlugin):
|
||||
"""Submit Solaris USD Render ROPs to Deadline
|
||||
"""Submit Solaris USD Render ROPs to Deadline.
|
||||
|
||||
Renders are submitted to a Deadline Web Service as
|
||||
supplied via the environment variable AVALON_DEADLINE.
|
||||
|
|
@ -26,7 +26,7 @@ class HoudiniSubmitRenderDeadline(pyblish.api.InstancePlugin):
|
|||
label = "Submit Render to Deadline"
|
||||
order = pyblish.api.IntegratorOrder
|
||||
hosts = ["houdini"]
|
||||
families = ["colorbleed.usdrender",
|
||||
families = ["usdrender",
|
||||
"redshift_rop"]
|
||||
targets = ["local"]
|
||||
|
||||
|
|
@ -50,9 +50,9 @@ class HoudiniSubmitRenderDeadline(pyblish.api.InstancePlugin):
|
|||
|
||||
# StartFrame to EndFrame by byFrameStep
|
||||
frames = "{start}-{end}x{step}".format(
|
||||
start=int(instance.data["startFrame"]),
|
||||
end=int(instance.data["endFrame"]),
|
||||
step=int(instance.data["byFrameStep"]),
|
||||
start=int(instance.data["startFrame"]),
|
||||
end=int(instance.data["endFrame"]),
|
||||
step=int(instance.data["byFrameStep"]),
|
||||
)
|
||||
|
||||
# Documentation for keys available at:
|
||||
|
|
|
|||
|
|
@ -31,12 +31,14 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
def process(self, context):
|
||||
|
||||
# Ensure no errors so far
|
||||
assert all(result["success"] for result in context.data["results"]), (
|
||||
"Errors found, aborting integration..")
|
||||
assert all(
|
||||
result["success"] for result in context.data["results"]
|
||||
), "Errors found, aborting integration.."
|
||||
|
||||
# Deadline connection
|
||||
AVALON_DEADLINE = api.Session.get("AVALON_DEADLINE",
|
||||
"http://localhost:8082")
|
||||
AVALON_DEADLINE = api.Session.get(
|
||||
"AVALON_DEADLINE", "http://localhost:8082"
|
||||
)
|
||||
assert AVALON_DEADLINE, "Requires AVALON_DEADLINE"
|
||||
|
||||
# Note that `publish` data member might change in the future.
|
||||
|
|
@ -45,8 +47,9 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
instance_names = sorted(instance.name for instance in actives)
|
||||
|
||||
if not instance_names:
|
||||
self.log.warning("No active instances found. "
|
||||
"Skipping submission..")
|
||||
self.log.warning(
|
||||
"No active instances found. " "Skipping submission.."
|
||||
)
|
||||
return
|
||||
|
||||
scene = context.data["currentFile"]
|
||||
|
|
@ -72,30 +75,24 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
"BatchName": batch_name,
|
||||
"Comment": context.data.get("comment", ""),
|
||||
"Priority": 50,
|
||||
"Frames": "1-1", # Always trigger a single frame
|
||||
"Frames": "1-1", # Always trigger a single frame
|
||||
"IsFrameDependent": False,
|
||||
"Name": job_name,
|
||||
"UserName": deadline_user,
|
||||
# "Comment": instance.context.data.get("comment", ""),
|
||||
# "InitialStatus": state
|
||||
|
||||
},
|
||||
"PluginInfo": {
|
||||
|
||||
"Build": None, # Don't force build
|
||||
"IgnoreInputs": True,
|
||||
|
||||
# Inputs
|
||||
"SceneFile": scene,
|
||||
"OutputDriver": "/out/REMOTE_PUBLISH",
|
||||
|
||||
# Mandatory for Deadline
|
||||
"Version": version,
|
||||
|
||||
},
|
||||
|
||||
# Mandatory for Deadline, may be empty
|
||||
"AuxFiles": []
|
||||
"AuxFiles": [],
|
||||
}
|
||||
|
||||
# Process submission per individual instance if the submission
|
||||
|
|
@ -108,14 +105,14 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
for instance in instance_names:
|
||||
# Clarify job name per submission (include instance name)
|
||||
payload["JobInfo"]["Name"] = job_name + " - %s" % instance
|
||||
self.submit_job(payload,
|
||||
instances=[instance],
|
||||
deadline=AVALON_DEADLINE)
|
||||
self.submit_job(
|
||||
payload, instances=[instance], deadline=AVALON_DEADLINE
|
||||
)
|
||||
else:
|
||||
# Submit a single job
|
||||
self.submit_job(payload,
|
||||
instances=instance_names,
|
||||
deadline=AVALON_DEADLINE)
|
||||
self.submit_job(
|
||||
payload, instances=instance_names, deadline=AVALON_DEADLINE
|
||||
)
|
||||
|
||||
def submit_job(self, payload, instances, deadline):
|
||||
|
||||
|
|
@ -130,16 +127,21 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
"AVALON_TOOLS",
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **api.Session)
|
||||
environment = dict(
|
||||
{key: os.environ[key] for key in keys if key in os.environ},
|
||||
**api.Session
|
||||
)
|
||||
environment["PYBLISH_ACTIVE_INSTANCES"] = ",".join(instances)
|
||||
|
||||
payload["JobInfo"].update({
|
||||
"EnvironmentKeyValue%d" % index: "{key}={value}".format(
|
||||
key=key,
|
||||
value=environment[key]
|
||||
) for index, key in enumerate(environment)
|
||||
})
|
||||
payload["JobInfo"].update(
|
||||
{
|
||||
"EnvironmentKeyValue%d"
|
||||
% index: "{key}={value}".format(
|
||||
key=key, value=environment[key]
|
||||
)
|
||||
for index, key in enumerate(environment)
|
||||
}
|
||||
)
|
||||
|
||||
# Submit
|
||||
self.log.info("Submitting..")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import openpype.api
|
|||
|
||||
|
||||
class ValidateVDBInputNode(pyblish.api.InstancePlugin):
|
||||
"""Validate that the node connected to the output node is of type VDB
|
||||
"""Validate that the node connected to the output node is of type VDB.
|
||||
|
||||
Regardless of the amount of VDBs create the output will need to have an
|
||||
equal amount of VDBs, points, primitives and vertices
|
||||
|
|
@ -24,8 +24,9 @@ class ValidateVDBInputNode(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Node connected to the output node is not"
|
||||
"of type VDB!")
|
||||
raise RuntimeError(
|
||||
"Node connected to the output node is not" "of type VDB!"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
|
|
@ -16,15 +16,17 @@ class ValidateAbcPrimitiveToDetail(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder + 0.1
|
||||
families = ["colorbleed.pointcache"]
|
||||
families = ["pointcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Primitive to Detail (Abc)"
|
||||
|
||||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Primitives found with inconsistent primitive "
|
||||
"to detail attributes. See log.")
|
||||
raise RuntimeError(
|
||||
"Primitives found with inconsistent primitive "
|
||||
"to detail attributes. See log."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -34,21 +36,27 @@ class ValidateAbcPrimitiveToDetail(pyblish.api.InstancePlugin):
|
|||
rop = instance[0]
|
||||
pattern = rop.parm("prim_to_detail_pattern").eval().strip()
|
||||
if not pattern:
|
||||
cls.log.debug("Alembic ROP has no 'Primitive to Detail' pattern. "
|
||||
"Validation is ignored..")
|
||||
cls.log.debug(
|
||||
"Alembic ROP has no 'Primitive to Detail' pattern. "
|
||||
"Validation is ignored.."
|
||||
)
|
||||
return
|
||||
|
||||
build_from_path = rop.parm("build_from_path").eval()
|
||||
if not build_from_path:
|
||||
cls.log.debug("Alembic ROP has 'Build from Path' disabled. "
|
||||
"Validation is ignored..")
|
||||
cls.log.debug(
|
||||
"Alembic ROP has 'Build from Path' disabled. "
|
||||
"Validation is ignored.."
|
||||
)
|
||||
return
|
||||
|
||||
path_attr = rop.parm("path_attrib").eval()
|
||||
if not path_attr:
|
||||
cls.log.error("The Alembic ROP node has no Path Attribute"
|
||||
"value set, but 'Build Hierarchy from Attribute'"
|
||||
"is enabled.")
|
||||
cls.log.error(
|
||||
"The Alembic ROP node has no Path Attribute"
|
||||
"value set, but 'Build Hierarchy from Attribute'"
|
||||
"is enabled."
|
||||
)
|
||||
return [rop.path()]
|
||||
|
||||
# Let's assume each attribute is explicitly named for now and has no
|
||||
|
|
@ -59,26 +67,32 @@ class ValidateAbcPrimitiveToDetail(pyblish.api.InstancePlugin):
|
|||
# Check if the primitive attribute exists
|
||||
frame = instance.data.get("startFrame", 0)
|
||||
geo = output.geometryAtFrame(frame)
|
||||
|
||||
|
||||
# If there are no primitives on the start frame then it might be
|
||||
# something that is emitted over time. As such we can't actually
|
||||
# validate whether the attributes exist, because they won't exist
|
||||
# yet. In that case, just warn the user and allow it.
|
||||
if len(geo.iterPrims()) == 0:
|
||||
cls.log.warning("No primitives found on current frame. Validation"
|
||||
" for Primitive to Detail will be skipped.")
|
||||
cls.log.warning(
|
||||
"No primitives found on current frame. Validation"
|
||||
" for Primitive to Detail will be skipped."
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
attrib = geo.findPrimAttrib(path_attr)
|
||||
if not attrib:
|
||||
cls.log.info("Geometry Primitives are missing "
|
||||
"path attribute: `%s`" % path_attr)
|
||||
cls.log.info(
|
||||
"Geometry Primitives are missing "
|
||||
"path attribute: `%s`" % path_attr
|
||||
)
|
||||
return [output.path()]
|
||||
|
||||
# Ensure at least a single string value is present
|
||||
if not attrib.strings():
|
||||
cls.log.info("Primitive path attribute has no "
|
||||
"string values: %s" % path_attr)
|
||||
cls.log.info(
|
||||
"Primitive path attribute has no "
|
||||
"string values: %s" % path_attr
|
||||
)
|
||||
return [output.path()]
|
||||
|
||||
paths = None
|
||||
|
|
@ -111,6 +125,8 @@ class ValidateAbcPrimitiveToDetail(pyblish.api.InstancePlugin):
|
|||
# Primitive to Detail attribute then we consider it
|
||||
# inconsistent and invalidate the ROP node's content.
|
||||
if len(values) > 1:
|
||||
cls.log.warning("Path has multiple values: %s (path: %s)"
|
||||
% (list(values), path))
|
||||
cls.log.warning(
|
||||
"Path has multiple values: %s (path: %s)"
|
||||
% (list(values), path)
|
||||
)
|
||||
return [output.path()]
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@ import openpype.api
|
|||
|
||||
class ValidateAlembicROPFaceSets(pyblish.api.InstancePlugin):
|
||||
"""Validate Face Sets are disabled for extraction to pointcache.
|
||||
|
||||
|
||||
When groups are saved as Face Sets with the Alembic these show up
|
||||
as shadingEngine connections in Maya - however, with animated groups
|
||||
these connections in Maya won't work as expected, it won't update per
|
||||
frame. Additionally, it can break shader assignments in some cases
|
||||
frame. Additionally, it can break shader assignments in some cases
|
||||
where it requires to first break this connection to allow a shader to
|
||||
be assigned.
|
||||
|
||||
|
||||
It is allowed to include Face Sets, so only an issue is logged to
|
||||
identify that it could introduce issues down the pipeline.
|
||||
|
||||
"""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder + 0.1
|
||||
families = ["colorbleed.pointcache"]
|
||||
families = ["pointcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Alembic ROP Face Sets"
|
||||
|
||||
|
|
@ -26,10 +26,12 @@ class ValidateAlembicROPFaceSets(pyblish.api.InstancePlugin):
|
|||
|
||||
rop = instance[0]
|
||||
facesets = rop.parm("facesets").eval()
|
||||
|
||||
|
||||
# 0 = No Face Sets
|
||||
# 1 = Save Non-Empty Groups as Face Sets
|
||||
# 2 = Save All Groups As Face Sets
|
||||
if facesets != 0:
|
||||
self.log.warning("Alembic ROP saves 'Face Sets' for Geometry. "
|
||||
"Are you sure you want this?")
|
||||
if facesets != 0:
|
||||
self.log.warning(
|
||||
"Alembic ROP saves 'Face Sets' for Geometry. "
|
||||
"Are you sure you want this?"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import colorbleed.api
|
|||
|
||||
|
||||
class ValidateAlembicInputNode(pyblish.api.InstancePlugin):
|
||||
"""Validate that the node connected to the output is correct
|
||||
"""Validate that the node connected to the output is correct.
|
||||
|
||||
The connected node cannot be of the following types for Alembic:
|
||||
- VDB
|
||||
|
|
@ -12,22 +12,24 @@ class ValidateAlembicInputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = colorbleed.api.ValidateContentsOrder + 0.1
|
||||
families = ["colorbleed.pointcache"]
|
||||
families = ["pointcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Input Node (Abc)"
|
||||
|
||||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Primitive types found that are not supported"
|
||||
"for Alembic output.")
|
||||
raise RuntimeError(
|
||||
"Primitive types found that are not supported"
|
||||
"for Alembic output."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
||||
invalid_prim_types = ["VDB", "Volume"]
|
||||
node = instance.data["output_node"]
|
||||
|
||||
|
||||
if not hasattr(node, "geometry"):
|
||||
# In the case someone has explicitly set an Object
|
||||
# node instead of a SOP node in Geometry context
|
||||
|
|
@ -35,15 +37,16 @@ class ValidateAlembicInputNode(pyblish.api.InstancePlugin):
|
|||
# export object transforms.
|
||||
cls.log.warning("No geometry output node found, skipping check..")
|
||||
return
|
||||
|
||||
|
||||
frame = instance.data.get("startFrame", 0)
|
||||
geo = node.geometryAtFrame(frame)
|
||||
|
||||
|
||||
invalid = False
|
||||
for prim_type in invalid_prim_types:
|
||||
if geo.countPrimType(prim_type) > 0:
|
||||
cls.log.error("Found a primitive which is of type '%s' !"
|
||||
% prim_type)
|
||||
cls.log.error(
|
||||
"Found a primitive which is of type '%s' !" % prim_type
|
||||
)
|
||||
invalid = True
|
||||
|
||||
if invalid:
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ class ValidateAnimationSettings(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output settings do no match for '%s'" %
|
||||
instance)
|
||||
raise RuntimeError(
|
||||
"Output settings do no match for '%s'" % instance
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pyblish.api
|
||||
import colorbleed.api
|
||||
import openpype.api
|
||||
|
||||
|
||||
class ValidateBypassed(pyblish.api.InstancePlugin):
|
||||
|
|
@ -11,7 +11,7 @@ class ValidateBypassed(pyblish.api.InstancePlugin):
|
|||
|
||||
"""
|
||||
|
||||
order = colorbleed.api.ValidateContentsOrder - 0.1
|
||||
order = openpype.api.ValidateContentsOrder - 0.1
|
||||
families = ["*"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate ROP Bypass"
|
||||
|
|
@ -27,8 +27,8 @@ class ValidateBypassed(pyblish.api.InstancePlugin):
|
|||
if invalid:
|
||||
rop = invalid[0]
|
||||
raise RuntimeError(
|
||||
"ROP node %s is set to bypass, publishing cannot continue.." %
|
||||
rop.path()
|
||||
"ROP node %s is set to bypass, publishing cannot continue.."
|
||||
% rop.path()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ class ValidateCameraROP(pyblish.api.InstancePlugin):
|
|||
"""Validate Camera ROP settings."""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
families = ['colorbleed.camera']
|
||||
hosts = ['houdini']
|
||||
label = 'Camera ROP'
|
||||
families = ["camera"]
|
||||
hosts = ["houdini"]
|
||||
label = "Camera ROP"
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -16,8 +16,10 @@ class ValidateCameraROP(pyblish.api.InstancePlugin):
|
|||
|
||||
node = instance[0]
|
||||
if node.parm("use_sop_path").eval():
|
||||
raise RuntimeError("Alembic ROP for Camera export should not be "
|
||||
"set to 'Use Sop Path'. Please disable.")
|
||||
raise RuntimeError(
|
||||
"Alembic ROP for Camera export should not be "
|
||||
"set to 'Use Sop Path'. Please disable."
|
||||
)
|
||||
|
||||
# Get the root and objects parameter of the Alembic ROP node
|
||||
root = node.parm("root").eval()
|
||||
|
|
@ -35,7 +37,7 @@ class ValidateCameraROP(pyblish.api.InstancePlugin):
|
|||
raise ValueError("Camera path does not exist: %s" % path)
|
||||
|
||||
if camera.type().name() != "cam":
|
||||
raise ValueError("Object set in Alembic ROP is not a camera: "
|
||||
"%s (type: %s)" % (camera, camera.type().name()))
|
||||
|
||||
|
||||
raise ValueError(
|
||||
"Object set in Alembic ROP is not a camera: "
|
||||
"%s (type: %s)" % (camera, camera.type().name())
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["colorbleed.imagesequence"]
|
||||
families = ["imagesequence"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate COP Output Node"
|
||||
|
||||
|
|
@ -20,8 +20,10 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid)
|
||||
raise RuntimeError(
|
||||
"Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -32,27 +34,27 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
if output_node is None:
|
||||
node = instance[0]
|
||||
cls.log.error("COP Output node in '%s' does not exist. "
|
||||
"Ensure a valid COP output path is set."
|
||||
% node.path())
|
||||
cls.log.error(
|
||||
"COP Output node in '%s' does not exist. "
|
||||
"Ensure a valid COP output path is set." % node.path()
|
||||
)
|
||||
|
||||
return [node.path()]
|
||||
|
||||
# Output node must be a Sop node.
|
||||
if not isinstance(output_node, hou.CopNode):
|
||||
cls.log.error("Output node %s is not a COP node. "
|
||||
"COP Path must point to a COP node, "
|
||||
"instead found category type: %s" % (
|
||||
output_node.path(),
|
||||
output_node.type().category().name()
|
||||
)
|
||||
)
|
||||
cls.log.error(
|
||||
"Output node %s is not a COP node. "
|
||||
"COP Path must point to a COP node, "
|
||||
"instead found category type: %s"
|
||||
% (output_node.path(), output_node.type().category().name())
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
||||
|
||||
# For the sake of completeness also assert the category type
|
||||
# is Cop2 to avoid potential edge case scenarios even though
|
||||
# the isinstance check above should be stricter than this category
|
||||
assert output_node.type().category().name() == "Cop2", (
|
||||
"Output node %s is not of category Cop2. This is a bug.." %
|
||||
output_node.path()
|
||||
"Output node %s is not of category Cop2. This is a bug.."
|
||||
% output_node.path()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,24 +15,23 @@ class ValidateFileExtension(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["pointcache",
|
||||
"camera",
|
||||
"vdbcache"]
|
||||
families = ["pointcache", "camera", "vdbcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Output File Extension"
|
||||
|
||||
family_extensions = {
|
||||
"pointcache": ".abc",
|
||||
"camera": ".abc",
|
||||
"vdbcache": ".vdb"
|
||||
"vdbcache": ".vdb",
|
||||
}
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("ROP node has incorrect "
|
||||
"file extension: %s" % invalid)
|
||||
raise RuntimeError(
|
||||
"ROP node has incorrect " "file extension: %s" % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from openpype.hosts.houdini.api import lib
|
|||
|
||||
|
||||
class ValidateFrameToken(pyblish.api.InstancePlugin):
|
||||
"""Validate if the unexpanded string contains the frame ('$F') token
|
||||
"""Validate if the unexpanded string contains the frame ('$F') token.
|
||||
|
||||
This validator will *only* check the output parameter of the node if
|
||||
the Valid Frame Range is not set to 'Render Current Frame'
|
||||
|
|
@ -29,8 +29,9 @@ class ValidateFrameToken(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output settings do no match for '%s'" %
|
||||
instance)
|
||||
raise RuntimeError(
|
||||
"Output settings do no match for '%s'" % instance
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
|
|
@ -24,5 +24,7 @@ class ValidateHoudiniCommercialLicense(pyblish.api.InstancePlugin):
|
|||
|
||||
license = hou.licenseCategory()
|
||||
if license != hou.licenseCategoryType.Commercial:
|
||||
raise RuntimeError("USD Publishing requires a full Commercial "
|
||||
"license. You are on: %s" % license)
|
||||
raise RuntimeError(
|
||||
"USD Publishing requires a full Commercial "
|
||||
"license. You are on: %s" % license
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
import pyblish.api
|
||||
import colorbleed.api
|
||||
import openpype.api
|
||||
|
||||
|
||||
class ValidateIntermediateDirectoriesChecked(pyblish.api.InstancePlugin):
|
||||
"""Validate Create Intermediate Directories is enabled on ROP node."""
|
||||
|
||||
order = colorbleed.api.ValidateContentsOrder
|
||||
families = ['colorbleed.pointcache',
|
||||
'colorbleed.camera',
|
||||
'colorbleed.vdbcache']
|
||||
hosts = ['houdini']
|
||||
label = 'Create Intermediate Directories Checked'
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
families = ["pointcache", "camera", "vdbcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Create Intermediate Directories Checked"
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Found ROP node with Create Intermediate "
|
||||
"Directories turned off: %s" % invalid)
|
||||
raise RuntimeError(
|
||||
"Found ROP node with Create Intermediate "
|
||||
"Directories turned off: %s" % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -30,5 +30,3 @@ class ValidateIntermediateDirectoriesChecked(pyblish.api.InstancePlugin):
|
|||
result.append(node.path())
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ def cook_in_range(node, start, end):
|
|||
node.cook(force=False)
|
||||
else:
|
||||
node.cook(force=False, frame_range=(start, start))
|
||||
|
||||
|
||||
|
||||
def get_errors(node):
|
||||
"""Get cooking errors.
|
||||
|
|
@ -29,8 +29,8 @@ class ValidateNoErrors(pyblish.api.InstancePlugin):
|
|||
"""Validate the Instance has no current cooking errors."""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
hosts = ['houdini']
|
||||
label = 'Validate no errors'
|
||||
hosts = ["houdini"]
|
||||
label = "Validate no errors"
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -45,20 +45,21 @@ class ValidateNoErrors(pyblish.api.InstancePlugin):
|
|||
for node in validate_nodes:
|
||||
self.log.debug("Validating for errors: %s" % node.path())
|
||||
errors = get_errors(node)
|
||||
|
||||
|
||||
if errors:
|
||||
# If there are current errors, then try an unforced cook
|
||||
# to see whether the error will disappear.
|
||||
self.log.debug("Recooking to revalidate error "
|
||||
"is up to date for: %s" % node.path())
|
||||
self.log.debug(
|
||||
"Recooking to revalidate error "
|
||||
"is up to date for: %s" % node.path()
|
||||
)
|
||||
current_frame = hou.intFrame()
|
||||
start = instance.data.get("startFrame", current_frame)
|
||||
end = instance.data.get("endFrame", current_frame)
|
||||
start = instance.data.get("frameStart", current_frame)
|
||||
end = instance.data.get("frameEnd", current_frame)
|
||||
cook_in_range(node, start=start, end=end)
|
||||
|
||||
|
||||
# Check for errors again after the forced recook
|
||||
errors = get_errors(node)
|
||||
if errors:
|
||||
self.log.error(errors)
|
||||
raise RuntimeError("Node has errors: %s" % node.path())
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import openpype.api
|
|||
|
||||
|
||||
class ValidatOutputNodeExists(pyblish.api.InstancePlugin):
|
||||
"""Validate if node attribute Create intermediate Directories is turned on
|
||||
"""Validate if node attribute Create intermediate Directories is turned on.
|
||||
|
||||
Rules:
|
||||
* The node must have Create intermediate Directories turned on to
|
||||
|
|
@ -13,7 +13,7 @@ class ValidatOutputNodeExists(pyblish.api.InstancePlugin):
|
|||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
families = ["*"]
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
label = "Output Node Exists"
|
||||
|
||||
def process(self, instance):
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ class ValidateOutputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["pointcache",
|
||||
"vdbcache"]
|
||||
families = ["pointcache", "vdbcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Output Node"
|
||||
|
||||
|
|
@ -23,8 +22,10 @@ class ValidateOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid)
|
||||
raise RuntimeError(
|
||||
"Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -35,39 +36,42 @@ class ValidateOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
if output_node is None:
|
||||
node = instance[0]
|
||||
cls.log.error("SOP Output node in '%s' does not exist. "
|
||||
"Ensure a valid SOP output path is set."
|
||||
% node.path())
|
||||
cls.log.error(
|
||||
"SOP Output node in '%s' does not exist. "
|
||||
"Ensure a valid SOP output path is set." % node.path()
|
||||
)
|
||||
|
||||
return [node.path()]
|
||||
|
||||
# Output node must be a Sop node.
|
||||
if not isinstance(output_node, hou.SopNode):
|
||||
cls.log.error("Output node %s is not a SOP node. "
|
||||
"SOP Path must point to a SOP node, "
|
||||
"instead found category type: %s" % (
|
||||
output_node.path(),
|
||||
output_node.type().category().name()
|
||||
)
|
||||
)
|
||||
cls.log.error(
|
||||
"Output node %s is not a SOP node. "
|
||||
"SOP Path must point to a SOP node, "
|
||||
"instead found category type: %s"
|
||||
% (output_node.path(), output_node.type().category().name())
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
||||
# For the sake of completeness also assert the category type
|
||||
# is Sop to avoid potential edge case scenarios even though
|
||||
# the isinstance check above should be stricter than this category
|
||||
assert output_node.type().category().name() == "Sop", (
|
||||
"Output node %s is not of category Sop. This is a bug.." %
|
||||
output_node.path()
|
||||
"Output node %s is not of category Sop. This is a bug.."
|
||||
% output_node.path()
|
||||
)
|
||||
|
||||
# Check if output node has incoming connections
|
||||
if not output_node.inputConnections():
|
||||
cls.log.error("Output node `%s` has no incoming connections"
|
||||
% output_node.path())
|
||||
cls.log.error(
|
||||
"Output node `%s` has no incoming connections"
|
||||
% output_node.path()
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
||||
# Ensure the output node has at least Geometry data
|
||||
if not output_node.geometry():
|
||||
cls.log.error("Output node `%s` has no geometry data."
|
||||
% output_node.path())
|
||||
cls.log.error(
|
||||
"Output node `%s` has no geometry data." % output_node.path()
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ class ValidatePrimitiveHierarchyPaths(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("See log for details. "
|
||||
"Invalid nodes: {0}".format(invalid))
|
||||
raise RuntimeError(
|
||||
"See log for details. " "Invalid nodes: {0}".format(invalid)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -32,15 +33,19 @@ class ValidatePrimitiveHierarchyPaths(pyblish.api.InstancePlugin):
|
|||
rop = instance[0]
|
||||
build_from_path = rop.parm("build_from_path").eval()
|
||||
if not build_from_path:
|
||||
cls.log.debug("Alembic ROP has 'Build from Path' disabled. "
|
||||
"Validation is ignored..")
|
||||
cls.log.debug(
|
||||
"Alembic ROP has 'Build from Path' disabled. "
|
||||
"Validation is ignored.."
|
||||
)
|
||||
return
|
||||
|
||||
path_attr = rop.parm("path_attrib").eval()
|
||||
if not path_attr:
|
||||
cls.log.error("The Alembic ROP node has no Path Attribute"
|
||||
"value set, but 'Build Hierarchy from Attribute'"
|
||||
"is enabled.")
|
||||
cls.log.error(
|
||||
"The Alembic ROP node has no Path Attribute"
|
||||
"value set, but 'Build Hierarchy from Attribute'"
|
||||
"is enabled."
|
||||
)
|
||||
return [rop.path()]
|
||||
|
||||
cls.log.debug("Checking for attribute: %s" % path_attr)
|
||||
|
|
@ -54,22 +59,28 @@ class ValidatePrimitiveHierarchyPaths(pyblish.api.InstancePlugin):
|
|||
# warning that the check can't be done consistently and skip
|
||||
# validation.
|
||||
if len(geo.iterPrims()) == 0:
|
||||
cls.log.warning("No primitives found on current frame. Validation"
|
||||
" for primitive hierarchy paths will be skipped,"
|
||||
" thus can't be validated.")
|
||||
cls.log.warning(
|
||||
"No primitives found on current frame. Validation"
|
||||
" for primitive hierarchy paths will be skipped,"
|
||||
" thus can't be validated."
|
||||
)
|
||||
return
|
||||
|
||||
# Check if there are any values for the primitives
|
||||
attrib = geo.findPrimAttrib(path_attr)
|
||||
if not attrib:
|
||||
cls.log.info("Geometry Primitives are missing "
|
||||
"path attribute: `%s`" % path_attr)
|
||||
cls.log.info(
|
||||
"Geometry Primitives are missing "
|
||||
"path attribute: `%s`" % path_attr
|
||||
)
|
||||
return [output.path()]
|
||||
|
||||
# Ensure at least a single string value is present
|
||||
if not attrib.strings():
|
||||
cls.log.info("Primitive path attribute has no "
|
||||
"string values: %s" % path_attr)
|
||||
cls.log.info(
|
||||
"Primitive path attribute has no "
|
||||
"string values: %s" % path_attr
|
||||
)
|
||||
return [output.path()]
|
||||
|
||||
paths = geo.primStringAttribValues(path_attr)
|
||||
|
|
@ -78,8 +89,8 @@ class ValidatePrimitiveHierarchyPaths(pyblish.api.InstancePlugin):
|
|||
invalid_prims = [i for i, path in enumerate(paths) if not path]
|
||||
if invalid_prims:
|
||||
num_prims = len(geo.iterPrims()) # faster than len(geo.prims())
|
||||
cls.log.info("Prims have no value for attribute `%s` "
|
||||
"(%s of %s prims)" % (path_attr,
|
||||
len(invalid_prims),
|
||||
num_prims))
|
||||
cls.log.info(
|
||||
"Prims have no value for attribute `%s` "
|
||||
"(%s of %s prims)" % (path_attr, len(invalid_prims), num_prims)
|
||||
)
|
||||
return [output.path()]
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ class ValidateRemotePublishOutNode(pyblish.api.ContextPlugin):
|
|||
|
||||
order = pyblish.api.ValidatorOrder - 0.4
|
||||
families = ["*"]
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
targets = ["deadline"]
|
||||
label = 'Remote Publish ROP node'
|
||||
label = "Remote Publish ROP node"
|
||||
actions = [openpype.api.RepairContextAction]
|
||||
|
||||
def process(self, context):
|
||||
|
|
@ -30,14 +30,14 @@ class ValidateRemotePublishOutNode(pyblish.api.ContextPlugin):
|
|||
assert node.type().name() == "shell", "Must be shell ROP node"
|
||||
assert node.parm("command").eval() == "", "Must have no command"
|
||||
assert not node.parm("shellexec").eval(), "Must not execute in shell"
|
||||
assert node.parm("prerender").eval() == cmd, (
|
||||
"REMOTE_PUBLISH node does not have correct prerender script."
|
||||
)
|
||||
assert node.parm("lprerender").eval() == "python", (
|
||||
"REMOTE_PUBLISH node prerender script type not set to 'python'"
|
||||
)
|
||||
assert (
|
||||
node.parm("prerender").eval() == cmd
|
||||
), "REMOTE_PUBLISH node does not have correct prerender script."
|
||||
assert (
|
||||
node.parm("lprerender").eval() == "python"
|
||||
), "REMOTE_PUBLISH node prerender script type not set to 'python'"
|
||||
|
||||
@classmethod
|
||||
def repair(cls, context):
|
||||
"""(Re)create the node if it fails to pass validation"""
|
||||
"""(Re)create the node if it fails to pass validation."""
|
||||
lib.create_remote_publish_node(force=True)
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ class ValidateRemotePublishEnabled(pyblish.api.ContextPlugin):
|
|||
|
||||
order = pyblish.api.ValidatorOrder - 0.39
|
||||
families = ["*"]
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
targets = ["deadline"]
|
||||
label = 'Remote Publish ROP enabled'
|
||||
label = "Remote Publish ROP enabled"
|
||||
actions = [openpype.api.RepairContextAction]
|
||||
|
||||
def process(self, context):
|
||||
|
|
@ -25,7 +25,7 @@ class ValidateRemotePublishEnabled(pyblish.api.ContextPlugin):
|
|||
|
||||
@classmethod
|
||||
def repair(cls, context):
|
||||
"""(Re)create the node if it fails to pass validation"""
|
||||
"""(Re)create the node if it fails to pass validation."""
|
||||
|
||||
node = hou.node("/out/REMOTE_PUBLISH")
|
||||
if not node:
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ class ValidateSopOutputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["pointcache",
|
||||
"vdbcache"]
|
||||
families = ["pointcache", "vdbcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Output Node"
|
||||
|
||||
|
|
@ -23,8 +22,10 @@ class ValidateSopOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid)
|
||||
raise RuntimeError(
|
||||
"Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -35,29 +36,29 @@ class ValidateSopOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
if output_node is None:
|
||||
node = instance[0]
|
||||
cls.log.error("SOP Output node in '%s' does not exist. "
|
||||
"Ensure a valid SOP output path is set."
|
||||
% node.path())
|
||||
cls.log.error(
|
||||
"SOP Output node in '%s' does not exist. "
|
||||
"Ensure a valid SOP output path is set." % node.path()
|
||||
)
|
||||
|
||||
return [node.path()]
|
||||
|
||||
# Output node must be a Sop node.
|
||||
if not isinstance(output_node, hou.SopNode):
|
||||
cls.log.error("Output node %s is not a SOP node. "
|
||||
"SOP Path must point to a SOP node, "
|
||||
"instead found category type: %s" % (
|
||||
output_node.path(),
|
||||
output_node.type().category().name()
|
||||
)
|
||||
)
|
||||
cls.log.error(
|
||||
"Output node %s is not a SOP node. "
|
||||
"SOP Path must point to a SOP node, "
|
||||
"instead found category type: %s"
|
||||
% (output_node.path(), output_node.type().category().name())
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
||||
# For the sake of completeness also assert the category type
|
||||
# is Sop to avoid potential edge case scenarios even though
|
||||
# the isinstance check above should be stricter than this category
|
||||
assert output_node.type().category().name() == "Sop", (
|
||||
"Output node %s is not of category Sop. This is a bug.." %
|
||||
output_node.path()
|
||||
"Output node %s is not of category Sop. This is a bug.."
|
||||
% output_node.path()
|
||||
)
|
||||
|
||||
# Ensure the node is cooked and succeeds to cook so we can correctly
|
||||
|
|
@ -73,6 +74,7 @@ class ValidateSopOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
# Ensure the output node has at least Geometry data
|
||||
if not output_node.geometry():
|
||||
cls.log.error("Output node `%s` has no geometry data."
|
||||
% output_node.path())
|
||||
cls.log.error(
|
||||
"Output node `%s` has no geometry data." % output_node.path()
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ class ValidateUSDLayerPathBackslashes(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["usdSetDress",
|
||||
"usdShade",
|
||||
"usd",
|
||||
"usdrender"]
|
||||
families = ["usdSetDress", "usdShade", "usd", "usdrender"]
|
||||
hosts = ["houdini"]
|
||||
label = "USD Layer path backslashes"
|
||||
optional = True
|
||||
|
|
@ -47,5 +44,7 @@ class ValidateUSDLayerPathBackslashes(pyblish.api.InstancePlugin):
|
|||
invalid.append(layer)
|
||||
|
||||
if invalid:
|
||||
raise RuntimeError("Loaded layers have backslashes. "
|
||||
"This is invalid for HUSK USD rendering.")
|
||||
raise RuntimeError(
|
||||
"Loaded layers have backslashes. "
|
||||
"This is invalid for HUSK USD rendering."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ def fullname(o):
|
|||
module = o.__module__
|
||||
if module is None or module == str.__module__:
|
||||
return o.__name__
|
||||
return module + '.' + o.__name__
|
||||
return module + "." + o.__name__
|
||||
|
||||
|
||||
class ValidateUsdModel(pyblish.api.InstancePlugin):
|
||||
|
|
@ -32,7 +32,7 @@ class ValidateUsdModel(pyblish.api.InstancePlugin):
|
|||
UsdRender.Settings,
|
||||
UsdRender.Product,
|
||||
UsdRender.Var,
|
||||
UsdLux.Light
|
||||
UsdLux.Light,
|
||||
]
|
||||
|
||||
def process(self, instance):
|
||||
|
|
@ -64,6 +64,7 @@ class ValidateUsdShade(ValidateUsdModel):
|
|||
Disallow Render settings, products, vars and Lux lights.
|
||||
|
||||
"""
|
||||
|
||||
families = ["usdShade"]
|
||||
label = "Validate USD Shade"
|
||||
|
||||
|
|
@ -71,5 +72,5 @@ class ValidateUsdShade(ValidateUsdModel):
|
|||
UsdRender.Settings,
|
||||
UsdRender.Product,
|
||||
UsdRender.Var,
|
||||
UsdLux.Light
|
||||
UsdLux.Light,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ValidateUSDOutputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["colorbleed.usd"]
|
||||
families = ["usd"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Output Node (USD)"
|
||||
|
||||
|
|
@ -20,8 +20,10 @@ class ValidateUSDOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid)
|
||||
raise RuntimeError(
|
||||
"Output node(s) `%s` are incorrect. "
|
||||
"See plug-in log for details." % invalid
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
@ -32,19 +34,19 @@ class ValidateUSDOutputNode(pyblish.api.InstancePlugin):
|
|||
|
||||
if output_node is None:
|
||||
node = instance[0]
|
||||
cls.log.error("USD node '%s' LOP path does not exist. "
|
||||
"Ensure a valid LOP path is set."
|
||||
% node.path())
|
||||
cls.log.error(
|
||||
"USD node '%s' LOP path does not exist. "
|
||||
"Ensure a valid LOP path is set." % node.path()
|
||||
)
|
||||
|
||||
return [node.path()]
|
||||
|
||||
# Output node must be a Sop node.
|
||||
if not isinstance(output_node, hou.LopNode):
|
||||
cls.log.error("Output node %s is not a LOP node. "
|
||||
"LOP Path must point to a LOP node, "
|
||||
"instead found category type: %s" % (
|
||||
output_node.path(),
|
||||
output_node.type().category().name()
|
||||
)
|
||||
)
|
||||
cls.log.error(
|
||||
"Output node %s is not a LOP node. "
|
||||
"LOP Path must point to a LOP node, "
|
||||
"instead found category type: %s"
|
||||
% (output_node.path(), output_node.type().category().name())
|
||||
)
|
||||
return [output_node.path()]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class ValidateUSDRenderProductNames(pyblish.api.InstancePlugin):
|
|||
"""Validate USD Render Product names are correctly set absolute paths."""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
families = ["colorbleed.usdrender"]
|
||||
families = ["usdrender"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate USD Render Product Names"
|
||||
optional = True
|
||||
|
|
@ -21,8 +21,9 @@ class ValidateUSDRenderProductNames(pyblish.api.InstancePlugin):
|
|||
invalid.append("Detected empty output filepath.")
|
||||
|
||||
if not os.path.isabs(filepath):
|
||||
invalid.append("Output file path is not "
|
||||
"absolute path: %s" % filepath)
|
||||
invalid.append(
|
||||
"Output file path is not " "absolute path: %s" % filepath
|
||||
)
|
||||
|
||||
if invalid:
|
||||
for message in invalid:
|
||||
|
|
|
|||
|
|
@ -41,11 +41,14 @@ class ValidateUsdSetDress(pyblish.api.InstancePlugin):
|
|||
break
|
||||
else:
|
||||
prim_path = node.GetPath()
|
||||
self.log.error("%s is not referenced geometry." %
|
||||
prim_path)
|
||||
self.log.error(
|
||||
"%s is not referenced geometry." % prim_path
|
||||
)
|
||||
invalid.append(node)
|
||||
|
||||
if invalid:
|
||||
raise RuntimeError("SetDress contains local geometry. "
|
||||
"This is not allowed, it must be an assembly "
|
||||
"of referenced assets.")
|
||||
raise RuntimeError(
|
||||
"SetDress contains local geometry. "
|
||||
"This is not allowed, it must be an assembly "
|
||||
"of referenced assets."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ class ValidateUSDShadeModelExists(pyblish.api.InstancePlugin):
|
|||
"""Validate the Instance has no current cooking errors."""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
hosts = ['houdini']
|
||||
hosts = ["houdini"]
|
||||
families = ["usdShade"]
|
||||
label = 'USD Shade model exists'
|
||||
label = "USD Shade model exists"
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -23,14 +23,19 @@ class ValidateUSDShadeModelExists(pyblish.api.InstancePlugin):
|
|||
shade_subset = subset.split(".", 1)[0]
|
||||
model_subset = re.sub("^usdShade", "usdModel", shade_subset)
|
||||
|
||||
asset_doc = io.find_one({"name": asset,
|
||||
"type": "asset"})
|
||||
asset_doc = io.find_one({"name": asset, "type": "asset"})
|
||||
if not asset_doc:
|
||||
raise RuntimeError("Asset does not exist: %s" % asset)
|
||||
|
||||
subset_doc = io.find_one({"name": model_subset,
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]})
|
||||
subset_doc = io.find_one(
|
||||
{
|
||||
"name": model_subset,
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"],
|
||||
}
|
||||
)
|
||||
if not subset_doc:
|
||||
raise RuntimeError("USD Model subset not found: "
|
||||
"%s (%s)" % (model_subset, asset))
|
||||
raise RuntimeError(
|
||||
"USD Model subset not found: "
|
||||
"%s (%s)" % (model_subset, asset)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import re
|
|||
import pyblish.api
|
||||
import openpype.api
|
||||
|
||||
from avalon import io
|
||||
import hou
|
||||
|
||||
|
||||
|
|
@ -46,15 +45,21 @@ class ValidateUsdShadeWorkspace(pyblish.api.InstancePlugin):
|
|||
highest = max(highest, other_version)
|
||||
|
||||
if version != highest:
|
||||
raise RuntimeError("Shading Workspace is not the latest version."
|
||||
" Found %s. Latest is %s." % (version, highest))
|
||||
raise RuntimeError(
|
||||
"Shading Workspace is not the latest version."
|
||||
" Found %s. Latest is %s." % (version, highest)
|
||||
)
|
||||
|
||||
# There were some issues with the editable node not having the right
|
||||
# configured path. So for now let's assure that is correct to.from
|
||||
value = ('avalon://`chs("../asset_name")`/'
|
||||
'usdShade`chs("../model_variantname1")`.usd')
|
||||
value = (
|
||||
'avalon://`chs("../asset_name")`/'
|
||||
'usdShade`chs("../model_variantname1")`.usd'
|
||||
)
|
||||
rop_value = rop.parm("lopoutput").rawValue()
|
||||
if rop_value != value:
|
||||
raise RuntimeError("Shading Workspace has invalid 'lopoutput'"
|
||||
" parameter value. The Shading Workspace"
|
||||
" needs to be reset to its default values.")
|
||||
raise RuntimeError(
|
||||
"Shading Workspace has invalid 'lopoutput'"
|
||||
" parameter value. The Shading Workspace"
|
||||
" needs to be reset to its default values."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import openpype.api
|
|||
|
||||
|
||||
class ValidateVDBInputNode(pyblish.api.InstancePlugin):
|
||||
"""Validate that the node connected to the output node is of type VDB
|
||||
"""Validate that the node connected to the output node is of type VDB.
|
||||
|
||||
Regardless of the amount of VDBs create the output will need to have an
|
||||
equal amount of VDBs, points, primitives and vertices
|
||||
|
|
@ -24,8 +24,9 @@ class ValidateVDBInputNode(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Node connected to the output node is not"
|
||||
"of type VDB!")
|
||||
raise RuntimeError(
|
||||
"Node connected to the output node is not" "of type VDB!"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import hou
|
|||
|
||||
|
||||
class ValidateVDBOutputNode(pyblish.api.InstancePlugin):
|
||||
"""Validate that the node connected to the output node is of type VDB
|
||||
"""Validate that the node connected to the output node is of type VDB.
|
||||
|
||||
Regardless of the amount of VDBs create the output will need to have an
|
||||
equal amount of VDBs, points, primitives and vertices
|
||||
|
|
@ -18,36 +18,41 @@ class ValidateVDBOutputNode(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder + 0.1
|
||||
families = ["colorbleed.vdbcache"]
|
||||
families = ["vdbcache"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Output Node (VDB)"
|
||||
|
||||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Node connected to the output node is not"
|
||||
" of type VDB!")
|
||||
raise RuntimeError(
|
||||
"Node connected to the output node is not" " of type VDB!"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
||||
node = instance.data["output_node"]
|
||||
if node is None:
|
||||
cls.log.error("SOP path is not correctly set on "
|
||||
"ROP node '%s'." % instance[0].path())
|
||||
cls.log.error(
|
||||
"SOP path is not correctly set on "
|
||||
"ROP node '%s'." % instance[0].path()
|
||||
)
|
||||
return [instance]
|
||||
|
||||
frame = instance.data.get("startFrame", 0)
|
||||
|
||||
frame = instance.data.get("frameStart", 0)
|
||||
geometry = node.geometryAtFrame(frame)
|
||||
if geometry is None:
|
||||
# No geometry data on this node, maybe the node hasn't cooked?
|
||||
cls.log.error("SOP node has no geometry data. "
|
||||
"Is it cooked? %s" % node.path())
|
||||
cls.log.error(
|
||||
"SOP node has no geometry data. "
|
||||
"Is it cooked? %s" % node.path()
|
||||
)
|
||||
return [node]
|
||||
|
||||
prims = geometry.prims()
|
||||
nr_of_prims = len(prims)
|
||||
|
||||
|
||||
# All primitives must be hou.VDB
|
||||
invalid_prim = False
|
||||
for prim in prims:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue