You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Certain multiple inheritance using generic alias errors in 3.13 #112903
Just entering these definitions in the REPL causes the error.
The stack trace (with info about variable b):
b=__main__.MutableMap[~V]
type(b)=<class 'types.GenericAlias'>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
class MyMap(typing.Dict[K, V], MutableMap[V]): ...
File "/home/russell/.pyenv/versions/3.13-dev/lib/python3.13/typing.py", line 1391, in __mro_entries__
return super().__mro_entries__(bases)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^
File "/home/russell/.pyenv/versions/3.13-dev/lib/python3.13/typing.py", line 1143, in __mro_entries__
if isinstance(b, _BaseGenericAlias) or issubclass(b, Generic):
~~~~~~~~~~^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class
This works "fine" before Python 3.13. If I swap the order of typing.Dict[K, V], MutableMap[V], the error no longer presents on 3.13.
I don't understand enough of intersection of these topics to know if this is now an expected error or something is considered wrong. This does seem related to #103369.
CPython versions tested on:
3.8, 3.9, 3.10, 3.11, 3.12, 3.13, CPython main branch
I'm marking this as a release blocker as it's a backwards-incompatible change that's new in Python 3.13 (@Yhg1s, please remove the label if you disagree!)
I don't see the backwards incompatibility. It's a regression in main, but it seems that a fix is ready to go in the next Alpha.
Can it be merged, or is there something I don't see that would require the RM's input?
I don't see the backwards incompatibility. It's a regression in main, but it seems that a fix is ready to go in the next Alpha. Can it be merged, or is there something I don't see that would require the RM's input?
The question is whether the proposed fix is the correct fix. The proposed fix uses typing._GenericAlias.__mro_entries__ to switch out instances of types.GenericAlias (a class that is unrelated to typing._GenericAlias) in the __bases__ tuple during the creation of a class that has both an instance of typing._GenericAlias and an instance of types.GenericAlias in its __orig_bases__ tuple. That feels very strange to me; I'd prefer for types.GenericAlias.__mro_entries__ to take charge of whether GenericAlias should be appearing in the __bases__ tuple (but I think that would require changes to C code rather than changes to pure Python code -- typing._GenericAlias is a pure-Python class, but types.GenericAlias is written in C).
I definitely feel like we should fix this regression before Python 3.13 is properly released, but it's probably okay to defer it for now? I don't feel qualified to comment on whether or not this should block a release, though (and if so, which release) -- that's surely up to the Release Manager :)
What's the best way to get the attention of typing-sig experts?
I can help, but I feel that I'd first need to become a typing expert myself -- a significant investment :)
I think all the people with relevant expertise on this area of code are already subscribed to this issue :) I'd say the active core devs who know this code best at this point are probably Jelle, me, Nikita and Serhiy. @carljm might also have some insight, though!
I can help, but I feel that I'd first need to become a typing expert myself -- a significant investment :)
FWIW, this issue doesn't have much to do with the intricacies of static typing (so most typing-sig experts won't have much to say on it), but it has everything to do with the mechanisms we use to achieve the runtime implementation of typing. https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__, and the references listed at the bottom of the docs for that method, would be the relevant reading required to understand what's going on here, if you are interested in helping :)
The difference between typing._GenericAlias and types.GenericAlias comes down to whether a generic alias is created by machinery internal to the typing module or a builtin PEP-585 alias from outside the typing module
Does it work with dict, collections.abc.Mapping and collections.abc.MutableMapping instead of typing.Dict, typing.Mapping and typing.MutableMapping? Does it work with mixed types?
It is weird. It fails for b = MutableMap, but issubclass(MutableMap, typing.Generic) does not fail, and isinstance(MutableMap, typing.GenericAlias) returns False, so the proposed fix should not work.
Interesting, typing.Mapping[K, V]) has type typing._GenericAlias, typing.MutableMapping[K, V]) has type typing._GenericAlias, but BaseMap[K, V] has type types.GenericAlias.
Thanks @serhiy-storchaka for the simpler examples. They helped me find that the proposed fix is wrong; I commented on the PR.
I think to fix this issue we need to either revert #103369, or add special handling to issubclass() calls in typing.py so they deal with GenericAlias correctly.
We have clearly established for a while now that generic aliases are not types; they have __mro_entries__ so they can be inherited, but otherwise they do not pretend to be types. I don't think we can (or should) backtrack on this position; background on it can be found in #89828. Reverting #103369 is just a very small partial rollback of this position, which just leaves us in an inconsistent state.
I do think the issubclass call in _BaseGenericAlias.__mro_entries__() is simply buggy as written, and must be protected by a prior isinstance(b, type) check. I put more details of that analysis into a comment on the PR.
Thanks again @rmartin16 for the early testing, thanks @encukou for bumping the issue (which I'd completely forgotten about!), and thanks @carljm for coming up with a fix!
Reacted by Russell Martin, Carl Meyer and Petr Viktorin
Activity
sobolevn commentedon Dec 9, 2023
Hm. Looks like this can fix it:
I will try to experiment with the fix a bit more to find if it is correct / full.
JelleZijlstra commentedon Dec 9, 2023
@rmartin16 thanks for the early testing of Python 3.13! It's very helpful.
And thanks @sobolevn for working on a fix.
pythongh-112903: Fix MRO resolution for `GenericAlias` types
AlexWaygood commentedon Dec 10, 2023
I'm marking this as a release blocker as it's a backwards-incompatible change that's new in Python 3.13 (@Yhg1s, please remove the label if you disagree!)
encukou commentedon Feb 6, 2024
I don't see the backwards incompatibility. It's a regression in
main, but it seems that a fix is ready to go in the next Alpha.Can it be merged, or is there something I don't see that would require the RM's input?
AlexWaygood commentedon Feb 7, 2024
The question is whether the proposed fix is the correct fix. The proposed fix uses
typing._GenericAlias.__mro_entries__to switch out instances oftypes.GenericAlias(a class that is unrelated totyping._GenericAlias) in the__bases__tuple during the creation of a class that has both an instance oftyping._GenericAliasand an instance oftypes.GenericAliasin its__orig_bases__tuple. That feels very strange to me; I'd prefer fortypes.GenericAlias.__mro_entries__to take charge of whetherGenericAliasshould be appearing in the__bases__tuple (but I think that would require changes to C code rather than changes to pure Python code --typing._GenericAliasis a pure-Python class, buttypes.GenericAliasis written in C).I definitely feel like we should fix this regression before Python 3.13 is properly released, but it's probably okay to defer it for now? I don't feel qualified to comment on whether or not this should block a release, though (and if so, which release) -- that's surely up to the Release Manager :)
AlexWaygood commentedon Feb 7, 2024
I have pretty low confidence in my opinions on the proposed fix FWIW, so I'd love it if others could chime in with their opinions!
1 remaining item
encukou commentedon Feb 8, 2024
What's the best way to get the attention of typing-sig experts?
I can help, but I feel that I'd first need to become a typing expert myself -- a significant investment :)
AlexWaygood commentedon Feb 8, 2024
I think all the people with relevant expertise on this area of code are already subscribed to this issue :) I'd say the active core devs who know this code best at this point are probably Jelle, me, Nikita and Serhiy. @carljm might also have some insight, though!
AlexWaygood commentedon Feb 8, 2024
FWIW, this issue doesn't have much to do with the intricacies of static typing (so most typing-sig experts won't have much to say on it), but it has everything to do with the mechanisms we use to achieve the runtime implementation of typing. https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__, and the references listed at the bottom of the docs for that method, would be the relevant reading required to understand what's going on here, if you are interested in helping :)
The difference between
typing._GenericAliasandtypes.GenericAliascomes down to whether a generic alias is created by machinery internal to thetypingmodule or a builtin PEP-585 alias from outside thetypingmoduleserhiy-storchaka commentedon Feb 8, 2024
Does it work with
dict,collections.abc.Mappingandcollections.abc.MutableMappinginstead oftyping.Dict,typing.Mappingandtyping.MutableMapping? Does it work with mixed types?serhiy-storchaka commentedon Feb 8, 2024
It is weird. It fails for
b = MutableMap, butissubclass(MutableMap, typing.Generic)does not fail, andisinstance(MutableMap, typing.GenericAlias)returns False, so the proposed fix should not work.serhiy-storchaka commentedon Feb 8, 2024
Ah, it is
MutableMap[K, V], notMutableMap.Interesting,
typing.Mapping[K, V])has typetyping._GenericAlias,typing.MutableMapping[K, V])has typetyping._GenericAlias, butBaseMap[K, V]has typetypes.GenericAlias.The simpler way to reproduce the issue is:
serhiy-storchaka commentedon Feb 8, 2024
Other, even simpler, example:
JelleZijlstra commentedon Feb 8, 2024
Thanks @serhiy-storchaka for the simpler examples. They helped me find that the proposed fix is wrong; I commented on the PR.
I think to fix this issue we need to either revert #103369, or add special handling to
issubclass()calls in typing.py so they deal withGenericAliascorrectly.carljm commentedon Feb 8, 2024
We have clearly established for a while now that generic aliases are not types; they have
__mro_entries__so they can be inherited, but otherwise they do not pretend to be types. I don't think we can (or should) backtrack on this position; background on it can be found in #89828. Reverting #103369 is just a very small partial rollback of this position, which just leaves us in an inconsistent state.I do think the
issubclasscall in_BaseGenericAlias.__mro_entries__()is simply buggy as written, and must be protected by a priorisinstance(b, type)check. I put more details of that analysis into a comment on the PR.pythongh-112903: Handle non-types in _BaseGenericAlias.__mro_entries__()
gh-112903: Handle non-types in _BaseGenericAlias.__mro_entries__() (#…
AlexWaygood commentedon Feb 9, 2024
Thanks again @rmartin16 for the early testing, thanks @encukou for bumping the issue (which I'd completely forgotten about!), and thanks @carljm for coming up with a fix!
pythongh-112903: Handle non-types in _BaseGenericAlias.__mro_entries_…