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

"Union requires two or more type arguments" reported for non-type annotation usage of Union (e.g. introspection) #2014

Closed
ghost opened this issue Oct 30, 2021 · 9 comments
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version

Comments

@ghost
Copy link

ghost commented Oct 30, 2021

Environment data

  • Language Server version: v2021.10.3
  • OS and version: macOS 11.6
  • Python version: 3.9.6

Expected behaviour

typing.Union with no subscript is valid when it is used in certain situations other than type annotation, such as for runtime introspection, for example, using typing.get_origin:

from typing import Union, get_origin

union_type = Union[int, float, bool]
assert get_origin(union_type) is Union  # is a union type
# get_origin will return the `Union` object itself

In such use cases, Pylance should not report issues.

Actual behaviour

Pylance reports "Union requires two or more type arguments."

This seems to be introduced in the latest 2021.10.3 (October 27) version, in this feature:

Enhancement: Added check for Union when only one type argument is provided and it is not an unpacked variadic type variable.

@ghost
Copy link
Author

ghost commented Oct 30, 2021

The same issue appears with typing.Generic as well.

@erictraut
Copy link
Contributor

The issue with Union has already been fixed in pyright. (See microsoft/pyright#2499). I'll file a separate issue for Generic.

@erictraut erictraut added bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version and removed triage labels Oct 30, 2021
@heejaechang
Copy link
Contributor

fixed in 2021.11.0

@coady
Copy link

coady commented Dec 1, 2023

This is still reported when Union[...] is used with a non-literal tuple, which is valid.

tup = int, float
Union[tup]  # Union requires two or more type arguments
Union[int]  # same

@erictraut
Copy link
Contributor

which is valid

This isn't valid. It doesn't crash at runtime, but Union is a special form that's part of the type system, and type checkers like pyright and mypy apply additional rules about what is is valid and what is not for these special forms. Tuples and tuple expressions are also not allowed here. Mypy generates the same error if you try to use a tuple here

I'll also note that the use of Union is no longer recommended. The modern way to express a union type within a type annotation is int | float.

@hellozyemlya
Copy link

which is valid

This isn't valid. It doesn't crash at runtime, but Union is a special form that's part of the type system, and type checkers like pyright and mypy apply additional rules about what is is valid and what is not for these special forms. Tuples and tuple expressions are also not allowed here. Mypy generates the same error if you try to use a tuple here

I'll also note that the use of Union is no longer recommended. The modern way to express a union type within a type annotation is int | float.

and what is a valid way to create union out of tuple of arguments?

@erictraut
Copy link
Contributor

and what is a valid way to create union out of tuple of arguments?

There isn't a valid way to do this in the Python type system. Could you describe your use case in more detail? You can use a type alias that refers to a union to define another union, if that helps.

@coady
Copy link

coady commented Dec 9, 2023

Tuples and tuple expressions are also not allowed here. Mypy generates the same error if you try to use a tuple here

There isn't a valid way to do this in the Python type system. Could you describe your use case in more detail?

My use case is the same as the original: runtime introspection. Mypy doesn't error if Union[a_tuple] is used in plain untyped code.

@hellozyemlya
Copy link

hellozyemlya commented Dec 9, 2023

and what is a valid way to create union out of tuple of arguments?

There isn't a valid way to do this in the Python type system. Could you describe your use case in more detail? You can use a type alias that refers to a union to define another union, if that helps.

As mentioned above - runtime introspection. My primary goal is "un-Optional" type. I check if type is Union\UnionType, and ensure that there is one last NoneType in get_args(my_type).

I worked-around that by following code:

    result = None
    for t in get_args(optional_type)[:-1]:
        if result is None:
            result = t
        else:
            result = result | t

seems to be working fine, and mypy & pyright are happy about that.

ps: Union and UnionType(str | int gives UnionType) seems to be different when comes to get_origin, still Union[str, int] == str | int equals True
pps: for some reason can't import UnionType(on homebrew 3.11 python) from typing, but type(str | int) resolves to proper type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version
Projects
None yet
Development

No branches or pull requests

4 participants