summaryrefslogtreecommitdiff
path: root/src/_pytest/logging.py
diff options
context:
space:
mode:
authorDaniel Hahler <git@thequod.de>2019-11-06 00:35:24 +0100
committerGitHub <noreply@github.com>2019-11-06 00:35:24 +0100
commite7320c6b547750e630ac59d8b40d48be25e779ce (patch)
treebccb01bc864aebe8c9b66e08921b776d979a1d9c /src/_pytest/logging.py
parent00f67494e5de70ffa4427bf0802a164c5790160d (diff)
parent1f5b454355d27bccda2ce1b3b145cfbde020fb76 (diff)
downloadpytest-e7320c6b547750e630ac59d8b40d48be25e779ce.tar.gz
Merge pull request #5926 from AtakamaLLC/optional-multiline
Add log-auto-indent option to control multiline formatting
Diffstat (limited to 'src/_pytest/logging.py')
-rw-r--r--src/_pytest/logging.py99
1 files changed, 87 insertions, 12 deletions
diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py
index dc45227b2..ccd79b834 100644
--- a/src/_pytest/logging.py
+++ b/src/_pytest/logging.py
@@ -10,6 +10,7 @@ from typing import Mapping
import pytest
from _pytest.compat import nullcontext
+from _pytest.config import _strtobool
from _pytest.config import create_terminal_writer
from _pytest.pathlib import Path
@@ -76,24 +77,87 @@ class PercentStyleMultiline(logging.PercentStyle):
formats the message as if each line were logged separately.
"""
+ def __init__(self, fmt, auto_indent):
+ super().__init__(fmt)
+ self._auto_indent = self._get_auto_indent(auto_indent)
+
@staticmethod
def _update_message(record_dict, message):
tmp = record_dict.copy()
tmp["message"] = message
return tmp
+ @staticmethod
+ def _get_auto_indent(auto_indent_option) -> int:
+ """Determines the current auto indentation setting
+
+ Specify auto indent behavior (on/off/fixed) by passing in
+ extra={"auto_indent": [value]} to the call to logging.log() or
+ using a --log-auto-indent [value] command line or the
+ log_auto_indent [value] config option.
+
+ Default behavior is auto-indent off.
+
+ Using the string "True" or "on" or the boolean True as the value
+ turns auto indent on, using the string "False" or "off" or the
+ boolean False or the int 0 turns it off, and specifying a
+ positive integer fixes the indentation position to the value
+ specified.
+
+ Any other values for the option are invalid, and will silently be
+ converted to the default.
+
+ :param any auto_indent_option: User specified option for indentation
+ from command line, config or extra kwarg. Accepts int, bool or str.
+ str option accepts the same range of values as boolean config options,
+ as well as positive integers represented in str form.
+
+ :returns: indentation value, which can be
+ -1 (automatically determine indentation) or
+ 0 (auto-indent turned off) or
+ >0 (explicitly set indentation position).
+ """
+
+ if type(auto_indent_option) is int:
+ return int(auto_indent_option)
+ elif type(auto_indent_option) is str:
+ try:
+ return int(auto_indent_option)
+ except ValueError:
+ pass
+ try:
+ if _strtobool(auto_indent_option):
+ return -1
+ except ValueError:
+ return 0
+ elif type(auto_indent_option) is bool:
+ if auto_indent_option:
+ return -1
+
+ return 0
+
def format(self, record):
if "\n" in record.message:
- lines = record.message.splitlines()
- formatted = self._fmt % self._update_message(record.__dict__, lines[0])
- # TODO optimize this by introducing an option that tells the
- # logging framework that the indentation doesn't
- # change. This allows to compute the indentation only once.
- indentation = _remove_ansi_escape_sequences(formatted).find(lines[0])
- lines[0] = formatted
- return ("\n" + " " * indentation).join(lines)
- else:
- return self._fmt % record.__dict__
+ 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)
+ else:
+ auto_indent = self._auto_indent
+
+ if auto_indent:
+ lines = record.message.splitlines()
+ formatted = self._fmt % self._update_message(record.__dict__, lines[0])
+
+ if auto_indent < 0:
+ indentation = _remove_ansi_escape_sequences(formatted).find(
+ lines[0]
+ )
+ else:
+ # optimizes logging by allowing a fixed indentation
+ indentation = auto_indent
+ lines[0] = formatted
+ return ("\n" + " " * indentation).join(lines)
+ return self._fmt % record.__dict__
def get_option_ini(config, *names):
@@ -187,6 +251,12 @@ def pytest_addoption(parser):
default=DEFAULT_LOG_DATE_FORMAT,
help="log date format as used by the logging module.",
)
+ add_option_ini(
+ "--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.",
+ )
@contextmanager
@@ -418,6 +488,7 @@ class LoggingPlugin:
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"),
)
self.log_level = get_actual_log_level(config, "log_level")
@@ -449,7 +520,7 @@ class LoggingPlugin:
if self._log_cli_enabled():
self._setup_cli_logging()
- def _create_formatter(self, log_format, log_date_format):
+ 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(
@@ -461,7 +532,10 @@ class LoggingPlugin:
else:
formatter = logging.Formatter(log_format, log_date_format)
- formatter._style = PercentStyleMultiline(formatter._style._fmt)
+ formatter._style = PercentStyleMultiline(
+ formatter._style._fmt, auto_indent=auto_indent
+ )
+
return formatter
def _setup_cli_logging(self):
@@ -478,6 +552,7 @@ class LoggingPlugin:
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"),
)
log_cli_level = get_actual_log_level(config, "log_cli_level", "log_level")