0

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))
mblw
  • 1,762
  • 1
  • 19
  • 28
  • Do you mean [these](https://docs.python.org/reference/datamodel.html#index-33)? Why are you trying to "check" this at runtime? And what do you mean by "check" in the first place? I suspect this may be an [XY problem](https://meta.stackexchange.com/q/66377/248627). – ChrisGPT was on strike Dec 11 '22 at 12:38
  • You could check whether something exists as *non-magic* method. If it doesn’t, but you’re sure it will exist as magic attribute, then you know. If you don’t know whether something exists at all you won’t be able to discover it programmatically. – deceze Dec 12 '22 at 06:26
  • @Chris I want to make proxy class that delegate all magic methods except several to its wrapped object. This is pretty close to what I want to do https://stackoverflow.com/questions/9057669/how-can-i-intercept-calls-to-pythons-magic-methods-in-new-style-classes BUT: if I try to wrap dataclass this solution fails on methods starts with internal methods of dataclass `__` – mblw Dec 12 '22 at 09:22

0 Answers0