Source code for tri_declarative.shortcut
import functools
from .declarative import get_members
from .dispatch import dispatch
from .namespace import (
Namespace,
setdefaults_path,
)
# This is just a marker class for declaring shortcuts, and later for collecting them
[docs]class Shortcut(Namespace):
shortcut = True
# decorator
[docs]def shortcut(f):
f.shortcut = True
return f
[docs]def is_shortcut(x):
return getattr(x, 'shortcut', False)
[docs]def class_shortcut(*decorator_args, **defaults):
def decorator(__target__):
@functools.wraps(__target__)
@shortcut
@dispatch(
**defaults
)
def class_shortcut_wrapper(cls, *args, **kwargs):
name = __target__.__name__
next_call_target = kwargs.pop('call_target', None)
if (
isinstance(next_call_target, Namespace)
and name == next_call_target.get('attribute', None)
):
# Next call is to the same attribute name, but on the base class.
initial_resolve = getattr(cls, name).__func__
# Loop until we find a super class implementation
base_class_candidate = cls
while getattr(base_class_candidate, name).__func__ == initial_resolve:
base_class_candidate = base_class_candidate.__bases__[0]
next_call_target_cls = base_class_candidate
next_call_target_attribute = next_call_target.attribute
# We need to retain the cls value for later use (as _final_cls).
setdefaults_path(kwargs, _final_cls=cls)
call_target_after_shortcut = Namespace(
call_target__cls=next_call_target_cls,
call_target__attribute=next_call_target_attribute,
)
else:
next_call_target_cls = kwargs.pop('_final_cls', cls)
if next_call_target is None:
# No call_target specified in the decorator, just use the cls (or _final_cls from earlier)
call_target_after_shortcut = Namespace(
call_target__cls=next_call_target_cls,
)
else:
# Merge decorator specified call_target with what final class we should have.
call_target_after_shortcut = Namespace(
call_target=next_call_target,
call_target__cls=next_call_target_cls,
)
result = __target__(cls, *args, call_target=call_target_after_shortcut, **kwargs)
shortcut_stack = [name] + getattr(result, '__tri_declarative_shortcut_stack', [])
try:
result.__tri_declarative_shortcut_stack = shortcut_stack
except AttributeError:
pass
return result
class_shortcut_wrapper.__doc__ = __target__.__doc__
return class_shortcut_wrapper
assert len(decorator_args) in (0, 1), "There are no (explicit) positional arguments to class_shortcut" # pragma: no mutate
if len(decorator_args) == 1:
return decorator(decorator_args[0])
return decorator
[docs]def get_shortcuts_by_name(class_):
return dict(get_members(class_, member_class=Shortcut, is_member=is_shortcut))