diff --git a/changelog/11387.feature.rst b/changelog/11387.feature.rst index 9cb4dd40e..bfcf25575 100644 --- a/changelog/11387.feature.rst +++ b/changelog/11387.feature.rst @@ -2,4 +2,4 @@ Added the new :confval:`verbosity_assertions` configuration option for fine-grai See :ref:`Fine-grained verbosity ` for more details. -For plugin authors, :attr:`config.output_verbosity ` can be used to retrieve the verbosity level for a specific :class:`pytest.VerbosityType`. +For plugin authors, :attr:`config.output_verbosity ` can be used to retrieve the verbosity level for a specific verbosity type. diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 81940d865..180a70eed 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -961,15 +961,6 @@ OptionGroup .. autoclass:: pytest.OptionGroup() :members: -OutputVerbosity -~~~~~~~~~~~~~~~ - -.. autoclass:: pytest.OutputVerbosity() - :members: - -.. autoclass:: pytest.VerbosityType() - :members: - PytestPluginManager ~~~~~~~~~~~~~~~~~~~ diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 8b442463c..6f729179a 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -12,8 +12,6 @@ from _pytest.assertion import util from _pytest.assertion.rewrite import assertstate_key from _pytest.config import Config from _pytest.config import hookimpl -from _pytest.config import OutputVerbosity -from _pytest.config import VerbosityType from _pytest.config.argparsing import Parser from _pytest.nodes import Item @@ -44,9 +42,9 @@ def pytest_addoption(parser: Parser) -> None: help="Enables the pytest_assertion_pass hook. " "Make sure to delete any previously generated pyc cache files.", ) - OutputVerbosity._add_ini( + Config._add_ini( parser, - VerbosityType.Assertions, + Config.VERBOSITY_ASSERTIONS, help=( "Specify a verbosity level for assertions, overriding the main level. " "Higher levels will provide more detailed explanation when an assertion fails." diff --git a/src/_pytest/assertion/truncate.py b/src/_pytest/assertion/truncate.py index d472e239a..b96ce9956 100644 --- a/src/_pytest/assertion/truncate.py +++ b/src/_pytest/assertion/truncate.py @@ -7,7 +7,7 @@ from typing import List from typing import Optional from _pytest.assertion import util -from _pytest.config import VerbosityType +from _pytest.config import Config from _pytest.nodes import Item DEFAULT_MAX_LINES = 8 @@ -26,7 +26,7 @@ def truncate_if_required( def _should_truncate_item(item: Item) -> bool: """Whether or not this test item is eligible for truncation.""" - verbose = item.config.output_verbosity.get(VerbosityType.Assertions) + verbose = item.config.get_verbosity(Config.VERBOSITY_ASSERTIONS) return verbose < 2 and not util.running_on_ci() diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 147875eec..65abe8d23 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -20,7 +20,6 @@ from _pytest._io.saferepr import _pformat_dispatch from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr_unlimited from _pytest.config import Config -from _pytest.config import VerbosityType # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -169,7 +168,7 @@ def assertrepr_compare( config, op: str, left: Any, right: Any, use_ascii: bool = False ) -> Optional[List[str]]: """Return specialised explanations for some operators/operands.""" - verbose = config.output_verbosity.get(VerbosityType.Assertions) + verbose = config.get_verbosity(Config.VERBOSITY_ASSERTIONS) # Strings which normalize equal are often hard to distinguish when printed; use ascii() to make this easier. # See issue #3246. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index f2c96652a..52bffe393 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -13,7 +13,6 @@ import shlex import sys import types import warnings -from enum import Enum from functools import lru_cache from pathlib import Path from textwrap import dedent @@ -23,6 +22,7 @@ from typing import Any from typing import Callable from typing import cast from typing import Dict +from typing import Final from typing import final from typing import Generator from typing import IO @@ -1022,12 +1022,6 @@ class Config: self.args_source = Config.ArgsSource.ARGS self.args: List[str] = [] - self.output_verbosity = OutputVerbosity(self) - """Access to output verbosity configuration. - - :type: OutputVerbosity - """ - if TYPE_CHECKING: from _pytest.cacheprovider import Cache @@ -1640,6 +1634,66 @@ class Config: """Deprecated, use getoption(skip=True) instead.""" return self.getoption(name, skip=True) + #: Verbosity for failed assertions (see :confval:`verbosity_assertions`). + VERBOSITY_ASSERTIONS: Final = "assertions" + _KNOWN_VERBOSITY_TYPES: Final = {VERBOSITY_ASSERTIONS} + _VERBOSITY_INI_DEFAULT = "auto" + + def get_verbosity(self, verbosity_type: Optional[str] = None) -> int: + r"""Access to fine-grained verbosity levels. + + .. code-block:: ini + + # content of pytest.ini + [pytest] + verbosity_assertions = 2 + + .. code-block:: console + + pytest -v + + .. code-block:: python + + print(config.get_verbosity()) # 1 + print(config.get_verbosity(Config.VERBOSITY_ASSERTIONS)) # 2 + """ + global_level = self.option.verbose + assert isinstance(global_level, int) + if ( + verbosity_type is None + or verbosity_type not in Config._KNOWN_VERBOSITY_TYPES + ): + return global_level + + level = self.getini(Config._ini_name(verbosity_type)) + + if level == Config._VERBOSITY_INI_DEFAULT: + return global_level + + return int(level) + + @staticmethod + def _ini_name(verbosity_type: str) -> str: + return f"verbosity_{verbosity_type}" + + @staticmethod + def _add_ini(parser: "Parser", verbosity_type: str, help: str) -> None: + """Add a output verbosity configuration option for the given output type. + + :param parser: Parser for command line arguments and ini-file values. + :param verbosity_type: Fine-grained verbosity category. + :param help: Description of the output this type controls. + + The value should be retrieved via a call to + :py:func:`config.get_verbosity(type) `. + """ + parser.addini( + Config._ini_name(verbosity_type), + help=help, + type="string", + default=Config._VERBOSITY_INI_DEFAULT, + ) + def _warn_about_missing_assertion(self, mode: str) -> None: if not _assertion_supported(): if mode == "plain": @@ -1669,80 +1723,6 @@ class Config: ) -class VerbosityType(Enum): - """Fine-grained verbosity categories.""" - - #: Application wide, controlled by ``-v``/``-q``. - Global = "global" - - #: Verbosity for failed assertions (see :confval:`verbosity_assertions`). - Assertions = "assertions" - - -class OutputVerbosity: - r"""Access to fine-grained verbosity levels. - - Access via :attr:`config.output_verbosity `. - - .. code-block:: ini - - # content of pytest.ini - [pytest] - verbosity_assertions = 2 - - .. code-block:: console - - pytest -v - - .. code-block:: python - - print(config.output_verbosity.get()) # 1 - print(config.output_verbosity.get(VerbosityType.Assertions)) # 2 - """ - - DEFAULT = "auto" - - def __init__(self, config: Config) -> None: - self._config = config - - def get(self, verbosity_type: VerbosityType = VerbosityType.Global) -> int: - """Return verbosity level for the given output type. - - :param verbosity_type: Fine-grained verbosity category. - - If the level is not configured, the value of ``config.option.verbose``. - """ - level = self._config.getini(OutputVerbosity._ini_name(verbosity_type)) - - if level == OutputVerbosity.DEFAULT: - assert isinstance(self._config.option.verbose, int) - return self._config.option.verbose - - return int(level) - - @staticmethod - def _ini_name(verbosity_type: VerbosityType) -> str: - return f"verbosity_{verbosity_type.value}" - - @staticmethod - def _add_ini(parser: "Parser", verbosity_type: VerbosityType, help: str) -> None: - """Add a output verbosity configuration option for the given output type. - - :param parser: Parser for command line arguments and ini-file values. - :param verbosity_type: Fine-grained verbosity category. - :param help: Description of the output this type controls. - - The value should be retrieved via a call to - :py:func:`config.output_verbosity.get(type) `. - """ - parser.addini( - OutputVerbosity._ini_name(verbosity_type), - help=help, - type="string", - default=OutputVerbosity.DEFAULT, - ) - - def _assertion_supported() -> bool: try: assert False diff --git a/src/pytest/__init__.py b/src/pytest/__init__.py index f0e0cff8c..0aa496a2f 100644 --- a/src/pytest/__init__.py +++ b/src/pytest/__init__.py @@ -15,10 +15,8 @@ from _pytest.config import ExitCode from _pytest.config import hookimpl from _pytest.config import hookspec from _pytest.config import main -from _pytest.config import OutputVerbosity from _pytest.config import PytestPluginManager from _pytest.config import UsageError -from _pytest.config import VerbosityType from _pytest.config.argparsing import OptionGroup from _pytest.config.argparsing import Parser from _pytest.debugging import pytestPDB as __pytestPDB @@ -128,7 +126,6 @@ __all__ = [ "Module", "MonkeyPatch", "OptionGroup", - "OutputVerbosity", "Package", "param", "Parser", @@ -164,7 +161,6 @@ __all__ = [ "TestReport", "TestShortLogReport", "UsageError", - "VerbosityType", "WarningsRecorder", "warns", "xfail", diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 4df33bd32..43f4d39cc 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -13,7 +13,7 @@ import pytest from _pytest import outcomes from _pytest.assertion import truncate from _pytest.assertion import util -from _pytest.config import VerbosityType +from _pytest.config import Config as _Config from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester @@ -23,26 +23,20 @@ def mock_config(verbose: int = 0, assertion_override: Optional[int] = None): def _highlight(self, source, lexer): return source - class OutputVerbosity: - @property - def verbose(self) -> int: - return verbose + class Config: + def get_terminal_writer(self): + return TerminalWriter() - def get(self, verbosity_type: VerbosityType = VerbosityType.Global) -> int: - if verbosity_type == VerbosityType.Assertions: + def get_verbosity(self, verbosity_type: Optional[str] = None) -> int: + if verbosity_type is None: + return verbose + if verbosity_type == _Config.VERBOSITY_ASSERTIONS: if assertion_override is not None: return assertion_override return verbose raise KeyError(f"Not mocked out: {verbosity_type}") - class Config: - def __init__(self) -> None: - self.output_verbosity = OutputVerbosity() - - def get_terminal_writer(self): - return TerminalWriter() - return Config() @@ -53,13 +47,13 @@ class TestMockConfig: def test_verbose_exposes_value(self): config = mock_config(verbose=TestMockConfig.SOME_VERBOSITY_LEVEL) - assert config.output_verbosity.verbose == TestMockConfig.SOME_VERBOSITY_LEVEL + assert config.get_verbosity() == TestMockConfig.SOME_VERBOSITY_LEVEL def test_get_assertion_override_not_set_verbose_value(self): config = mock_config(verbose=TestMockConfig.SOME_VERBOSITY_LEVEL) assert ( - config.output_verbosity.get(VerbosityType.Assertions) + config.get_verbosity(_Config.VERBOSITY_ASSERTIONS) == TestMockConfig.SOME_VERBOSITY_LEVEL ) @@ -70,7 +64,7 @@ class TestMockConfig: ) assert ( - config.output_verbosity.get(VerbosityType.Assertions) + config.get_verbosity(_Config.VERBOSITY_ASSERTIONS) == TestMockConfig.SOME_OTHER_VERBOSITY_LEVEL ) @@ -78,7 +72,7 @@ class TestMockConfig: config = mock_config(verbose=TestMockConfig.SOME_VERBOSITY_LEVEL) with pytest.raises(KeyError): - config.output_verbosity.get(VerbosityType.Global) + config.get_verbosity("--- NOT A VERBOSITY LEVEL ---") class TestImportHookInstallation: diff --git a/testing/test_config.py b/testing/test_config.py index e4bec2c51..cf3b56753 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -20,9 +20,7 @@ from _pytest.config import _strtobool from _pytest.config import Config from _pytest.config import ConftestImportFailure from _pytest.config import ExitCode -from _pytest.config import OutputVerbosity from _pytest.config import parse_warning_filter -from _pytest.config import VerbosityType from _pytest.config.argparsing import Parser from _pytest.config.exceptions import UsageError from _pytest.config.findpaths import determine_setup @@ -2186,14 +2184,14 @@ class TestDebugOptions: ) -class TestOutputVerbosity: - SOME_OUTPUT_TYPE = VerbosityType.Assertions +class TestVerbosity: + SOME_OUTPUT_TYPE = Config.VERBOSITY_ASSERTIONS SOME_OUTPUT_VERBOSITY_LEVEL = 5 class VerbosityIni: def pytest_addoption(self, parser: Parser) -> None: - OutputVerbosity._add_ini( - parser, TestOutputVerbosity.SOME_OUTPUT_TYPE, help="some help text" + Config._add_ini( + parser, TestVerbosity.SOME_OUTPUT_TYPE, help="some help text" ) def test_level_matches_verbose_when_not_specified( @@ -2208,34 +2206,34 @@ class TestOutputVerbosity: ), encoding="utf-8", ) - pytester.plugins = [TestOutputVerbosity.VerbosityIni()] + pytester.plugins = [TestVerbosity.VerbosityIni()] config = pytester.parseconfig(tmp_path) assert ( - config.output_verbosity.get(TestOutputVerbosity.SOME_OUTPUT_TYPE) + config.get_verbosity(TestVerbosity.SOME_OUTPUT_TYPE) == config.option.verbose ) def test_level_matches_specified_override( self, pytester: Pytester, tmp_path: Path ) -> None: - setting_name = f"verbosity_{TestOutputVerbosity.SOME_OUTPUT_TYPE.value}" + setting_name = f"verbosity_{TestVerbosity.SOME_OUTPUT_TYPE}" tmp_path.joinpath("pytest.ini").write_text( textwrap.dedent( f"""\ [pytest] addopts = --verbose - {setting_name} = {TestOutputVerbosity.SOME_OUTPUT_VERBOSITY_LEVEL} + {setting_name} = {TestVerbosity.SOME_OUTPUT_VERBOSITY_LEVEL} """ ), encoding="utf-8", ) - pytester.plugins = [TestOutputVerbosity.VerbosityIni()] + pytester.plugins = [TestVerbosity.VerbosityIni()] config = pytester.parseconfig(tmp_path) assert ( - config.output_verbosity.get(TestOutputVerbosity.SOME_OUTPUT_TYPE) - == TestOutputVerbosity.SOME_OUTPUT_VERBOSITY_LEVEL + config.get_verbosity(TestVerbosity.SOME_OUTPUT_TYPE) + == TestVerbosity.SOME_OUTPUT_VERBOSITY_LEVEL )