mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge branch 'develop' into feature/global-collect-audio-plugin
This commit is contained in:
commit
7668fb830c
578 changed files with 42504 additions and 4815 deletions
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
"""
|
||||
|
||||
from openpype.api import Logger
|
||||
from openpype.lib import Logger
|
||||
from openpype.pipeline import load
|
||||
|
||||
log = Logger().get_logger(__name__)
|
||||
log = Logger.get_logger(__name__)
|
||||
|
||||
|
||||
class SetFrameRangeLoader(load.LoaderPlugin):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Shot/Asset mame</title>
|
||||
<description>
|
||||
## Invalid Shot/Asset name in subset
|
||||
|
||||
Following Node with name `{node_name}`:
|
||||
Is in context of `{correct_name}` but Node _asset_ knob is set as `{wrong_name}`.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Either use Repair or Select button.
|
||||
2. If you chose Select then rename asset knob to correct name.
|
||||
3. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="multiple_outputs">
|
||||
<title>Found multiple outputs</title>
|
||||
<description>
|
||||
## Invalid output amount
|
||||
|
||||
Backdrop is having more than one outgoing connections.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use button `Center node in node graph` and navigate to the backdrop.
|
||||
2. Reorganize nodes the way only one outgoing connection is present.
|
||||
3. Hit reload button on the publisher.
|
||||
</description>
|
||||
<detail>
|
||||
### How could this happen?
|
||||
|
||||
More than one node, which are found above the backdrop, are linked downstream or more output connections from a node also linked downstream.
|
||||
</detail>
|
||||
</error>
|
||||
<error id="no_nodes">
|
||||
<title>Empty backdrop</title>
|
||||
<description>
|
||||
## Invalid empty backdrop
|
||||
|
||||
Backdrop is empty and no nodes are found above it.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use button `Center node in node graph` and navigate to the backdrop.
|
||||
2. Add any node above it or delete it.
|
||||
3. Hit reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
36
openpype/hosts/nuke/plugins/publish/help/validate_gizmo.xml
Normal file
36
openpype/hosts/nuke/plugins/publish/help/validate_gizmo.xml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="multiple_outputs">
|
||||
<title>Found multiple outputs</title>
|
||||
<description>
|
||||
## Invalid amount of Output nodes
|
||||
|
||||
Group node `{node_name}` is having more than one Output node.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use button `Open Group`.
|
||||
2. Remove redundant Output node.
|
||||
3. Hit reload button on the publisher.
|
||||
</description>
|
||||
<detail>
|
||||
### How could this happen?
|
||||
|
||||
Perhaps you had created exciently more than one Output node.
|
||||
</detail>
|
||||
</error>
|
||||
<error id="no_inputs">
|
||||
<title>Missing Input nodes</title>
|
||||
<description>
|
||||
## Missing Input nodes
|
||||
|
||||
Make sure there is at least one connected Input node inside the group node with name `{node_name}`
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use button `Open Group`.
|
||||
2. Add at least one Input node and connect to other nodes.
|
||||
3. Hit reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
18
openpype/hosts/nuke/plugins/publish/help/validate_knobs.xml
Normal file
18
openpype/hosts/nuke/plugins/publish/help/validate_knobs.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Knobs value</title>
|
||||
<description>
|
||||
## Invalid node's knobs values
|
||||
|
||||
Following node knobs needs to be repaired:
|
||||
|
||||
{invalid_items}
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair button.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Output format</title>
|
||||
<description>
|
||||
## Invalid format setting
|
||||
|
||||
Either the Reformat node inside of the render group is missing or the Reformat node output format knob is not set to `root.format`.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair button.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Proxy mode</title>
|
||||
<description>
|
||||
## Invalid proxy mode value
|
||||
|
||||
Nuke is set to use Proxy. This is not supported by publisher.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair button.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Rendered Frames</title>
|
||||
<description>
|
||||
## Missing Rendered Frames
|
||||
|
||||
Render node "{node_name}" is set to "Use existing frames", but frames are missing.
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair button.
|
||||
2. Set different target.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Script attributes</title>
|
||||
<description>
|
||||
## Invalid Script attributes
|
||||
|
||||
Following script root attributes need to be fixed:
|
||||
|
||||
{failed_attributes}
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Knobs values</title>
|
||||
<description>
|
||||
## Invalid node's knobs values
|
||||
|
||||
Following write node knobs needs to be repaired:
|
||||
|
||||
{xml_msg}
|
||||
|
||||
### How to repair?
|
||||
|
||||
1. Use Repair button.
|
||||
2. Hit Reload button on the publisher.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -8,6 +8,7 @@ from openpype.hosts.nuke.api.lib import (
|
|||
add_publish_knob,
|
||||
get_avalon_knob_data
|
||||
)
|
||||
from openpype.pipeline import KnownPublishError
|
||||
|
||||
|
||||
class CollectWorkfile(pyblish.api.ContextPlugin):
|
||||
|
|
@ -22,6 +23,12 @@ class CollectWorkfile(pyblish.api.ContextPlugin):
|
|||
|
||||
current_file = os.path.normpath(nuke.root().name())
|
||||
|
||||
if current_file.lower() == "root":
|
||||
raise KnownPublishError(
|
||||
"Workfile is not correct file name. \n"
|
||||
"Use workfile tool to manage the name correctly."
|
||||
)
|
||||
|
||||
knob_data = get_avalon_knob_data(root)
|
||||
|
||||
add_publish_knob(root)
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import nuke
|
||||
|
||||
import pyblish.api
|
||||
import openpype.api
|
||||
from openpype.hosts.nuke.api.lib import (
|
||||
recreate_instance,
|
||||
reset_selection,
|
||||
select_nodes
|
||||
|
||||
import openpype.hosts.nuke.api.lib as nlib
|
||||
import openpype.hosts.nuke.api as nuke_api
|
||||
from openpype.pipeline.publish import (
|
||||
ValidateContentsOrder,
|
||||
PublishXmlValidationError,
|
||||
)
|
||||
|
||||
|
||||
class SelectInvalidInstances(pyblish.api.Action):
|
||||
"""Select invalid instances in Outliner."""
|
||||
|
||||
label = "Select Instances"
|
||||
label = "Select"
|
||||
icon = "briefcase"
|
||||
on = "failed"
|
||||
|
||||
|
|
@ -39,6 +39,7 @@ class SelectInvalidInstances(pyblish.api.Action):
|
|||
instances = pyblish.api.instances_by_plugin(failed, plugin)
|
||||
|
||||
if instances:
|
||||
self.deselect()
|
||||
self.log.info(
|
||||
"Selecting invalid nodes: %s" % ", ".join(
|
||||
[str(x) for x in instances]
|
||||
|
|
@ -50,12 +51,12 @@ class SelectInvalidInstances(pyblish.api.Action):
|
|||
self.deselect()
|
||||
|
||||
def select(self, instances):
|
||||
select_nodes(
|
||||
nlib.select_nodes(
|
||||
[nuke.toNode(str(x)) for x in instances]
|
||||
)
|
||||
|
||||
def deselect(self):
|
||||
reset_selection()
|
||||
nlib.reset_selection()
|
||||
|
||||
|
||||
class RepairSelectInvalidInstances(pyblish.api.Action):
|
||||
|
|
@ -85,12 +86,12 @@ class RepairSelectInvalidInstances(pyblish.api.Action):
|
|||
context_asset = context.data["assetEntity"]["name"]
|
||||
for instance in instances:
|
||||
origin_node = instance[0]
|
||||
recreate_instance(
|
||||
nuke_api.lib.recreate_instance(
|
||||
origin_node, avalon_data={"asset": context_asset}
|
||||
)
|
||||
|
||||
|
||||
class ValidateInstanceInContext(pyblish.api.InstancePlugin):
|
||||
class ValidateCorrectAssetName(pyblish.api.InstancePlugin):
|
||||
"""Validator to check if instance asset match context asset.
|
||||
|
||||
When working in per-shot style you always publish data in context of
|
||||
|
|
@ -99,15 +100,31 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin):
|
|||
|
||||
Action on this validator will select invalid instances in Outliner.
|
||||
"""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
label = "Instance in same Context"
|
||||
order = ValidateContentsOrder
|
||||
label = "Validate correct asset name"
|
||||
hosts = ["nuke"]
|
||||
actions = [SelectInvalidInstances, RepairSelectInvalidInstances]
|
||||
actions = [
|
||||
SelectInvalidInstances,
|
||||
RepairSelectInvalidInstances
|
||||
]
|
||||
optional = True
|
||||
|
||||
def process(self, instance):
|
||||
asset = instance.data.get("asset")
|
||||
context_asset = instance.context.data["assetEntity"]["name"]
|
||||
msg = "{} has asset {}".format(instance.name, asset)
|
||||
assert asset == context_asset, msg
|
||||
|
||||
msg = (
|
||||
"Instance `{}` has wrong shot/asset name:\n"
|
||||
"Correct: `{}` | Wrong: `{}`").format(
|
||||
instance.name, asset, context_asset)
|
||||
|
||||
self.log.debug(msg)
|
||||
|
||||
if asset != context_asset:
|
||||
raise PublishXmlValidationError(
|
||||
self, msg, formatting_data={
|
||||
"node_name": instance[0]["name"].value(),
|
||||
"wrong_name": asset,
|
||||
"correct_name": context_asset
|
||||
}
|
||||
)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import nuke
|
||||
import pyblish
|
||||
from openpype.hosts.nuke.api.lib import maintained_selection
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
|
||||
|
||||
class SelectCenterInNodeGraph(pyblish.api.Action):
|
||||
|
|
@ -47,8 +48,9 @@ class SelectCenterInNodeGraph(pyblish.api.Action):
|
|||
|
||||
@pyblish.api.log
|
||||
class ValidateBackdrop(pyblish.api.InstancePlugin):
|
||||
"""Validate amount of nodes on backdrop node in case user
|
||||
forgotten to add nodes above the publishing backdrop node"""
|
||||
""" Validate amount of nodes on backdrop node in case user
|
||||
forgoten to add nodes above the publishing backdrop node.
|
||||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
optional = True
|
||||
|
|
@ -63,8 +65,25 @@ class ValidateBackdrop(pyblish.api.InstancePlugin):
|
|||
msg_multiple_outputs = (
|
||||
"Only one outcoming connection from "
|
||||
"\"{}\" is allowed").format(instance.data["name"])
|
||||
assert len(connections_out.keys()) <= 1, msg_multiple_outputs
|
||||
|
||||
msg_no_content = "No content on backdrop node: \"{}\"".format(
|
||||
if len(connections_out.keys()) > 1:
|
||||
raise PublishXmlValidationError(
|
||||
self,
|
||||
msg_multiple_outputs,
|
||||
"multiple_outputs"
|
||||
)
|
||||
|
||||
msg_no_nodes = "No content on backdrop node: \"{}\"".format(
|
||||
instance.data["name"])
|
||||
assert len(instance) > 1, msg_no_content
|
||||
|
||||
self.log.debug(
|
||||
"Amount of nodes on instance: {}".format(
|
||||
len(instance))
|
||||
)
|
||||
|
||||
if len(instance) == 1:
|
||||
raise PublishXmlValidationError(
|
||||
self,
|
||||
msg_no_nodes,
|
||||
"no_nodes"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import nuke
|
||||
import pyblish
|
||||
from openpype.hosts.nuke.api.lib import maintained_selection
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
from openpype.hosts.nuke.api import maintained_selection
|
||||
import nuke
|
||||
|
||||
|
||||
class OpenFailedGroupNode(pyblish.api.Action):
|
||||
|
|
@ -8,7 +9,7 @@ class OpenFailedGroupNode(pyblish.api.Action):
|
|||
Centering failed instance node in node grap
|
||||
"""
|
||||
|
||||
label = "Open Gizmo in Node Graph"
|
||||
label = "Open Group"
|
||||
icon = "wrench"
|
||||
on = "failed"
|
||||
|
||||
|
|
@ -48,11 +49,23 @@ class ValidateGizmo(pyblish.api.InstancePlugin):
|
|||
|
||||
with grpn:
|
||||
connections_out = nuke.allNodes('Output')
|
||||
msg_multiple_outputs = "Only one outcoming connection from "
|
||||
"\"{}\" is allowed".format(instance.data["name"])
|
||||
assert len(connections_out) <= 1, msg_multiple_outputs
|
||||
msg_multiple_outputs = (
|
||||
"Only one outcoming connection from "
|
||||
"\"{}\" is allowed").format(instance.data["name"])
|
||||
|
||||
if len(connections_out) > 1:
|
||||
raise PublishXmlValidationError(
|
||||
self, msg_multiple_outputs, "multiple_outputs",
|
||||
{"node_name": grpn["name"].value()}
|
||||
)
|
||||
|
||||
connections_in = nuke.allNodes('Input')
|
||||
msg_missing_inputs = "At least one Input node has to be used in: "
|
||||
"\"{}\"".format(instance.data["name"])
|
||||
assert len(connections_in) >= 1, msg_missing_inputs
|
||||
msg_missing_inputs = (
|
||||
"At least one Input node has to be inside Group: "
|
||||
"\"{}\"").format(instance.data["name"])
|
||||
|
||||
if len(connections_in) == 0:
|
||||
raise PublishXmlValidationError(
|
||||
self, msg_missing_inputs, "no_inputs",
|
||||
{"node_name": grpn["name"].value()}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import nuke
|
||||
|
||||
import six
|
||||
import pyblish.api
|
||||
import openpype.api
|
||||
|
||||
from openpype.pipeline.publish import (
|
||||
RepairContextAction,
|
||||
PublishXmlValidationError,
|
||||
)
|
||||
|
||||
|
||||
class ValidateKnobs(pyblish.api.ContextPlugin):
|
||||
|
|
@ -23,15 +27,25 @@ class ValidateKnobs(pyblish.api.ContextPlugin):
|
|||
order = pyblish.api.ValidatorOrder
|
||||
label = "Validate Knobs"
|
||||
hosts = ["nuke"]
|
||||
actions = [openpype.api.RepairContextAction]
|
||||
actions = [RepairContextAction]
|
||||
optional = True
|
||||
|
||||
def process(self, context):
|
||||
|
||||
invalid = self.get_invalid(context, compute=True)
|
||||
if invalid:
|
||||
raise RuntimeError(
|
||||
"Found knobs with invalid values:\n{}".format(invalid)
|
||||
invalid_items = [
|
||||
(
|
||||
"Node __{node_name}__ with knob _{label}_ "
|
||||
"expecting _{expected}_, "
|
||||
"but is set to _{current}_"
|
||||
).format(**i)
|
||||
for i in invalid
|
||||
]
|
||||
raise PublishXmlValidationError(
|
||||
self,
|
||||
"Found knobs with invalid values:\n{}".format(invalid),
|
||||
formatting_data={
|
||||
"invalid_items": "\n".join(invalid_items)}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -54,15 +68,24 @@ class ValidateKnobs(pyblish.api.ContextPlugin):
|
|||
# Filter families.
|
||||
families = [instance.data["family"]]
|
||||
families += instance.data.get("families", [])
|
||||
families = list(set(families) & set(cls.knobs.keys()))
|
||||
|
||||
if not families:
|
||||
continue
|
||||
|
||||
# Get all knobs to validate.
|
||||
knobs = {}
|
||||
for family in families:
|
||||
# check if dot in family
|
||||
if "." in family:
|
||||
family = family.split(".")[0]
|
||||
|
||||
# avoid families not in settings
|
||||
if family not in cls.knobs:
|
||||
continue
|
||||
|
||||
# get presets of knobs
|
||||
for preset in cls.knobs[family]:
|
||||
knobs.update({preset: cls.knobs[family][preset]})
|
||||
knobs[preset] = cls.knobs[family][preset]
|
||||
|
||||
# Get invalid knobs.
|
||||
nodes = []
|
||||
|
|
@ -71,8 +94,7 @@ class ValidateKnobs(pyblish.api.ContextPlugin):
|
|||
nodes.append(node)
|
||||
if node.Class() == "Group":
|
||||
node.begin()
|
||||
for i in nuke.allNodes():
|
||||
nodes.append(i)
|
||||
nodes.extend(iter(nuke.allNodes()))
|
||||
node.end()
|
||||
|
||||
for node in nodes:
|
||||
|
|
@ -84,6 +106,7 @@ class ValidateKnobs(pyblish.api.ContextPlugin):
|
|||
if node[knob].value() != expected:
|
||||
invalid_knobs.append(
|
||||
{
|
||||
"node_name": node.name(),
|
||||
"knob": node[knob],
|
||||
"name": node[knob].name(),
|
||||
"label": node[knob].label(),
|
||||
|
|
@ -99,7 +122,9 @@ class ValidateKnobs(pyblish.api.ContextPlugin):
|
|||
def repair(cls, instance):
|
||||
invalid = cls.get_invalid(instance)
|
||||
for data in invalid:
|
||||
if isinstance(data["expected"], unicode):
|
||||
# TODO: will need to improve type definitions
|
||||
# with the new settings for knob types
|
||||
if isinstance(data["expected"], six.text_type):
|
||||
data["knob"].setValue(str(data["expected"]))
|
||||
continue
|
||||
|
||||
|
|
|
|||
|
|
@ -1,43 +1,9 @@
|
|||
import nuke
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class RepairWriteResolutionDifference(pyblish.api.Action):
|
||||
|
||||
label = "Repair"
|
||||
icon = "wrench"
|
||||
on = "failed"
|
||||
|
||||
def process(self, context, plugin):
|
||||
|
||||
# Get the errored instances
|
||||
failed = []
|
||||
for result in context.data["results"]:
|
||||
if (result["error"] is not None and result["instance"] is not None
|
||||
and result["instance"] not in failed):
|
||||
failed.append(result["instance"])
|
||||
|
||||
# Apply pyblish.logic to get the instances for the plug-in
|
||||
instances = pyblish.api.instances_by_plugin(failed, plugin)
|
||||
|
||||
for instance in instances:
|
||||
reformat = instance[0].dependencies()[0]
|
||||
if reformat.Class() != "Reformat":
|
||||
reformat = nuke.nodes.Reformat(inputs=[instance[0].input(0)])
|
||||
|
||||
xpos = instance[0].xpos()
|
||||
ypos = instance[0].ypos() - 26
|
||||
|
||||
dependent_ypos = instance[0].dependencies()[0].ypos()
|
||||
if (instance[0].ypos() - dependent_ypos) <= 51:
|
||||
xpos += 110
|
||||
|
||||
reformat.setXYpos(xpos, ypos)
|
||||
|
||||
instance[0].setInput(0, reformat)
|
||||
|
||||
reformat["resize"].setValue("none")
|
||||
from openpype.hosts.nuke.api import maintained_selection
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
from openpype.pipeline.publish import RepairAction
|
||||
import nuke
|
||||
|
||||
|
||||
class ValidateOutputResolution(pyblish.api.InstancePlugin):
|
||||
|
|
@ -52,27 +18,75 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin):
|
|||
families = ["render", "render.local", "render.farm"]
|
||||
label = "Write Resolution"
|
||||
hosts = ["nuke"]
|
||||
actions = [RepairWriteResolutionDifference]
|
||||
actions = [RepairAction]
|
||||
|
||||
missing_msg = "Missing Reformat node in render group node"
|
||||
resolution_msg = "Reformat is set to wrong format"
|
||||
|
||||
def process(self, instance):
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise PublishXmlValidationError(self, invalid)
|
||||
|
||||
# Skip bounding box check if a reformat node exists.
|
||||
if instance[0].dependencies()[0].Class() == "Reformat":
|
||||
return
|
||||
@classmethod
|
||||
def get_reformat(cls, instance):
|
||||
reformat = None
|
||||
for inode in instance:
|
||||
if inode.Class() != "Reformat":
|
||||
continue
|
||||
reformat = inode
|
||||
|
||||
msg = "Bounding box is outside the format."
|
||||
assert self.check_resolution(instance), msg
|
||||
return reformat
|
||||
|
||||
def check_resolution(self, instance):
|
||||
node = instance[0]
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
def _check_resolution(instance, reformat):
|
||||
root_width = instance.data["resolutionWidth"]
|
||||
root_height = instance.data["resolutionHeight"]
|
||||
|
||||
root_width = instance.data["resolutionWidth"]
|
||||
root_height = instance.data["resolutionHeight"]
|
||||
write_width = reformat.format().width()
|
||||
write_height = reformat.format().height()
|
||||
|
||||
write_width = node.format().width()
|
||||
write_height = node.format().height()
|
||||
if (root_width != write_width) or (root_height != write_height):
|
||||
return None
|
||||
else:
|
||||
return True
|
||||
|
||||
if (root_width != write_width) or (root_height != write_height):
|
||||
return None
|
||||
else:
|
||||
return True
|
||||
# check if reformat is in render node
|
||||
reformat = cls.get_reformat(instance)
|
||||
if not reformat:
|
||||
return cls.missing_msg
|
||||
|
||||
# check if reformat is set to correct root format
|
||||
correct_format = _check_resolution(instance, reformat)
|
||||
if not correct_format:
|
||||
return cls.resolution_msg
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
invalid = cls.get_invalid(instance)
|
||||
grp_node = instance[0]
|
||||
|
||||
if cls.missing_msg == invalid:
|
||||
# make sure we are inside of the group node
|
||||
with grp_node:
|
||||
# find input node and select it
|
||||
_input = None
|
||||
for inode in instance:
|
||||
if inode.Class() != "Input":
|
||||
continue
|
||||
_input = inode
|
||||
|
||||
# add reformat node under it
|
||||
with maintained_selection():
|
||||
_input['selected'].setValue(True)
|
||||
_rfn = nuke.createNode("Reformat", "name Reformat01")
|
||||
_rfn["resize"].setValue(0)
|
||||
_rfn["black_outside"].setValue(1)
|
||||
|
||||
cls.log.info("I am adding reformat node")
|
||||
|
||||
if cls.resolution_msg == invalid:
|
||||
reformat = cls.get_reformat(instance)
|
||||
reformat["format"].setValue(nuke.root()["format"].value())
|
||||
cls.log.info("I am fixing reformat to root.format")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import pyblish
|
||||
import nuke
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
|
||||
|
||||
class FixProxyMode(pyblish.api.Action):
|
||||
|
|
@ -7,7 +8,7 @@ class FixProxyMode(pyblish.api.Action):
|
|||
Togger off proxy switch OFF
|
||||
"""
|
||||
|
||||
label = "Proxy toggle to OFF"
|
||||
label = "Repair"
|
||||
icon = "wrench"
|
||||
on = "failed"
|
||||
|
||||
|
|
@ -30,4 +31,7 @@ class ValidateProxyMode(pyblish.api.ContextPlugin):
|
|||
rootNode = nuke.root()
|
||||
isProxy = rootNode["proxy"].value()
|
||||
|
||||
assert not isProxy, "Proxy mode should be toggled OFF"
|
||||
if isProxy:
|
||||
raise PublishXmlValidationError(
|
||||
self, "Proxy mode should be toggled OFF"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
from openpype.api import ValidationException
|
||||
import clique
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
|
||||
|
||||
@pyblish.api.log
|
||||
|
|
@ -36,7 +36,7 @@ class RepairActionBase(pyblish.api.Action):
|
|||
|
||||
|
||||
class RepairCollectionActionToLocal(RepairActionBase):
|
||||
label = "Repair > rerender with `Local` machine"
|
||||
label = "Repair - rerender with \"Local\""
|
||||
|
||||
def process(self, context, plugin):
|
||||
instances = self.get_instance(context, plugin)
|
||||
|
|
@ -44,7 +44,7 @@ class RepairCollectionActionToLocal(RepairActionBase):
|
|||
|
||||
|
||||
class RepairCollectionActionToFarm(RepairActionBase):
|
||||
label = "Repair > rerender `On farm` with remote machines"
|
||||
label = "Repair - rerender with \"On farm\""
|
||||
|
||||
def process(self, context, plugin):
|
||||
instances = self.get_instance(context, plugin)
|
||||
|
|
@ -63,6 +63,10 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
|
||||
def process(self, instance):
|
||||
|
||||
f_data = {
|
||||
"node_name": instance[0]["name"].value()
|
||||
}
|
||||
|
||||
for repre in instance.data["representations"]:
|
||||
|
||||
if not repre.get("files"):
|
||||
|
|
@ -71,7 +75,8 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
"Check properties of write node (group) and"
|
||||
"select 'Local' option in 'Publish' dropdown.")
|
||||
self.log.error(msg)
|
||||
raise ValidationException(msg)
|
||||
raise PublishXmlValidationError(
|
||||
self, msg, formatting_data=f_data)
|
||||
|
||||
if isinstance(repre["files"], str):
|
||||
return
|
||||
|
|
@ -82,21 +87,23 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
|
||||
collection = collections[0]
|
||||
|
||||
fstartH = instance.data["frameStartHandle"]
|
||||
fendH = instance.data["frameEndHandle"]
|
||||
f_start_h = instance.data["frameStartHandle"]
|
||||
f_end_h = instance.data["frameEndHandle"]
|
||||
|
||||
frame_length = int(fendH - fstartH + 1)
|
||||
frame_length = int(f_end_h - f_start_h + 1)
|
||||
|
||||
if frame_length != 1:
|
||||
if len(collections) != 1:
|
||||
msg = "There are multiple collections in the folder"
|
||||
self.log.error(msg)
|
||||
raise ValidationException(msg)
|
||||
raise PublishXmlValidationError(
|
||||
self, msg, formatting_data=f_data)
|
||||
|
||||
if not collection.is_contiguous():
|
||||
msg = "Some frames appear to be missing"
|
||||
self.log.error(msg)
|
||||
raise ValidationException(msg)
|
||||
raise PublishXmlValidationError(
|
||||
self, msg, formatting_data=f_data)
|
||||
|
||||
collected_frames_len = len(collection.indexes)
|
||||
coll_start = min(collection.indexes)
|
||||
|
|
@ -105,7 +112,8 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
self.log.info("frame_length: {}".format(frame_length))
|
||||
self.log.info("collected_frames_len: {}".format(
|
||||
collected_frames_len))
|
||||
self.log.info("fstartH-fendH: {}-{}".format(fstartH, fendH))
|
||||
self.log.info("f_start_h-f_end_h: {}-{}".format(
|
||||
f_start_h, f_end_h))
|
||||
self.log.info(
|
||||
"coll_start-coll_end: {}-{}".format(coll_start, coll_end))
|
||||
|
||||
|
|
@ -116,13 +124,19 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
if ("slate" in instance.data["families"]) \
|
||||
and (frame_length != collected_frames_len):
|
||||
collected_frames_len -= 1
|
||||
fstartH += 1
|
||||
f_start_h += 1
|
||||
|
||||
assert ((collected_frames_len >= frame_length)
|
||||
and (coll_start <= fstartH)
|
||||
and (coll_end >= fendH)), (
|
||||
"{} missing frames. Use repair to render all frames"
|
||||
).format(__name__)
|
||||
if (
|
||||
collected_frames_len != frame_length
|
||||
and coll_start <= f_start_h
|
||||
and coll_end >= f_end_h
|
||||
):
|
||||
raise PublishXmlValidationError(
|
||||
self, (
|
||||
"{} missing frames. Use repair to "
|
||||
"render all frames"
|
||||
).format(__name__), formatting_data=f_data
|
||||
)
|
||||
|
||||
instance.data["collection"] = collection
|
||||
|
||||
|
|
|
|||
|
|
@ -1,156 +0,0 @@
|
|||
import pyblish.api
|
||||
|
||||
from openpype.client import get_project, get_asset_by_id, get_asset_by_name
|
||||
from openpype.pipeline import legacy_io
|
||||
|
||||
|
||||
@pyblish.api.log
|
||||
class ValidateScript(pyblish.api.InstancePlugin):
|
||||
""" Validates file output. """
|
||||
|
||||
order = pyblish.api.ValidatorOrder + 0.1
|
||||
families = ["workfile"]
|
||||
label = "Check script settings"
|
||||
hosts = ["nuke"]
|
||||
optional = True
|
||||
|
||||
def process(self, instance):
|
||||
ctx_data = instance.context.data
|
||||
project_name = legacy_io.active_project()
|
||||
asset_name = ctx_data["asset"]
|
||||
# TODO repace query with using 'instance.data["assetEntity"]'
|
||||
asset = get_asset_by_name(project_name, asset_name)
|
||||
asset_data = asset["data"]
|
||||
|
||||
# These attributes will be checked
|
||||
attributes = [
|
||||
"fps",
|
||||
"frameStart",
|
||||
"frameEnd",
|
||||
"resolutionWidth",
|
||||
"resolutionHeight",
|
||||
"handleStart",
|
||||
"handleEnd"
|
||||
]
|
||||
|
||||
# Value of these attributes can be found on parents
|
||||
hierarchical_attributes = [
|
||||
"fps",
|
||||
"resolutionWidth",
|
||||
"resolutionHeight",
|
||||
"pixelAspect",
|
||||
"handleStart",
|
||||
"handleEnd"
|
||||
]
|
||||
|
||||
missing_attributes = []
|
||||
asset_attributes = {}
|
||||
for attr in attributes:
|
||||
if attr in asset_data:
|
||||
asset_attributes[attr] = asset_data[attr]
|
||||
|
||||
elif attr in hierarchical_attributes:
|
||||
# TODO this should be probably removed
|
||||
# Hierarchical attributes is not a thing since Pype 2?
|
||||
|
||||
# Try to find attribute on parent
|
||||
parent_id = asset['parent']
|
||||
parent_type = "project"
|
||||
if asset_data['visualParent'] is not None:
|
||||
parent_type = "asset"
|
||||
parent_id = asset_data['visualParent']
|
||||
|
||||
value = self.check_parent_hierarchical(
|
||||
project_name, parent_type, parent_id, attr
|
||||
)
|
||||
if value is None:
|
||||
missing_attributes.append(attr)
|
||||
else:
|
||||
asset_attributes[attr] = value
|
||||
else:
|
||||
missing_attributes.append(attr)
|
||||
|
||||
# Raise error if attributes weren't found on asset in database
|
||||
if len(missing_attributes) > 0:
|
||||
atr = ", ".join(missing_attributes)
|
||||
msg = 'Missing attributes "{}" in asset "{}"'
|
||||
message = msg.format(atr, asset_name)
|
||||
raise ValueError(message)
|
||||
|
||||
# Get handles from database, Default is 0 (if not found)
|
||||
handle_start = 0
|
||||
handle_end = 0
|
||||
if "handleStart" in asset_attributes:
|
||||
handle_start = asset_attributes["handleStart"]
|
||||
if "handleEnd" in asset_attributes:
|
||||
handle_end = asset_attributes["handleEnd"]
|
||||
|
||||
asset_attributes["fps"] = float("{0:.4f}".format(
|
||||
asset_attributes["fps"]))
|
||||
|
||||
# Get values from nukescript
|
||||
script_attributes = {
|
||||
"handleStart": ctx_data["handleStart"],
|
||||
"handleEnd": ctx_data["handleEnd"],
|
||||
"fps": float("{0:.4f}".format(ctx_data["fps"])),
|
||||
"frameStart": ctx_data["frameStart"],
|
||||
"frameEnd": ctx_data["frameEnd"],
|
||||
"resolutionWidth": ctx_data["resolutionWidth"],
|
||||
"resolutionHeight": ctx_data["resolutionHeight"],
|
||||
"pixelAspect": ctx_data["pixelAspect"]
|
||||
}
|
||||
|
||||
# Compare asset's values Nukescript X Database
|
||||
not_matching = []
|
||||
for attr in attributes:
|
||||
self.log.debug("asset vs script attribute \"{}\": {}, {}".format(
|
||||
attr, asset_attributes[attr], script_attributes[attr])
|
||||
)
|
||||
if asset_attributes[attr] != script_attributes[attr]:
|
||||
not_matching.append(attr)
|
||||
|
||||
# Raise error if not matching
|
||||
if len(not_matching) > 0:
|
||||
msg = "Attributes '{}' are not set correctly"
|
||||
# Alert user that handles are set if Frame start/end not match
|
||||
if (
|
||||
(("frameStart" in not_matching) or ("frameEnd" in not_matching)) and
|
||||
((handle_start > 0) or (handle_end > 0))
|
||||
):
|
||||
msg += " (`handle_start` are set to {})".format(handle_start)
|
||||
msg += " (`handle_end` are set to {})".format(handle_end)
|
||||
message = msg.format(", ".join(not_matching))
|
||||
raise ValueError(message)
|
||||
|
||||
def check_parent_hierarchical(
|
||||
self, project_name, parent_type, parent_id, attr
|
||||
):
|
||||
if parent_id is None:
|
||||
return None
|
||||
|
||||
doc = None
|
||||
if parent_type == "project":
|
||||
doc = get_project(project_name)
|
||||
elif parent_type == "asset":
|
||||
doc = get_asset_by_id(project_name, parent_id)
|
||||
|
||||
if not doc:
|
||||
return None
|
||||
|
||||
doc_data = doc["data"]
|
||||
if attr in doc_data:
|
||||
self.log.info(attr)
|
||||
return doc_data[attr]
|
||||
|
||||
if parent_type == "project":
|
||||
return None
|
||||
|
||||
parent_id = doc_data.get("visualParent")
|
||||
new_parent_type = "asset"
|
||||
if parent_id is None:
|
||||
parent_id = doc["parent"]
|
||||
new_parent_type = "project"
|
||||
|
||||
return self.check_parent_hierarchical(
|
||||
project_name, new_parent_type, parent_id, attr
|
||||
)
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
from pprint import pformat
|
||||
import pyblish.api
|
||||
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
from openpype.pipeline.publish import RepairAction
|
||||
from openpype.hosts.nuke.api.lib import (
|
||||
get_avalon_knob_data,
|
||||
WorkfileSettings
|
||||
)
|
||||
import nuke
|
||||
|
||||
|
||||
@pyblish.api.log
|
||||
class ValidateScriptAttributes(pyblish.api.InstancePlugin):
|
||||
""" Validates file output. """
|
||||
|
||||
order = pyblish.api.ValidatorOrder + 0.1
|
||||
families = ["workfile"]
|
||||
label = "Validatte script attributes"
|
||||
hosts = ["nuke"]
|
||||
optional = True
|
||||
actions = [RepairAction]
|
||||
|
||||
def process(self, instance):
|
||||
root = nuke.root()
|
||||
knob_data = get_avalon_knob_data(root)
|
||||
asset = instance.data["assetEntity"]
|
||||
# get asset data frame values
|
||||
frame_start = asset["data"]["frameStart"]
|
||||
frame_end = asset["data"]["frameEnd"]
|
||||
handle_start = asset["data"]["handleStart"]
|
||||
handle_end = asset["data"]["handleEnd"]
|
||||
|
||||
# These attributes will be checked
|
||||
attributes = [
|
||||
"fps",
|
||||
"frameStart",
|
||||
"frameEnd",
|
||||
"resolutionWidth",
|
||||
"resolutionHeight",
|
||||
"handleStart",
|
||||
"handleEnd"
|
||||
]
|
||||
|
||||
# get only defined attributes from asset data
|
||||
asset_attributes = {
|
||||
attr: asset["data"][attr]
|
||||
for attr in attributes
|
||||
if attr in asset["data"]
|
||||
}
|
||||
# fix float to max 4 digints (only for evaluating)
|
||||
fps_data = float("{0:.4f}".format(
|
||||
asset_attributes["fps"]))
|
||||
# fix frame values to include handles
|
||||
asset_attributes.update({
|
||||
"frameStart": frame_start - handle_start,
|
||||
"frameEnd": frame_end + handle_end,
|
||||
"fps": fps_data
|
||||
})
|
||||
|
||||
self.log.debug(pformat(
|
||||
asset_attributes
|
||||
))
|
||||
|
||||
# Get format
|
||||
_format = root["format"].value()
|
||||
|
||||
# Get values from nukescript
|
||||
script_attributes = {
|
||||
"handleStart": int(knob_data["handleStart"]),
|
||||
"handleEnd": int(knob_data["handleEnd"]),
|
||||
"fps": float("{0:.4f}".format(root['fps'].value())),
|
||||
"frameStart": int(root["first_frame"].getValue()),
|
||||
"frameEnd": int(root["last_frame"].getValue()),
|
||||
"resolutionWidth": _format.width(),
|
||||
"resolutionHeight": _format.height(),
|
||||
"pixelAspect": _format.pixelAspect()
|
||||
}
|
||||
self.log.debug(pformat(
|
||||
script_attributes
|
||||
))
|
||||
|
||||
# Compare asset's values Nukescript X Database
|
||||
not_matching = []
|
||||
for attr in attributes:
|
||||
self.log.debug(
|
||||
"Asset vs Script attribute \"{}\": {}, {}".format(
|
||||
attr,
|
||||
asset_attributes[attr],
|
||||
script_attributes[attr]
|
||||
)
|
||||
)
|
||||
if asset_attributes[attr] != script_attributes[attr]:
|
||||
not_matching.append({
|
||||
"name": attr,
|
||||
"expected": asset_attributes[attr],
|
||||
"actual": script_attributes[attr]
|
||||
})
|
||||
|
||||
# Raise error if not matching
|
||||
if not_matching:
|
||||
msg = "Following attributes are not set correctly: \n{}"
|
||||
attrs_wrong_str = "\n".join([
|
||||
(
|
||||
"`{0}` is set to `{1}`, "
|
||||
"but should be set to `{2}`"
|
||||
).format(at["name"], at["actual"], at["expected"])
|
||||
for at in not_matching
|
||||
])
|
||||
attrs_wrong_html = "<br/>".join([
|
||||
(
|
||||
"-- __{0}__ is set to __{1}__, "
|
||||
"but should be set to __{2}__"
|
||||
).format(at["name"], at["actual"], at["expected"])
|
||||
for at in not_matching
|
||||
])
|
||||
raise PublishXmlValidationError(
|
||||
self, msg.format(attrs_wrong_str),
|
||||
formatting_data={
|
||||
"failed_attributes": attrs_wrong_html
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
cls.log.debug("__ repairing instance: {}".format(instance))
|
||||
WorkfileSettings().set_context_settings()
|
||||
|
|
@ -3,8 +3,9 @@ import toml
|
|||
import nuke
|
||||
|
||||
import pyblish.api
|
||||
import openpype.api
|
||||
|
||||
from openpype.pipeline import discover_creator_plugins
|
||||
from openpype.pipeline.publish import RepairAction
|
||||
from openpype.hosts.nuke.api.lib import get_avalon_knob_data
|
||||
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ class ValidateWriteLegacy(pyblish.api.InstancePlugin):
|
|||
families = ["write"]
|
||||
label = "Validate Write Legacy"
|
||||
hosts = ["nuke"]
|
||||
actions = [openpype.api.RepairAction]
|
||||
actions = [RepairAction]
|
||||
|
||||
def process(self, instance):
|
||||
node = instance[0]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
import openpype.utils
|
||||
from openpype.pipeline.publish import get_errored_instances_from_context
|
||||
from openpype.hosts.nuke.api.lib import (
|
||||
get_write_node_template_attr,
|
||||
get_node_path
|
||||
set_node_knobs_from_settings,
|
||||
color_gui_to_int
|
||||
)
|
||||
from openpype.pipeline import PublishXmlValidationError
|
||||
|
||||
|
||||
@pyblish.api.log
|
||||
|
|
@ -14,18 +15,29 @@ class RepairNukeWriteNodeAction(pyblish.api.Action):
|
|||
icon = "wrench"
|
||||
|
||||
def process(self, context, plugin):
|
||||
instances = openpype.utils.filter_instances(context, plugin)
|
||||
instances = get_errored_instances_from_context(context)
|
||||
|
||||
for instance in instances:
|
||||
node = instance[1]
|
||||
correct_data = get_write_node_template_attr(node)
|
||||
for k, v in correct_data.items():
|
||||
node[k].setValue(v)
|
||||
write_group_node = instance[0]
|
||||
# get write node from inside of group
|
||||
write_node = None
|
||||
for x in instance:
|
||||
if x.Class() == "Write":
|
||||
write_node = x
|
||||
|
||||
correct_data = get_write_node_template_attr(write_group_node)
|
||||
|
||||
set_node_knobs_from_settings(write_node, correct_data["knobs"])
|
||||
|
||||
self.log.info("Node attributes were fixed")
|
||||
|
||||
|
||||
class ValidateNukeWriteNode(pyblish.api.InstancePlugin):
|
||||
""" Validates file output. """
|
||||
""" Validate Write node's knobs.
|
||||
|
||||
Compare knobs on write node inside the render group
|
||||
with settings. At the moment supporting only `file` knob.
|
||||
"""
|
||||
|
||||
order = pyblish.api.ValidatorOrder
|
||||
optional = True
|
||||
|
|
@ -35,38 +47,72 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin):
|
|||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
write_group_node = instance[0]
|
||||
|
||||
node = instance[1]
|
||||
correct_data = get_write_node_template_attr(node)
|
||||
# get write node from inside of group
|
||||
write_node = None
|
||||
for x in instance:
|
||||
if x.Class() == "Write":
|
||||
write_node = x
|
||||
|
||||
if write_node is None:
|
||||
return
|
||||
|
||||
correct_data = get_write_node_template_attr(write_group_node)
|
||||
|
||||
if correct_data:
|
||||
check_knobs = correct_data["knobs"]
|
||||
else:
|
||||
return
|
||||
|
||||
check = []
|
||||
for k, v in correct_data.items():
|
||||
if k is 'file':
|
||||
padding = len(v.split('#'))
|
||||
ref_path = get_node_path(v, padding)
|
||||
n_path = get_node_path(node[k].value(), padding)
|
||||
isnt = False
|
||||
for i, p in enumerate(ref_path):
|
||||
if str(n_path[i]) not in str(p):
|
||||
if not isnt:
|
||||
isnt = True
|
||||
else:
|
||||
continue
|
||||
if isnt:
|
||||
check.append([k, v, node[k].value()])
|
||||
self.log.debug("__ write_node: {}".format(
|
||||
write_node
|
||||
))
|
||||
|
||||
for knob_data in check_knobs:
|
||||
key = knob_data["name"]
|
||||
value = knob_data["value"]
|
||||
node_value = write_node[key].value()
|
||||
|
||||
# fix type differences
|
||||
if type(node_value) in (int, float):
|
||||
if isinstance(value, list):
|
||||
value = color_gui_to_int(value)
|
||||
else:
|
||||
value = float(value)
|
||||
node_value = float(node_value)
|
||||
else:
|
||||
if str(node[k].value()) not in str(v):
|
||||
check.append([k, v, node[k].value()])
|
||||
value = str(value)
|
||||
node_value = str(node_value)
|
||||
|
||||
self.log.debug("__ key: {} | value: {}".format(
|
||||
key, value
|
||||
))
|
||||
if (
|
||||
node_value != value
|
||||
and key != "file"
|
||||
and key != "tile_color"
|
||||
):
|
||||
check.append([key, value, write_node[key].value()])
|
||||
|
||||
self.log.info(check)
|
||||
|
||||
msg = "Node's attribute `{0}` is not correct!\n" \
|
||||
"\nCorrect: `{1}` \n\nWrong: `{2}` \n\n"
|
||||
|
||||
if check:
|
||||
print_msg = ""
|
||||
for item in check:
|
||||
print_msg += msg.format(item[0], item[1], item[2])
|
||||
print_msg += "`RMB` click to the validator and `A` to fix!"
|
||||
self._make_error(check)
|
||||
|
||||
assert not check, print_msg
|
||||
def _make_error(self, check):
|
||||
# sourcery skip: merge-assign-and-aug-assign, move-assign-in-block
|
||||
dbg_msg = "Write node's knobs values are not correct!\n"
|
||||
msg_add = "Knob '{0}' > Correct: `{1}` > Wrong: `{2}`"
|
||||
|
||||
details = [
|
||||
msg_add.format(item[0], item[1], item[2])
|
||||
for item in check
|
||||
]
|
||||
xml_msg = "<br/>".join(details)
|
||||
dbg_msg += "\n\t".join(details)
|
||||
|
||||
raise PublishXmlValidationError(
|
||||
self, dbg_msg, formatting_data={"xml_msg": xml_msg}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue