Description
Bug report
Checklist
- I am confident this is a bug in CPython, not a bug in a third-party project
- I have searched the CPython issue tracker, and am confident this bug has not been reported before
A clear and concise description of the bug
(I originally posted about this on python-list a little over a week ago, but didn't get any replies.) I was playing around with 3.12.0b4 recently and noticed an odd (to me, at least) behavior with types.get_original_bases()
.
>>> T = typing.TypeVar("T")
>>> class FirstBase(typing.Generic[T]):
... pass
...
>>> class SecondBase(typing.Generic[T]):
... pass
...
>>> class First(FirstBase[int]):
... pass
...
>>> class Second(SecondBase[int]):
... pass
...
>>> class Example(First, Second):
... pass
...
>>> types.get_original_bases(Example)
(__main__.FirstBase[int],)
>>> Example.__bases__
(<class '__main__.First'>, <class '__main__.Second'>)
>>> types.get_original_bases(First)
(__main__.FirstBase[int],)
In summary, types.get_original_bases(Example)
is returning the original base types for First
, rather than its own.
I believe this happens because __orig_bases__
is only set when one or more of a generic type's bases are not types. In this case both bases are types, so Example
doesn't get its own __orig_bases__
. Then when types.get_original_bases()
tries to get __orig_bases__
on Example
, it searches the MRO and finds __orig_bases__
on First
.
The same thing also happens if all the bases are “bare” generic types.
>>> class First(typing.Generic[T]):
... pass
...
>>> class Second(typing.Generic[T]):
... pass
...
>>> class Example(First, Second):
... pass
...
>>> types.get_original_bases(Example)
(typing.Generic[~T],)
I'm not entirely clear if this is a bug, or an intended (but unfortunate) behavior. I would personally expect types.get_original_bases()
to check if the type has its own __orig_bases__
attribute, and to fall back to __bases__
otherwise.
For example, the way it works currently makes it unnecessarily difficult to write a function that recurses down a type's inheritance tree inspecting the original bases—I currently have to work around this behavior via hacks like checking "__orig_bases__" in cls.__dict__
or any(types.get_original_bases(cls) == types.get_original_bases(base) for base in cls.__bases__)
. (Unless I'm missing some simpler solution.)
Is this something that could (should?) be addressed before 3.12 lands?
Your environment
% docker run -it --rm python:3.12-rc
Python 3.12.0b4 (main, Jul 28 2023, 03:58:56) [GCC 12.2.0] on linux
Linked PRs
Metadata
Metadata
Assignees
Projects
Status