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.