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

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

Closed
flying-sheep mannequin opened this issue Jan 13, 2017 · 19 comments
Closed

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

flying-sheep mannequin opened this issue Jan 13, 2017 · 19 comments
Labels
3.8 (EOL) end of life stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@flying-sheep
Copy link
Mannequin

flying-sheep mannequin commented Jan 13, 2017

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

    @flying-sheep
    Copy link
    Mannequin Author

    flying-sheep mannequin commented Jan 13, 2017

    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.

    @flying-sheep flying-sheep mannequin added the stdlib Python modules in the Lib dir label Jan 13, 2017
    @evanunderscore
    Copy link
    Mannequin

    evanunderscore mannequin commented Jan 14, 2017

    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.

    @ilevkivskyi
    Copy link
    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?

    @ilevkivskyi ilevkivskyi added the type-feature A feature request or enhancement label Jan 15, 2017
    @gvanrossum
    Copy link
    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.

    @ilevkivskyi
    Copy link
    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.

    @gvanrossum
    Copy link
    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.

    @ilevkivskyi
    Copy link
    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).

    @gvanrossum
    Copy link
    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\>


    @ilevkivskyi
    Copy link
    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?

    @gvanrossum
    Copy link
    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.

    @ilevkivskyi
    Copy link
    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?

    @gvanrossum
    Copy link
    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.)

    @ilevkivskyi
    Copy link
    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?

    @gvanrossum
    Copy link
    Member

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

    @ilevkivskyi
    Copy link
    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.

    @flying-sheep
    Copy link
    Mannequin Author

    flying-sheep mannequin commented Jan 16, 2017

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

    @ilevkivskyi
    Copy link
    Member

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

    @ilevkivskyi
    Copy link
    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.

    @ilevkivskyi
    Copy link
    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

    @ilevkivskyi ilevkivskyi added the 3.8 (EOL) end of life label May 30, 2019
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 (EOL) end of life stdlib Python modules in the Lib dir type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants