Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

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

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

Comments

@pxeger
Copy link

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

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 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

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 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

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
Copy link
Author

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

@septatrix
Copy link
Contributor

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

While the given reason is valid for isinstance I think the given reason does not really apply to issubclass and more likely due to TypedDict not having an MRO (as discussed here https://bugs.python.org/issue41249).
Therefore a subclass check would need to manually inspect annotations and totality. With a MRO or other access to the bases this would not be a problem at all as it is already possible for e.g. NamedTuple and subclassing generic types from collection.abc.
The reasoning given mainly regards generic aliases like issubclass(Mapping[str, int], dict).

jessecomeau87 pushed a commit to jessecomeau87/Python that referenced this issue May 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants