Source code for pacman.model.decorators.overrides
import inspect
[docs]class overrides(object):
""" A decorator for indicating that a method overrides another method in\
a super class. This checks that the method does actually exist,
copies the doc-string for the method, and enforces that the method\
overridden is specified, making maintenance easier.
"""
__slots__ = [
# The method in the superclass that this method overrides
"_super_class_method",
# True if the doc string is to be extended, False to set if not set
"_extend_doc",
# Any additional arguments required by the subclass method
"_additional_arguments"
]
def __init__(
self, super_class_method, extend_doc=True,
additional_arguments=None):
"""
:param super_class_method: The method to override in the superclass
:param extend_doc:\
True the method doc string should be appended to the super-method\
doc string, False if the documentation should be set to the\
super-method doc string only if there isn't a doc string already
:param additional_arguments:\
Additional arguments taken by the subclass method over the\
superclass method e.g. that are to be injected
"""
self._super_class_method = super_class_method
self._extend_doc = extend_doc
self._additional_arguments = additional_arguments
if additional_arguments is None:
self._additional_arguments = {}
if isinstance(super_class_method, property):
self._super_class_method = super_class_method.fget
def __call__(self, method):
# Check and fail if this is a property
if isinstance(method, property):
raise AttributeError(
"Please ensure that the override decorator is the last"
" decorator before the method declaration")
# Check that the name matches
if method.__name__ != self._super_class_method.__name__:
raise AttributeError(
"Super class method name {} does not match {}. "
"Ensure override is the last decorator before the method "
"declaration".format(
self._super_class_method.__name__, method.__name__))
# Check that the arguments match (except for __init__ as this might
# take extra arguments or pass arguments not specified)
if method.__name__ != "__init__":
method_args = inspect.getargspec(method)
super_args = inspect.getargspec(self._super_class_method)
all_args = [
arg for arg in method_args.args
if arg not in self._additional_arguments
]
default_args = None
if method_args.defaults is not None:
default_args = [
arg for arg in method_args.defaults
if arg not in self._additional_arguments
]
if len(all_args) != len(super_args.args):
raise AttributeError(
"Method has {} arguments but super class method has {}"
" arguments".format(
len(method_args.args), len(super_args.args)))
for arg, super_arg in zip(all_args, super_args.args):
if arg != super_arg:
raise AttributeError(
"Missing argument {}".format(super_arg))
if ((default_args is None and
super_args.defaults is not None) or
(default_args is not None and
super_args.defaults is None) or
(default_args is not None and
super_args.defaults is not None and
len(default_args) !=
len(super_args.defaults))):
raise AttributeError(
"Default arguments don't match super class method")
if (self._super_class_method.__doc__ is not None and
method.__doc__ is None):
method.__doc__ = self._super_class_method.__doc__
elif (self._extend_doc and
self._super_class_method.__doc__ is not None):
method.__doc__ = (
self._super_class_method.__doc__ +
method.__doc__
)
return method