Skip to content

Commit f631c40

Browse files
committed
Fix positional-only parameters order
1 parent dbafef5 commit f631c40

File tree

5 files changed

+70
-7
lines changed

5 files changed

+70
-7
lines changed

e2e_projects/my_lib/src/my_lib/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ def some_func(a, b: str = "111", c: Callable[[str], int] | None = None) -> int |
104104
return c(b)
105105
return None
106106

107-
def func_with_star_clone(a, *, b, **kwargs): pass # pragma: no mutate
108-
def func_with_star(a, *, b, **kwargs):
109-
return a + b + len(kwargs)
107+
def func_with_star_clone(a, /, b, *, c, **kwargs): pass # pragma: no mutate
108+
def func_with_star(a, /, b, *, c, **kwargs):
109+
return a + b + c + len(kwargs)
110110

111111
def func_with_arbitrary_args_clone(*args, **kwargs): pass # pragma: no mutate
112112
def func_with_arbitrary_args(*args, **kwargs):

e2e_projects/my_lib/tests/test_my_lib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def test_that_signatures_are_preserved():
6161

6262
def test_signature_functions_are_callable():
6363
assert some_func(True, c=lambda s: int(s), b="222") == 222
64-
assert func_with_star(1, b=2, x='x', y='y', z='z') == 6
64+
assert func_with_star(1, b=2, c=3, x='x', y='y', z='z') == 9
6565
assert func_with_arbitrary_args('a', 'b', foo=123, bar=456) == 4
6666

6767
def test_signature_is_coroutine():

src/mutmut/file_mutation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,10 @@ def function_trampoline_arrangement(function: cst.FunctionDef, mutants: Iterable
258258

259259
def create_trampoline_wrapper(function: cst.FunctionDef, mangled_name: str, class_name: str | None) -> cst.FunctionDef:
260260
args: list[cst.Element | cst.StarredElement] = []
261-
for param in function.params.params:
262-
args.append(cst.Element(param.name))
263261
for pos_only_param in function.params.posonly_params:
264262
args.append(cst.Element(pos_only_param.name))
263+
for param in function.params.params:
264+
args.append(cst.Element(param.name))
265265
if isinstance(function.params.star_arg, cst.Param):
266266
args.append(cst.StarredElement(function.params.star_arg.name))
267267

tests/e2e/test_e2e_my_lib.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def test_my_lib_result_snapshot():
7777
"my_lib.x_some_func__mutmut_3": 1,
7878
"my_lib.x_func_with_star__mutmut_1": 1,
7979
"my_lib.x_func_with_star__mutmut_2": 1,
80+
"my_lib.x_func_with_star__mutmut_3": 1,
8081
"my_lib.x_func_with_arbitrary_args__mutmut_1": 1,
8182
}
8283
}

tests/test_mutation regression.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,68 @@
11
from inline_snapshot import snapshot
2+
import libcst as cst
23

3-
from mutmut.file_mutation import mutate_file_contents
4+
from mutmut.file_mutation import mutate_file_contents, create_trampoline_wrapper
5+
6+
7+
def _get_trampoline_wrapper(
8+
source: str, mangled_name: str, class_name: str | None = None
9+
) -> str:
10+
function = cst.ensure_type(cst.parse_statement(source), cst.FunctionDef)
11+
trampoline = create_trampoline_wrapper(
12+
function, mangled_name, class_name=class_name
13+
)
14+
return cst.Module([trampoline]).code.strip()
15+
16+
17+
def test_create_trampoline_wrapper_async_method():
18+
source = "async def foo(a: str, b, *args, **kwargs) -> dict[str, int]: pass"
19+
20+
assert _get_trampoline_wrapper(source, "x_foo__mutmut") == snapshot("""\
21+
async def foo(a: str, b, *args, **kwargs) -> dict[str, int]:
22+
args = [a, b, *args]
23+
kwargs = {**kwargs}
24+
return await _mutmut_trampoline(x_foo__mutmut_orig, x_foo__mutmut_mutants, args, kwargs, None)\
25+
""")
26+
27+
28+
def test_create_trampoline_wrapper_async_generator():
29+
source = """
30+
async def foo():
31+
for i in range(10):
32+
yield i
33+
"""
34+
35+
assert _get_trampoline_wrapper(source, "x_foo__mutmut") == snapshot("""\
36+
async def foo():
37+
args = []
38+
kwargs = {}
39+
async for i in _mutmut_trampoline(x_foo__mutmut_orig, x_foo__mutmut_mutants, args, kwargs, None):
40+
yield i\
41+
""")
42+
43+
44+
def test_create_trampoline_wrapper_with_positionals_only_args():
45+
source = "def foo(p1, p2=None, /, p_or_kw=None, *, kw): pass"
46+
47+
assert _get_trampoline_wrapper(source, "x_foo__mutmut") == snapshot("""\
48+
def foo(p1, p2=None, /, p_or_kw=None, *, kw):
49+
args = [p1, p2, p_or_kw]
50+
kwargs = {'kw': kw}
51+
return _mutmut_trampoline(x_foo__mutmut_orig, x_foo__mutmut_mutants, args, kwargs, None)\
52+
""")
53+
54+
55+
def test_create_trampoline_wrapper_for_class_method():
56+
source = "def foo(self, a, b): pass"
57+
58+
assert _get_trampoline_wrapper(
59+
source, "x_foo__mutmut", class_name="Person"
60+
) == snapshot("""\
61+
def foo(self, a, b):
62+
args = [a, b]
63+
kwargs = {}
64+
return _mutmut_trampoline(object.__getattribute__(self, 'x_foo__mutmut_orig'), object.__getattribute__(self, 'x_foo__mutmut_mutants'), args, kwargs, self)\
65+
""")
466

567

668
def test_module_mutation():

0 commit comments

Comments
 (0)