from collections.abc import ABCMeta, abstractmethod
class MixinError(TypeError): pass
class MixinMeta(type):
"""Build classes that easily mix in to other classes."""
def __new__(self, name, bases, namespace):
cls = super(MixinMeta, self).__new__(self, name, bases, namespace)
if "__mixins__" not in namespace:
cls.__mixins__ = tuple(name for name in namespace if name != "__module__")
return cls
def mixes_in(cls, target):
"""Class decorator to add the __mixins__ of cls into target.
If any mixin attribute's name is already bound on the target,
raise a MixinError.
The target is returned, modified.
"""
# check for all mixin attrs before adding
for attr in cls.__mixins__:
if hasattr(target, attr):
raise MixinError("Attribute already exists: %s" % attr)
for attr in cls.__mixins__:
setattr(target, attr, getattr(cls, attr))
return cls.register(target)
class OverlayError(TypeError): pass
class OverlayMeta(type):
"""Build classes that easily wrap the methods of other classes."""
def __new__(self, name, bases, namespace):
cls = super(OverlayMeta, self).__new__(self, name, bases, namespace)
cls.__overlays__ = tuple(name for name in namespace if name != "__module__")
return cls
def overlays(cls, target):
"""Class decorator to wrap the target's methods.
If any overlay attribute's name is not bound on the target,
raise an OverlayError.
The target is used as the base class for a new class, which is
returned.
"""
# check for all overlay attrs before adding
for attr in cls.__overlays__:
if not hasattr(target, attr):
raise OverlayError("Expected attribute: %s" % attr)
class Temp(target):
__doc__ = target.__doc__
for attr in cls.__overlays__:
locals()[attr] = getattr(cls, attr)
del attr
Temp.__name__ = target.__name__
return Temp