mirror of https://github.com/Delgan/loguru.git
231 lines
6.9 KiB
Python
231 lines
6.9 KiB
Python
import os
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from loguru import logger
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"format, validator",
|
|
[
|
|
("{name}", lambda r: r == "tests.test_formatting"),
|
|
("{time}", lambda r: re.fullmatch(r"\d+-\d+-\d+T\d+:\d+:\d+[.,]\d+[+-]\d{4}", r)),
|
|
("{elapsed}", lambda r: re.fullmatch(r"\d:\d{2}:\d{2}\.\d{6}", r)),
|
|
("{elapsed.seconds}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{line}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{level}", lambda r: r == "DEBUG"),
|
|
("{level.name}", lambda r: r == "DEBUG"),
|
|
("{level.no}", lambda r: r == "10"),
|
|
("{level.icon}", lambda r: r == "🐞"),
|
|
("{file}", lambda r: r == "test_formatting.py"),
|
|
("{file.name}", lambda r: r == "test_formatting.py"),
|
|
("{file.path}", lambda r: os.path.normcase(r) == os.path.normcase(__file__)),
|
|
("{function}", lambda r: r == "test_log_formatters"),
|
|
("{module}", lambda r: r == "test_formatting"),
|
|
("{thread}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{thread.id}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{thread.name}", lambda r: isinstance(r, str) and r != ""),
|
|
("{process}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{process.id}", lambda r: re.fullmatch(r"\d+", r)),
|
|
("{process.name}", lambda r: isinstance(r, str) and r != ""),
|
|
("{message}", lambda r: r == "Message"),
|
|
("%s {{a}} 天 {{1}} %d", lambda r: r == "%s {a} 天 {1} %d"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize("use_log_function", [False, True])
|
|
def test_log_formatters(format, validator, writer, use_log_function):
|
|
message = "Message"
|
|
|
|
logger.add(writer, format=format)
|
|
|
|
if use_log_function:
|
|
logger.log("DEBUG", message)
|
|
else:
|
|
logger.debug(message)
|
|
|
|
result = writer.read().rstrip("\n")
|
|
assert validator(result)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"format, validator",
|
|
[
|
|
("{time}.log", lambda r: re.fullmatch(r"\d+-\d+-\d+_\d+-\d+-\d+\_\d+.log", r)),
|
|
("%s_{{a}}_天_{{1}}_%d", lambda r: r == "%s_{a}_天_{1}_%d"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize("part", ["file", "dir", "both"])
|
|
def test_file_formatters(tmp_path, format, validator, part):
|
|
if part == "file":
|
|
file = tmp_path.joinpath(format)
|
|
elif part == "dir":
|
|
file = tmp_path.joinpath(format, "log.log")
|
|
elif part == "both":
|
|
file = tmp_path.joinpath(format, format)
|
|
|
|
logger.add(file)
|
|
logger.debug("Message")
|
|
|
|
files = [f for f in tmp_path.glob("**/*") if f.is_file()]
|
|
|
|
assert len(files) == 1
|
|
|
|
file = files[0]
|
|
|
|
if part == "file":
|
|
assert validator(file.name)
|
|
elif part == "dir":
|
|
assert file.name == "log.log"
|
|
assert validator(file.parent.name)
|
|
elif part == "both":
|
|
assert validator(file.name)
|
|
assert validator(file.parent.name)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"message, args, kwargs, expected",
|
|
[
|
|
("{1, 2, 3} - {0} - {", [], {}, "{1, 2, 3} - {0} - {"),
|
|
("{} + {} = {}", [1, 2, 3], {}, "1 + 2 = 3"),
|
|
("{a} + {b} = {c}", [], dict(a=1, b=2, c=3), "1 + 2 = 3"),
|
|
("{0} + {two} = {1}", [1, 3], dict(two=2, nope=4), "1 + 2 = 3"),
|
|
(
|
|
"{self} or {message} or {level}",
|
|
[],
|
|
dict(self="a", message="b", level="c"),
|
|
"a or b or c",
|
|
),
|
|
("{:.2f}", [1], {}, "1.00"),
|
|
("{0:0{three}d}", [5], dict(three=3), "005"),
|
|
("{{nope}} {my_dict} {}", ["{{!}}"], dict(my_dict={"a": 1}), "{nope} {'a': 1} {{!}}"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize("use_log_function", [False, True])
|
|
def test_log_formatting(writer, message, args, kwargs, expected, use_log_function):
|
|
logger.add(writer, format="{message}", colorize=False)
|
|
|
|
if use_log_function:
|
|
logger.log(10, message, *args, **kwargs)
|
|
else:
|
|
logger.debug(message, *args, **kwargs)
|
|
|
|
assert writer.read() == expected + "\n"
|
|
|
|
|
|
def test_f_globals_name_absent(writer, f_globals_name_absent):
|
|
logger.add(writer, format="{name} {message}", colorize=False)
|
|
logger.info("Foobar")
|
|
assert writer.read() == "None Foobar\n"
|
|
|
|
|
|
def test_extra_formatting(writer):
|
|
logger.configure(extra={"test": "my_test", "dict": {"a": 10}})
|
|
logger.add(writer, format="{extra[test]} -> {extra[dict]} -> {message}")
|
|
logger.debug("level: {name}", name="DEBUG")
|
|
assert writer.read() == "my_test -> {'a': 10} -> level: DEBUG\n"
|
|
|
|
|
|
def test_kwargs_in_extra_dict():
|
|
extra_dicts = []
|
|
messages = []
|
|
|
|
def sink(message):
|
|
extra_dicts.append(message.record["extra"])
|
|
messages.append(str(message))
|
|
|
|
logger.add(sink, format="{message}")
|
|
logger.info("A")
|
|
logger.info("B", foo=123)
|
|
logger.bind(merge=True).info("C", other=False)
|
|
logger.bind(override=False).info("D", override=True)
|
|
logger.info("Formatted kwargs: {foobar}", foobar=123)
|
|
logger.info("Ignored args: {}", 456)
|
|
logger.info("Both: {foobar} {}", 456, foobar=123)
|
|
logger.opt(lazy=True).info("Lazy: {lazy}", lazy=lambda: 789)
|
|
|
|
assert messages == [
|
|
"A\n",
|
|
"B\n",
|
|
"C\n",
|
|
"D\n",
|
|
"Formatted kwargs: 123\n",
|
|
"Ignored args: 456\n",
|
|
"Both: 123 456\n",
|
|
"Lazy: 789\n",
|
|
]
|
|
|
|
assert extra_dicts == [
|
|
{},
|
|
{"foo": 123},
|
|
{"merge": True, "other": False},
|
|
{"override": True},
|
|
{"foobar": 123},
|
|
{},
|
|
{"foobar": 123},
|
|
{"lazy": 789},
|
|
]
|
|
|
|
|
|
def test_non_string_message(writer):
|
|
logger.add(writer, format="{message}")
|
|
|
|
logger.info(1)
|
|
logger.info({})
|
|
logger.info(b"test")
|
|
|
|
assert writer.read() == "1\n{}\nb'test'\n"
|
|
|
|
|
|
@pytest.mark.parametrize("colors", [True, False])
|
|
def test_non_string_message_is_str_in_record(writer, colors):
|
|
output = ""
|
|
|
|
def sink(message):
|
|
nonlocal output
|
|
assert isinstance(message.record["message"], str)
|
|
output += message
|
|
|
|
def format(record):
|
|
assert isinstance(record["message"], str)
|
|
return "[{message}]\n"
|
|
|
|
logger.add(sink, format=format, catch=False)
|
|
logger.opt(colors=colors).info(123)
|
|
assert output == "[123]\n"
|
|
|
|
|
|
@pytest.mark.parametrize("colors", [True, False])
|
|
def test_missing_positional_field_during_formatting(writer, colors):
|
|
logger.add(writer)
|
|
|
|
with pytest.raises(IndexError):
|
|
logger.opt(colors=colors).info("Foo {} {}", 123)
|
|
|
|
|
|
@pytest.mark.parametrize("colors", [True, False])
|
|
def test_missing_named_field_during_formatting(writer, colors):
|
|
logger.add(writer)
|
|
|
|
with pytest.raises(KeyError):
|
|
logger.opt(colors=colors).info("Foo {bar}", baz=123)
|
|
|
|
|
|
def test_not_formattable_message(writer):
|
|
logger.add(writer)
|
|
|
|
with pytest.raises(AttributeError):
|
|
logger.info(123, baz=456)
|
|
|
|
|
|
def test_not_formattable_message_with_colors(writer):
|
|
logger.add(writer)
|
|
|
|
with pytest.raises(TypeError):
|
|
logger.opt(colors=True).info(123, baz=456)
|
|
|
|
|
|
def test_invalid_color_markup(writer):
|
|
with pytest.raises(ValueError):
|
|
logger.add(writer, format="<red>Not closed tag", colorize=True)
|