You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
import inspect
|
|
|
|
|
|
class TraitImplementError(RuntimeError):
|
|
def __init__(self, message):
|
|
super().__init__(message)
|
|
self.message = message
|
|
|
|
|
|
def check_is_subclass(implementor, protocol):
|
|
if not issubclass(implementor, protocol):
|
|
raise TraitImplementError(
|
|
f'implementor {implementor.__name__} is not a subclass of {protocol.__name__}')
|
|
|
|
|
|
def impl(protocol: type):
|
|
"""
|
|
Decorate a class to make it a trait implementation.
|
|
:param protocol: Protocol class to be decorated.
|
|
:return: decorator function
|
|
"""
|
|
|
|
def decorator(implementor: type):
|
|
implemented = implementor.__bases__[0]
|
|
implementor_methods = []
|
|
check_is_subclass(implementor, protocol)
|
|
p_module = protocol.__module__
|
|
for name, method in inspect.getmembers(protocol, inspect.isfunction):
|
|
if p_module == method.__module__:
|
|
implementor_methods.append((name, getattr(implementor, name)))
|
|
for name, method in implementor_methods:
|
|
setattr(implemented, name, method)
|
|
|
|
return decorator
|
|
|
|
|
|
def trait(implementor):
|
|
"""
|
|
Decorate a class to make it a trait implementation.
|
|
:param implementor: trait class to be decorated.
|
|
:return: None. Shadowing subclass
|
|
"""
|
|
implemented, protocol = implementor.__bases__
|
|
implementor_methods = []
|
|
check_is_subclass(implementor, protocol)
|
|
p_module = protocol.__module__
|
|
for name, method in inspect.getmembers(protocol, inspect.isfunction):
|
|
if p_module == method.__module__:
|
|
implementor_methods.append((name, getattr(implementor, name)))
|
|
for name, method in implementor_methods:
|
|
setattr(implemented, name, method)
|