Skip to content

Provide a way to check for *real* typing.Union instances #73448

Closed

Description

@flying-sheep
BPO 29262
Nosy @gvanrossum, @flying-sheep, @ilevkivskyi, @evanunderscore
PRs
  • bpo-29262: Add get_origin() and get_args() introspection helpers to typing #13685
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-05-30.23:47:25.261>
    created_at = <Date 2017-01-13.15:45:47.284>
    labels = ['3.8', 'type-feature', 'library']
    title = 'Provide a way to check for *real* typing.Union instances'
    updated_at = <Date 2019-05-30.23:47:25.256>
    user = 'https://github.com/flying-sheep'

    bugs.python.org fields:

    activity = <Date 2019-05-30.23:47:25.256>
    actor = 'levkivskyi'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-05-30.23:47:25.261>
    closer = 'levkivskyi'
    components = ['Library (Lib)']
    creation = <Date 2017-01-13.15:45:47.284>
    creator = 'flying sheep'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 29262
    keywords = ['patch']
    message_count = 19.0
    messages = ['285410', '285483', '285520', '285521', '285522', '285523', '285524', '285525', '285526', '285527', '285528', '285529', '285530', '285531', '285532', '285548', '286422', '293287', '344012']
    nosy_count = 4.0
    nosy_names = ['gvanrossum', 'flying sheep', 'levkivskyi', 'evan_']
    pr_nums = ['13685']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue29262'
    versions = ['Python 3.8']

    Activity

    1. flying-sheep commented on Jan 13, 2017

      flying-sheepmannequin
      MannequinAuthor

      typing.Union prevents the use of isinstance and issubclass via a hook.

      This is presumably to prevent errors that would arise if someone tried to do issubclass(A, Union[A, B]) or isinstance(A(), Union[A, B]), because Union isn’t specified in the PEP to allow a check like this, and doesn’t implement it. (Instead it throws said error)

      However, as far as I can see there is no blessed way to check if an object was returned by Union.__getitem__(). A simple way that works is:

      sig = inspect.signature(f)
      ann = sig.parameters['arg1'].annotation
      is_an_union = isinstance(ann, typing._Union)

      but _Union is a private class, and an implementation detail.

      is there a blessed way to do this? If not, one should be added.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Jan 13, 2017
    3. evanunderscore commented on Jan 14, 2017

      evanunderscoremannequin
      Mannequin

      I'm also interested in this. I've been using 'thing.__origin__ is typing.Union', but this doesn't work in some of the older versions of typing.

    4. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      In principle, such a function could be added if it is not called isinstance. For example, we could add a helper is_union(tp) (or maybe also is_generic(tp) etc). Such function(s) will be simple one-liners wrapping private API in a right way (e.g. using _gorg instead of origin where needed etc).

      Guido, what do you think?

    5. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      Hm, maybe isinstance(t, Union) should actually be allowed? (Though isinstance(x, Union[int, str]) should not be!) After all we can write isinstance(t, Callable) as well, even though isinstance(x, Callable[[int], int]) is disallowed.

    6. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      This will be a bit unusual since isinstance is typically called for instances (i.e. not types) as in isinstance(func, Callable). But on the other hand this is probably what one would expect when one sees isinstance(tp, Union). Thus I am fine with doing it this way.

      If there are no objections/other ideas, then I will make a PR upstream in next few days.

    7. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      Hm, let me back-pedal a bit. The situation with Callable is murky, as e.g. isinstance(typing.Tuple[int, int], typing.Callable) returns True.

      Maybe we need to take a step back and look at the needs for code that wants to implement runtime type checking more in general? ISTM we have ways to access the parameters of a parameterized type (typically t.__parameters__) but we don't have a reasonable way yet to determine what kind of thing t is.

    8. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      Maybe we need to take a step back and look at the needs for code that wants to implement runtime type checking more in general?

      I would say that the most convenient way for me would be a set of "inspect-style" simple helpers like is_union, is_generic, get_parameters (similar to inspect.ismethod, inspect.getargspec etc).

      ISTM we have ways to access the parameters of a parameterized type (typically t.__parameters__) but we don't have a reasonable way yet to determine what kind of thing t is.

      There is one way that I see right now: using _gorg. For example, _gorg(Tuple[int, str]) is Tuple, _gorg(Callable[..., str]) is Callable, etc. This will also work for Union if we relax the assert that requires type to be instance of GenericMeta (now there is a common internal API used by almost everything in typing).

    9. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      Maybe a proposal should be discussed as an addendum to PEP-484? Or would
      Mark Shannon reject that?

      On Sun, Jan 15, 2017 at 2:48 PM, Ivan Levkivskyi <report@bugs.python.org>
      wrote:

      Ivan Levkivskyi added the comment:

      Maybe we need to take a step back and look at the needs for code that
      wants to implement runtime type checking more in general?

      I would say that the most convenient way for me would be a set of
      "inspect-style" simple helpers like is_union, is_generic,
      get_parameters (similar to inspect.ismethod, inspect.getargspec etc).

      ISTM we have ways to access the parameters of a parameterized type
      (typically t.parameters) but we don't have a reasonable way yet to
      determine what kind of thing t is.

      There is one way that I see right now: using _gorg. For example,
      _gorg(Tuple[int, str]) is Tuple, _gorg(Callable[..., str]) is Callable, etc. This will also work for Union if we relax the assert
      that requires type to be instance of GenericMeta (now there is a common
      internal API used by almost everything in typing).

      ----------


      Python tracker <report@bugs.python.org>
      <http://bugs.python.org/issue29262\>


    10. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      Maybe a proposal should be discussed as an addendum to PEP-484? Or would
      Mark Shannon reject that?

      On one hand, I would like to involve a wider audience to this discussion. On the other hand, an addition to the PEP could slow things down. Maybe a discussion on python-dev followed by implementation plus extensive docs would work?

    11. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      Posting to python-dev would probably cause more friction than a PR for the
      PEPs repo. But maybe the best way to do this is to use a third party module
      with a proposed API? E.g. typing_inspect. We could then iterate quickly on
      the design and implementation there, and we could commit to keeping it in
      sync with changes to typing.py, so flying sheep's package could depend on
      it.

    12. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      I have a similar idea. We already have mypy_extensions for runtime counterparts of experimental features. However, the runtime inspections are not related to mypy, so that I am not sure. I am just a bit worried there will be to many things to keep in mind/in sync. What do you think?

      By the way maybe later we could add typing.inspect similar to typing.re and typing.io?

    13. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      I think it should be separate from mypy_extensions, since it's not even
      related to mypy.

      Regarding typing.re and typing.io, typing.inspect would be a typed version
      of the inspect module, so that's not quite the same. (Though I consider
      typing.re/io mistakes now -- people seem to mostly ignore it and use the
      toplevel names.)

    14. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      OK, I agree.

      How then it should be done logistically? Should I just make a separate repo on GitHub for this? Or will it be inside typing (like mypy_extesions is inside mypy) but published on PyPI separately?

    15. gvanrossum commented on Jan 15, 2017

      @gvanrossum
      Member

      Up to you, but the latter might make it clearer that the two are to be kept
      in sync.

    16. ilevkivskyi commented on Jan 15, 2017

      @ilevkivskyi
      Member

      OK, I will make a PR to typing adding a folder (as it is done for mypy_extensions) with a basic set of runtime type inspection functions.

    17. flying-sheep commented on Jan 16, 2017

      flying-sheepmannequin
      MannequinAuthor

      Cool! This set of basic initial check will consist of all the is_* functions that were mentioned right?

      FWIW I also think that this is the way to go, as it’s not obvious if the semantics should be “conforms to this type annotation” or “is a type annotation of that kind” or other variants.

      In case this isn’t already too much future think: What should be the way forward from there? E.g. when working with Union[A, B], you will probably want to get “(A, B)”.

      So will that mean more introspection functions (like union_types(Union[str,int]),
      or public APIs for typings (e.g. a_union.__iter__() or a_union.types)?

    18. ilevkivskyi commented on Jan 28, 2017

      @ilevkivskyi
      Member

      Cross-posting the link to upstream work on this: python/typing#377

    19. ilevkivskyi commented on May 9, 2017

      @ilevkivskyi
      Member

      The discussed functionality is published as a separate package:
      https://pypi.python.org/pypi/typing-inspect
      https://github.com/ilevkivskyi/typing_inspect

      After the API is settled, some introspection functions may be added directly to typing.

    20. ilevkivskyi commented on May 30, 2019

      @ilevkivskyi
      Member

      New changeset 4c23aff by Ivan Levkivskyi in branch 'master':
      bpo-29262: Add get_origin() and get_args() introspection helpers to typing (GH-13685)
      4c23aff

    21. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.8 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions