microsoft / pyright

Static Type Checker for Python
Other
13.12k stars 1.4k forks source link

typing.Literal with tuple argument not understood #8696

Closed dcnieho closed 1 month ago

dcnieho commented 1 month ago

Environment data

Code Snippet

import typing

values = ('a','b','c')
t = typing.Literal[values]

def get_values() -> tuple[int]:
    return (1,2,3)
t1 = typing.Literal[get_values()]

Repro Steps

put code in empty .py file, see Pylance analysis output

Expected behavior

No squiggles, Pylance correctly deduces t as typing.Literal['a','b','c'] and t1 as typing.Literal[1,2,3] (or, given that that is runtime, at least no squiggle)

Actual behavior

When run, code works correctly (you can instantiate a typing.Literal with a tuple of values), but Pylance provides yellow squiggles under values and get_values() with the following errors:

Variable not allowed in type expression Pylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
Type arguments for "Literal" must be None, a literal value (int, bool, str, or bytes), or an enum valuePylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
(variable) values: Any

and

Call expression not allowed in type expression Pylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
Type arguments for "Literal" must be None, a literal value (int, bool, str, or bytes), or an enum valuePylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
(function) def get_values() -> tuple[int]

respectively

heejaechang commented 1 month ago

are you trying to create new type alias by t = typing.Literal[values]? or did you mean to do t: typing.Literal[...] ?

for this

def get_values() -> tuple[int]:
    return (1,2,3)

did you mean def get_values() -> tuple[int, ...] ?

same for t1 = typing.Literal[get_values()]

....

that said, see https://docs.python.org/3/library/typing.html#typing.Literal and https://peps.python.org/pep-0586/#legal-parameters-for-literal-at-type-check-time

at runtime, what you have might not error out, but it won't have any meaning at runtime?

see this At runtime, an arbitrary value is allowed as type argument to Literal[...], but type checkers may impose restrictions

dcnieho commented 1 month ago

Thanks for the quick reply! I do indeed mean t = typing.Literal[values], in my actual code i am constructing the literal type object with a set of accepted values only known at run time, and then use it for runtime type checking.

If the type check warnings are expected at type check time (I indeed do not see a tuple of arguments being flattened mentioned in the docs), then i guess this can be closed.

erictraut commented 1 month ago

Could someone from the pylance team please transfer this to the pyright project? Since this is a value expression and not a type expression, rules for type expressions shouldn't be enforced.

erictraut commented 1 month ago

This is addressed in pyright 1.1.376.