Home > Enterprise >  Get generic type of class at runtime with Python 3.6
Get generic type of class at runtime with Python 3.6

Time:12-16

Following a solution described in this question: How to access the type arguments of typing.Generic?

I have successfully solved a generic type at runtime in Python 3.8. However I can't seem to be able to access the __args__ field described in the solution for Python 3.6. I'm not sure why, here's my code:

def get_generic_type_arg(cls):
    if py_version >= (3, 8):
        t = cls.__orig_bases__[0]
        return get_args(t)[0]
    else:
        t = cls.__args__
        return None

class EventContract:
    @classmethod
    def get_version(cls) -> int:
        return int(cls.__name__[1:])


RT = TypeVar('RT', bound=EventContract)


class QueryContract(Generic[RT], EventContract):
    """ Base class for query contracts that are versioned. """

    @classmethod  # Do not override this
    def get_response_class(cls) -> Type[RT]:
        return get_generic_type_arg(cls)

    def build_result(self, *args, **kwargs):
        return self.get_response_class()(**kwargs)


@dataclasses.dataclass
class V1Response(EventContract):
    value: int


@dataclasses.dataclass
class V1(QueryContract[V1Response]):
    id: int
    name: str

When trying to call get_generic_type on cls I get an AttributeError. I also tried to fetch its base class using t.__bases__[0] which gives me the QueryContract with no generic arguments (__args__ gives me another attribute error). I am calling the get_response_class method on V1. Any ideas ?

CodePudding user response:

I have figured out how to do it. For some reason, __orig_bases__ wasn't working but after rebuilding my Python 3.6 and using a VENV, it works. This is the final working method:

py_version = sys.version_info
if py_version >= (3, 8):
    from typing import get_args


def get_generic_type_arg(cls):
    t = cls.__orig_bases__[0]
    if py_version >= (3, 8):
        return get_args(t)[0]
    else:
        return t.__args__[0]

Python 3.6 also requires to install dataclasses as a library though it wasn't part of this issue. Also note that __args__ seems to be undocumented in Python 3.6 and removed from Python 3.8.

  • Related