import sys
from contextlib import contextmanager
from tqdm import tqdm
from nukecontexts import import_nuke, logger
nuke = import_nuke()
[docs]class NukeContextError(ValueError):
def __init__(self, message, *args):
self.message = message
super(NukeContextError, self).__init__(message, *args)
[docs]class Progress(object):
"""
Convenience wrapper class around :func:`tqdm.tqdm` for easy progress bars
Usage:
>>> with Progress(iterable) as progress:
>>> for item in progress:
>>> #do something
"""
[docs] def __init__(self, iterable, name='nukecontexts', output=sys.stdout):
"""
:param interable: Iterable to generate progress bar for
:type interable: iter
:param name: Progress bar label (default: 'nukecontexts')
:type name: str
:param output: Output stream (default: ``sys.stdout``)
:type output: io.TextIOWrapper or io.StringIO
"""
self.name = name
self.iterable = iterable
self.output = output
def __enter__(self):
"""
:return: Progress bar
:rtype: tqdm.tqdm
"""
return tqdm(iterable=self.iterable,
desc=self.name,
file=self.output)
def __exit__(self, exc_type, exc_value, traceback):
pass
[docs]@contextmanager
def inventory(var):
"""
Given a variable name, create a node inventory on entry and a separate node
inventory on exit and save any new nodes into the newly created variable.
Beware that the new variable is created in ``__builtins__`` and is
therefore accessible even after the context manager has exited.
**Use with namespace in mind!**
:param var: Variable name
:type var: str
"""
import nuke
before = nuke.allNodes()
yield
after = nuke.allNodes()
__builtins__[var] = [node for node in after if node not in before]
[docs]@contextmanager
def enabled(nodes, log=logger):
"""
Given a list of nodes (:class:`~nuke.Node`), enable on entry and restore
to original value on exit.
:param nodes: Nodes
:type nodes: list
:param log: Logger
:type log: logging.Logger
"""
with AttributeSetter(nodes, 'disable', False, log=log):
yield
[docs]@contextmanager
def disabled(nodes, log=logger):
"""
Given a list of nodes (:class:`~nuke.Node`), disable on entry and restore
to original value on exit.
:param nodes: Nodes
:type nodes: list
:param log: Logger
:type log: logging.Logger
"""
with AttributeSetter(nodes, 'disable', True, log=log):
yield
[docs]@contextmanager
def set_attr(nodes, attr, value, log=logger):
"""
Given a list of nodes (:class:`~nuke.Node`), set a given ``attr`` to
``value`` on entry and restore to original value on exit.
:param nodes: Nodes
:type nodes: list
:param attr: Attribute
:type attr: str
:param value: Value
:type value: str, int, float, bool
:param log: Logger
:type log: logging.Logger
"""
with AttributeSetter(nodes, attr, value, log=log):
yield
[docs]class AttributeSetter(object):
[docs] def __init__(self, nodes, attr, value, log=logger):
"""
Given a list of nodes (:class:`~nuke.Node`), set a given ``attr`` to
``value`` on entry and restore to original value on exit.
:param nodes: Nodes
:type nodes: list
:param attr: Attribute
:type attr: str
:param value: Value
:type value: str, int, float, bool
:param log: Logger
:type log: logging.Logger
"""
if not isinstance(nodes, list):
nodes = [nodes]
self.nodes = nodes
self.attr = attr
self.value = value
self.log = log
def __enter__(self):
self.enter_values = {}
for node in self.nodes:
try:
assert node
except AssertionError:
raise NukeContextError('Invalid node')
try:
self.enter_values[node] = node[self.attr].value()
except NameError as err:
raise NukeContextError('Node \'{0}\': {1}'.format(
node.name(), err.args[0]))
logger.info('Entering context: ({0}|{1}|{2})'.format(
node.name(), self.attr, self.value))
try:
node[self.attr].setValue(self.value)
except TypeError as err:
raise NukeContextError('Attribute \'{0}\': {1}'.format(
self.attr, err.args[0]))
def __exit__(self, exc_type, exc_value, traceback):
for node, enter_value in self.enter_values.iteritems():
logger.info('Restoring context: ({0}|{1}|{2})'.format(
node.name(), self.attr, enter_value))
node[self.attr].setValue(enter_value)
[docs]@contextmanager
def multiple_contexts(contexts):
"""
Given a list of contextmanagers, sequentially enter all contextmanagers,
raise :class:`Exception` in case errors occur in contexts.
**Deprecated**. Use :func:`contextlib.nested(*contexts)`.
:param contexts: List of contextmanagers
:type contexts: list
"""
msg = ('nukecontexts.ctx.multiple_contexts() is deprecated. '
'Use contextlib.nested(*contexts)')
nuke.warning(msg)
for ctx in contexts:
ctx.__enter__()
err = None
exc_info = (None, None, None)
try:
yield
except Exception as err:
exc_info = sys.exc_info()
# exc_info gets passed to each subsequent ctx.__exit__
# unless one of them suppresses the exception by returning True
for ctx in reversed(contexts):
if ctx.__exit__(*exc_info):
err = False
exc_info = (None, None, None)
if err:
raise err