I wonder what check I should make to check whether method is magic? Not dunder (two underscore before and after), ONLY and ONLY magic methods. If be more specific methods that not goes through __getattr__
This is my current solution, but I want to simplify set of __ignore_attributes__
and make this solution more robust.
class ParameterizedMeta(ABCMeta):
@_tp_cache
def __getitem__(cls, *values):
# methods have default implementation not places here
values = cls.__subclass_parseargs__(*values)
parameters = cls.__subclass_parameters__(*values)
name = cls.__subclass_name__(parameters)
bases = cls.__subclass_bases__(parameters)
subclass = type(name, bases, parameters)
subclass.__subclass_post_init__()
return subclass
__ignore_attributes__ = {
"__class__",
"__mro__",
"__new__",
"__init__",
"__setattr__",
"__getattr__",
"__delattr__",
"__getattribute__",
"__eq__",
"__ne__",
"__init_subclass__",
"__class_getitem__",
"__subclasshook__",
"__module__",
"__name__",
"__qualname__",
"__dict__",
"__slots__",
"__size__",
"__sizeof__",
"__weakref__",
"__abstractmethods__",
"__orig_class__",
"__post_init__",
"__type__",
...
}
__force_attributes__ = [
"__hash__",
"__str__",
"__repr__",
]
__proxy_meta_bypass__ = {"__type__", ...}
class ProxyMeta(ParameterizedMeta):
__type__: type[Serializable]
def __getattr__(self, item) -> Any:
# If requested attribute is one of predefined prevent infinite recursion
if item in __proxy_meta_bypass__ :
raise AttributeError
return getattr(self.__type__, item)
def __subclass_post_init__(self):
if not isinstance(self.__type__, type):
return
attributes = set(dir(self.__type__) + __force_attributes__)
def delegate(attribute: str):
def proxy(s, *args, **kwargs):
func = getattr(s.__value__, attribute)
return func(*args, **kwargs)
proxy.__name__ = str(attributes)
return proxy
def check_is_magic(attribute: str):
if not attribute.startswith("__") or not attribute.endswith("__"):
return False
if attribute in __ignore_attributes__:
return False
value = getattr(self.__type__, attribute)
if not callable(value):
return False
return True
for name in filter(check_is_magic, attributes):
setattr(self, name, delegate(name))