Skip to content
Prev Previous commit
Next Next commit
Add ParamSpec test case
  • Loading branch information
ilevkivskyi committed Aug 21, 2022
commit b56adc86a1baf5adee7e76b637e2672913bc47aa
19 changes: 19 additions & 0 deletions test-data/unit/check-varargs.test
Original file line number Diff line number Diff line change
Expand Up @@ -970,3 +970,22 @@ def bar(**kwargs: Unpack[Person]) -> None: ...
reveal_type([foo, bar]) # N: Revealed type is "builtins.list[def (*, name: builtins.str, age: builtins.int)]"
reveal_type([bar, foo]) # N: Revealed type is "builtins.list[def (*, name: builtins.str, age: builtins.int)]"
[builtins fixtures/dict.pyi]

[case testUnpackKwargsParamSpec]
from typing import Callable, Any, TypeVar, List
from typing_extensions import ParamSpec, Unpack, TypedDict

class Person(TypedDict):
name: str
age: int

P = ParamSpec('P')
T = TypeVar('T')

def dec(f: Callable[P, T]) -> Callable[P, List[T]]: ...

@dec
def g(**kwargs: Unpack[Person]) -> int: ...

reveal_type(g) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> builtins.list[builtins.int]"
[builtins fixtures/dict.pyi]
Copy link
Copy Markdown
Member

@sobolevn sobolevn Aug 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some other cases that I think are worth covering:

  1. When TypedDict has kwargs argument (because it is special cased in the implementation)
  2. When TypedDict has invalid chars for aguments, like T = TypedDict("T", {"@": int})
  3. When TypedDict is empty, no keys
  4. When TypedDict has a key that overrides other arguments like T = TypedDict("T", {"a": int}) and def some(a: str, **kwargs: Unpack[T]): ... (and similar cases like def some(a: str, /, **kwargs: Unpack[T]) and def some(*, a: str, **kwargs: Unpack[T]))
  5. We can also check overrides with compatible / incompatible typed dics
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the tests (and also fixed error messages for incompatible overrides). Btw on non-identifier keys, Python allows them:

>>> def foo(**a):
...     print(a)
... 
>>> foo(**{"@": 1})
{'@': 1}

Note I already had a test for named argument overlap, so I added the same one for positional-only (which should be allowed).