diff --git a/.gitignore b/.gitignore index 23e7c9966..935da3b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ coverage.xml # generated by pip pip-wheel-metadata/ + +# pytest debug logs generated via --debug +pytestdebug.log diff --git a/changelog/8954.feature.rst b/changelog/8954.feature.rst new file mode 100644 index 000000000..7edb43007 --- /dev/null +++ b/changelog/8954.feature.rst @@ -0,0 +1 @@ +``--debug`` flag now accepts a :class:`str` file to route debug logs into, remains defaulted to `pytestdebug.log`. diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index 78da45f0c..e3739ce93 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -80,10 +80,14 @@ def pytest_addoption(parser: Parser) -> None: ) group.addoption( "--debug", - action="store_true", + action="store", + nargs="?", + const="pytestdebug.log", dest="debug", - default=False, - help="store internal tracing debug information in 'pytestdebug.log'.", + metavar="DEBUG_FILE_NAME", + help="store internal tracing debug information in this log file.\n" + "This file is opened with 'w' and truncated as a result, care advised.\n" + "Defaults to 'pytestdebug.log'.", ) group._addoption( "-o", @@ -98,8 +102,10 @@ def pytest_addoption(parser: Parser) -> None: def pytest_cmdline_parse(): outcome = yield config: Config = outcome.get_result() + if config.option.debug: - path = os.path.abspath("pytestdebug.log") + # --debug | --debug was provided. + path = config.option.debug debugfile = open(path, "w") debugfile.write( "versions pytest-%s, py-%s, " @@ -114,11 +120,11 @@ def pytest_cmdline_parse(): ) config.trace.root.setwriter(debugfile.write) undo_tracing = config.pluginmanager.enable_tracing() - sys.stderr.write("writing pytestdebug information to %s\n" % path) + sys.stderr.write("writing pytest debug information to %s\n" % path) def unset_tracing() -> None: debugfile.close() - sys.stderr.write("wrote pytestdebug information to %s\n" % debugfile.name) + sys.stderr.write("wrote pytest debug information to %s\n" % debugfile.name) config.trace.root.setwriter(None) undo_tracing() diff --git a/testing/test_config.py b/testing/test_config.py index 1fdcea9bf..996a332a0 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -2042,3 +2042,55 @@ def test_parse_warning_filter_failure(arg: str) -> None: with pytest.raises(warnings._OptionError): parse_warning_filter(arg, escape=True) + + +class TestDebugOptions: + def test_without_debug_does_not_write_log(self, pytester: Pytester) -> None: + result = pytester.runpytest() + result.stderr.no_fnmatch_line( + "*writing pytest debug information to*pytestdebug.log" + ) + result.stderr.no_fnmatch_line( + "*wrote pytest debug information to*pytestdebug.log" + ) + assert not [f.name for f in pytester.path.glob("**/*.log")] + + def test_with_only_debug_writes_pytestdebug_log(self, pytester: Pytester) -> None: + result = pytester.runpytest("--debug") + result.stderr.fnmatch_lines( + [ + "*writing pytest debug information to*pytestdebug.log", + "*wrote pytest debug information to*pytestdebug.log", + ] + ) + assert "pytestdebug.log" in [f.name for f in pytester.path.glob("**/*.log")] + + def test_multiple_custom_debug_logs(self, pytester: Pytester) -> None: + result = pytester.runpytest("--debug", "bar.log") + result.stderr.fnmatch_lines( + [ + "*writing pytest debug information to*bar.log", + "*wrote pytest debug information to*bar.log", + ] + ) + result = pytester.runpytest("--debug", "foo.log") + result.stderr.fnmatch_lines( + [ + "*writing pytest debug information to*foo.log", + "*wrote pytest debug information to*foo.log", + ] + ) + + assert {"bar.log", "foo.log"} == { + f.name for f in pytester.path.glob("**/*.log") + } + + def test_debug_help(self, pytester: Pytester) -> None: + result = pytester.runpytest("-h") + result.stdout.fnmatch_lines( + [ + "*store internal tracing debug information in this log*", + "*This file is opened with 'w' and truncated as a result*", + "*Defaults to 'pytestdebug.log'.", + ] + )