Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No (public) way to dynamically introspect if an annotation is a TypedDict #751

Closed
pxeger opened this issue Sep 14, 2020 · 6 comments
Closed

No (public) way to dynamically introspect if an annotation is a TypedDict #751

pxeger opened this issue Sep 14, 2020 · 6 comments

Comments

@pxeger
Copy link

@pxeger pxeger commented Sep 14, 2020

I want to know the Origin of an annotation. This works fine for basically everything, but there is no way to check if an annotation is a TypedDict subclass without resorting to (semantically) private API (by checking if it is an instance of _TypedDictMeta), because issubclass(x, TypedDict) fails. I believe this is because you don't want people thinking isinstance(x, TypedDict) will work to actually validate the keys on a dict. However, I don't think there's any reason to prevent issubclass on it

https://github.com/python/cpython/blob/1b4552c/Lib/typing.py#L1901

Here is an example use-case:

from typing import Dict, get_origin

def validate(data, annotation) -> bool:
    """check if `data` conforms to the type given in `annotation`"""
    # this works
    if get_origin(annotation) is Dict:
        return isinstance(data, dict)
    # but this doesn't...
    elif is_a_typed_dict(annotation):
        return isinstance(data, dict) and validate_typeddict_keys(data, annotation)

    ...

This could be solved in one of the following ways:

  • allow issubclass on TypedDicts
    • or allow it only on TypedDict itself and not subclasses of it, e.g. using a _root classvar like NamedTuple does for its magic
      • although I see no reason not to allow it in that case either
  • make _TypedDictMeta public API (rename to TypedDictMeta)
  • make get_origin work on TypedDicts (not ideal because it isn't really a type)
@pxeger pxeger changed the title No (public) way to dynamically introspect if an object is a TypedDict No (public) way to dynamically introspect if an annotation is a TypedDict Sep 14, 2020
@gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Sep 14, 2020

This is reasonable. Can you show us a function that when added to typing.py would solve your problem? (E.g. is_typed_dict() -- how should it be implemented?)

@pxeger
Copy link
Author

@pxeger pxeger commented Sep 14, 2020

Simply:

def is_typed_dict(cls: type) -> bool:
    return isinstance(cls, _TypedDictMeta)

would do. Is there a reason that we can't just allow issubclass on TypedDicts though?

@gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Sep 14, 2020

PEP 589 explicitly rejects supporting isinstance or issubclass for TypedDict, so let's not go there.

Are you willing to make a contribution? There would actually have to be several -- this should be added to typing.py in the CPython 3.10 stdlib, to typing.py and typing_extensions in the typing repo. (Hm, maybe only to typing_extensions? typing.py there is only relevant for Python versions that are no longer supported, like 2.7 and 3.4.)

@pxeger
Copy link
Author

@pxeger pxeger commented Sep 14, 2020

typing.py there is only relevant for Python versions that are no longer supported, like 2.7 and 3.4.)

https://github.com/python/typing/#workflow-for-cpython-changes says:

At Guido's discretion, he will from time to time copy typing.py and test_typing.py from the python/typing GitHub repo to the cpython repo.

Is that note out of date then?

@gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Sep 14, 2020

Ouch, yes. That is totally out of date. The "master" copy of those files now lives in the CPython repo and the version here is only maintained (or at least not killed) for the benefit of Python 2.7 users of mypy and pytype.

pxeger added a commit to pxeger/cpython that referenced this issue Sep 15, 2020
@pxeger
Copy link
Author

@pxeger pxeger commented Sep 15, 2020

Should I create a BPO for this? It seems like the CPython pull request workflow is heavily centered around using those issue numbers.

Done, see bpo-41792

xzy3 pushed a commit to xzy3/cpython that referenced this issue Oct 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.