From 63bb8cce05c3627851bd40016ea536b9e8f26324 Mon Sep 17 00:00:00 2001 From: fan wu <336798967+FanWu-ai@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:15:25 -0700 Subject: [PATCH] Preserve positional-only parameters in curry signatures --- toolz/functoolz.py | 2 +- toolz/tests/test_functoolz.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/toolz/functoolz.py b/toolz/functoolz.py index b4cacac4..9cb81a02 100644 --- a/toolz/functoolz.py +++ b/toolz/functoolz.py @@ -257,7 +257,7 @@ def __signature__(self): elif kind == param.VAR_POSITIONAL: if kwonly: continue - elif param.name in keywords: + elif param.name in keywords and kind != param.POSITIONAL_ONLY: default = keywords[param.name] kind = param.KEYWORD_ONLY kwonly = True diff --git a/toolz/tests/test_functoolz.py b/toolz/tests/test_functoolz.py index d35e0de2..a8f8091c 100644 --- a/toolz/tests/test_functoolz.py +++ b/toolz/tests/test_functoolz.py @@ -238,6 +238,36 @@ def h(x, func=int): assert curry(h, func=str)(0.0) == '0.0' +@pytest.mark.parametrize('kwargs', [{'a': 10}, {'b': 20}, {'a': 10, 'b': 20}]) +def test_curry_signature_positional_only_keywords(kwargs): + def f(a=1, b=2, /, c=3, *args, **keywords): + return a, b, c, args, keywords + + curried = curry(f, **kwargs) + signature = inspect.signature(curried) + + assert signature == inspect.signature(f) + bound = signature.bind(4, 5, 6, 7) + assert curried(*bound.args, **bound.kwargs) == (4, 5, 6, (7,), kwargs) + assert curried() == (1, 2, 3, (), kwargs) + + +def test_curry_signature_positional_only_and_keyword_bound(): + def f(a=1, /, b=2, *args, **kwargs): + return a, b, args, kwargs + + curried = curry(f, a=10, b=20) + signature = inspect.signature(curried) + + assert signature.parameters['a'].kind == inspect.Parameter.POSITIONAL_ONLY + assert signature.parameters['a'].default == 1 + assert signature.parameters['b'].kind == inspect.Parameter.KEYWORD_ONLY + assert signature.parameters['b'].default == 20 + assert 'args' not in signature.parameters + bound = signature.bind(3, b=4) + assert curried(*bound.args, **bound.kwargs) == (3, 4, (), {'a': 10}) + + def test_curry_passes_errors(): @curry def f(a, b):