Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion returns/contrib/mypy/_typeops/transform_callable.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ def diff(self, applied_args: list[FuncArg]) -> CallableType:
# longer be filled positionally, so every remaining positional
# parameter after it must become keyword-only. Otherwise the partial
# would accept positional arguments that raise a ``TypeError`` at
# runtime. See issue #2191.
# runtime. Variadic positional parameters become unreachable too.
# See issue #2191.
keyword_hole_at = self._keyword_hole_at(
original_args,
applied_args,
Expand All @@ -173,6 +174,7 @@ def diff(self, applied_args: list[FuncArg]) -> CallableType:
self._remaining_arg(arg, keyword_only=index > keyword_hole_at)
for index, arg in enumerate(original_args)
if not self._was_applied(arg, index, intermediate_names)
and (arg.kind != ARG_STAR or index < keyword_hole_at)
])

def _keyword_hole_at(
Expand Down
42 changes: 39 additions & 3 deletions typesafety/test_curry/test_partial/test_partial_arguments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
main:14: note: Revealed type is "def (a: int, b: int, c: int =, *args: float, d: str, e: bool =, **kwargs: str) -> str"
main:15: note: Revealed type is "def (b: int, c: int =, *args: float, d: str, e: bool =, **kwargs: str) -> str"
main:16: note: Revealed type is "def (c: int =, *args: float, d: str, e: bool =, **kwargs: str) -> str"
main:17: note: Revealed type is "def (*args: float, d: str, e: bool =, **kwargs: str) -> str"
main:18: note: Revealed type is "def (*args: float, e: bool =, **kwargs: str) -> str"
main:19: note: Revealed type is "def (*args: float, d: str, **kwargs: str) -> str"
main:17: note: Revealed type is "def (*, d: str, e: bool =, **kwargs: str) -> str"
main:18: note: Revealed type is "def (*, e: bool =, **kwargs: str) -> str"
main:19: note: Revealed type is "def (*, d: str, **kwargs: str) -> str"
main:20: note: Revealed type is "def (c: int =, *args: float, e: bool =, **kwargs: str) -> str"
main:21: note: Revealed type is "def (c: int =, *args: float, d: str, **kwargs: str) -> str"
main:22: note: Revealed type is "def (*args: float, d: str, e: bool =, **kwargs: str) -> str"
Expand Down Expand Up @@ -211,3 +211,39 @@
from returns.curry import partial

reveal_type(partial((lambda x, y: str(x + y)), 1)) # N: Revealed type is "def (y: Any) -> str"


- case: partial_variadic_argument_binding
disable_cache: false
main: |
from returns.curry import partial

def multiple(first: int, *args: int, flag: bool = False) -> str:
...

bound = partial(multiple, first=1)
reveal_type(bound) # N: Revealed type is "def (*, flag: bool =) -> str"
reveal_type(bound(flag=True)) # N: Revealed type is "str"
bound(True) # E: Too many positional arguments [call-arg]

keyword_bound = partial(multiple, flag=True)
reveal_type(keyword_bound) # N: Revealed type is "def (first: int, *args: int) -> str"
reveal_type(keyword_bound(1, 2, 3)) # N: Revealed type is "str"

positional_bound = partial(multiple, 1, 2)
reveal_type(positional_bound) # N: Revealed type is "def (*args: int, flag: bool =) -> str"
reveal_type(positional_bound(3, 4, flag=True)) # N: Revealed type is "str"


- case: partial_keyword_hole_before_varargs_keeps_prefix
disable_cache: false
main: |
from returns.curry import partial

def multiple(first: int, second: int, *args: int, flag: bool = False) -> str:
...

bound = partial(multiple, second=2)
reveal_type(bound) # N: Revealed type is "def (first: int, *, flag: bool =) -> str"
bound(1, flag=True)
bound(1, True) # E: Too many positional arguments [call-arg]
Loading