[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot] 2024-04-13 00:00:18 +00:00
parent 72ad6dc953
commit f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions

View file

@ -1,17 +1,19 @@
# mypy: allow-untyped-defs
"""Access and control log capturing."""
from __future__ import annotations
import io
import logging
import os
import re
from contextlib import contextmanager
from contextlib import nullcontext
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import io
from io import StringIO
import logging
from logging import LogRecord
import os
from pathlib import Path
import re
from types import TracebackType
from typing import AbstractSet
from typing import Dict
@ -50,15 +52,15 @@ if TYPE_CHECKING:
else:
logging_StreamHandler = logging.StreamHandler
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")
caplog_handler_key = StashKey["LogCaptureHandler"]()
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')
caplog_handler_key = StashKey['LogCaptureHandler']()
caplog_records_key = StashKey[Dict[str, List[logging.LogRecord]]]()
def _remove_ansi_escape_sequences(text: str) -> str:
return _ANSI_ESCAPE_SEQ.sub("", text)
return _ANSI_ESCAPE_SEQ.sub('', text)
class DatetimeFormatter(logging.Formatter):
@ -67,8 +69,8 @@ class DatetimeFormatter(logging.Formatter):
:func:`time.strftime` in case of microseconds in format string.
"""
def formatTime(self, record: LogRecord, datefmt: Optional[str] = None) -> str:
if datefmt and "%f" in datefmt:
def formatTime(self, record: LogRecord, datefmt: str | None = None) -> str:
if datefmt and '%f' in datefmt:
ct = self.converter(record.created)
tz = timezone(timedelta(seconds=ct.tm_gmtoff), ct.tm_zone)
# Construct `datetime.datetime` object from `struct_time`
@ -85,21 +87,21 @@ class ColoredLevelFormatter(DatetimeFormatter):
log format passed to __init__."""
LOGLEVEL_COLOROPTS: Mapping[int, AbstractSet[str]] = {
logging.CRITICAL: {"red"},
logging.ERROR: {"red", "bold"},
logging.WARNING: {"yellow"},
logging.WARN: {"yellow"},
logging.INFO: {"green"},
logging.DEBUG: {"purple"},
logging.CRITICAL: {'red'},
logging.ERROR: {'red', 'bold'},
logging.WARNING: {'yellow'},
logging.WARN: {'yellow'},
logging.INFO: {'green'},
logging.DEBUG: {'purple'},
logging.NOTSET: set(),
}
LEVELNAME_FMT_REGEX = re.compile(r"%\(levelname\)([+-.]?\d*(?:\.\d+)?s)")
LEVELNAME_FMT_REGEX = re.compile(r'%\(levelname\)([+-.]?\d*(?:\.\d+)?s)')
def __init__(self, terminalwriter: TerminalWriter, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._terminalwriter = terminalwriter
self._original_fmt = self._style._fmt
self._level_to_fmt_mapping: Dict[int, str] = {}
self._level_to_fmt_mapping: dict[int, str] = {}
for level, color_opts in self.LOGLEVEL_COLOROPTS.items():
self.add_color_level(level, *color_opts)
@ -123,15 +125,15 @@ class ColoredLevelFormatter(DatetimeFormatter):
return
levelname_fmt = levelname_fmt_match.group()
formatted_levelname = levelname_fmt % {"levelname": logging.getLevelName(level)}
formatted_levelname = levelname_fmt % {'levelname': logging.getLevelName(level)}
# add ANSI escape sequences around the formatted levelname
color_kwargs = {name: True for name in color_opts}
colorized_formatted_levelname = self._terminalwriter.markup(
formatted_levelname, **color_kwargs
formatted_levelname, **color_kwargs,
)
self._level_to_fmt_mapping[level] = self.LEVELNAME_FMT_REGEX.sub(
colorized_formatted_levelname, self._fmt
colorized_formatted_levelname, self._fmt,
)
def format(self, record: logging.LogRecord) -> str:
@ -147,12 +149,12 @@ class PercentStyleMultiline(logging.PercentStyle):
formats the message as if each line were logged separately.
"""
def __init__(self, fmt: str, auto_indent: Union[int, str, bool, None]) -> None:
def __init__(self, fmt: str, auto_indent: int | str | bool | None) -> None:
super().__init__(fmt)
self._auto_indent = self._get_auto_indent(auto_indent)
@staticmethod
def _get_auto_indent(auto_indent_option: Union[int, str, bool, None]) -> int:
def _get_auto_indent(auto_indent_option: int | str | bool | None) -> int:
"""Determine the current auto indentation setting.
Specify auto indent behavior (on/off/fixed) by passing in
@ -206,8 +208,8 @@ class PercentStyleMultiline(logging.PercentStyle):
return 0
def format(self, record: logging.LogRecord) -> str:
if "\n" in record.message:
if hasattr(record, "auto_indent"):
if '\n' in record.message:
if hasattr(record, 'auto_indent'):
# Passed in from the "extra={}" kwarg on the call to logging.log().
auto_indent = self._get_auto_indent(record.auto_indent) # type: ignore[attr-defined]
else:
@ -215,17 +217,17 @@ class PercentStyleMultiline(logging.PercentStyle):
if auto_indent:
lines = record.message.splitlines()
formatted = self._fmt % {**record.__dict__, "message": lines[0]}
formatted = self._fmt % {**record.__dict__, 'message': lines[0]}
if auto_indent < 0:
indentation = _remove_ansi_escape_sequences(formatted).find(
lines[0]
lines[0],
)
else:
# Optimizes logging by allowing a fixed indentation.
indentation = auto_indent
lines[0] = formatted
return ("\n" + " " * indentation).join(lines)
return ('\n' + ' ' * indentation).join(lines)
return self._fmt % record.__dict__
@ -240,114 +242,114 @@ def get_option_ini(config: Config, *names: str):
def pytest_addoption(parser: Parser) -> None:
"""Add options to control log capturing."""
group = parser.getgroup("logging")
group = parser.getgroup('logging')
def add_option_ini(option, dest, default=None, type=None, **kwargs):
parser.addini(
dest, default=default, type=type, help="Default value for " + option
dest, default=default, type=type, help='Default value for ' + option,
)
group.addoption(option, dest=dest, **kwargs)
add_option_ini(
"--log-level",
dest="log_level",
'--log-level',
dest='log_level',
default=None,
metavar="LEVEL",
metavar='LEVEL',
help=(
"Level of messages to catch/display."
'Level of messages to catch/display.'
" Not set by default, so it depends on the root/parent log handler's"
' effective level, where it is "WARNING" by default.'
),
)
add_option_ini(
"--log-format",
dest="log_format",
'--log-format',
dest='log_format',
default=DEFAULT_LOG_FORMAT,
help="Log format used by the logging module",
help='Log format used by the logging module',
)
add_option_ini(
"--log-date-format",
dest="log_date_format",
'--log-date-format',
dest='log_date_format',
default=DEFAULT_LOG_DATE_FORMAT,
help="Log date format used by the logging module",
help='Log date format used by the logging module',
)
parser.addini(
"log_cli",
'log_cli',
default=False,
type="bool",
type='bool',
help='Enable log display during test run (also known as "live logging")',
)
add_option_ini(
"--log-cli-level", dest="log_cli_level", default=None, help="CLI logging level"
'--log-cli-level', dest='log_cli_level', default=None, help='CLI logging level',
)
add_option_ini(
"--log-cli-format",
dest="log_cli_format",
'--log-cli-format',
dest='log_cli_format',
default=None,
help="Log format used by the logging module",
help='Log format used by the logging module',
)
add_option_ini(
"--log-cli-date-format",
dest="log_cli_date_format",
'--log-cli-date-format',
dest='log_cli_date_format',
default=None,
help="Log date format used by the logging module",
help='Log date format used by the logging module',
)
add_option_ini(
"--log-file",
dest="log_file",
'--log-file',
dest='log_file',
default=None,
help="Path to a file when logging will be written to",
help='Path to a file when logging will be written to',
)
add_option_ini(
"--log-file-mode",
dest="log_file_mode",
default="w",
choices=["w", "a"],
help="Log file open mode",
'--log-file-mode',
dest='log_file_mode',
default='w',
choices=['w', 'a'],
help='Log file open mode',
)
add_option_ini(
"--log-file-level",
dest="log_file_level",
'--log-file-level',
dest='log_file_level',
default=None,
help="Log file logging level",
help='Log file logging level',
)
add_option_ini(
"--log-file-format",
dest="log_file_format",
'--log-file-format',
dest='log_file_format',
default=None,
help="Log format used by the logging module",
help='Log format used by the logging module',
)
add_option_ini(
"--log-file-date-format",
dest="log_file_date_format",
'--log-file-date-format',
dest='log_file_date_format',
default=None,
help="Log date format used by the logging module",
help='Log date format used by the logging module',
)
add_option_ini(
"--log-auto-indent",
dest="log_auto_indent",
'--log-auto-indent',
dest='log_auto_indent',
default=None,
help="Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.",
help='Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.',
)
group.addoption(
"--log-disable",
action="append",
'--log-disable',
action='append',
default=[],
dest="logger_disable",
help="Disable a logger by name. Can be passed multiple times.",
dest='logger_disable',
help='Disable a logger by name. Can be passed multiple times.',
)
_HandlerType = TypeVar("_HandlerType", bound=logging.Handler)
_HandlerType = TypeVar('_HandlerType', bound=logging.Handler)
# Not using @contextmanager for performance reasons.
class catching_logs(Generic[_HandlerType]):
"""Context manager that prepares the whole logging machinery properly."""
__slots__ = ("handler", "level", "orig_level")
__slots__ = ('handler', 'level', 'orig_level')
def __init__(self, handler: _HandlerType, level: Optional[int] = None) -> None:
def __init__(self, handler: _HandlerType, level: int | None = None) -> None:
self.handler = handler
self.level = level
@ -363,9 +365,9 @@ class catching_logs(Generic[_HandlerType]):
def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
root_logger = logging.getLogger()
if self.level is not None:
@ -379,7 +381,7 @@ class LogCaptureHandler(logging_StreamHandler):
def __init__(self) -> None:
"""Create a new log handler."""
super().__init__(StringIO())
self.records: List[logging.LogRecord] = []
self.records: list[logging.LogRecord] = []
def emit(self, record: logging.LogRecord) -> None:
"""Keep the log records in a list in addition to the log text."""
@ -410,10 +412,10 @@ class LogCaptureFixture:
def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None:
check_ispytest(_ispytest)
self._item = item
self._initial_handler_level: Optional[int] = None
self._initial_handler_level: int | None = None
# Dict of log name -> log level.
self._initial_logger_levels: Dict[Optional[str], int] = {}
self._initial_disabled_logging_level: Optional[int] = None
self._initial_logger_levels: dict[str | None, int] = {}
self._initial_disabled_logging_level: int | None = None
def _finalize(self) -> None:
"""Finalize the fixture.
@ -437,8 +439,8 @@ class LogCaptureFixture:
return self._item.stash[caplog_handler_key]
def get_records(
self, when: Literal["setup", "call", "teardown"]
) -> List[logging.LogRecord]:
self, when: Literal['setup', 'call', 'teardown'],
) -> list[logging.LogRecord]:
"""Get the logging records for one of the possible test phases.
:param when:
@ -457,12 +459,12 @@ class LogCaptureFixture:
return _remove_ansi_escape_sequences(self.handler.stream.getvalue())
@property
def records(self) -> List[logging.LogRecord]:
def records(self) -> list[logging.LogRecord]:
"""The list of log records."""
return self.handler.records
@property
def record_tuples(self) -> List[Tuple[str, int, str]]:
def record_tuples(self) -> list[tuple[str, int, str]]:
"""A list of a stripped down version of log records intended
for use in assertion comparison.
@ -473,7 +475,7 @@ class LogCaptureFixture:
return [(r.name, r.levelno, r.getMessage()) for r in self.records]
@property
def messages(self) -> List[str]:
def messages(self) -> list[str]:
"""A list of format-interpolated log messages.
Unlike 'records', which contains the format string and parameters for
@ -496,7 +498,7 @@ class LogCaptureFixture:
self.handler.clear()
def _force_enable_logging(
self, level: Union[int, str], logger_obj: logging.Logger
self, level: int | str, logger_obj: logging.Logger,
) -> int:
"""Enable the desired logging level if the global level was disabled via ``logging.disabled``.
@ -529,7 +531,7 @@ class LogCaptureFixture:
return original_disable_level
def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None:
def set_level(self, level: int | str, logger: str | None = None) -> None:
"""Set the threshold level of a logger for the duration of a test.
Logging messages which are less severe than this level will not be captured.
@ -556,7 +558,7 @@ class LogCaptureFixture:
@contextmanager
def at_level(
self, level: Union[int, str], logger: Optional[str] = None
self, level: int | str, logger: str | None = None,
) -> Generator[None, None, None]:
"""Context manager that sets the level for capturing of logs. After
the end of the 'with' statement the level is restored to its original
@ -614,7 +616,7 @@ def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]:
result._finalize()
def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[int]:
def get_log_level_for_setting(config: Config, *setting_names: str) -> int | None:
for setting_name in setting_names:
log_level = config.getoption(setting_name)
if log_level is None:
@ -633,14 +635,14 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i
raise UsageError(
f"'{log_level}' is not recognized as a logging level name for "
f"'{setting_name}'. Please consider passing the "
"logging level num instead."
'logging level num instead.',
) from e
# run after terminalreporter/capturemanager are configured
@hookimpl(trylast=True)
def pytest_configure(config: Config) -> None:
config.pluginmanager.register(LoggingPlugin(config), "logging-plugin")
config.pluginmanager.register(LoggingPlugin(config), 'logging-plugin')
class LoggingPlugin:
@ -656,11 +658,11 @@ class LoggingPlugin:
# Report logging.
self.formatter = self._create_formatter(
get_option_ini(config, "log_format"),
get_option_ini(config, "log_date_format"),
get_option_ini(config, "log_auto_indent"),
get_option_ini(config, 'log_format'),
get_option_ini(config, 'log_date_format'),
get_option_ini(config, 'log_auto_indent'),
)
self.log_level = get_log_level_for_setting(config, "log_level")
self.log_level = get_log_level_for_setting(config, 'log_level')
self.caplog_handler = LogCaptureHandler()
self.caplog_handler.setFormatter(self.formatter)
self.report_handler = LogCaptureHandler()
@ -668,52 +670,52 @@ class LoggingPlugin:
# File logging.
self.log_file_level = get_log_level_for_setting(
config, "log_file_level", "log_level"
config, 'log_file_level', 'log_level',
)
log_file = get_option_ini(config, "log_file") or os.devnull
log_file = get_option_ini(config, 'log_file') or os.devnull
if log_file != os.devnull:
directory = os.path.dirname(os.path.abspath(log_file))
if not os.path.isdir(directory):
os.makedirs(directory)
self.log_file_mode = get_option_ini(config, "log_file_mode") or "w"
self.log_file_mode = get_option_ini(config, 'log_file_mode') or 'w'
self.log_file_handler = _FileHandler(
log_file, mode=self.log_file_mode, encoding="UTF-8"
log_file, mode=self.log_file_mode, encoding='UTF-8',
)
log_file_format = get_option_ini(config, "log_file_format", "log_format")
log_file_format = get_option_ini(config, 'log_file_format', 'log_format')
log_file_date_format = get_option_ini(
config, "log_file_date_format", "log_date_format"
config, 'log_file_date_format', 'log_date_format',
)
log_file_formatter = DatetimeFormatter(
log_file_format, datefmt=log_file_date_format
log_file_format, datefmt=log_file_date_format,
)
self.log_file_handler.setFormatter(log_file_formatter)
# CLI/live logging.
self.log_cli_level = get_log_level_for_setting(
config, "log_cli_level", "log_level"
config, 'log_cli_level', 'log_level',
)
if self._log_cli_enabled():
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
terminal_reporter = config.pluginmanager.get_plugin('terminalreporter')
# Guaranteed by `_log_cli_enabled()`.
assert terminal_reporter is not None
capture_manager = config.pluginmanager.get_plugin("capturemanager")
capture_manager = config.pluginmanager.get_plugin('capturemanager')
# if capturemanager plugin is disabled, live logging still works.
self.log_cli_handler: Union[
_LiveLoggingStreamHandler, _LiveLoggingNullHandler
] = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
self.log_cli_handler: (
_LiveLoggingStreamHandler | _LiveLoggingNullHandler
) = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
else:
self.log_cli_handler = _LiveLoggingNullHandler()
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"),
get_option_ini(config, "log_auto_indent"),
get_option_ini(config, 'log_cli_format', 'log_format'),
get_option_ini(config, 'log_cli_date_format', 'log_date_format'),
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:
def _disable_loggers(self, loggers_to_disable: list[str]) -> None:
if not loggers_to_disable:
return
@ -723,18 +725,18 @@ class LoggingPlugin:
def _create_formatter(self, log_format, log_date_format, auto_indent):
# 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
color = getattr(self._config.option, 'color', 'no')
if color != 'no' and ColoredLevelFormatter.LEVELNAME_FMT_REGEX.search(
log_format,
):
formatter: logging.Formatter = ColoredLevelFormatter(
create_terminal_writer(self._config), log_format, log_date_format
create_terminal_writer(self._config), log_format, log_date_format,
)
else:
formatter = DatetimeFormatter(log_format, log_date_format)
formatter._style = PercentStyleMultiline(
formatter._style._fmt, auto_indent=auto_indent
formatter._style._fmt, auto_indent=auto_indent,
)
return formatter
@ -756,7 +758,7 @@ class LoggingPlugin:
fpath.parent.mkdir(exist_ok=True, parents=True)
# https://github.com/python/mypy/issues/11193
stream: io.TextIOWrapper = fpath.open(mode=self.log_file_mode, encoding="UTF-8") # type: ignore[assignment]
stream: io.TextIOWrapper = fpath.open(mode=self.log_file_mode, encoding='UTF-8') # type: ignore[assignment]
old_stream = self.log_file_handler.setStream(stream)
if old_stream:
old_stream.close()
@ -764,12 +766,12 @@ class LoggingPlugin:
def _log_cli_enabled(self) -> bool:
"""Return whether live logging is enabled."""
enabled = self._config.getoption(
"--log-cli-level"
) is not None or self._config.getini("log_cli")
'--log-cli-level',
) is not None or self._config.getini('log_cli')
if not enabled:
return False
terminal_reporter = self._config.pluginmanager.get_plugin("terminalreporter")
terminal_reporter = self._config.pluginmanager.get_plugin('terminalreporter')
if terminal_reporter is None:
# terminal reporter is disabled e.g. by pytest-xdist.
return False
@ -778,7 +780,7 @@ class LoggingPlugin:
@hookimpl(wrapper=True, tryfirst=True)
def pytest_sessionstart(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("sessionstart")
self.log_cli_handler.set_when('sessionstart')
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
with catching_logs(self.log_file_handler, level=self.log_file_level):
@ -786,7 +788,7 @@ class LoggingPlugin:
@hookimpl(wrapper=True, tryfirst=True)
def pytest_collection(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("collection")
self.log_cli_handler.set_when('collection')
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
with catching_logs(self.log_file_handler, level=self.log_file_level):
@ -797,7 +799,7 @@ class LoggingPlugin:
if session.config.option.collectonly:
return (yield)
if self._log_cli_enabled() and self._config.getoption("verbose") < 1:
if self._log_cli_enabled() and self._config.getoption('verbose') < 1:
# The verbose flag is needed to avoid messy test progress output.
self._config.option.verbose = 1
@ -808,11 +810,11 @@ class LoggingPlugin:
@hookimpl
def pytest_runtest_logstart(self) -> None:
self.log_cli_handler.reset()
self.log_cli_handler.set_when("start")
self.log_cli_handler.set_when('start')
@hookimpl
def pytest_runtest_logreport(self) -> None:
self.log_cli_handler.set_when("logreport")
self.log_cli_handler.set_when('logreport')
def _runtest_for(self, item: nodes.Item, when: str) -> Generator[None, None, None]:
"""Implement the internals of the pytest_runtest_xxx() hooks."""
@ -832,39 +834,39 @@ class LoggingPlugin:
yield
finally:
log = report_handler.stream.getvalue().strip()
item.add_report_section(when, "log", log)
item.add_report_section(when, 'log', log)
@hookimpl(wrapper=True)
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("setup")
self.log_cli_handler.set_when('setup')
empty: Dict[str, List[logging.LogRecord]] = {}
empty: dict[str, list[logging.LogRecord]] = {}
item.stash[caplog_records_key] = empty
yield from self._runtest_for(item, "setup")
yield from self._runtest_for(item, 'setup')
@hookimpl(wrapper=True)
def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("call")
self.log_cli_handler.set_when('call')
yield from self._runtest_for(item, "call")
yield from self._runtest_for(item, 'call')
@hookimpl(wrapper=True)
def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("teardown")
self.log_cli_handler.set_when('teardown')
try:
yield from self._runtest_for(item, "teardown")
yield from self._runtest_for(item, 'teardown')
finally:
del item.stash[caplog_records_key]
del item.stash[caplog_handler_key]
@hookimpl
def pytest_runtest_logfinish(self) -> None:
self.log_cli_handler.set_when("finish")
self.log_cli_handler.set_when('finish')
@hookimpl(wrapper=True, tryfirst=True)
def pytest_sessionfinish(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("sessionfinish")
self.log_cli_handler.set_when('sessionfinish')
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
with catching_logs(self.log_file_handler, level=self.log_file_level):
@ -901,7 +903,7 @@ class _LiveLoggingStreamHandler(logging_StreamHandler):
def __init__(
self,
terminal_reporter: TerminalReporter,
capture_manager: Optional[CaptureManager],
capture_manager: CaptureManager | None,
) -> None:
super().__init__(stream=terminal_reporter) # type: ignore[arg-type]
self.capture_manager = capture_manager
@ -913,11 +915,11 @@ class _LiveLoggingStreamHandler(logging_StreamHandler):
"""Reset the handler; should be called before the start of each test."""
self._first_record_emitted = False
def set_when(self, when: Optional[str]) -> None:
def set_when(self, when: str | None) -> None:
"""Prepare for the given test phase (setup/call/teardown)."""
self._when = when
self._section_name_shown = False
if when == "start":
if when == 'start':
self._test_outcome_written = False
def emit(self, record: logging.LogRecord) -> None:
@ -928,14 +930,14 @@ class _LiveLoggingStreamHandler(logging_StreamHandler):
)
with ctx_manager:
if not self._first_record_emitted:
self.stream.write("\n")
self.stream.write('\n')
self._first_record_emitted = True
elif self._when in ("teardown", "finish"):
elif self._when in ('teardown', 'finish'):
if not self._test_outcome_written:
self._test_outcome_written = True
self.stream.write("\n")
self.stream.write('\n')
if not self._section_name_shown and self._when:
self.stream.section("live log " + self._when, sep="-", bold=True)
self.stream.section('live log ' + self._when, sep='-', bold=True)
self._section_name_shown = True
super().emit(record)