Conversation
LaTranquillum
left a comment
There was a problem hiding this comment.
The per-item example in doc/en/how-to/logging.rst:283 can overwrite an earlier test's log because item.name is not unique across modules.
Using the PR's pytest_runtest_setup hook unchanged in conftest.py, these two files reproduce the problem:
# test_a.py
import logging
def test_same():
logging.warning("UNIQUE_MESSAGE_A")# test_b.py
import logging
def test_same():
logging.warning("UNIQUE_MESSAGE_B")On CPython 3.14.2 / pytest 9.1.1 / macOS, running PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q test_a.py test_b.py reports 2 passed, but the only file, logs/test_same.log, contains only UNIQUE_MESSAGE_B. With the default write mode, the second call to set_log_path() truncates the first test's log.
Could the example derive a filesystem-safe filename from the full item.nodeid instead? For example, using sha256(item.nodeid.encode()).hexdigest() as the filename stem preserved two separate files containing the respective messages in the same reproduction. That requires from hashlib import sha256. Append mode alone would combine the logs rather than provide the advertised separate file per test item.
Validation was limited to these two tests with the original example and the same two tests with the changed filename (four test executions); no full suite or docs build was run.
Disclosure: Codex assisted with the investigation, ran the local reproductions, and drafted this feedback; I reviewed the finding and authorized submission.
Explain how to access set_log_path() on LoggingPlugin and provide examples for configuring dynamic log file paths in pytest_configure and pytest_runtest_setup hooks. Fixes pytest-dev#8086
7c75f10 to
dd76b0a
Compare
|
Good catch, thanks for the clear reproduction! I have updated the from hashlib import sha256
from pathlib import Path
import pytest
@pytest.hookimpl(wrapper=True, tryfirst=True)
def pytest_runtest_setup(item: pytest.Item):
logging_plugin = item.config.pluginmanager.get_plugin("logging-plugin")
if logging_plugin is not None:
# item.nodeid uniquely identifies each test; hashing avoids
# filesystem-unsafe characters (such as "::" or parameters).
log_name = sha256(item.nodeid.encode()).hexdigest()
log_file = Path(item.config.rootpath) / "logs" / f"{log_name}.log"
logging_plugin.set_log_path(str(log_file))
return (yield) |
Description
This PR improves the documentation for
set_log_path()indoc/en/how-to/logging.rst, resolving #8086.Currently, the documentation notes that
set_log_path()can be called to customize thelog_filepath dynamically, but does not explain how to access the method or provide hook examples.This change:
set_log_path()is a method on theLoggingPlugininstance, retrievable viaconfig.pluginmanager.get_plugin("logging-plugin").pytest_configurehook example for generating dynamic, timestamped session log files, highlighting the need for@pytest.hookimpl(trylast=True).pytest_runtest_setuphook wrapper example for recording per-test log files.changelog/8086.doc.rstand updatesAUTHORS.Closes #8086.
Checklist
sphinx-build -W --keep-going.pre-commit.testing/logging/test_reporting.py).changelog/8086.doc.rst.AUTHORSin alphabetical order.