mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-09 21:04:17 +00:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
72ad6dc953
commit
f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue