Skip to content

Commit b4a8a10

Browse files
superbobrycopybara-github
authored andcommitted
Fixed *args and **kwargs handling in the functools overlay
pytype is sometimes able to convert args/kwargs to positional/keyword arguments. The functools overlay did not account for that prior to this change, and ended up passing the same arguments twice! See added test case for a minimal repro. PiperOrigin-RevId: 821665368
1 parent 71b91b1 commit b4a8a10

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

pytype/abstract/_function_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ def call(
192192
self.func.__self__ # pytype: disable=attribute-error
193193
)
194194
args = args.simplify(node, self.ctx, match_signature=sig)
195+
del sig
195196
posargs = [u.AssignToNewVariable(node) for u in args.posargs]
196197
namedargs = {
197198
k: u.AssignToNewVariable(node) for k, u in args.namedargs.items()

pytype/overlays/functools_overlay.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ def call(
115115
) -> tuple[cfg.CFGNode, cfg.Variable]:
116116
# ``NativeFunction.call`` does not forward *args and **kwargs to the
117117
# underlying function, so we do it here to avoid changing core pytype APIs.
118+
#
119+
# The simplification below ensures that the *args/**kwargs cannot in fact
120+
# be split into individual arguments. This logic follow the implementation
121+
# in the base class.
122+
sig = None
123+
if isinstance(
124+
self.func.__self__, # pytype: disable=attribute-error
125+
abstract.CallableClass,
126+
):
127+
sig = function.Signature.from_callable(
128+
self.func.__self__ # pytype: disable=attribute-error
129+
)
130+
args = args.simplify(node, self.ctx, match_signature=sig)
131+
del sig
132+
118133
starargs = args.starargs
119134
starstarargs = args.starstarargs
120135
if starargs is not None:

pytype/tests/test_functions1.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,17 @@ def f(a, b=None):
10791079
partial_f(0)
10801080
""")
10811081

1082+
def test_functools_partial_with_starstar(self):
1083+
self.Check("""
1084+
import functools
1085+
def f(a: str, b: int, c: list):
1086+
pass
1087+
partial_f = functools.partial(f, "foo")
1088+
1089+
def test(**kwargs):
1090+
partial_f(42, **kwargs)
1091+
""")
1092+
10821093
def test_functools_partial_overloaded(self):
10831094
self.Check("""
10841095
import functools

0 commit comments

Comments
 (0)