Merge branch 'main' into dev1

This commit is contained in:
Ben Nguyen Tran 2024-04-28 21:40:49 -04:00 committed by GitHub
commit 36d82f0254
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 126 additions and 5 deletions

View File

@ -208,6 +208,7 @@ option names are:
If you need to record the whole test suite logging calls to a file, you can pass
``--log-file=/path/to/log/file``. This log file is opened in write mode by default which
means that it will be overwritten at each run tests session.
You can specify the level of verbosity of the log file by passing ```--log-file-verbose=1``
If you'd like the file opened in append mode instead, then you can pass ``--log-file-mode=a``.
Note that relative paths for the log-file location, whether passed on the CLI or declared in a
config file, are always resolved relative to the current working directory.

View File

@ -2107,6 +2107,7 @@ All the command-line flags can be obtained by running ``pytest --help``::
--log-cli-date-format=LOG_CLI_DATE_FORMAT
Log date format used by the logging module
--log-file=LOG_FILE Path to a file when logging will be written to
--log-file-verbose={0,1} Log file verbose
--log-file-mode={w,a}
Log file open mode
--log-file-level=LOG_FILE_LEVEL
@ -2207,6 +2208,8 @@ All the command-line flags can be obtained by running ``pytest --help``::
log_cli_date_format (string):
Default value for --log-cli-date-format
log_file (string): Default value for --log-file
log_file_verbose (int):
Default value for --log-file-verbose
log_file_mode (string):
Default value for --log-file-mode
log_file_level (string):

View File

@ -1576,6 +1576,7 @@ class Config:
``paths``, ``pathlist``, ``args`` and ``linelist`` : empty list ``[]``
``bool`` : ``False``
``string`` : empty string ``""``
``int`` : ``0``
If neither the ``default`` nor the ``type`` parameter is passed
while registering the configuration through
@ -1643,6 +1644,8 @@ class Config:
return value
elif type == "bool":
return _strtobool(str(value).strip())
elif type == "int":
return int(str(value).strip())
elif type == "string":
return value
elif type is None:

View File

@ -180,7 +180,7 @@ class Parser:
name: str,
help: str,
type: Optional[
Literal["string", "paths", "pathlist", "args", "linelist", "bool"]
Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"]
] = None,
default: Any = NOT_SET,
) -> None:
@ -190,7 +190,7 @@ class Parser:
Name of the ini-variable.
:param type:
Type of the variable. Can be:
* ``int``: an integer
* ``string``: a string
* ``bool``: a boolean
* ``args``: a list of strings, separated as in a shell
@ -215,7 +215,16 @@ class Parser:
The value of ini-variables can be retrieved via a call to
:py:func:`config.getini(name) <pytest.Config.getini>`.
"""
assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool")
assert type in (
None,
"string",
"paths",
"pathlist",
"args",
"linelist",
"bool",
"int",
)
if default is NOT_SET:
default = get_ini_default_for_type(type)
@ -224,7 +233,9 @@ class Parser:
def get_ini_default_for_type(
type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool"]],
type: Optional[
Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"]
],
) -> Any:
"""
Used by addini to get the default value for a given ini-option type, when
@ -236,6 +247,8 @@ def get_ini_default_for_type(
return []
elif type == "bool":
return False
elif type == "int":
return 0
else:
return ""

View File

@ -299,6 +299,13 @@ def pytest_addoption(parser: Parser) -> None:
default=None,
help="Path to a file when logging will be written to",
)
add_option_ini(
"--log-file-verbose",
dest="log_file_verbose",
default=0,
type="int",
help="Log file verbose",
)
add_option_ini(
"--log-file-mode",
dest="log_file_mode",
@ -677,6 +684,8 @@ class LoggingPlugin:
if not os.path.isdir(directory):
os.makedirs(directory)
self.log_file_verbose = get_option_ini(config, "log_file_verbose")
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"
@ -837,6 +846,22 @@ class LoggingPlugin:
@hookimpl(wrapper=True)
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
if self.log_file_verbose and int(self.log_file_verbose) >= 1:
old_log_file_formatter = self.log_file_handler.formatter
self.log_file_handler.setFormatter(logging.Formatter())
self.log_file_handler.emit(
logging.LogRecord(
"N/A",
logging.INFO,
"N/A",
0,
f"Running at {item.nodeid}",
None,
None,
)
)
self.log_file_handler.setFormatter(old_log_file_formatter)
self.log_cli_handler.set_when("setup")
empty: Dict[str, List[logging.LogRecord]] = {}

View File

@ -8,6 +8,6 @@ import pytest
result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)]
@pytest.mark.parametrize("a, b,expected_result", result_index)
@pytest.mark.parametrize("a, b, expected_result", result_index)
def test_add(a: int, b: int, expected_result: int) -> None:
assert add_function.add(a, b) == expected_result

76
testing/test_log_file.py Normal file
View File

@ -0,0 +1,76 @@
import os
from _pytest.pytester import Pytester
def test_log_file_verbose(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makepyfile(
"""
import logging
def test_verbose1():
logging.info("test 1")
def test_verbose2():
logging.warning("test 2")
"""
)
result = pytester.runpytest(
"-s", f"--log-file={log_file}", "--log-file-verbose=1", "--log-file-level=INFO"
)
rec = pytester.inline_run()
rec.assertoutcome(passed=2)
# make sure that we get a '0' exit code for the testsuite
assert result.ret == 0
assert os.path.isfile(log_file)
with open(log_file, encoding="utf-8") as rfh:
contents = rfh.read()
for s in [
"Running at test_log_file_verbose.py::test_verbose1",
"test 1",
"Running at test_log_file_verbose.py::test_verbose2",
"test 2",
]:
assert s in contents
def test_log_file_verbose0(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makepyfile(
"""
import logging
def test_verbose1():
logging.info("test 1")
def test_verbose2():
logging.warning("test 2")
"""
)
result = pytester.runpytest(
"-s", f"--log-file={log_file}", "--log-file-verbose=0", "--log-file-level=INFO"
)
rec = pytester.inline_run()
rec.assertoutcome(passed=2)
# make sure that we get a '0' exit code for the testsuite
assert result.ret == 0
assert os.path.isfile(log_file)
with open(log_file, encoding="utf-8") as rfh:
contents = rfh.read()
for s in ["test 1", "test 2"]:
assert s in contents
for s in [
"Running at test_log_file_verbose0.py::test_verbose1",
"Running at test_log_file_verbose.py::test_verbose2",
]:
assert s not in contents