Skip to content

Commit 3bcd78a

Browse files
committed
Add "verbosity_subtests" option and revamp tests
1 parent 8122383 commit 3bcd78a

File tree

6 files changed

+479
-531
lines changed

6 files changed

+479
-531
lines changed

doc/en/reference/reference.rst

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,8 +2066,26 @@ passed multiple times. The expected format is ``name=value``. For example::
20662066
[pytest]
20672067
verbosity_assertions = 2
20682068
2069-
Defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of
2070-
"auto" can be used to explicitly use the global verbosity level.
2069+
If not set, defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of
2070+
``"auto"`` can be used to explicitly use the global verbosity level.
2071+
2072+
2073+
.. confval:: verbosity_subtests
2074+
2075+
Set the verbosity level specifically for **passed** subtests.
2076+
2077+
.. code-block:: ini
2078+
2079+
[pytest]
2080+
verbosity_subtests = 1
2081+
2082+
A value of ``1`` or higher will show output for **passed** subtests (**failed** subtests are always reported).
2083+
Passed subtests output can be suppressed with the value ``0``, which overwrites the ``-v`` command-line option.
2084+
2085+
If not set, defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of
2086+
``"auto"`` can be used to explicitly use the global verbosity level.
2087+
2088+
See also: :ref:`subtests`.
20712089

20722090

20732091
.. confval:: verbosity_test_cases
@@ -2079,8 +2097,8 @@ passed multiple times. The expected format is ``name=value``. For example::
20792097
[pytest]
20802098
verbosity_test_cases = 2
20812099
2082-
Defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of
2083-
"auto" can be used to explicitly use the global verbosity level.
2100+
If not set, defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of
2101+
``"auto"`` can be used to explicitly use the global verbosity level.
20842102

20852103

20862104
.. confval:: xfail_strict

src/_pytest/config/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,9 @@ def getvalueorskip(self, name: str, path=None):
17721772
VERBOSITY_ASSERTIONS: Final = "assertions"
17731773
#: Verbosity type for test case execution (see :confval:`verbosity_test_cases`).
17741774
VERBOSITY_TEST_CASES: Final = "test_cases"
1775+
#: Verbosity type for failed subtests (see :confval:`verbosity_subtests`).
1776+
VERBOSITY_SUBTESTS: Final = "subtests"
1777+
17751778
_VERBOSITY_INI_DEFAULT: Final = "auto"
17761779

17771780
def get_verbosity(self, verbosity_type: str | None = None) -> int:

src/_pytest/subtests.py

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,13 @@
4444

4545

4646
def pytest_addoption(parser: Parser) -> None:
47-
group = parser.getgroup("subtests")
48-
group.addoption(
49-
"--no-subtests-shortletter",
50-
action="store_true",
51-
dest="no_subtests_shortletter",
52-
default=False,
53-
help="Disables subtest output 'dots' in non-verbose mode (EXPERIMENTAL)",
54-
)
55-
group.addoption(
56-
"--no-subtests-reports",
57-
action="store_true",
58-
dest="no_subtests_reports",
59-
default=False,
60-
help="Disables subtest output unless it's a failed subtest (EXPERIMENTAL)",
47+
Config._add_verbosity_ini(
48+
parser,
49+
Config.VERBOSITY_SUBTESTS,
50+
help=(
51+
"Specify verbosity level for subtests. "
52+
"Higher levels will generate output for passed subtests. Failed subtests are always reported."
53+
),
6154
)
6255

6356

@@ -372,14 +365,14 @@ def pytest_report_teststatus(
372365
if report.when != "call":
373366
return None
374367

368+
quiet = config.get_verbosity(Config.VERBOSITY_SUBTESTS) == 0
375369
if isinstance(report, SubtestReport):
376370
outcome = report.outcome
377371
description = report._sub_test_description()
378-
no_output = ("", "", "")
379372

380373
if hasattr(report, "wasxfail"):
381-
if config.option.no_subtests_reports and outcome != "skipped":
382-
return no_output
374+
if quiet:
375+
return "", "", ""
383376
elif outcome == "skipped":
384377
category = "xfailed"
385378
short = "y" # x letter is used for regular xfail, y for subtest xfail
@@ -394,26 +387,28 @@ def pytest_report_teststatus(
394387
# passed in case of xfail.
395388
# Let's pass this report to the next hook.
396389
return None
397-
short = "" if config.option.no_subtests_shortletter else short
398-
return f"subtests {category}", short, f"{description} {status}"
399-
400-
if config.option.no_subtests_reports and outcome != "failed":
401-
return no_output
402-
elif report.passed:
403-
short = "" if config.option.no_subtests_shortletter else ","
404-
return f"subtests {outcome}", short, f"{description} SUBPASSED"
405-
elif report.skipped:
406-
short = "" if config.option.no_subtests_shortletter else "-"
407-
return outcome, short, f"{description} SUBSKIPPED"
408-
elif outcome == "failed":
409-
short = "" if config.option.no_subtests_shortletter else "u"
410-
return outcome, short, f"{description} SUBFAILED"
390+
return category, short, f"{status}{description}"
391+
392+
if report.failed:
393+
return outcome, "u", f"SUBFAILED{description}"
394+
else:
395+
if report.passed:
396+
if quiet:
397+
return "", "", ""
398+
else:
399+
return f"subtests {outcome}", "u", f"SUBPASSED{description}"
400+
elif report.skipped:
401+
if quiet:
402+
return "", "", ""
403+
else:
404+
return outcome, "-", f"SUBSKIPPED{description}"
405+
411406
else:
412407
failed_subtests_count = config.stash[failed_subtests_key][report.nodeid]
413-
# Top-level test, fail it it contains failed subtests and it has passed.
408+
# Top-level test, fail if it contains failed subtests and it has passed.
414409
if report.passed and failed_subtests_count > 0:
415410
report.outcome = "failed"
416411
suffix = "s" if failed_subtests_count > 1 else ""
417-
report.longrepr = f"Contains {failed_subtests_count} failed subtest{suffix}"
412+
report.longrepr = f"contains {failed_subtests_count} failed subtest{suffix}"
418413

419414
return None

src/_pytest/terminal.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,9 +1527,13 @@ def _get_line_with_reprcrash_message(
15271527
line = f"{word} {node}"
15281528
line_width = wcswidth(line)
15291529

1530+
msg: str | None
15301531
try:
1531-
# Type ignored intentionally -- possible AttributeError expected.
1532-
msg = rep.longrepr.reprcrash.message # type: ignore[union-attr]
1532+
if isinstance(rep.longrepr, str):
1533+
msg = rep.longrepr
1534+
else:
1535+
# Type ignored intentionally -- possible AttributeError expected.
1536+
msg = rep.longrepr.reprcrash.message # type: ignore[union-attr]
15331537
except AttributeError:
15341538
pass
15351539
else:

src/pytest/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
from _pytest.runner import CallInfo
7272
from _pytest.stash import Stash
7373
from _pytest.stash import StashKey
74+
from _pytest.subtests import SubtestReport
7475
from _pytest.subtests import Subtests
7576
from _pytest.terminal import TerminalReporter
7677
from _pytest.terminal import TestShortLogReport
@@ -149,6 +150,7 @@
149150
"Session",
150151
"Stash",
151152
"StashKey",
153+
"SubtestReport",
152154
"Subtests",
153155
"TempPathFactory",
154156
"TempdirFactory",

0 commit comments

Comments
 (0)