Skip to content

Commit 8e857f4

Browse files
RonnyPfannschmidtpatchback[bot]
authored andcommitted
Merge pull request #14125 from RonnyPfannschmidt/fix-719-parametrize-trailing-comma
fix(parametrize): handle trailing comma in string argnames (cherry picked from commit 5f59a74)
1 parent 72ae54c commit 8e857f4

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

changelog/719.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed :ref:`@pytest.mark.parametrize <pytest.mark.parametrize ref>` not unpacking single-element tuple values when using a string argnames with a trailing comma (e.g., ``"arg,"``).
2+
3+
The trailing comma form now correctly behaves like the tuple form ``("arg",)``, treating argvalues as a list of tuples to unpack.

src/_pytest/mark/structures.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,12 @@ def _parse_parametrize_args(
169169
**kwargs,
170170
) -> tuple[Sequence[str], bool]:
171171
if isinstance(argnames, str):
172+
# A trailing comma indicates tuple-style: "arg," is equivalent to ("arg",)
173+
# In this case, argvalues should be a list of tuples, not wrapped values.
174+
# See https://github.com/pytest-dev/pytest/issues/719
175+
has_trailing_comma = argnames.rstrip().endswith(",")
172176
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
173-
force_tuple = len(argnames) == 1
177+
force_tuple = len(argnames) == 1 and not has_trailing_comma
174178
else:
175179
force_tuple = False
176180
return argnames, force_tuple

testing/python/metafunc.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,46 @@ def func(arg1, arg2="qwe"):
7676
assert metafunc.function is func
7777
assert metafunc.cls is None
7878

79+
def test_parametrize_single_arg_trailing_comma(self) -> None:
80+
"""Test that trailing comma in string argnames behaves like tuple argnames.
81+
82+
Regression test for https://github.com/pytest-dev/pytest/issues/719
83+
84+
When using a single argument with:
85+
- "arg" (string, no comma): argvalues is a list of values
86+
- "arg," (string, trailing comma): argvalues is a list of tuples (like tuple form)
87+
- ("arg",) (tuple): argvalues is a list of tuples
88+
"""
89+
90+
def func(arg):
91+
pass # pragma: no cover
92+
93+
scenarios = [("a",), ("b",)]
94+
95+
# Tuple form: argvalues are tuples, unpacked to get the value
96+
metafunc = self.Metafunc(func)
97+
metafunc.parametrize(("arg",), scenarios)
98+
assert metafunc._calls[0].params == {"arg": "a"}
99+
assert metafunc._calls[1].params == {"arg": "b"}
100+
101+
# String with trailing comma: should behave like tuple form
102+
metafunc = self.Metafunc(func)
103+
metafunc.parametrize("arg,", scenarios)
104+
assert metafunc._calls[0].params == {"arg": "a"}
105+
assert metafunc._calls[1].params == {"arg": "b"}
106+
107+
# String without comma: argvalues are values directly (tuples are passed as-is)
108+
metafunc = self.Metafunc(func)
109+
metafunc.parametrize("arg", scenarios)
110+
assert metafunc._calls[0].params == {"arg": ("a",)}
111+
assert metafunc._calls[1].params == {"arg": ("b",)}
112+
113+
# String without comma with plain values: values are used directly
114+
metafunc = self.Metafunc(func)
115+
metafunc.parametrize("arg", ["a", "b"])
116+
assert metafunc._calls[0].params == {"arg": "a"}
117+
assert metafunc._calls[1].params == {"arg": "b"}
118+
79119
def test_parametrize_error(self) -> None:
80120
def func(x, y):
81121
pass
@@ -1255,6 +1295,41 @@ def test_hello(arg1, arg2):
12551295
["*(1, 4)*", "*(1, 5)*", "*(2, 4)*", "*(2, 5)*", "*4 failed*"]
12561296
)
12571297

1298+
def test_parametrize_single_arg_trailing_comma_functional(
1299+
self, pytester: Pytester
1300+
) -> None:
1301+
"""Test that trailing comma in string argnames behaves like tuple argnames.
1302+
1303+
Regression test for https://github.com/pytest-dev/pytest/issues/719
1304+
"""
1305+
pytester.makepyfile(
1306+
"""
1307+
import pytest
1308+
1309+
scenarios = [('a',), ('b',)]
1310+
1311+
@pytest.mark.parametrize(("arg",), scenarios)
1312+
def test_tuple_form(arg):
1313+
# Tuple argnames: values are unpacked from tuples
1314+
assert arg in ('a', 'b')
1315+
assert isinstance(arg, str)
1316+
1317+
@pytest.mark.parametrize("arg,", scenarios)
1318+
def test_string_trailing_comma(arg):
1319+
# String with trailing comma: should behave like tuple form
1320+
assert arg in ('a', 'b')
1321+
assert isinstance(arg, str)
1322+
1323+
@pytest.mark.parametrize("arg", scenarios)
1324+
def test_string_no_comma(arg):
1325+
# String without comma: tuples are passed as-is
1326+
assert arg in (('a',), ('b',))
1327+
assert isinstance(arg, tuple)
1328+
"""
1329+
)
1330+
result = pytester.runpytest("-v")
1331+
result.assert_outcomes(passed=6)
1332+
12581333
def test_parametrize_and_inner_getfixturevalue(self, pytester: Pytester) -> None:
12591334
p = pytester.makepyfile(
12601335
"""

0 commit comments

Comments
 (0)