Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7431] Add --suppress-logger CLI option #10371

Merged
merged 12 commits into from
Oct 23, 2022
1 change: 1 addition & 0 deletions changelog/7431.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``--log-disable`` CLI option added to disable individual loggers.
7 changes: 7 additions & 0 deletions doc/en/how-to/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ These options can also be customized through ``pytest.ini`` file:
log_format = %(asctime)s %(levelname)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S

Specific loggers can be disabled via ``--log-disable={logger_name}``.
This argument can be passed multiple times:

.. code-block:: bash

pytest --log-disable=main --log-disable=testing

Further it is possible to disable reporting of captured content (stdout,
stderr and logs) on failed tests completely with:

Expand Down
16 changes: 16 additions & 0 deletions src/_pytest/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,13 @@ def add_option_ini(option, dest, default=None, type=None, **kwargs):
default=None,
help="Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.",
)
group.addoption(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the new option just a command line option and not an ini option? I guess that it can't be specified in e.g. pytest.ini, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to use addopts to set that for every invocation if one chooses, is that what you are asking?

Copy link
Contributor

@twmr twmr Oct 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, kind of. In the logging plugin we have the add_option_ini function which is used for most parameters of the logging plugin. I think that whenever we don't use this function, we should explain in a comment why we don't use it. Even better would be an explanation in the docstring of pytest_addoption in logging.py that explains if new options should be added as ini options, as cli options or as both.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still time to change this, as 7.2.0 was not released yet. 😁

"--log-disable",
action="append",
default=[],
dest="logger_disable",
help="Disable a logger by name. Can be passed multipe times.",
)


_HandlerType = TypeVar("_HandlerType", bound=logging.Handler)
Expand Down Expand Up @@ -594,6 +601,15 @@ def __init__(self, config: Config) -> None:
get_option_ini(config, "log_auto_indent"),
)
self.log_cli_handler.setFormatter(log_cli_formatter)
self._disable_loggers(loggers_to_disable=config.option.logger_disable)

def _disable_loggers(self, loggers_to_disable: List[str]) -> None:
if not loggers_to_disable:
return

for name in loggers_to_disable:
logger = logging.getLogger(name)
logger.disabled = True

def _create_formatter(self, log_format, log_date_format, auto_indent):
# Color option doesn't exist if terminal plugin is disabled.
Expand Down
69 changes: 69 additions & 0 deletions testing/logging/test_reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,3 +1165,72 @@ def test_log_file_cli_subdirectories_are_successfully_created(
result = pytester.runpytest("--log-file=foo/bar/logf.log")
assert "logf.log" in os.listdir(expected)
assert result.ret == ExitCode.OK


def test_disable_loggers(testdir):
testdir.makepyfile(
"""
import logging
import os
disabled_log = logging.getLogger('disabled')
test_log = logging.getLogger('test')
def test_logger_propagation(caplog):
with caplog.at_level(logging.DEBUG):
disabled_log.warning("no log; no stderr")
test_log.debug("Visible text!")
assert caplog.record_tuples == [('test', 10, 'Visible text!')]
"""
)
result = testdir.runpytest("--log-disable=disabled", "-s")
assert result.ret == ExitCode.OK
assert not result.stderr.lines


def test_disable_loggers_does_not_propagate(testdir):
testdir.makepyfile(
"""
import logging
import os

parent_logger = logging.getLogger("parent")
child_logger = parent_logger.getChild("child")

def test_logger_propagation_to_parent(caplog):
with caplog.at_level(logging.DEBUG):
parent_logger.warning("some parent logger message")
child_logger.warning("some child logger message")
assert len(caplog.record_tuples) == 1
assert caplog.record_tuples[0][0] == "parent"
assert caplog.record_tuples[0][2] == "some parent logger message"
"""
)

result = testdir.runpytest("--log-disable=parent.child", "-s")
assert result.ret == ExitCode.OK
assert not result.stderr.lines


def test_log_disabling_works_with_log_cli(testdir):
testdir.makepyfile(
"""
import logging
disabled_log = logging.getLogger('disabled')
test_log = logging.getLogger('test')

def test_log_cli_works(caplog):
test_log.info("Visible text!")
disabled_log.warning("This string will be suppressed.")
"""
)
result = testdir.runpytest(
"--log-cli-level=DEBUG",
"--log-disable=disabled",
)
assert result.ret == ExitCode.OK
result.stdout.fnmatch_lines(
"INFO test:test_log_disabling_works_with_log_cli.py:6 Visible text!"
)
result.stdout.no_fnmatch_line(
"WARNING disabled:test_log_disabling_works_with_log_cli.py:7 This string will be suppressed."
)
assert not result.stderr.lines