Skip to content

Commit 4cd4ca7

Browse files
committed
fix Argument.__repr__ crash when _action is not initialized
1 parent 602fc18 commit 4cd4ca7

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

changelog/13817.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a secondary `AttributeError` masking the original error when an option argument fails to initialize.

src/_pytest/config/argparsing.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,13 @@ def type(self) -> Any | None:
306306
return self._action.type
307307

308308
def __repr__(self) -> str:
309+
action = getattr(self, "_action", None)
310+
if action is None:
311+
return "Argument(<uninitialized>)"
309312
args: list[str] = []
310313
args += ["opts: " + repr(self.names())]
311314
args += ["dest: " + repr(self.dest)]
312-
if self._action.type:
315+
if action.type:
313316
args += ["type: " + repr(self.type)]
314317
args += ["default: " + repr(self.default)]
315318
return "Argument({})".format(", ".join(args))

testing/test_parseopt.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,28 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
341341
monkeypatch.setenv("COMP_POINT", str(len("pytest " + arg)))
342342
result = pytester.run("bash", str(script), arg)
343343
result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"])
344+
345+
346+
def test_argument_repr_uninitialized() -> None:
347+
"""Argument.__repr__ should not crash if _action is not set yet."""
348+
arg = parseopt.Argument.__new__(parseopt.Argument)
349+
result = repr(arg)
350+
assert result == "Argument(<uninitialized>)"
351+
352+
353+
def test_argument_repr_initialized(parser: parseopt.Parser) -> None:
354+
"""Argument.__repr__ works normally when properly initialized."""
355+
parser.addoption("--myflag", dest="myflag", help="test flag")
356+
option = parser._anonymous.options[-1]
357+
result = repr(option)
358+
assert "opts:" in result
359+
assert "dest:" in result
360+
361+
362+
def test_argument_repr_with_type(parser: parseopt.Parser) -> None:
363+
"""Argument.__repr__ includes type when set."""
364+
parser.addoption("--count", type=int, dest="count", help="count")
365+
option = parser._anonymous.options[-1]
366+
result = repr(option)
367+
assert "type:" in result
368+
assert "int" in result

0 commit comments

Comments
 (0)