Use same code for setting up cli/non-cli formatter
A method _create_formatter was introduced that is used for both the log_cli_formatter and the log_formatter. Consequences of this commit are: * Captured logs that are output for each failing test are formatted using the ColoredLevelFromatter. * The formatter used for writing to a file still uses the non-colored logging.Formatter class.
This commit is contained in:
parent
10ca84ffc5
commit
d4b85da8c7
|
@ -0,0 +1,2 @@
|
|||
Captured logs that are output for each failing test are formatted using the
|
||||
ColoredLevelFromatter.
|
|
@ -17,6 +17,11 @@ from _pytest.pathlib import Path
|
|||
|
||||
DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s"
|
||||
DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S"
|
||||
_ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m")
|
||||
|
||||
|
||||
def _remove_ansi_escape_sequences(text):
|
||||
return _ANSI_ESCAPE_SEQ.sub("", text)
|
||||
|
||||
|
||||
class ColoredLevelFormatter(logging.Formatter):
|
||||
|
@ -256,8 +261,8 @@ class LogCaptureFixture(object):
|
|||
|
||||
@property
|
||||
def text(self):
|
||||
"""Returns the log text."""
|
||||
return self.handler.stream.getvalue()
|
||||
"""Returns the formatted log text."""
|
||||
return _remove_ansi_escape_sequences(self.handler.stream.getvalue())
|
||||
|
||||
@property
|
||||
def records(self):
|
||||
|
@ -393,7 +398,7 @@ class LoggingPlugin(object):
|
|||
config.option.verbose = 1
|
||||
|
||||
self.print_logs = get_option_ini(config, "log_print")
|
||||
self.formatter = logging.Formatter(
|
||||
self.formatter = self._create_formatter(
|
||||
get_option_ini(config, "log_format"),
|
||||
get_option_ini(config, "log_date_format"),
|
||||
)
|
||||
|
@ -427,6 +432,19 @@ class LoggingPlugin(object):
|
|||
if self._log_cli_enabled():
|
||||
self._setup_cli_logging()
|
||||
|
||||
def _create_formatter(self, log_format, log_date_format):
|
||||
# color option doesn't exist if terminal plugin is disabled
|
||||
color = getattr(self._config.option, "color", "no")
|
||||
if color != "no" and ColoredLevelFormatter.LEVELNAME_FMT_REGEX.search(
|
||||
log_format
|
||||
):
|
||||
formatter = ColoredLevelFormatter(
|
||||
create_terminal_writer(self._config), log_format, log_date_format
|
||||
)
|
||||
else:
|
||||
formatter = logging.Formatter(log_format, log_date_format)
|
||||
return formatter
|
||||
|
||||
def _setup_cli_logging(self):
|
||||
config = self._config
|
||||
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
|
||||
|
@ -437,23 +455,12 @@ class LoggingPlugin(object):
|
|||
capture_manager = config.pluginmanager.get_plugin("capturemanager")
|
||||
# if capturemanager plugin is disabled, live logging still works.
|
||||
log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
|
||||
log_cli_format = get_option_ini(config, "log_cli_format", "log_format")
|
||||
log_cli_date_format = get_option_ini(
|
||||
config, "log_cli_date_format", "log_date_format"
|
||||
|
||||
log_cli_formatter = self._create_formatter(
|
||||
get_option_ini(config, "log_cli_format", "log_format"),
|
||||
get_option_ini(config, "log_cli_date_format", "log_date_format"),
|
||||
)
|
||||
if (
|
||||
config.option.color != "no"
|
||||
and ColoredLevelFormatter.LEVELNAME_FMT_REGEX.search(log_cli_format)
|
||||
):
|
||||
log_cli_formatter = ColoredLevelFormatter(
|
||||
create_terminal_writer(config),
|
||||
log_cli_format,
|
||||
datefmt=log_cli_date_format,
|
||||
)
|
||||
else:
|
||||
log_cli_formatter = logging.Formatter(
|
||||
log_cli_format, datefmt=log_cli_date_format
|
||||
)
|
||||
|
||||
log_cli_level = get_actual_log_level(config, "log_cli_level", "log_level")
|
||||
self.log_cli_handler = log_cli_handler
|
||||
self.live_logs_context = lambda: catching_logs(
|
||||
|
|
|
@ -1084,3 +1084,48 @@ def test_log_set_path(testdir):
|
|||
with open(os.path.join(report_dir_base, "test_second"), "r") as rfh:
|
||||
content = rfh.read()
|
||||
assert "message from test 2" in content
|
||||
|
||||
|
||||
def test_colored_captured_log(testdir):
|
||||
"""
|
||||
Test that the level names of captured log messages of a failing test are
|
||||
colored.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def test_foo():
|
||||
logger.info('text going to logger from call')
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("--log-level=INFO", "--color=yes")
|
||||
assert result.ret == 1
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*-- Captured log call --*",
|
||||
"\x1b[32mINFO \x1b[0m*text going to logger from call",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_colored_ansi_esc_caplogtext(testdir):
|
||||
"""
|
||||
Make sure that caplog.text does not contain ANSI escape sequences.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def test_foo(caplog):
|
||||
logger.info('text going to logger from call')
|
||||
assert '\x1b' not in caplog.text
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("--log-level=INFO", "--color=yes")
|
||||
assert result.ret == 0
|
||||
|
|
Loading…
Reference in New Issue