From 02e3f33d1115599d0b8f817ca5067a32008874ee Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Fri, 24 Oct 2025 12:43:27 -0700 Subject: [PATCH] Another fix to the argument handling in the functools overlay Turns out * positional arguments aren't necessarily present in `Signature.param_names`; * *args/**kwargs need special handling as well. PiperOrigin-RevId: 823630645 --- pytype/overlays/functools_overlay.py | 7 ++++++- pytype/tests/test_attr2.py | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/pytype/overlays/functools_overlay.py b/pytype/overlays/functools_overlay.py index dfc8e044e..adc69c8de 100644 --- a/pytype/overlays/functools_overlay.py +++ b/pytype/overlays/functools_overlay.py @@ -179,7 +179,12 @@ def get_signatures(self) -> Sequence[function.Signature]: for name, value, _ in sig.iter_args(args): if value is None: continue - if sig.param_names.index(name) < sig.posonly_count: + if name == sig.varargs_name or name == sig.kwargs_name: + continue # Nothing to do for packed parameters. + if ( + name not in sig.param_names or + sig.param_names.index(name) < sig.posonly_count + ): # The parameter is positional-only, meaning that it cannot be # overwritten via a keyword argument. Remove it. bound_param_names.add(name) diff --git a/pytype/tests/test_attr2.py b/pytype/tests/test_attr2.py index 81dff20c9..88ecf1d43 100644 --- a/pytype/tests/test_attr2.py +++ b/pytype/tests/test_attr2.py @@ -244,6 +244,33 @@ class Foo: assert_type(foo.x, int) """) + def test_partial_with_star_args_as_converter(self): + self.Check(""" + import attr + import functools + def f(*args: str) -> str: + return "".join(args) + @attr.s + class Foo: + x = attr.ib(converter=functools.partial(f, "foo", "bar")) + foo = Foo(x=0) + assert_type(foo.x, str) + """) + + def test_partial_as_converter_with_factory(self): + # This is a smoke test for signature construction in the functools overlay. + self.Check(""" + import collections + import functools + import attr + @attr.s(auto_attribs=True) + class Foo(object): + x = attr.ib( + factory=dict, + converter=functools.partial(collections.defaultdict, lambda: 0), + ) + """) + def test_partial_overloaded_as_converter(self): self.Check(""" import attr