Repository navigation
typing.get_origin behaves differently between standard collections and typing collections #95539
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Aug 1, 2022 The fact that
get_origin(Dict)returnsdictis not documented. It looks to me like an implementation artifact.Many things in the
typingmodule are implementation artifacts. The implementation was rewritten several times, so some behavior of the current code is now different from the behavior of the earlier implementations, and some behavior was reproduced for backward compatibility even if it now does not make much sense.types.GenericAliasandtypes.UnionTypewere written from scratch and do nor reproduce every peculiarity of thetypingmodule.What is the use case for
get_origin(Dict)andget_origin(dict)?This had a side effect on the behavior of the pydantic package, which has some logic to determine the
SHAPEof a type hint here, and it relies onget_originto do so, causing Dict and dict to be determined as different types, and with some later side effect in the rest of the package.An example was documented here
Does this code work as intended? I see few suspicious things:
- It contains the condition
origin is dict or origin is Dict. But bothget_origin(Dict[x, y])andget_origin(Dict)returndict, notDict. Is the second part of the condition really needed? - If this condition is true, the code evaluates
get_args(self.type_)[1]. Butget_args(Dict)is an empty tuple, and you get an IndexError. This code does not work withDict, you should not expect it to work withdicteither.
- It contains the condition
the code actually works
- Second part of the if might be redundant, I'm not sure
- Note it doesn't call
get_argsfrom the typing package, but an internal implementation that wraps theget_argsfrom typing
but now that you point it out, some adjustments will still need to be made to support
get_argsondictAnyway, regardless to that package code\usage or assumptions, I was just thinking that since
dictandDictare meant to be interchangeable (please correct me if I'm wrong), then it makes sense to try and make them behave as similar as possible (and specifically in the typing package)also fine to leave as if there is a disagreement here
WDYT?I was just thinking that since
dictandDictare meant to be interchangeable (please correct me if I'm wrong), then it makes sense to try and make them behave as similar as possible (and specifically in the typing package)Makes sense to me.
If you need to use a wrapper for
get_argsin any case, you can add a wrapper forget_originas well.If you make
get_origin(dict)returningdictyou can break some unrelated code, like many functions were broken when ``isinstance(list[int], type)returned True. On other hand, it can make some code simpler or more correct. We need to analyze the usage ofget_origin` in many different contexts before changing it.It is also not clear what change do you need. Should it only work with a limited set of builtin Python types and types defined in the stdlib? Should it work with arbitrary type? Or any type with
__class_getitem__? What if__class_getitem__is None or a method always raising a TypeError.Yep, can definitely do that, but I think the discussion here is regardless of the usage of the pydantic package
I think it's a general discussion on what is the expected behaviour of
get_originI think the guideline should be to make standard collections behave as similar as possible to the typing collections in order to allow for easier transition between them (as I understand the collections from the typing module are expected to be deprecated in the future)
so
get_originshould return for any standard collection the equivalent that would have returned for object from the typing package, i.e this listfor context, I'm a user of the pydantic package, and just trying to make my first steps in open source contributing :), and came across that bug opened for pydantic, which led my to this issue. I'm not aware enough to all the implications or nuances such a change might impose
Bug report
typing.get_origin behaves differently between standard collections, and typing collections
more specifically
get_origin(dict)isNone, whileget_origin(Dict)is<class 'dict'>the same holds for other collections as well
This is true from python3.9 where support for standard collections was added
to my understanding dict should be able to be a drop-in replacement for Dict, which is not true in case relying on get_origin
I suggest updating get_origin to return the relevant class for builtin collections as opposed to
Nonewhich returns todaynote, this might mean a breaking change, as pointed out here, but id does make Dict and dict behave more similarly