1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
# ----------------------------------------------------------------------------
# Copyright (c) 2013--, scikit-bio development team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE.txt, distributed with this software.
# ----------------------------------------------------------------------------
from ._exception import OverrideError
# Adapted from http://stackoverflow.com/a/8313042/579416
def overrides(interface_class):
"""Indicate that a member is being overridden from a specific parent class.
Decorator for class-level members. Used to indicate that a member is being
overridden from a specific parent class. If the member does not have a docstring,
it will pull one from the parent class. When chaining decorators, this should be
first as it is relatively nondestructive.
Parameters
----------
interface_class : class
The class which has a member overridden by the decorated member.
Returns
-------
function
The function is not changed or replaced.
Raises
------
OverrideError
If the `interface_class` does not possess a member of the same name
as the decorated member.
"""
def overrider(method):
if method.__name__ not in dir(interface_class):
raise OverrideError(
f"{method.__name__} is not present in parent "
f"class: {interface_class.__name__}."
)
backup = classproperty.__get__
classproperty.__get__ = lambda x, y, z: x
if method.__doc__ is None:
method.__doc__ = getattr(interface_class, method.__name__).__doc__
classproperty.__get__ = backup
return method
return overrider
class classproperty(property):
"""Decorator for class-level properties.
Supports read access only. The property will be read-only within an
instance. However, the property can always be redefined on the class, since
Python classes are mutable.
Parameters
----------
func : function
Method to make a class property.
Returns
-------
property
Decorated method.
Raises
------
AttributeError
If the property is set on an instance.
"""
def __init__(self, func):
name = func.__name__
doc = func.__doc__
super(classproperty, self).__init__(classmethod(func))
self.__name__ = name
self.__doc__ = doc
def __get__(self, cls, owner):
return self.fget.__get__(None, owner)()
def __set__(self, obj, value):
raise AttributeError("can't set attribute")
class classonlymethod(classmethod):
"""Just like `classmethod`, but it can't be called on an instance."""
def __get__(self, obj, cls=None):
if obj is not None:
raise TypeError(
f"Class-only method called on an instance. Use "
f"{cls.__name__}.{self.__func__.__name__} "
"instead."
)
return super().__get__(obj, cls)
|