import attr
import networkx as nx
import nukeuuid
from nuketemplate import import_nuke, logger
from .exceptions import AbstractGraphError
nuke = import_nuke()
[docs]def is_node_in_nx_graph(instance, attribute, value):
"""
Input validator for :class:`~nuketemplate.graph.AbstractGraph`.
Check whether start and end node inputs are part of the graph.
:param instance: :class:`~nuketemplate.graph.AbstractGraph` instance
:type instance: :class:`~nuketemplate.graph.AbstractGraph`
:param _type: Attribute
:type _type: :class:`~attr.Attribute`
:param _attr: Input node
:type _attr: :class:`~nuketemplate.graph.GenericNode` or
:class:`~nuketemplate.graph.NukeNode`
"""
if value not in instance.nx_graph.nodes():
raise AbstractGraphError('{0} node must be in nx_graph'.format(
attribute.name.title()))
[docs]@attr.s(repr=False)
class GenericNode(object):
"""
Generic Node, used with :class:`~nuketemplate.graph.AbstractGraph`
:param name: Node name
:type name: str
"""
name = attr.ib()
def __repr__(self):
return 'GenericNode({0})'.format(self.name)
[docs]@attr.s(repr=False)
class NukeNode(GenericNode):
"""
Nuke Node, used with :class:`~nuketemplate.graph.AbstractGraph`,
inherits from :class:`~nuketemplate.graph.GenericNode`
:param name: Node name
:type name: str
:param _type: Nuke node type
:type _type: str
:param _attr: Nuke node attributes
:type _attr: dict
:param _id: Node UUIDs
:type _id: dict
:param _nuke_node: Nuke node, generated by :func:`~NukeNode.build()`
:type _nuke_node: :class:`~nuke.Node`
:param _nuke_name: Nuke node name, generated by :func:`~NukeNode.build()`
:type _nuke_name: str
"""
_type = attr.ib(repr=False)
_attr = attr.ib(repr=False, hash=False)
_id = attr.ib(repr=False, hash=False)
_nuke_node = attr.ib(default=None, repr=False)
_nuke_name = attr.ib(default=None, repr=True)
def _set_attr(self):
"""
Set the ``_nuke_node`` attributes from the object's ``_attr`` dict.
"""
for attr_, value in self._attr.iteritems():
try:
self._nuke_node[attr_].setValue(value)
except TypeError:
self._nuke_node[attr_].setValue(str(value))
except NameError:
continue
def _set_id(self):
"""
Set the ``_nuke_node`` UUID(s) from the object's ``_id`` dict.
"""
nukeuuid.set_uuid(self._nuke_node, **self._id)
[docs] def build(self):
"""
Build and return the Nuke node.
:return: Nuke node
:rtype: :class:`~nuke.Node`
"""
if self._nuke_node:
raise ValueError('Node already exists')
self._nuke_node = nuke.createNode(self._type, inpanel=False)
self._nuke_node['name'].setValue(self.name)
self._set_attr()
self._set_attr()
self._set_id()
return self._nuke_node
def __repr__(self):
return 'NukeNode({0})'.format(self.name)
[docs]@attr.s
class AbstractGraph(object):
"""
Abstraction of a NetworkX Directed Graph, adds ``start``, ``end``
attributes for simplified graph combination.
:param nx_graph: NetworkX directed graph
:type nx_graph: :class:`~nx.classes.graph.Graph`
:param start: Start node
:type start: :class:`~nuketemplate.graph.GenericNode` or
:class:`~nuketemplate.graph.NukeNode`
:param end: :class:`~nuketemplate.graph.GenericNode` or
:class:`~nuketemplate.graph.NukeNode`
:type end: str
:param end_slot: End node input slot, for nodes with multiple inputs
:type end_slot: int
"""
nx_graph = attr.ib(validator=attr.validators.instance_of(
nx.classes.graph.Graph))
start = attr.ib(default=None)
end = attr.ib(default=None)
end_slot = attr.ib(default=0)
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
try:
return object.__getattribute__(self.nx_graph, name)
except AttributeError:
raise AttributeError()