-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
Bug report
Bug description:
baltus-atomicrules observe that when executing __init__
in a Generic class, the value of __orig_class__
is available in version 3.6 but not in 3.7. And others found that this is still the case from 3.8 to 3.12. To be specific, mitar reproduced on 3.8 to 3.10, LostInDarkMath reproduced on 3.11, and I reproduced on 3.12.
baltus-atomicrules attached a simple example that defines a Generic class and then accesses __orig_class__
in the associated __init__
method.
N = TypeVar('N')
class ZZ(Generic[N]):
def __init__(self):
print("__orig_class__ is: ", self.__orig_class__)
In 3.6, this code runs fine:
In [42]: import Simple
In [51]: a = Simple.ZZ[int]
In [56]: b = a()
__orig_class__ is: Simple.ZZ[int]
In 3.7+ however, the value of __orig_class__
is not available:
In [4]: import Simple
In [5]: a = Simple.ZZ[int]
In [6]: b = a()
AttributeError Traceback (most recent call last)
<ipython-input-6-52a6c422c17e> in <module>
----> 1 b = a()
/tool/pandora64/.package/python-3.7.0/lib/python3.7/typing.py in __call__(self, *args, **kwargs)
668 raise TypeError(f"Type {self._name} cannot be instantiated; "
669 f"use {self._name.lower()}() instead")
--> 670 result = self.__origin__(*args, **kwargs)
671 try:
672 result.__orig_class__ = self
/proj/emu_scratch4/users/dbaltus/python/experiment/Simple.py in __init__(self)
4 class ZZ(Generic[N]):
5 def __init__(self):
----> 6 print("__orig_class__ is: ", self.__orig_class__)
AttributeError: 'ZZ' object has no attribute '__orig_class__'
> /proj/emu_scratch4/users/dbaltus/python/experiment/Simple.py(6)__init__()
2
3 N = TypeVar('N')
4 class ZZ(Generic[N]):
5 def __init__(self):
----> 6 print("__orig_class__ is: ", self.__orig_class__)
ipdb> q
This occurs because in 3.7, the __call__
method of _GenericAlias
does not set the value of __orig_class__
until after __init__
is called. (It is done differently in 3.6).
def __call__(self, *args, **kwargs):
if not self._inst:
raise TypeError(f"Type {self._name} cannot be instantiated; "
f"use {self._name.lower()}() instead")
result = self.__origin__(*args, **kwargs)
try:
result.__orig_class__ = self
except AttributeError:
pass
return result
srittau told us to open a new issue here, and locked the old conversation. I think it would be helpful to open a issue here for tracking and back-ref that old issue: python/typing#658
Workaround
Future people encountering this can use pytypes.get_orig_class
as a workaround. Source code: https://github.com/Stewori/pytypes/blob/3846f1be3e44892c8e60f750f7581cbddd8be383/pytypes/type_util.py#L182
CPython versions tested on:
3.12
Operating systems tested on:
Linux, macOS