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

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)