# -*- 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)