Source code for python.tk_houdini.utils

# -*- coding: utf-8 -*-
"""Action manager, parameter template wrappers and graceful error decorator."""
from __future__ import absolute_import, division, print_function, unicode_literals

import functools

from .action_manager import HoudiniActionManager
from .parm_template_wrappers import (
    Parm,
    ParmFolder,
    ParmGroup,
    wrap_node_parameter_group,
)

__all__ = (
    "gracefully_error_hook_method",
    "HoudiniActionManager",
    "Parm",
    "ParmFolder",
    "ParmGroup",
    "wrap_node_parameter_group",
)


[docs]def gracefully_error_hook_method(*called_args, **decorator_kwargs): """Wrap a hook instance method declaration to just log exception and continue. Useful for when Houdini is in a state that's likely crash/seg fault from Python exceptions raised, without providing useful stack traces i.e. during scene loading. :param called_args: Arguments, if any, from the decoration syntax :type called_args: tuple :param decorator_kwargs: ``message`` or ``default_return`` keyworded arguments for customising log message and return value to use when failing gracefully. :type decorator_kwargs: dict[str] :return: Decorator or wrapped function, depending on decorator syntax used :rtype: object """ class Decorator: """Using decorator class to parse decoration keyworded arguments better.""" DEFAULT_MESSAGE = "Gracefully logging error" TITLE_TEMPLATE = "%s [returning %r]" def __init__(self, message=None, default_return=None): """Construct with optional custom message and return value for errors. :keyword message: Custom log/title message to use upon error. :type message: str :keyword default_return: Custom value to return upon error. :type default_return: object """ self.default_return = default_return self.message = message or self.DEFAULT_MESSAGE def __call__(self, hook_instance_method): """Wrap a hook instance method so it gracefully errors. :param hook_instance_method: Bound hook method to wrap. :type hook_instance_method: object :return: Wrapped method that logs to hook's logger. :rtype: object """ @functools.wraps(hook_instance_method) def wrapped_func(hook, *args, **kwargs): import hou import traceback result = self.default_return try: result = hook_instance_method(hook, *args, **kwargs) except Exception as error: hook.logger.exception(self.TITLE_TEMPLATE, self.message, result) if hou.isUIAvailable(): hou.ui.displayMessage( str(error), title=self.TITLE_TEMPLATE % (self.message, result), severity=hou.severityType.Error, details=traceback.format_exc(), details_label="Copy this for pipeline", ) return result return wrapped_func # when using @gracefully_error_hook_method if called_args and callable(called_args[0]): func_to_wrap = called_args[0] decorator = Decorator() return decorator(func_to_wrap) # when using @gracefully_error_hook_method() # when using @gracefully_error_hook_method("message", 123) # when using @gracefully_error_hook_method(message="message", default_return=123) return Decorator(*called_args, **decorator_kwargs)