From 810b878ef8eac6f39cfff35705a6a10083ace0bc Mon Sep 17 00:00:00 2001 From: Anton <44246099+antonblr@users.noreply.github.com> Date: Tue, 8 Dec 2020 12:20:02 -0800 Subject: [PATCH] Migrate to pytester: test_capture.py, test_terminal.py, approx.py (#8108) * Migrate to pytester: test_capture.py, test_config.py, approx.py * migrate test_terminal.py * revert test_config.py * more typing in test_terminal.py * try-out 'tr' fixture update * revert 'tr' fixture, update test_config.py --- testing/python/approx.py | 7 +- testing/test_capture.py | 388 +++++++++++----------- testing/test_config.py | 654 +++++++++++++++++++----------------- testing/test_terminal.py | 701 ++++++++++++++++++++------------------- 4 files changed, 928 insertions(+), 822 deletions(-) diff --git a/testing/python/approx.py b/testing/python/approx.py index b37c9f757..91c1f3f85 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -7,6 +7,7 @@ from operator import ne from typing import Optional import pytest +from _pytest.pytester import Pytester from pytest import approx inf, nan = float("inf"), float("nan") @@ -456,12 +457,12 @@ class TestApprox: ) mocked_doctest_runner.run(test) - def test_unicode_plus_minus(self, testdir): + def test_unicode_plus_minus(self, pytester: Pytester) -> None: """ Comparing approx instances inside lists should not produce an error in the detailed diff. Integration test for issue #2111. """ - testdir.makepyfile( + pytester.makepyfile( """ import pytest def test_foo(): @@ -469,7 +470,7 @@ class TestApprox: """ ) expected = "4.0e-06" - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [f"*At index 0 diff: 3 != 4 ± {expected}", "=* 1 failed in *="] ) diff --git a/testing/test_capture.py b/testing/test_capture.py index e6bbc9a5d..3a5c617fe 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -13,11 +13,13 @@ from typing import TextIO import pytest from _pytest import capture from _pytest.capture import _get_multicapture +from _pytest.capture import CaptureFixture from _pytest.capture import CaptureManager from _pytest.capture import CaptureResult from _pytest.capture import MultiCapture from _pytest.config import ExitCode -from _pytest.pytester import Testdir +from _pytest.monkeypatch import MonkeyPatch +from _pytest.pytester import Pytester # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) @@ -55,7 +57,7 @@ def TeeStdCapture( class TestCaptureManager: @pytest.mark.parametrize("method", ["no", "sys", "fd"]) - def test_capturing_basic_api(self, method): + def test_capturing_basic_api(self, method) -> None: capouter = StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin try: @@ -96,9 +98,9 @@ class TestCaptureManager: @pytest.mark.parametrize("method", ["fd", "sys"]) -def test_capturing_unicode(testdir, method): +def test_capturing_unicode(pytester: Pytester, method: str) -> None: obj = "'b\u00f6y'" - testdir.makepyfile( + pytester.makepyfile( """\ # taken from issue 227 from nosetests def test_unicode(): @@ -108,24 +110,24 @@ def test_capturing_unicode(testdir, method): """ % obj ) - result = testdir.runpytest("--capture=%s" % method) + result = pytester.runpytest("--capture=%s" % method) result.stdout.fnmatch_lines(["*1 passed*"]) @pytest.mark.parametrize("method", ["fd", "sys"]) -def test_capturing_bytes_in_utf8_encoding(testdir, method): - testdir.makepyfile( +def test_capturing_bytes_in_utf8_encoding(pytester: Pytester, method: str) -> None: + pytester.makepyfile( """\ def test_unicode(): print('b\\u00f6y') """ ) - result = testdir.runpytest("--capture=%s" % method) + result = pytester.runpytest("--capture=%s" % method) result.stdout.fnmatch_lines(["*1 passed*"]) -def test_collect_capturing(testdir): - p = testdir.makepyfile( +def test_collect_capturing(pytester: Pytester) -> None: + p = pytester.makepyfile( """ import sys @@ -134,7 +136,7 @@ def test_collect_capturing(testdir): import xyz42123 """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "*Captured stdout*", @@ -146,8 +148,8 @@ def test_collect_capturing(testdir): class TestPerTestCapturing: - def test_capture_and_fixtures(self, testdir): - p = testdir.makepyfile( + def test_capture_and_fixtures(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ def setup_module(mod): print("setup module") @@ -161,7 +163,7 @@ class TestPerTestCapturing: assert 0 """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "setup module*", @@ -173,8 +175,8 @@ class TestPerTestCapturing: ) @pytest.mark.xfail(reason="unimplemented feature") - def test_capture_scope_cache(self, testdir): - p = testdir.makepyfile( + def test_capture_scope_cache(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ import sys def setup_module(func): @@ -188,7 +190,7 @@ class TestPerTestCapturing: print("in teardown") """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "*test_func():*", @@ -200,8 +202,8 @@ class TestPerTestCapturing: ] ) - def test_no_carry_over(self, testdir): - p = testdir.makepyfile( + def test_no_carry_over(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ def test_func1(): print("in func1") @@ -210,13 +212,13 @@ class TestPerTestCapturing: assert 0 """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) s = result.stdout.str() assert "in func1" not in s assert "in func2" in s - def test_teardown_capturing(self, testdir): - p = testdir.makepyfile( + def test_teardown_capturing(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ def setup_function(function): print("setup func1") @@ -228,7 +230,7 @@ class TestPerTestCapturing: pass """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "*teardown_function*", @@ -240,8 +242,8 @@ class TestPerTestCapturing: ] ) - def test_teardown_capturing_final(self, testdir): - p = testdir.makepyfile( + def test_teardown_capturing_final(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ def teardown_module(mod): print("teardown module") @@ -250,7 +252,7 @@ class TestPerTestCapturing: pass """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "*def teardown_module(mod):*", @@ -260,8 +262,8 @@ class TestPerTestCapturing: ] ) - def test_capturing_outerr(self, testdir): - p1 = testdir.makepyfile( + def test_capturing_outerr(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( """\ import sys def test_capturing(): @@ -273,7 +275,7 @@ class TestPerTestCapturing: raise ValueError """ ) - result = testdir.runpytest(p1) + result = pytester.runpytest(p1) result.stdout.fnmatch_lines( [ "*test_capturing_outerr.py .F*", @@ -289,8 +291,8 @@ class TestPerTestCapturing: class TestLoggingInteraction: - def test_logging_stream_ownership(self, testdir): - p = testdir.makepyfile( + def test_logging_stream_ownership(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ def test_logging(): import logging @@ -300,11 +302,11 @@ class TestLoggingInteraction: stream.close() # to free memory/release resources """ ) - result = testdir.runpytest_subprocess(p) + result = pytester.runpytest_subprocess(p) assert result.stderr.str().find("atexit") == -1 - def test_logging_and_immediate_setupteardown(self, testdir): - p = testdir.makepyfile( + def test_logging_and_immediate_setupteardown(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ import logging def setup_function(function): @@ -321,7 +323,7 @@ class TestLoggingInteraction: ) for optargs in (("--capture=sys",), ("--capture=fd",)): print(optargs) - result = testdir.runpytest_subprocess(p, *optargs) + result = pytester.runpytest_subprocess(p, *optargs) s = result.stdout.str() result.stdout.fnmatch_lines( ["*WARN*hello3", "*WARN*hello1", "*WARN*hello2"] # errors show first! @@ -329,8 +331,8 @@ class TestLoggingInteraction: # verify proper termination assert "closed" not in s - def test_logging_and_crossscope_fixtures(self, testdir): - p = testdir.makepyfile( + def test_logging_and_crossscope_fixtures(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ import logging def setup_module(function): @@ -347,7 +349,7 @@ class TestLoggingInteraction: ) for optargs in (("--capture=sys",), ("--capture=fd",)): print(optargs) - result = testdir.runpytest_subprocess(p, *optargs) + result = pytester.runpytest_subprocess(p, *optargs) s = result.stdout.str() result.stdout.fnmatch_lines( ["*WARN*hello3", "*WARN*hello1", "*WARN*hello2"] # errors come first @@ -355,8 +357,8 @@ class TestLoggingInteraction: # verify proper termination assert "closed" not in s - def test_conftestlogging_is_shown(self, testdir): - testdir.makeconftest( + def test_conftestlogging_is_shown(self, pytester: Pytester) -> None: + pytester.makeconftest( """\ import logging logging.basicConfig() @@ -364,20 +366,20 @@ class TestLoggingInteraction: """ ) # make sure that logging is still captured in tests - result = testdir.runpytest_subprocess("-s", "-p", "no:capturelog") + result = pytester.runpytest_subprocess("-s", "-p", "no:capturelog") assert result.ret == ExitCode.NO_TESTS_COLLECTED result.stderr.fnmatch_lines(["WARNING*hello435*"]) assert "operation on closed file" not in result.stderr.str() - def test_conftestlogging_and_test_logging(self, testdir): - testdir.makeconftest( + def test_conftestlogging_and_test_logging(self, pytester: Pytester) -> None: + pytester.makeconftest( """\ import logging logging.basicConfig() """ ) # make sure that logging is still captured in tests - p = testdir.makepyfile( + p = pytester.makepyfile( """\ def test_hello(): import logging @@ -385,14 +387,14 @@ class TestLoggingInteraction: assert 0 """ ) - result = testdir.runpytest_subprocess(p, "-p", "no:capturelog") + result = pytester.runpytest_subprocess(p, "-p", "no:capturelog") assert result.ret != 0 result.stdout.fnmatch_lines(["WARNING*hello433*"]) assert "something" not in result.stderr.str() assert "operation on closed file" not in result.stderr.str() - def test_logging_after_cap_stopped(self, testdir): - testdir.makeconftest( + def test_logging_after_cap_stopped(self, pytester: Pytester) -> None: + pytester.makeconftest( """\ import pytest import logging @@ -406,7 +408,7 @@ class TestLoggingInteraction: """ ) # make sure that logging is still captured in tests - p = testdir.makepyfile( + p = pytester.makepyfile( """\ def test_hello(log_on_teardown): import logging @@ -415,7 +417,7 @@ class TestLoggingInteraction: raise KeyboardInterrupt() """ ) - result = testdir.runpytest_subprocess(p, "--log-cli-level", "info") + result = pytester.runpytest_subprocess(p, "--log-cli-level", "info") assert result.ret != 0 result.stdout.fnmatch_lines( ["*WARNING*hello433*", "*WARNING*Logging on teardown*"] @@ -428,8 +430,8 @@ class TestLoggingInteraction: class TestCaptureFixture: @pytest.mark.parametrize("opt", [[], ["-s"]]) - def test_std_functional(self, testdir, opt): - reprec = testdir.inline_runsource( + def test_std_functional(self, pytester: Pytester, opt) -> None: + reprec = pytester.inline_runsource( """\ def test_hello(capsys): print(42) @@ -440,8 +442,8 @@ class TestCaptureFixture: ) reprec.assertoutcome(passed=1) - def test_capsyscapfd(self, testdir): - p = testdir.makepyfile( + def test_capsyscapfd(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ def test_one(capsys, capfd): pass @@ -449,7 +451,7 @@ class TestCaptureFixture: pass """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( [ "*ERROR*setup*test_one*", @@ -460,11 +462,11 @@ class TestCaptureFixture: ] ) - def test_capturing_getfixturevalue(self, testdir): + def test_capturing_getfixturevalue(self, pytester: Pytester) -> None: """Test that asking for "capfd" and "capsys" using request.getfixturevalue in the same test is an error. """ - testdir.makepyfile( + pytester.makepyfile( """\ def test_one(capsys, request): request.getfixturevalue("capfd") @@ -472,7 +474,7 @@ class TestCaptureFixture: request.getfixturevalue("capsys") """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*test_one*", @@ -483,21 +485,23 @@ class TestCaptureFixture: ] ) - def test_capsyscapfdbinary(self, testdir): - p = testdir.makepyfile( + def test_capsyscapfdbinary(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ def test_one(capsys, capfdbinary): pass """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines( ["*ERROR*setup*test_one*", "E*capfdbinary*capsys*same*time*", "*1 error*"] ) @pytest.mark.parametrize("method", ["sys", "fd"]) - def test_capture_is_represented_on_failure_issue128(self, testdir, method): - p = testdir.makepyfile( + def test_capture_is_represented_on_failure_issue128( + self, pytester: Pytester, method + ) -> None: + p = pytester.makepyfile( """\ def test_hello(cap{}): print("xxx42xxx") @@ -506,11 +510,11 @@ class TestCaptureFixture: method ) ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines(["xxx42xxx"]) - def test_stdfd_functional(self, testdir): - reprec = testdir.inline_runsource( + def test_stdfd_functional(self, pytester: Pytester) -> None: + reprec = pytester.inline_runsource( """\ def test_hello(capfd): import os @@ -523,13 +527,13 @@ class TestCaptureFixture: reprec.assertoutcome(passed=1) @pytest.mark.parametrize("nl", ("\n", "\r\n", "\r")) - def test_cafd_preserves_newlines(self, capfd, nl): + def test_cafd_preserves_newlines(self, capfd, nl) -> None: print("test", end=nl) out, err = capfd.readouterr() assert out.endswith(nl) - def test_capfdbinary(self, testdir): - reprec = testdir.inline_runsource( + def test_capfdbinary(self, pytester: Pytester) -> None: + reprec = pytester.inline_runsource( """\ def test_hello(capfdbinary): import os @@ -542,8 +546,8 @@ class TestCaptureFixture: ) reprec.assertoutcome(passed=1) - def test_capsysbinary(self, testdir): - p1 = testdir.makepyfile( + def test_capsysbinary(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( r""" def test_hello(capsysbinary): import sys @@ -567,7 +571,7 @@ class TestCaptureFixture: print("stderr after", file=sys.stderr) """ ) - result = testdir.runpytest(str(p1), "-rA") + result = pytester.runpytest(str(p1), "-rA") result.stdout.fnmatch_lines( [ "*- Captured stdout call -*", @@ -578,18 +582,18 @@ class TestCaptureFixture: ] ) - def test_partial_setup_failure(self, testdir): - p = testdir.makepyfile( + def test_partial_setup_failure(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ def test_hello(capsys, missingarg): pass """ ) - result = testdir.runpytest(p) + result = pytester.runpytest(p) result.stdout.fnmatch_lines(["*test_partial_setup_failure*", "*1 error*"]) - def test_keyboardinterrupt_disables_capturing(self, testdir): - p = testdir.makepyfile( + def test_keyboardinterrupt_disables_capturing(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """\ def test_hello(capfd): import os @@ -597,26 +601,28 @@ class TestCaptureFixture: raise KeyboardInterrupt() """ ) - result = testdir.runpytest_subprocess(p) + result = pytester.runpytest_subprocess(p) result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) assert result.ret == 2 - def test_capture_and_logging(self, testdir): + def test_capture_and_logging(self, pytester: Pytester) -> None: """#14""" - p = testdir.makepyfile( + p = pytester.makepyfile( """\ import logging def test_log(capsys): logging.error('x') """ ) - result = testdir.runpytest_subprocess(p) + result = pytester.runpytest_subprocess(p) assert "closed" not in result.stderr.str() @pytest.mark.parametrize("fixture", ["capsys", "capfd"]) @pytest.mark.parametrize("no_capture", [True, False]) - def test_disabled_capture_fixture(self, testdir, fixture, no_capture): - testdir.makepyfile( + def test_disabled_capture_fixture( + self, pytester: Pytester, fixture: str, no_capture: bool + ) -> None: + pytester.makepyfile( """\ def test_disabled({fixture}): print('captured before') @@ -632,7 +638,7 @@ class TestCaptureFixture: ) ) args = ("-s",) if no_capture else () - result = testdir.runpytest_subprocess(*args) + result = pytester.runpytest_subprocess(*args) result.stdout.fnmatch_lines(["*while capture is disabled*", "*= 2 passed in *"]) result.stdout.no_fnmatch_line("*captured before*") result.stdout.no_fnmatch_line("*captured after*") @@ -641,12 +647,12 @@ class TestCaptureFixture: else: result.stdout.no_fnmatch_line("*test_normal executed*") - def test_disabled_capture_fixture_twice(self, testdir: Testdir) -> None: + def test_disabled_capture_fixture_twice(self, pytester: Pytester) -> None: """Test that an inner disabled() exit doesn't undo an outer disabled(). Issue #7148. """ - testdir.makepyfile( + pytester.makepyfile( """ def test_disabled(capfd): print('captured before') @@ -659,7 +665,7 @@ class TestCaptureFixture: assert capfd.readouterr() == ('captured before\\ncaptured after\\n', '') """ ) - result = testdir.runpytest_subprocess() + result = pytester.runpytest_subprocess() result.stdout.fnmatch_lines( [ "*while capture is disabled 1", @@ -670,10 +676,10 @@ class TestCaptureFixture: ) @pytest.mark.parametrize("fixture", ["capsys", "capfd"]) - def test_fixture_use_by_other_fixtures(self, testdir, fixture): + def test_fixture_use_by_other_fixtures(self, pytester: Pytester, fixture) -> None: """Ensure that capsys and capfd can be used by other fixtures during setup and teardown.""" - testdir.makepyfile( + pytester.makepyfile( """\ import sys import pytest @@ -700,15 +706,17 @@ class TestCaptureFixture: fixture=fixture ) ) - result = testdir.runpytest_subprocess() + result = pytester.runpytest_subprocess() result.stdout.fnmatch_lines(["*1 passed*"]) result.stdout.no_fnmatch_line("*stdout contents begin*") result.stdout.no_fnmatch_line("*stderr contents begin*") @pytest.mark.parametrize("cap", ["capsys", "capfd"]) - def test_fixture_use_by_other_fixtures_teardown(self, testdir, cap): + def test_fixture_use_by_other_fixtures_teardown( + self, pytester: Pytester, cap + ) -> None: """Ensure we can access setup and teardown buffers from teardown when using capsys/capfd (##3033)""" - testdir.makepyfile( + pytester.makepyfile( """\ import sys import pytest @@ -730,13 +738,13 @@ class TestCaptureFixture: cap=cap ) ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(passed=1) -def test_setup_failure_does_not_kill_capturing(testdir): - sub1 = testdir.mkpydir("sub1") - sub1.join("conftest.py").write( +def test_setup_failure_does_not_kill_capturing(pytester: Pytester) -> None: + sub1 = pytester.mkpydir("sub1") + sub1.joinpath("conftest.py").write_text( textwrap.dedent( """\ def pytest_runtest_setup(item): @@ -744,26 +752,26 @@ def test_setup_failure_does_not_kill_capturing(testdir): """ ) ) - sub1.join("test_mod.py").write("def test_func1(): pass") - result = testdir.runpytest(testdir.tmpdir, "--traceconfig") + sub1.joinpath("test_mod.py").write_text("def test_func1(): pass") + result = pytester.runpytest(pytester.path, "--traceconfig") result.stdout.fnmatch_lines(["*ValueError(42)*", "*1 error*"]) -def test_capture_conftest_runtest_setup(testdir): - testdir.makeconftest( +def test_capture_conftest_runtest_setup(pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_runtest_setup(): print("hello19") """ ) - testdir.makepyfile("def test_func(): pass") - result = testdir.runpytest() + pytester.makepyfile("def test_func(): pass") + result = pytester.runpytest() assert result.ret == 0 result.stdout.no_fnmatch_line("*hello19*") -def test_capture_badoutput_issue412(testdir): - testdir.makepyfile( +def test_capture_badoutput_issue412(pytester: Pytester) -> None: + pytester.makepyfile( """ import os @@ -773,7 +781,7 @@ def test_capture_badoutput_issue412(testdir): assert 0 """ ) - result = testdir.runpytest("--capture=fd") + result = pytester.runpytest("--capture=fd") result.stdout.fnmatch_lines( """ *def test_func* @@ -784,21 +792,21 @@ def test_capture_badoutput_issue412(testdir): ) -def test_capture_early_option_parsing(testdir): - testdir.makeconftest( +def test_capture_early_option_parsing(pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_runtest_setup(): print("hello19") """ ) - testdir.makepyfile("def test_func(): pass") - result = testdir.runpytest("-vs") + pytester.makepyfile("def test_func(): pass") + result = pytester.runpytest("-vs") assert result.ret == 0 assert "hello19" in result.stdout.str() -def test_capture_binary_output(testdir): - testdir.makepyfile( +def test_capture_binary_output(pytester: Pytester) -> None: + pytester.makepyfile( r""" import pytest @@ -814,13 +822,13 @@ def test_capture_binary_output(testdir): test_foo() """ ) - result = testdir.runpytest("--assert=plain") + result = pytester.runpytest("--assert=plain") result.assert_outcomes(passed=2) -def test_error_during_readouterr(testdir): +def test_error_during_readouterr(pytester: Pytester) -> None: """Make sure we suspend capturing if errors occur during readouterr""" - testdir.makepyfile( + pytester.makepyfile( pytest_xyz=""" from _pytest.capture import FDCapture @@ -831,26 +839,26 @@ def test_error_during_readouterr(testdir): FDCapture.snap = bad_snap """ ) - result = testdir.runpytest_subprocess("-p", "pytest_xyz", "--version") + result = pytester.runpytest_subprocess("-p", "pytest_xyz", "--version") result.stderr.fnmatch_lines( ["*in bad_snap", " raise Exception('boom')", "Exception: boom"] ) class TestCaptureIO: - def test_text(self): + def test_text(self) -> None: f = capture.CaptureIO() f.write("hello") s = f.getvalue() assert s == "hello" f.close() - def test_unicode_and_str_mixture(self): + def test_unicode_and_str_mixture(self) -> None: f = capture.CaptureIO() f.write("\u00f6") pytest.raises(TypeError, f.write, b"hello") - def test_write_bytes_to_buffer(self): + def test_write_bytes_to_buffer(self) -> None: """In python3, stdout / stderr are text io wrappers (exposing a buffer property of the underlying bytestream). See issue #1407 """ @@ -860,7 +868,7 @@ class TestCaptureIO: class TestTeeCaptureIO(TestCaptureIO): - def test_text(self): + def test_text(self) -> None: sio = io.StringIO() f = capture.TeeCaptureIO(sio) f.write("hello") @@ -871,14 +879,14 @@ class TestTeeCaptureIO(TestCaptureIO): f.close() sio.close() - def test_unicode_and_str_mixture(self): + def test_unicode_and_str_mixture(self) -> None: sio = io.StringIO() f = capture.TeeCaptureIO(sio) f.write("\u00f6") pytest.raises(TypeError, f.write, b"hello") -def test_dontreadfrominput(): +def test_dontreadfrominput() -> None: from _pytest.capture import DontReadFromInput f = DontReadFromInput() @@ -923,8 +931,8 @@ def test_captureresult() -> None: @pytest.fixture -def tmpfile(testdir) -> Generator[BinaryIO, None, None]: - f = testdir.makepyfile("").open("wb+") +def tmpfile(pytester: Pytester) -> Generator[BinaryIO, None, None]: + f = pytester.makepyfile("").open("wb+") yield f if not f.closed: f.close() @@ -946,7 +954,7 @@ def lsof_check(): class TestFDCapture: - def test_simple(self, tmpfile): + def test_simple(self, tmpfile: BinaryIO) -> None: fd = tmpfile.fileno() cap = capture.FDCapture(fd) data = b"hello" @@ -960,22 +968,22 @@ class TestFDCapture: cap.done() assert s == "hello" - def test_simple_many(self, tmpfile): + def test_simple_many(self, tmpfile: BinaryIO) -> None: for i in range(10): self.test_simple(tmpfile) - def test_simple_many_check_open_files(self, testdir): + def test_simple_many_check_open_files(self, pytester: Pytester) -> None: with lsof_check(): - with testdir.makepyfile("").open("wb+") as tmpfile: + with pytester.makepyfile("").open("wb+") as tmpfile: self.test_simple_many(tmpfile) - def test_simple_fail_second_start(self, tmpfile): + def test_simple_fail_second_start(self, tmpfile: BinaryIO) -> None: fd = tmpfile.fileno() cap = capture.FDCapture(fd) cap.done() pytest.raises(AssertionError, cap.start) - def test_stderr(self): + def test_stderr(self) -> None: cap = capture.FDCapture(2) cap.start() print("hello", file=sys.stderr) @@ -983,14 +991,14 @@ class TestFDCapture: cap.done() assert s == "hello\n" - def test_stdin(self): + def test_stdin(self) -> None: cap = capture.FDCapture(0) cap.start() x = os.read(0, 100).strip() cap.done() assert x == b"" - def test_writeorg(self, tmpfile): + def test_writeorg(self, tmpfile: BinaryIO) -> None: data1, data2 = b"foo", b"bar" cap = capture.FDCapture(tmpfile.fileno()) cap.start() @@ -1004,7 +1012,7 @@ class TestFDCapture: stmp = stmp_file.read() assert stmp == data2 - def test_simple_resume_suspend(self): + def test_simple_resume_suspend(self) -> None: with saved_fd(1): cap = capture.FDCapture(1) cap.start() @@ -1038,7 +1046,7 @@ class TestFDCapture: ) ) - def test_capfd_sys_stdout_mode(self, capfd): + def test_capfd_sys_stdout_mode(self, capfd) -> None: assert "b" not in sys.stdout.mode @@ -1064,7 +1072,7 @@ class TestStdCapture: finally: cap.stop_capturing() - def test_capturing_done_simple(self): + def test_capturing_done_simple(self) -> None: with self.getcapture() as cap: sys.stdout.write("hello") sys.stderr.write("world") @@ -1072,7 +1080,7 @@ class TestStdCapture: assert out == "hello" assert err == "world" - def test_capturing_reset_simple(self): + def test_capturing_reset_simple(self) -> None: with self.getcapture() as cap: print("hello world") sys.stderr.write("hello error\n") @@ -1080,7 +1088,7 @@ class TestStdCapture: assert out == "hello world\n" assert err == "hello error\n" - def test_capturing_readouterr(self): + def test_capturing_readouterr(self) -> None: with self.getcapture() as cap: print("hello world") sys.stderr.write("hello error\n") @@ -1091,7 +1099,7 @@ class TestStdCapture: out, err = cap.readouterr() assert err == "error2" - def test_capture_results_accessible_by_attribute(self): + def test_capture_results_accessible_by_attribute(self) -> None: with self.getcapture() as cap: sys.stdout.write("hello") sys.stderr.write("world") @@ -1099,13 +1107,13 @@ class TestStdCapture: assert capture_result.out == "hello" assert capture_result.err == "world" - def test_capturing_readouterr_unicode(self): + def test_capturing_readouterr_unicode(self) -> None: with self.getcapture() as cap: print("hxąć") out, err = cap.readouterr() assert out == "hxąć\n" - def test_reset_twice_error(self): + def test_reset_twice_error(self) -> None: with self.getcapture() as cap: print("hello") out, err = cap.readouterr() @@ -1113,7 +1121,7 @@ class TestStdCapture: assert out == "hello\n" assert not err - def test_capturing_modify_sysouterr_in_between(self): + def test_capturing_modify_sysouterr_in_between(self) -> None: oldout = sys.stdout olderr = sys.stderr with self.getcapture() as cap: @@ -1129,7 +1137,7 @@ class TestStdCapture: assert sys.stdout == oldout assert sys.stderr == olderr - def test_capturing_error_recursive(self): + def test_capturing_error_recursive(self) -> None: with self.getcapture() as cap1: print("cap1") with self.getcapture() as cap2: @@ -1139,7 +1147,7 @@ class TestStdCapture: assert out1 == "cap1\n" assert out2 == "cap2\n" - def test_just_out_capture(self): + def test_just_out_capture(self) -> None: with self.getcapture(out=True, err=False) as cap: sys.stdout.write("hello") sys.stderr.write("world") @@ -1147,7 +1155,7 @@ class TestStdCapture: assert out == "hello" assert not err - def test_just_err_capture(self): + def test_just_err_capture(self) -> None: with self.getcapture(out=False, err=True) as cap: sys.stdout.write("hello") sys.stderr.write("world") @@ -1155,14 +1163,14 @@ class TestStdCapture: assert err == "world" assert not out - def test_stdin_restored(self): + def test_stdin_restored(self) -> None: old = sys.stdin with self.getcapture(in_=True): newstdin = sys.stdin assert newstdin != sys.stdin assert sys.stdin is old - def test_stdin_nulled_by_default(self): + def test_stdin_nulled_by_default(self) -> None: print("XXX this test may well hang instead of crashing") print("XXX which indicates an error in the underlying capturing") print("XXX mechanisms") @@ -1173,7 +1181,7 @@ class TestStdCapture: class TestTeeStdCapture(TestStdCapture): captureclass = staticmethod(TeeStdCapture) - def test_capturing_error_recursive(self): + def test_capturing_error_recursive(self) -> None: r"""For TeeStdCapture since we passthrough stderr/stdout, cap1 should get all output, while cap2 should only get "cap2\n".""" @@ -1190,8 +1198,8 @@ class TestTeeStdCapture(TestStdCapture): class TestStdCaptureFD(TestStdCapture): captureclass = staticmethod(StdCaptureFD) - def test_simple_only_fd(self, testdir): - testdir.makepyfile( + def test_simple_only_fd(self, pytester: Pytester) -> None: + pytester.makepyfile( """\ import os def test_x(): @@ -1199,7 +1207,7 @@ class TestStdCaptureFD(TestStdCapture): assert 0 """ ) - result = testdir.runpytest_subprocess() + result = pytester.runpytest_subprocess() result.stdout.fnmatch_lines( """ *test_x* @@ -1231,8 +1239,8 @@ class TestStdCaptureFD(TestStdCapture): class TestStdCaptureFDinvalidFD: - def test_stdcapture_fd_invalid_fd(self, testdir): - testdir.makepyfile( + def test_stdcapture_fd_invalid_fd(self, pytester: Pytester) -> None: + pytester.makepyfile( """ import os from fnmatch import fnmatch @@ -1270,11 +1278,11 @@ class TestStdCaptureFDinvalidFD: cap.stop_capturing() """ ) - result = testdir.runpytest_subprocess("--capture=fd") + result = pytester.runpytest_subprocess("--capture=fd") assert result.ret == 0 assert result.parseoutcomes()["passed"] == 3 - def test_fdcapture_invalid_fd_with_fd_reuse(self, testdir): + def test_fdcapture_invalid_fd_with_fd_reuse(self, pytester: Pytester) -> None: with saved_fd(1): os.close(1) cap = capture.FDCaptureBinary(1) @@ -1289,7 +1297,7 @@ class TestStdCaptureFDinvalidFD: with pytest.raises(OSError): os.write(1, b"done") - def test_fdcapture_invalid_fd_without_fd_reuse(self, testdir): + def test_fdcapture_invalid_fd_without_fd_reuse(self, pytester: Pytester) -> None: with saved_fd(1), saved_fd(2): os.close(1) os.close(2) @@ -1306,12 +1314,14 @@ class TestStdCaptureFDinvalidFD: os.write(2, b"done") -def test_capture_not_started_but_reset(): +def test_capture_not_started_but_reset() -> None: capsys = StdCapture() capsys.stop_capturing() -def test_using_capsys_fixture_works_with_sys_stdout_encoding(capsys): +def test_using_capsys_fixture_works_with_sys_stdout_encoding( + capsys: CaptureFixture[str], +) -> None: test_text = "test text" print(test_text.encode(sys.stdout.encoding, "replace")) @@ -1320,7 +1330,7 @@ def test_using_capsys_fixture_works_with_sys_stdout_encoding(capsys): assert err == "" -def test_capsys_results_accessible_by_attribute(capsys): +def test_capsys_results_accessible_by_attribute(capsys: CaptureFixture[str]) -> None: sys.stdout.write("spam") sys.stderr.write("eggs") capture_result = capsys.readouterr() @@ -1340,8 +1350,8 @@ def test_fdcapture_tmpfile_remains_the_same() -> None: assert capfile2 == capfile -def test_close_and_capture_again(testdir): - testdir.makepyfile( +def test_close_and_capture_again(pytester: Pytester) -> None: + pytester.makepyfile( """ import os def test_close(): @@ -1351,7 +1361,7 @@ def test_close_and_capture_again(testdir): assert 0 """ ) - result = testdir.runpytest_subprocess() + result = pytester.runpytest_subprocess() result.stdout.fnmatch_lines( """ *test_capture_again* @@ -1365,9 +1375,9 @@ def test_close_and_capture_again(testdir): @pytest.mark.parametrize( "method", ["SysCapture(2)", "SysCapture(2, tee=True)", "FDCapture(2)"] ) -def test_capturing_and_logging_fundamentals(testdir, method: str) -> None: +def test_capturing_and_logging_fundamentals(pytester: Pytester, method: str) -> None: # here we check a fundamental feature - p = testdir.makepyfile( + p = pytester.makepyfile( """ import sys, os import py, logging @@ -1392,7 +1402,7 @@ def test_capturing_and_logging_fundamentals(testdir, method: str) -> None: """ % (method,) ) - result = testdir.runpython(p) + result = pytester.runpython(p) result.stdout.fnmatch_lines( """ suspend, captured*hello1* @@ -1407,8 +1417,8 @@ def test_capturing_and_logging_fundamentals(testdir, method: str) -> None: assert "atexit" not in result.stderr.str() -def test_error_attribute_issue555(testdir): - testdir.makepyfile( +def test_error_attribute_issue555(pytester: Pytester) -> None: + pytester.makepyfile( """ import sys def test_capattr(): @@ -1416,7 +1426,7 @@ def test_error_attribute_issue555(testdir): assert sys.stderr.errors == "replace" """ ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(passed=1) @@ -1438,8 +1448,8 @@ def test_py36_windowsconsoleio_workaround_non_standard_streams() -> None: _py36_windowsconsoleio_workaround(stream) -def test_dontreadfrominput_has_encoding(testdir): - testdir.makepyfile( +def test_dontreadfrominput_has_encoding(pytester: Pytester) -> None: + pytester.makepyfile( """ import sys def test_capattr(): @@ -1448,12 +1458,14 @@ def test_dontreadfrominput_has_encoding(testdir): assert sys.stderr.encoding """ ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(passed=1) -def test_crash_on_closing_tmpfile_py27(testdir): - p = testdir.makepyfile( +def test_crash_on_closing_tmpfile_py27( + pytester: Pytester, monkeypatch: MonkeyPatch +) -> None: + p = pytester.makepyfile( """ import threading import sys @@ -1480,19 +1492,19 @@ def test_crash_on_closing_tmpfile_py27(testdir): """ ) # Do not consider plugins like hypothesis, which might output to stderr. - testdir.monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1") - result = testdir.runpytest_subprocess(str(p)) + monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1") + result = pytester.runpytest_subprocess(str(p)) assert result.ret == 0 assert result.stderr.str() == "" result.stdout.no_fnmatch_line("*OSError*") -def test_global_capture_with_live_logging(testdir): +def test_global_capture_with_live_logging(pytester: Pytester) -> None: # Issue 3819 # capture should work with live cli logging # Teardown report seems to have the capture for the whole process (setup, capture, teardown) - testdir.makeconftest( + pytester.makeconftest( """ def pytest_runtest_logreport(report): if "test_global" in report.nodeid: @@ -1504,7 +1516,7 @@ def test_global_capture_with_live_logging(testdir): """ ) - testdir.makepyfile( + pytester.makepyfile( """ import logging import sys @@ -1526,7 +1538,7 @@ def test_global_capture_with_live_logging(testdir): print("end test") """ ) - result = testdir.runpytest_subprocess("--log-cli-level=INFO") + result = pytester.runpytest_subprocess("--log-cli-level=INFO") assert result.ret == 0 with open("caplog") as f: @@ -1546,11 +1558,13 @@ def test_global_capture_with_live_logging(testdir): @pytest.mark.parametrize("capture_fixture", ["capsys", "capfd"]) -def test_capture_with_live_logging(testdir, capture_fixture): +def test_capture_with_live_logging( + pytester: Pytester, capture_fixture: CaptureFixture[str] +) -> None: # Issue 3819 # capture should work with live cli logging - testdir.makepyfile( + pytester.makepyfile( """ import logging import sys @@ -1575,21 +1589,21 @@ def test_capture_with_live_logging(testdir, capture_fixture): ) ) - result = testdir.runpytest_subprocess("--log-cli-level=INFO") + result = pytester.runpytest_subprocess("--log-cli-level=INFO") assert result.ret == 0 -def test_typeerror_encodedfile_write(testdir): +def test_typeerror_encodedfile_write(pytester: Pytester) -> None: """It should behave the same with and without output capturing (#4861).""" - p = testdir.makepyfile( + p = pytester.makepyfile( """ def test_fails(): import sys sys.stdout.write(b"foo") """ ) - result_without_capture = testdir.runpytest("-s", str(p)) - result_with_capture = testdir.runpytest(str(p)) + result_without_capture = pytester.runpytest("-s", str(p)) + result_with_capture = pytester.runpytest(str(p)) assert result_with_capture.ret == result_without_capture.ret out = result_with_capture.stdout.str() @@ -1598,7 +1612,7 @@ def test_typeerror_encodedfile_write(testdir): ) -def test_stderr_write_returns_len(capsys): +def test_stderr_write_returns_len(capsys: CaptureFixture[str]) -> None: """Write on Encoded files, namely captured stderr, should return number of characters written.""" assert sys.stderr.write("Foo") == 3 @@ -1623,9 +1637,9 @@ def test__get_multicapture() -> None: ) -def test_logging_while_collecting(testdir): +def test_logging_while_collecting(pytester: Pytester) -> None: """Issue #6240: Calls to logging.xxx() during collection causes all logging calls to be duplicated to stderr""" - p = testdir.makepyfile( + p = pytester.makepyfile( """\ import logging @@ -1636,7 +1650,7 @@ def test_logging_while_collecting(testdir): assert False """ ) - result = testdir.runpytest_subprocess(p) + result = pytester.runpytest_subprocess(p) assert result.ret == ExitCode.TESTS_FAILED result.stdout.fnmatch_lines( [ diff --git a/testing/test_config.py b/testing/test_config.py index f3fa64372..b931797d4 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -8,6 +8,7 @@ from typing import List from typing import Sequence from typing import Tuple from typing import Type +from typing import Union import attr import py.path @@ -27,7 +28,7 @@ from _pytest.config.findpaths import determine_setup from _pytest.config.findpaths import get_common_ancestor from _pytest.config.findpaths import locate_config from _pytest.monkeypatch import MonkeyPatch -from _pytest.pytester import Testdir +from _pytest.pytester import Pytester class TestParseIni: @@ -36,7 +37,7 @@ class TestParseIni: ) def test_getcfg_and_config( self, - testdir: Testdir, + pytester: Pytester, tmp_path: Path, section: str, filename: str, @@ -58,12 +59,12 @@ class TestParseIni: ) _, _, cfg = locate_config([sub]) assert cfg["name"] == "value" - config = testdir.parseconfigure(str(sub)) + config = pytester.parseconfigure(str(sub)) assert config.inicfg["name"] == "value" - def test_setupcfg_uses_toolpytest_with_pytest(self, testdir): - p1 = testdir.makepyfile("def test(): pass") - testdir.makefile( + def test_setupcfg_uses_toolpytest_with_pytest(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile("def test(): pass") + pytester.makefile( ".cfg", setup=""" [tool:pytest] @@ -71,15 +72,17 @@ class TestParseIni: [pytest] testpaths=ignored """ - % p1.basename, + % p1.name, ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*, configfile: setup.cfg, *", "* 1 passed in *"]) assert result.ret == 0 - def test_append_parse_args(self, testdir, tmpdir, monkeypatch): + def test_append_parse_args( + self, pytester: Pytester, tmp_path: Path, monkeypatch: MonkeyPatch + ) -> None: monkeypatch.setenv("PYTEST_ADDOPTS", '--color no -rs --tb="short"') - tmpdir.join("pytest.ini").write( + tmp_path.joinpath("pytest.ini").write_text( textwrap.dedent( """\ [pytest] @@ -87,21 +90,21 @@ class TestParseIni: """ ) ) - config = testdir.parseconfig(tmpdir) + config = pytester.parseconfig(tmp_path) assert config.option.color == "no" assert config.option.reportchars == "s" assert config.option.tbstyle == "short" assert config.option.verbose - def test_tox_ini_wrong_version(self, testdir): - testdir.makefile( + def test_tox_ini_wrong_version(self, pytester: Pytester) -> None: + pytester.makefile( ".ini", tox=""" [pytest] minversion=999.0 """, ) - result = testdir.runpytest() + result = pytester.runpytest() assert result.ret != 0 result.stderr.fnmatch_lines( ["*tox.ini: 'minversion' requires pytest-999.0, actual pytest-*"] @@ -111,8 +114,8 @@ class TestParseIni: "section, name", [("tool:pytest", "setup.cfg"), ("pytest", "tox.ini"), ("pytest", "pytest.ini")], ) - def test_ini_names(self, testdir, name, section): - testdir.tmpdir.join(name).write( + def test_ini_names(self, pytester: Pytester, name, section) -> None: + pytester.path.joinpath(name).write_text( textwrap.dedent( """ [{section}] @@ -122,22 +125,22 @@ class TestParseIni: ) ) ) - config = testdir.parseconfig() + config = pytester.parseconfig() assert config.getini("minversion") == "1.0" - def test_pyproject_toml(self, testdir): - testdir.makepyprojecttoml( + def test_pyproject_toml(self, pytester: Pytester) -> None: + pytester.makepyprojecttoml( """ [tool.pytest.ini_options] minversion = "1.0" """ ) - config = testdir.parseconfig() + config = pytester.parseconfig() assert config.getini("minversion") == "1.0" - def test_toxini_before_lower_pytestini(self, testdir): - sub = testdir.tmpdir.mkdir("sub") - sub.join("tox.ini").write( + def test_toxini_before_lower_pytestini(self, pytester: Pytester) -> None: + sub = pytester.mkdir("sub") + sub.joinpath("tox.ini").write_text( textwrap.dedent( """ [pytest] @@ -145,7 +148,7 @@ class TestParseIni: """ ) ) - testdir.tmpdir.join("pytest.ini").write( + pytester.path.joinpath("pytest.ini").write_text( textwrap.dedent( """ [pytest] @@ -153,26 +156,26 @@ class TestParseIni: """ ) ) - config = testdir.parseconfigure(sub) + config = pytester.parseconfigure(sub) assert config.getini("minversion") == "2.0" - def test_ini_parse_error(self, testdir): - testdir.tmpdir.join("pytest.ini").write("addopts = -x") - result = testdir.runpytest() + def test_ini_parse_error(self, pytester: Pytester) -> None: + pytester.path.joinpath("pytest.ini").write_text("addopts = -x") + result = pytester.runpytest() assert result.ret != 0 result.stderr.fnmatch_lines(["ERROR: *pytest.ini:1: no section header defined"]) @pytest.mark.xfail(reason="probably not needed") - def test_confcutdir(self, testdir): - sub = testdir.mkdir("sub") - sub.chdir() - testdir.makeini( + def test_confcutdir(self, pytester: Pytester) -> None: + sub = pytester.mkdir("sub") + os.chdir(sub) + pytester.makeini( """ [pytest] addopts = --qwe """ ) - result = testdir.inline_run("--confcutdir=.") + result = pytester.inline_run("--confcutdir=.") assert result.ret == 0 @pytest.mark.parametrize( @@ -243,24 +246,29 @@ class TestParseIni: ) @pytest.mark.filterwarnings("default") def test_invalid_config_options( - self, testdir, ini_file_text, invalid_keys, warning_output, exception_text - ): - testdir.makeconftest( + self, + pytester: Pytester, + ini_file_text, + invalid_keys, + warning_output, + exception_text, + ) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("conftest_ini_key", "") """ ) - testdir.makepyfile("def test(): pass") - testdir.makeini(ini_file_text) + pytester.makepyfile("def test(): pass") + pytester.makeini(ini_file_text) - config = testdir.parseconfig() + config = pytester.parseconfig() assert sorted(config._get_unknown_ini_keys()) == sorted(invalid_keys) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(warning_output) - result = testdir.runpytest("--strict-config") + result = pytester.runpytest("--strict-config") if exception_text: result.stderr.fnmatch_lines("ERROR: " + exception_text) assert result.ret == pytest.ExitCode.USAGE_ERROR @@ -269,9 +277,9 @@ class TestParseIni: assert result.ret == pytest.ExitCode.OK @pytest.mark.filterwarnings("default") - def test_silence_unknown_key_warning(self, testdir: Testdir) -> None: + def test_silence_unknown_key_warning(self, pytester: Pytester) -> None: """Unknown config key warnings can be silenced using filterwarnings (#7620)""" - testdir.makeini( + pytester.makeini( """ [pytest] filterwarnings = @@ -279,15 +287,15 @@ class TestParseIni: foobar=1 """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.no_fnmatch_line("*PytestConfigWarning*") @pytest.mark.filterwarnings("default") def test_disable_warnings_plugin_disables_config_warnings( - self, testdir: Testdir + self, pytester: Pytester ) -> None: """Disabling 'warnings' plugin also disables config time warnings""" - testdir.makeconftest( + pytester.makeconftest( """ import pytest def pytest_configure(config): @@ -297,7 +305,7 @@ class TestParseIni: ) """ ) - result = testdir.runpytest("-pno:warnings") + result = pytester.runpytest("-pno:warnings") result.stdout.no_fnmatch_line("*PytestConfigWarning*") @pytest.mark.parametrize( @@ -371,8 +379,12 @@ class TestParseIni: ], ) def test_missing_required_plugins( - self, testdir, monkeypatch, ini_file_text, exception_text - ): + self, + pytester: Pytester, + monkeypatch: MonkeyPatch, + ini_file_text: str, + exception_text: str, + ) -> None: """Check 'required_plugins' option with various settings. This test installs a mock "myplugin-1.5" which is used in the parametrized test cases. @@ -405,26 +417,28 @@ class TestParseIni: def my_dists(): return [DummyDist(entry_points)] - testdir.makepyfile(myplugin1_module="# my plugin module") - testdir.syspathinsert() + pytester.makepyfile(myplugin1_module="# my plugin module") + pytester.syspathinsert() monkeypatch.setattr(importlib_metadata, "distributions", my_dists) - testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - testdir.makeini(ini_file_text) + pytester.makeini(ini_file_text) if exception_text: with pytest.raises(pytest.UsageError, match=exception_text): - testdir.parseconfig() + pytester.parseconfig() else: - testdir.parseconfig() + pytester.parseconfig() - def test_early_config_cmdline(self, testdir, monkeypatch): + def test_early_config_cmdline( + self, pytester: Pytester, monkeypatch: MonkeyPatch + ) -> None: """early_config contains options registered by third-party plugins. This is a regression involving pytest-cov (and possibly others) introduced in #7700. """ - testdir.makepyfile( + pytester.makepyfile( myplugin=""" def pytest_addoption(parser): parser.addoption('--foo', default=None, dest='foo') @@ -434,50 +448,52 @@ class TestParseIni: """ ) monkeypatch.setenv("PYTEST_PLUGINS", "myplugin") - testdir.syspathinsert() - result = testdir.runpytest("--foo=1") + pytester.syspathinsert() + result = pytester.runpytest("--foo=1") result.stdout.fnmatch_lines("* no tests ran in *") class TestConfigCmdlineParsing: - def test_parsing_again_fails(self, testdir): - config = testdir.parseconfig() + def test_parsing_again_fails(self, pytester: Pytester) -> None: + config = pytester.parseconfig() pytest.raises(AssertionError, lambda: config.parse([])) - def test_explicitly_specified_config_file_is_loaded(self, testdir): - testdir.makeconftest( + def test_explicitly_specified_config_file_is_loaded( + self, pytester: Pytester + ) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("custom", "") """ ) - testdir.makeini( + pytester.makeini( """ [pytest] custom = 0 """ ) - testdir.makefile( + pytester.makefile( ".ini", custom=""" [pytest] custom = 1 """, ) - config = testdir.parseconfig("-c", "custom.ini") + config = pytester.parseconfig("-c", "custom.ini") assert config.getini("custom") == "1" - testdir.makefile( + pytester.makefile( ".cfg", custom_tool_pytest_section=""" [tool:pytest] custom = 1 """, ) - config = testdir.parseconfig("-c", "custom_tool_pytest_section.cfg") + config = pytester.parseconfig("-c", "custom_tool_pytest_section.cfg") assert config.getini("custom") == "1" - testdir.makefile( + pytester.makefile( ".toml", custom=""" [tool.pytest.ini_options] @@ -486,11 +502,11 @@ class TestConfigCmdlineParsing: ] # this is here on purpose, as it makes this an invalid '.ini' file """, ) - config = testdir.parseconfig("-c", "custom.toml") + config = pytester.parseconfig("-c", "custom.toml") assert config.getini("custom") == "1" - def test_absolute_win32_path(self, testdir): - temp_ini_file = testdir.makefile( + def test_absolute_win32_path(self, pytester: Pytester) -> None: + temp_ini_file = pytester.makefile( ".ini", custom=""" [pytest] @@ -499,103 +515,103 @@ class TestConfigCmdlineParsing: ) from os.path import normpath - temp_ini_file = normpath(str(temp_ini_file)) - ret = pytest.main(["-c", temp_ini_file]) + temp_ini_file_norm = normpath(str(temp_ini_file)) + ret = pytest.main(["-c", temp_ini_file_norm]) assert ret == ExitCode.OK class TestConfigAPI: - def test_config_trace(self, testdir) -> None: - config = testdir.parseconfig() + def test_config_trace(self, pytester: Pytester) -> None: + config = pytester.parseconfig() values: List[str] = [] config.trace.root.setwriter(values.append) config.trace("hello") assert len(values) == 1 assert values[0] == "hello [config]\n" - def test_config_getoption(self, testdir): - testdir.makeconftest( + def test_config_getoption(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addoption("--hello", "-X", dest="hello") """ ) - config = testdir.parseconfig("--hello=this") + config = pytester.parseconfig("--hello=this") for x in ("hello", "--hello", "-X"): assert config.getoption(x) == "this" pytest.raises(ValueError, config.getoption, "qweqwe") - def test_config_getoption_unicode(self, testdir): - testdir.makeconftest( + def test_config_getoption_unicode(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addoption('--hello', type=str) """ ) - config = testdir.parseconfig("--hello=this") + config = pytester.parseconfig("--hello=this") assert config.getoption("hello") == "this" - def test_config_getvalueorskip(self, testdir): - config = testdir.parseconfig() + def test_config_getvalueorskip(self, pytester: Pytester) -> None: + config = pytester.parseconfig() pytest.raises(pytest.skip.Exception, config.getvalueorskip, "hello") verbose = config.getvalueorskip("verbose") assert verbose == config.option.verbose - def test_config_getvalueorskip_None(self, testdir): - testdir.makeconftest( + def test_config_getvalueorskip_None(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addoption("--hello") """ ) - config = testdir.parseconfig() + config = pytester.parseconfig() with pytest.raises(pytest.skip.Exception): config.getvalueorskip("hello") - def test_getoption(self, testdir): - config = testdir.parseconfig() + def test_getoption(self, pytester: Pytester) -> None: + config = pytester.parseconfig() with pytest.raises(ValueError): config.getvalue("x") assert config.getoption("x", 1) == 1 - def test_getconftest_pathlist(self, testdir, tmpdir): + def test_getconftest_pathlist(self, pytester: Pytester, tmpdir) -> None: somepath = tmpdir.join("x", "y", "z") p = tmpdir.join("conftest.py") p.write("pathlist = ['.', %r]" % str(somepath)) - config = testdir.parseconfigure(p) + config = pytester.parseconfigure(p) assert config._getconftest_pathlist("notexist", path=tmpdir) is None - pl = config._getconftest_pathlist("pathlist", path=tmpdir) + pl = config._getconftest_pathlist("pathlist", path=tmpdir) or [] print(pl) assert len(pl) == 2 assert pl[0] == tmpdir assert pl[1] == somepath @pytest.mark.parametrize("maybe_type", ["not passed", "None", '"string"']) - def test_addini(self, testdir, maybe_type): + def test_addini(self, pytester: Pytester, maybe_type: str) -> None: if maybe_type == "not passed": type_string = "" else: type_string = f", {maybe_type}" - testdir.makeconftest( + pytester.makeconftest( f""" def pytest_addoption(parser): parser.addini("myname", "my new ini value"{type_string}) """ ) - testdir.makeini( + pytester.makeini( """ [pytest] myname=hello """ ) - config = testdir.parseconfig() + config = pytester.parseconfig() val = config.getini("myname") assert val == "hello" pytest.raises(ValueError, config.getini, "other") - def make_conftest_for_pathlist(self, testdir): - testdir.makeconftest( + def make_conftest_for_pathlist(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("paths", "my new ini value", type="pathlist") @@ -603,36 +619,36 @@ class TestConfigAPI: """ ) - def test_addini_pathlist_ini_files(self, testdir): - self.make_conftest_for_pathlist(testdir) - p = testdir.makeini( + def test_addini_pathlist_ini_files(self, pytester: Pytester) -> None: + self.make_conftest_for_pathlist(pytester) + p = pytester.makeini( """ [pytest] paths=hello world/sub.py """ ) - self.check_config_pathlist(testdir, p) + self.check_config_pathlist(pytester, p) - def test_addini_pathlist_pyproject_toml(self, testdir): - self.make_conftest_for_pathlist(testdir) - p = testdir.makepyprojecttoml( + def test_addini_pathlist_pyproject_toml(self, pytester: Pytester) -> None: + self.make_conftest_for_pathlist(pytester) + p = pytester.makepyprojecttoml( """ [tool.pytest.ini_options] paths=["hello", "world/sub.py"] """ ) - self.check_config_pathlist(testdir, p) + self.check_config_pathlist(pytester, p) - def check_config_pathlist(self, testdir, config_path): - config = testdir.parseconfig() + def check_config_pathlist(self, pytester: Pytester, config_path: Path) -> None: + config = pytester.parseconfig() values = config.getini("paths") assert len(values) == 2 - assert values[0] == config_path.dirpath("hello") - assert values[1] == config_path.dirpath("world/sub.py") + assert values[0] == config_path.parent.joinpath("hello") + assert values[1] == config_path.parent.joinpath("world/sub.py") pytest.raises(ValueError, config.getini, "other") - def make_conftest_for_args(self, testdir): - testdir.makeconftest( + def make_conftest_for_args(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("args", "new args", type="args") @@ -640,35 +656,35 @@ class TestConfigAPI: """ ) - def test_addini_args_ini_files(self, testdir): - self.make_conftest_for_args(testdir) - testdir.makeini( + def test_addini_args_ini_files(self, pytester: Pytester) -> None: + self.make_conftest_for_args(pytester) + pytester.makeini( """ [pytest] args=123 "123 hello" "this" """ ) - self.check_config_args(testdir) + self.check_config_args(pytester) - def test_addini_args_pyproject_toml(self, testdir): - self.make_conftest_for_args(testdir) - testdir.makepyprojecttoml( + def test_addini_args_pyproject_toml(self, pytester: Pytester) -> None: + self.make_conftest_for_args(pytester) + pytester.makepyprojecttoml( """ [tool.pytest.ini_options] args = ["123", "123 hello", "this"] """ ) - self.check_config_args(testdir) + self.check_config_args(pytester) - def check_config_args(self, testdir): - config = testdir.parseconfig() + def check_config_args(self, pytester: Pytester) -> None: + config = pytester.parseconfig() values = config.getini("args") assert values == ["123", "123 hello", "this"] values = config.getini("a2") assert values == list("123") - def make_conftest_for_linelist(self, testdir): - testdir.makeconftest( + def make_conftest_for_linelist(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("xy", "", type="linelist") @@ -676,29 +692,29 @@ class TestConfigAPI: """ ) - def test_addini_linelist_ini_files(self, testdir): - self.make_conftest_for_linelist(testdir) - testdir.makeini( + def test_addini_linelist_ini_files(self, pytester: Pytester) -> None: + self.make_conftest_for_linelist(pytester) + pytester.makeini( """ [pytest] xy= 123 345 second line """ ) - self.check_config_linelist(testdir) + self.check_config_linelist(pytester) - def test_addini_linelist_pprojecttoml(self, testdir): - self.make_conftest_for_linelist(testdir) - testdir.makepyprojecttoml( + def test_addini_linelist_pprojecttoml(self, pytester: Pytester) -> None: + self.make_conftest_for_linelist(pytester) + pytester.makepyprojecttoml( """ [tool.pytest.ini_options] xy = ["123 345", "second line"] """ ) - self.check_config_linelist(testdir) + self.check_config_linelist(pytester) - def check_config_linelist(self, testdir): - config = testdir.parseconfig() + def check_config_linelist(self, pytester: Pytester) -> None: + config = pytester.parseconfig() values = config.getini("xy") assert len(values) == 2 assert values == ["123 345", "second line"] @@ -708,38 +724,40 @@ class TestConfigAPI: @pytest.mark.parametrize( "str_val, bool_val", [("True", True), ("no", False), ("no-ini", True)] ) - def test_addini_bool(self, testdir, str_val, bool_val): - testdir.makeconftest( + def test_addini_bool( + self, pytester: Pytester, str_val: str, bool_val: bool + ) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("strip", "", type="bool", default=True) """ ) if str_val != "no-ini": - testdir.makeini( + pytester.makeini( """ [pytest] strip=%s """ % str_val ) - config = testdir.parseconfig() + config = pytester.parseconfig() assert config.getini("strip") is bool_val - def test_addinivalue_line_existing(self, testdir): - testdir.makeconftest( + def test_addinivalue_line_existing(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("xy", "", type="linelist") """ ) - testdir.makeini( + pytester.makeini( """ [pytest] xy= 123 """ ) - config = testdir.parseconfig() + config = pytester.parseconfig() values = config.getini("xy") assert len(values) == 1 assert values == ["123"] @@ -748,14 +766,14 @@ class TestConfigAPI: assert len(values) == 2 assert values == ["123", "456"] - def test_addinivalue_line_new(self, testdir): - testdir.makeconftest( + def test_addinivalue_line_new(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("xy", "", type="linelist") """ ) - config = testdir.parseconfig() + config = pytester.parseconfig() assert not config.getini("xy") config.addinivalue_line("xy", "456") values = config.getini("xy") @@ -766,19 +784,17 @@ class TestConfigAPI: assert len(values) == 2 assert values == ["456", "123"] - def test_confcutdir_check_isdir(self, testdir): + def test_confcutdir_check_isdir(self, pytester: Pytester) -> None: """Give an error if --confcutdir is not a valid directory (#2078)""" exp_match = r"^--confcutdir must be a directory, given: " with pytest.raises(pytest.UsageError, match=exp_match): - testdir.parseconfig( - "--confcutdir", testdir.tmpdir.join("file").ensure(file=1) - ) + pytester.parseconfig("--confcutdir", pytester.path.joinpath("file")) with pytest.raises(pytest.UsageError, match=exp_match): - testdir.parseconfig("--confcutdir", testdir.tmpdir.join("inexistant")) - config = testdir.parseconfig( - "--confcutdir", testdir.tmpdir.join("dir").ensure(dir=1) - ) - assert config.getoption("confcutdir") == str(testdir.tmpdir.join("dir")) + pytester.parseconfig("--confcutdir", pytester.path.joinpath("inexistant")) + + p = pytester.mkdir("dir") + config = pytester.parseconfig("--confcutdir", p) + assert config.getoption("confcutdir") == str(p) @pytest.mark.parametrize( "names, expected", @@ -796,12 +812,12 @@ class TestConfigAPI: (["source/python/bar/__init__.py", "setup.py"], ["bar"]), ], ) - def test_iter_rewritable_modules(self, names, expected): + def test_iter_rewritable_modules(self, names, expected) -> None: assert list(_iter_rewritable_modules(names)) == expected class TestConfigFromdictargs: - def test_basic_behavior(self, _sys_snapshot): + def test_basic_behavior(self, _sys_snapshot) -> None: option_dict = {"verbose": 444, "foo": "bar", "capture": "no"} args = ["a", "b"] @@ -824,8 +840,12 @@ class TestConfigFromdictargs: assert config.option.verbose == 4 assert config.option.capture == "no" - def test_inifilename(self, tmpdir): - tmpdir.join("foo/bar.ini").ensure().write( + def test_inifilename(self, tmp_path: Path) -> None: + d1 = tmp_path.joinpath("foo") + d1.mkdir() + p1 = d1.joinpath("bar.ini") + p1.touch() + p1.write_text( textwrap.dedent( """\ [pytest] @@ -837,8 +857,11 @@ class TestConfigFromdictargs: inifile = "../../foo/bar.ini" option_dict = {"inifilename": inifile, "capture": "no"} - cwd = tmpdir.join("a/b") - cwd.join("pytest.ini").ensure().write( + cwd = tmp_path.joinpath("a/b") + cwd.mkdir(parents=True) + p2 = cwd.joinpath("pytest.ini") + p2.touch() + p2.write_text( textwrap.dedent( """\ [pytest] @@ -847,7 +870,8 @@ class TestConfigFromdictargs: """ ) ) - with cwd.ensure(dir=True).as_cwd(): + with MonkeyPatch.context() as mp: + mp.chdir(cwd) config = Config.fromdictargs(option_dict, ()) inipath = py.path.local(inifile) @@ -861,18 +885,20 @@ class TestConfigFromdictargs: assert config.inicfg.get("should_not_be_set") is None -def test_options_on_small_file_do_not_blow_up(testdir) -> None: +def test_options_on_small_file_do_not_blow_up(pytester: Pytester) -> None: def runfiletest(opts: Sequence[str]) -> None: - reprec = testdir.inline_run(*opts) + reprec = pytester.inline_run(*opts) passed, skipped, failed = reprec.countoutcomes() assert failed == 2 assert skipped == passed == 0 - path = testdir.makepyfile( - """ + path = str( + pytester.makepyfile( + """ def test_f1(): assert 0 def test_f2(): assert 0 """ + ) ) runfiletest([path]) @@ -887,7 +913,9 @@ def test_options_on_small_file_do_not_blow_up(testdir) -> None: runfiletest(["-v", "-v", path]) -def test_preparse_ordering_with_setuptools(testdir, monkeypatch): +def test_preparse_ordering_with_setuptools( + pytester: Pytester, monkeypatch: MonkeyPatch +) -> None: monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) class EntryPoint: @@ -909,18 +937,20 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch): return (Dist,) monkeypatch.setattr(importlib_metadata, "distributions", my_dists) - testdir.makeconftest( + pytester.makeconftest( """ pytest_plugins = "mytestplugin", """ ) monkeypatch.setenv("PYTEST_PLUGINS", "mytestplugin") - config = testdir.parseconfig() + config = pytester.parseconfig() plugin = config.pluginmanager.getplugin("mytestplugin") assert plugin.x == 42 -def test_setuptools_importerror_issue1479(testdir, monkeypatch): +def test_setuptools_importerror_issue1479( + pytester: Pytester, monkeypatch: MonkeyPatch +) -> None: monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) class DummyEntryPoint: @@ -941,10 +971,12 @@ def test_setuptools_importerror_issue1479(testdir, monkeypatch): monkeypatch.setattr(importlib_metadata, "distributions", distributions) with pytest.raises(ImportError): - testdir.parseconfig() + pytester.parseconfig() -def test_importlib_metadata_broken_distribution(testdir, monkeypatch): +def test_importlib_metadata_broken_distribution( + pytester: Pytester, monkeypatch: MonkeyPatch +) -> None: """Integration test for broken distributions with 'files' metadata being None (#5389)""" monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) @@ -965,11 +997,13 @@ def test_importlib_metadata_broken_distribution(testdir, monkeypatch): return (Distribution(),) monkeypatch.setattr(importlib_metadata, "distributions", distributions) - testdir.parseconfig() + pytester.parseconfig() @pytest.mark.parametrize("block_it", [True, False]) -def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block_it): +def test_plugin_preparse_prevents_setuptools_loading( + pytester: Pytester, monkeypatch: MonkeyPatch, block_it: bool +) -> None: monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) plugin_module_placeholder = object() @@ -992,7 +1026,7 @@ def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block monkeypatch.setattr(importlib_metadata, "distributions", distributions) args = ("-p", "no:mytestplugin") if block_it else () - config = testdir.parseconfig(*args) + config = pytester.parseconfig(*args) config.pluginmanager.import_plugin("mytestplugin") if block_it: assert "mytestplugin" not in sys.modules @@ -1006,7 +1040,12 @@ def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block @pytest.mark.parametrize( "parse_args,should_load", [(("-p", "mytestplugin"), True), ((), False)] ) -def test_disable_plugin_autoload(testdir, monkeypatch, parse_args, should_load): +def test_disable_plugin_autoload( + pytester: Pytester, + monkeypatch: MonkeyPatch, + parse_args: Union[Tuple[str, str], Tuple[()]], + should_load: bool, +) -> None: class DummyEntryPoint: project_name = name = "mytestplugin" group = "pytest11" @@ -1035,8 +1074,8 @@ def test_disable_plugin_autoload(testdir, monkeypatch, parse_args, should_load): monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1") monkeypatch.setattr(importlib_metadata, "distributions", distributions) - monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin()) - config = testdir.parseconfig(*parse_args) + monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin()) # type: ignore[misc] + config = pytester.parseconfig(*parse_args) has_loaded = config.pluginmanager.get_plugin("mytestplugin") is not None assert has_loaded == should_load if should_load: @@ -1045,9 +1084,9 @@ def test_disable_plugin_autoload(testdir, monkeypatch, parse_args, should_load): assert PseudoPlugin.attrs_used == [] -def test_plugin_loading_order(testdir): +def test_plugin_loading_order(pytester: Pytester) -> None: """Test order of plugin loading with `-p`.""" - p1 = testdir.makepyfile( + p1 = pytester.makepyfile( """ def test_terminal_plugin(request): import myplugin @@ -1066,37 +1105,37 @@ def test_plugin_loading_order(testdir): """ }, ) - testdir.syspathinsert() - result = testdir.runpytest("-p", "myplugin", str(p1)) + pytester.syspathinsert() + result = pytester.runpytest("-p", "myplugin", str(p1)) assert result.ret == 0 -def test_cmdline_processargs_simple(testdir): - testdir.makeconftest( +def test_cmdline_processargs_simple(pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_cmdline_preparse(args): args.append("-h") """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*pytest*", "*-h*"]) -def test_invalid_options_show_extra_information(testdir): +def test_invalid_options_show_extra_information(pytester: Pytester) -> None: """Display extra information when pytest exits due to unrecognized options in the command-line.""" - testdir.makeini( + pytester.makeini( """ [pytest] addopts = --invalid-option """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stderr.fnmatch_lines( [ "*error: unrecognized arguments: --invalid-option*", - "* inifile: %s*" % testdir.tmpdir.join("tox.ini"), - "* rootdir: %s*" % testdir.tmpdir, + "* inifile: %s*" % pytester.path.joinpath("tox.ini"), + "* rootdir: %s*" % pytester.path, ] ) @@ -1110,42 +1149,49 @@ def test_invalid_options_show_extra_information(testdir): ["-v", "dir2", "dir1"], ], ) -def test_consider_args_after_options_for_rootdir(testdir, args): +def test_consider_args_after_options_for_rootdir( + pytester: Pytester, args: List[str] +) -> None: """ Consider all arguments in the command-line for rootdir discovery, even if they happen to occur after an option. #949 """ # replace "dir1" and "dir2" from "args" into their real directory - root = testdir.tmpdir.mkdir("myroot") - d1 = root.mkdir("dir1") - d2 = root.mkdir("dir2") + root = pytester.mkdir("myroot") + d1 = root.joinpath("dir1") + d1.mkdir() + d2 = root.joinpath("dir2") + d2.mkdir() for i, arg in enumerate(args): if arg == "dir1": - args[i] = d1 + args[i] = str(d1) elif arg == "dir2": - args[i] = d2 - with root.as_cwd(): - result = testdir.runpytest(*args) + args[i] = str(d2) + with MonkeyPatch.context() as mp: + mp.chdir(root) + result = pytester.runpytest(*args) result.stdout.fnmatch_lines(["*rootdir: *myroot"]) -def test_toolongargs_issue224(testdir): - result = testdir.runpytest("-m", "hello" * 500) +def test_toolongargs_issue224(pytester: Pytester) -> None: + result = pytester.runpytest("-m", "hello" * 500) assert result.ret == ExitCode.NO_TESTS_COLLECTED -def test_config_in_subdirectory_colon_command_line_issue2148(testdir): +def test_config_in_subdirectory_colon_command_line_issue2148( + pytester: Pytester, +) -> None: conftest_source = """ def pytest_addoption(parser): parser.addini('foo', 'foo') """ - testdir.makefile( + pytester.makefile( ".ini", **{"pytest": "[pytest]\nfoo = root", "subdir/pytest": "[pytest]\nfoo = subdir"}, ) - testdir.makepyfile( + pytester.makepyfile( **{ "conftest": conftest_source, "subdir/conftest": conftest_source, @@ -1156,12 +1202,12 @@ def test_config_in_subdirectory_colon_command_line_issue2148(testdir): } ) - result = testdir.runpytest("subdir/test_foo.py::test_foo") + result = pytester.runpytest("subdir/test_foo.py::test_foo") assert result.ret == 0 -def test_notify_exception(testdir, capfd): - config = testdir.parseconfig() +def test_notify_exception(pytester: Pytester, capfd) -> None: + config = pytester.parseconfig() with pytest.raises(ValueError) as excinfo: raise ValueError(1) config.notify_exception(excinfo, config.option) @@ -1177,7 +1223,7 @@ def test_notify_exception(testdir, capfd): _, err = capfd.readouterr() assert not err - config = testdir.parseconfig("-p", "no:terminal") + config = pytester.parseconfig("-p", "no:terminal") with pytest.raises(ValueError) as excinfo: raise ValueError(1) config.notify_exception(excinfo, config.option) @@ -1185,9 +1231,9 @@ def test_notify_exception(testdir, capfd): assert "ValueError" in err -def test_no_terminal_discovery_error(testdir): - testdir.makepyfile("raise TypeError('oops!')") - result = testdir.runpytest("-p", "no:terminal", "--collect-only") +def test_no_terminal_discovery_error(pytester: Pytester) -> None: + pytester.makepyfile("raise TypeError('oops!')") + result = pytester.runpytest("-p", "no:terminal", "--collect-only") assert result.ret == ExitCode.INTERRUPTED @@ -1226,10 +1272,10 @@ def test_get_plugin_specs_as_list() -> None: assert _get_plugin_specs_as_list(("foo", "bar")) == ["foo", "bar"] -def test_collect_pytest_prefix_bug_integration(testdir): +def test_collect_pytest_prefix_bug_integration(pytester: Pytester) -> None: """Integration test for issue #3775""" - p = testdir.copy_example("config/collect_pytest_prefix") - result = testdir.runpytest(p) + p = pytester.copy_example("config/collect_pytest_prefix") + result = pytester.runpytest(p) result.stdout.fnmatch_lines(["* 1 passed *"]) @@ -1396,9 +1442,9 @@ class TestRootdir: class TestOverrideIniArgs: @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) - def test_override_ini_names(self, testdir, name): + def test_override_ini_names(self, pytester: Pytester, name: str) -> None: section = "[pytest]" if name != "setup.cfg" else "[tool:pytest]" - testdir.tmpdir.join(name).write( + pytester.path.joinpath(name).write_text( textwrap.dedent( """ {section} @@ -1407,40 +1453,40 @@ class TestOverrideIniArgs: ) ) ) - testdir.makeconftest( + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("custom", "")""" ) - testdir.makepyfile( + pytester.makepyfile( """ def test_pass(pytestconfig): ini_val = pytestconfig.getini("custom") print('\\ncustom_option:%s\\n' % ini_val)""" ) - result = testdir.runpytest("--override-ini", "custom=2.0", "-s") + result = pytester.runpytest("--override-ini", "custom=2.0", "-s") assert result.ret == 0 result.stdout.fnmatch_lines(["custom_option:2.0"]) - result = testdir.runpytest( + result = pytester.runpytest( "--override-ini", "custom=2.0", "--override-ini=custom=3.0", "-s" ) assert result.ret == 0 result.stdout.fnmatch_lines(["custom_option:3.0"]) - def test_override_ini_pathlist(self, testdir): - testdir.makeconftest( + def test_override_ini_pathlist(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("paths", "my new ini value", type="pathlist")""" ) - testdir.makeini( + pytester.makeini( """ [pytest] paths=blah.py""" ) - testdir.makepyfile( + pytester.makepyfile( """ import py.path def test_pathlist(pytestconfig): @@ -1449,13 +1495,13 @@ class TestOverrideIniArgs: for cpf in config_paths: print('\\nuser_path:%s' % cpf.basename)""" ) - result = testdir.runpytest( + result = pytester.runpytest( "--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s" ) result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"]) - def test_override_multiple_and_default(self, testdir): - testdir.makeconftest( + def test_override_multiple_and_default(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_addoption(parser): addini = parser.addini @@ -1464,14 +1510,14 @@ class TestOverrideIniArgs: addini("custom_option_3", "", default=False, type="bool") addini("custom_option_4", "", default=True, type="bool")""" ) - testdir.makeini( + pytester.makeini( """ [pytest] custom_option_1=custom_option_1 custom_option_2=custom_option_2 """ ) - testdir.makepyfile( + pytester.makepyfile( """ def test_multiple_options(pytestconfig): prefix = "custom_option" @@ -1480,7 +1526,7 @@ class TestOverrideIniArgs: print('\\nini%d:%s' % (x, ini_value)) """ ) - result = testdir.runpytest( + result = pytester.runpytest( "--override-ini", "custom_option_1=fulldir=/tmp/user1", "-o", @@ -1500,14 +1546,14 @@ class TestOverrideIniArgs: ] ) - def test_override_ini_usage_error_bad_style(self, testdir): - testdir.makeini( + def test_override_ini_usage_error_bad_style(self, pytester: Pytester) -> None: + pytester.makeini( """ [pytest] xdist_strict=False """ ) - result = testdir.runpytest("--override-ini", "xdist_strict", "True") + result = pytester.runpytest("--override-ini", "xdist_strict", "True") result.stderr.fnmatch_lines( [ "ERROR: -o/--override-ini expects option=value style (got: 'xdist_strict').", @@ -1515,32 +1561,38 @@ class TestOverrideIniArgs: ) @pytest.mark.parametrize("with_ini", [True, False]) - def test_override_ini_handled_asap(self, testdir, with_ini): + def test_override_ini_handled_asap( + self, pytester: Pytester, with_ini: bool + ) -> None: """-o should be handled as soon as possible and always override what's in ini files (#2238)""" if with_ini: - testdir.makeini( + pytester.makeini( """ [pytest] python_files=test_*.py """ ) - testdir.makepyfile( + pytester.makepyfile( unittest_ini_handle=""" def test(): pass """ ) - result = testdir.runpytest("--override-ini", "python_files=unittest_*.py") + result = pytester.runpytest("--override-ini", "python_files=unittest_*.py") result.stdout.fnmatch_lines(["*1 passed in*"]) - def test_addopts_before_initini(self, monkeypatch, _config_for_test, _sys_snapshot): + def test_addopts_before_initini( + self, monkeypatch: MonkeyPatch, _config_for_test, _sys_snapshot + ) -> None: cache_dir = ".custom_cache" monkeypatch.setenv("PYTEST_ADDOPTS", "-o cache_dir=%s" % cache_dir) config = _config_for_test config._preparse([], addopts=True) assert config._override_ini == ["cache_dir=%s" % cache_dir] - def test_addopts_from_env_not_concatenated(self, monkeypatch, _config_for_test): + def test_addopts_from_env_not_concatenated( + self, monkeypatch: MonkeyPatch, _config_for_test + ) -> None: """PYTEST_ADDOPTS should not take values from normal args (#4265).""" monkeypatch.setenv("PYTEST_ADDOPTS", "-o") config = _config_for_test @@ -1551,32 +1603,34 @@ class TestOverrideIniArgs: in excinfo.value.args[0] ) - def test_addopts_from_ini_not_concatenated(self, testdir): + def test_addopts_from_ini_not_concatenated(self, pytester: Pytester) -> None: """`addopts` from ini should not take values from normal args (#4265).""" - testdir.makeini( + pytester.makeini( """ [pytest] addopts=-o """ ) - result = testdir.runpytest("cache_dir=ignored") + result = pytester.runpytest("cache_dir=ignored") result.stderr.fnmatch_lines( [ "%s: error: argument -o/--override-ini: expected one argument (via addopts config)" - % (testdir.request.config._parser.optparser.prog,) + % (pytester._request.config._parser.optparser.prog,) ] ) assert result.ret == _pytest.config.ExitCode.USAGE_ERROR - def test_override_ini_does_not_contain_paths(self, _config_for_test, _sys_snapshot): + def test_override_ini_does_not_contain_paths( + self, _config_for_test, _sys_snapshot + ) -> None: """Check that -o no longer swallows all options after it (#3103)""" config = _config_for_test config._preparse(["-o", "cache_dir=/cache", "/some/test/path"]) assert config._override_ini == ["cache_dir=/cache"] - def test_multiple_override_ini_options(self, testdir): + def test_multiple_override_ini_options(self, pytester: Pytester) -> None: """Ensure a file path following a '-o' option does not generate an error (#3103)""" - testdir.makepyfile( + pytester.makepyfile( **{ "conftest.py": """ def pytest_addoption(parser): @@ -1594,19 +1648,19 @@ class TestOverrideIniArgs: """, } ) - result = testdir.runpytest("-o", "foo=1", "-o", "bar=0", "test_foo.py") + result = pytester.runpytest("-o", "foo=1", "-o", "bar=0", "test_foo.py") assert "ERROR:" not in result.stderr.str() result.stdout.fnmatch_lines(["collected 1 item", "*= 1 passed in *="]) -def test_help_via_addopts(testdir): - testdir.makeini( +def test_help_via_addopts(pytester: Pytester) -> None: + pytester.makeini( """ [pytest] addopts = --unknown-option-should-allow-for-help --help """ ) - result = testdir.runpytest() + result = pytester.runpytest() assert result.ret == 0 result.stdout.fnmatch_lines( [ @@ -1618,8 +1672,8 @@ def test_help_via_addopts(testdir): ) -def test_help_and_version_after_argument_error(testdir): - testdir.makeconftest( +def test_help_and_version_after_argument_error(pytester: Pytester) -> None: + pytester.makeconftest( """ def validate(arg): raise argparse.ArgumentTypeError("argerror") @@ -1632,13 +1686,13 @@ def test_help_and_version_after_argument_error(testdir): ) """ ) - testdir.makeini( + pytester.makeini( """ [pytest] addopts = --invalid-option-should-allow-for-help """ ) - result = testdir.runpytest("--help") + result = pytester.runpytest("--help") result.stdout.fnmatch_lines( [ "usage: *", @@ -1650,19 +1704,19 @@ def test_help_and_version_after_argument_error(testdir): [ "ERROR: usage: *", "%s: error: argument --invalid-option-should-allow-for-help: expected one argument" - % (testdir.request.config._parser.optparser.prog,), + % (pytester._request.config._parser.optparser.prog,), ] ) # Does not display full/default help. assert "to see available markers type: pytest --markers" not in result.stdout.lines assert result.ret == ExitCode.USAGE_ERROR - result = testdir.runpytest("--version") + result = pytester.runpytest("--version") result.stderr.fnmatch_lines([f"pytest {pytest.__version__}"]) assert result.ret == ExitCode.USAGE_ERROR -def test_help_formatter_uses_py_get_terminal_width(monkeypatch): +def test_help_formatter_uses_py_get_terminal_width(monkeypatch: MonkeyPatch) -> None: from _pytest.config.argparsing import DropShorterLongHelpFormatter monkeypatch.setenv("COLUMNS", "90") @@ -1677,39 +1731,39 @@ def test_help_formatter_uses_py_get_terminal_width(monkeypatch): assert formatter._width == 42 -def test_config_does_not_load_blocked_plugin_from_args(testdir): +def test_config_does_not_load_blocked_plugin_from_args(pytester: Pytester) -> None: """This tests that pytest's config setup handles "-p no:X".""" - p = testdir.makepyfile("def test(capfd): pass") - result = testdir.runpytest(str(p), "-pno:capture") + p = pytester.makepyfile("def test(capfd): pass") + result = pytester.runpytest(str(p), "-pno:capture") result.stdout.fnmatch_lines(["E fixture 'capfd' not found"]) assert result.ret == ExitCode.TESTS_FAILED - result = testdir.runpytest(str(p), "-pno:capture", "-s") + result = pytester.runpytest(str(p), "-pno:capture", "-s") result.stderr.fnmatch_lines(["*: error: unrecognized arguments: -s"]) assert result.ret == ExitCode.USAGE_ERROR -def test_invocation_args(testdir): +def test_invocation_args(pytester: Pytester) -> None: """Ensure that Config.invocation_* arguments are correctly defined""" class DummyPlugin: pass - p = testdir.makepyfile("def test(): pass") + p = pytester.makepyfile("def test(): pass") plugin = DummyPlugin() - rec = testdir.inline_run(p, "-v", plugins=[plugin]) + rec = pytester.inline_run(p, "-v", plugins=[plugin]) calls = rec.getcalls("pytest_runtest_protocol") assert len(calls) == 1 call = calls[0] config = call.item.config - assert config.invocation_params.args == (p, "-v") - assert config.invocation_params.dir == Path(str(testdir.tmpdir)) + assert config.invocation_params.args == (str(p), "-v") + assert config.invocation_params.dir == pytester.path plugins = config.invocation_params.plugins assert len(plugins) == 2 assert plugins[0] is plugin - assert type(plugins[1]).__name__ == "Collect" # installed by testdir.inline_run() + assert type(plugins[1]).__name__ == "Collect" # installed by pytester.inline_run() # args cannot be None with pytest.raises(TypeError): @@ -1724,7 +1778,7 @@ def test_invocation_args(testdir): if x not in _pytest.config.essential_plugins ], ) -def test_config_blocked_default_plugins(testdir, plugin): +def test_config_blocked_default_plugins(pytester: Pytester, plugin: str) -> None: if plugin == "debugging": # Fixed in xdist master (after 1.27.0). # https://github.com/pytest-dev/pytest-xdist/pull/422 @@ -1735,8 +1789,8 @@ def test_config_blocked_default_plugins(testdir, plugin): else: pytest.skip("does not work with xdist currently") - p = testdir.makepyfile("def test(): pass") - result = testdir.runpytest(str(p), "-pno:%s" % plugin) + p = pytester.makepyfile("def test(): pass") + result = pytester.runpytest(str(p), "-pno:%s" % plugin) if plugin == "python": assert result.ret == ExitCode.USAGE_ERROR @@ -1752,8 +1806,8 @@ def test_config_blocked_default_plugins(testdir, plugin): if plugin != "terminal": result.stdout.fnmatch_lines(["* 1 passed in *"]) - p = testdir.makepyfile("def test(): assert 0") - result = testdir.runpytest(str(p), "-pno:%s" % plugin) + p = pytester.makepyfile("def test(): assert 0") + result = pytester.runpytest(str(p), "-pno:%s" % plugin) assert result.ret == ExitCode.TESTS_FAILED if plugin != "terminal": result.stdout.fnmatch_lines(["* 1 failed in *"]) @@ -1762,8 +1816,8 @@ def test_config_blocked_default_plugins(testdir, plugin): class TestSetupCfg: - def test_pytest_setup_cfg_unsupported(self, testdir): - testdir.makefile( + def test_pytest_setup_cfg_unsupported(self, pytester: Pytester) -> None: + pytester.makefile( ".cfg", setup=""" [pytest] @@ -1771,10 +1825,10 @@ class TestSetupCfg: """, ) with pytest.raises(pytest.fail.Exception): - testdir.runpytest() + pytester.runpytest() - def test_pytest_custom_cfg_unsupported(self, testdir): - testdir.makefile( + def test_pytest_custom_cfg_unsupported(self, pytester: Pytester) -> None: + pytester.makefile( ".cfg", custom=""" [pytest] @@ -1782,33 +1836,35 @@ class TestSetupCfg: """, ) with pytest.raises(pytest.fail.Exception): - testdir.runpytest("-c", "custom.cfg") + pytester.runpytest("-c", "custom.cfg") class TestPytestPluginsVariable: - def test_pytest_plugins_in_non_top_level_conftest_unsupported(self, testdir): - testdir.makepyfile( + def test_pytest_plugins_in_non_top_level_conftest_unsupported( + self, pytester: Pytester + ) -> None: + pytester.makepyfile( **{ "subdirectory/conftest.py": """ pytest_plugins=['capture'] """ } ) - testdir.makepyfile( + pytester.makepyfile( """ def test_func(): pass """ ) - res = testdir.runpytest() + res = pytester.runpytest() assert res.ret == 2 msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" res.stdout.fnmatch_lines([f"*{msg}*", f"*subdirectory{os.sep}conftest.py*"]) @pytest.mark.parametrize("use_pyargs", [True, False]) def test_pytest_plugins_in_non_top_level_conftest_unsupported_pyargs( - self, testdir, use_pyargs - ): + self, pytester: Pytester, use_pyargs: bool + ) -> None: """When using --pyargs, do not emit the warning about non-top-level conftest warnings (#4039, #4044)""" files = { @@ -1819,11 +1875,11 @@ class TestPytestPluginsVariable: "src/pkg/sub/conftest.py": "pytest_plugins=['capture']", "src/pkg/sub/test_bar.py": "def test(): pass", } - testdir.makepyfile(**files) - testdir.syspathinsert(testdir.tmpdir.join("src")) + pytester.makepyfile(**files) + pytester.syspathinsert(pytester.path.joinpath("src")) args = ("--pyargs", "pkg") if use_pyargs else () - res = testdir.runpytest(*args) + res = pytester.runpytest(*args) assert res.ret == (0 if use_pyargs else 2) msg = ( msg @@ -1834,33 +1890,35 @@ class TestPytestPluginsVariable: res.stdout.fnmatch_lines([f"*{msg}*"]) def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_top_level_conftest( - self, testdir - ): - subdirectory = testdir.tmpdir.join("subdirectory") + self, pytester: Pytester + ) -> None: + subdirectory = pytester.path.joinpath("subdirectory") subdirectory.mkdir() - testdir.makeconftest( + pytester.makeconftest( """ pytest_plugins=['capture'] """ ) - testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py")) + pytester.path.joinpath("conftest.py").rename( + subdirectory.joinpath("conftest.py") + ) - testdir.makepyfile( + pytester.makepyfile( """ def test_func(): pass """ ) - res = testdir.runpytest_subprocess() + res = pytester.runpytest_subprocess() assert res.ret == 2 msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" res.stdout.fnmatch_lines([f"*{msg}*", f"*subdirectory{os.sep}conftest.py*"]) def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_false_positives( - self, testdir - ): - testdir.makepyfile( + self, pytester: Pytester + ) -> None: + pytester.makepyfile( "def test_func(): pass", **{ "subdirectory/conftest": "pass", @@ -1871,13 +1929,13 @@ class TestPytestPluginsVariable: """, }, ) - res = testdir.runpytest_subprocess() + res = pytester.runpytest_subprocess() assert res.ret == 0 msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" assert msg not in res.stdout.str() -def test_conftest_import_error_repr(tmpdir): +def test_conftest_import_error_repr(tmpdir: py.path.local) -> None: """`ConftestImportFailure` should use a short error message and readable path to the failed conftest.py file.""" path = tmpdir.join("foo/conftest.py") @@ -1893,7 +1951,7 @@ def test_conftest_import_error_repr(tmpdir): raise ConftestImportFailure(path, exc_info) from exc -def test_strtobool(): +def test_strtobool() -> None: assert _strtobool("YES") assert not _strtobool("NO") with pytest.raises(ValueError): diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 0b861f25a..a4d22d2aa 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -20,7 +20,7 @@ from _pytest._io.wcwidth import wcswidth from _pytest.config import Config from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch -from _pytest.pytester import Testdir +from _pytest.pytester import Pytester from _pytest.reports import BaseReport from _pytest.reports import CollectReport from _pytest.terminal import _folded_skips @@ -76,8 +76,8 @@ def test_plugin_nameversion(input, expected): class TestTerminal: - def test_pass_skip_fail(self, testdir, option): - testdir.makepyfile( + def test_pass_skip_fail(self, pytester: Pytester, option) -> None: + pytester.makepyfile( """ import pytest def test_ok(): @@ -88,7 +88,7 @@ class TestTerminal: assert 0 """ ) - result = testdir.runpytest(*option.args) + result = pytester.runpytest(*option.args) if option.verbosity > 0: result.stdout.fnmatch_lines( [ @@ -105,16 +105,16 @@ class TestTerminal: [" def test_func():", "> assert 0", "E assert 0"] ) - def test_internalerror(self, testdir, linecomp): - modcol = testdir.getmodulecol("def test_one(): pass") + def test_internalerror(self, pytester: Pytester, linecomp) -> None: + modcol = pytester.getmodulecol("def test_one(): pass") rep = TerminalReporter(modcol.config, file=linecomp.stringio) with pytest.raises(ValueError) as excinfo: raise ValueError("hello") rep.pytest_internalerror(excinfo.getrepr()) linecomp.assert_contains_lines(["INTERNALERROR> *ValueError*hello*"]) - def test_writeline(self, testdir, linecomp): - modcol = testdir.getmodulecol("def test_one(): pass") + def test_writeline(self, pytester: Pytester, linecomp) -> None: + modcol = pytester.getmodulecol("def test_one(): pass") rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep.write_fspath_result(modcol.nodeid, ".") rep.write_line("hello world") @@ -123,8 +123,8 @@ class TestTerminal: assert lines[1].endswith(modcol.name + " .") assert lines[2] == "hello world" - def test_show_runtest_logstart(self, testdir, linecomp): - item = testdir.getitem("def test_func(): pass") + def test_show_runtest_logstart(self, pytester: Pytester, linecomp) -> None: + item = pytester.getitem("def test_func(): pass") tr = TerminalReporter(item.config, file=linecomp.stringio) item.config.pluginmanager.register(tr) location = item.reportinfo() @@ -133,7 +133,9 @@ class TestTerminal: ) linecomp.assert_contains_lines(["*test_show_runtest_logstart.py*"]) - def test_runtest_location_shown_before_test_starts(self, pytester): + def test_runtest_location_shown_before_test_starts( + self, pytester: Pytester + ) -> None: pytester.makepyfile( """ def test_1(): @@ -146,7 +148,9 @@ class TestTerminal: child.sendeof() child.kill(15) - def test_report_collect_after_half_a_second(self, pytester, monkeypatch): + def test_report_collect_after_half_a_second( + self, pytester: Pytester, monkeypatch: MonkeyPatch + ) -> None: """Test for "collecting" being updated after 0.5s""" pytester.makepyfile( @@ -173,8 +177,10 @@ class TestTerminal: rest = child.read().decode("utf8") assert "= \x1b[32m\x1b[1m2 passed\x1b[0m\x1b[32m in" in rest - def test_itemreport_subclasses_show_subclassed_file(self, testdir): - testdir.makepyfile( + def test_itemreport_subclasses_show_subclassed_file( + self, pytester: Pytester + ) -> None: + pytester.makepyfile( **{ "tests/test_p1": """ class BaseTests(object): @@ -197,10 +203,10 @@ class TestTerminal: """, } ) - result = testdir.runpytest("tests/test_p2.py", "--rootdir=tests") + result = pytester.runpytest("tests/test_p2.py", "--rootdir=tests") result.stdout.fnmatch_lines(["tests/test_p2.py .*", "=* 1 passed in *"]) - result = testdir.runpytest("-vv", "-rA", "tests/test_p2.py", "--rootdir=tests") + result = pytester.runpytest("-vv", "-rA", "tests/test_p2.py", "--rootdir=tests") result.stdout.fnmatch_lines( [ "tests/test_p2.py::TestMore::test_p1 <- test_p1.py PASSED *", @@ -208,7 +214,7 @@ class TestTerminal: "PASSED tests/test_p2.py::TestMore::test_p1", ] ) - result = testdir.runpytest("-vv", "-rA", "tests/test_p3.py", "--rootdir=tests") + result = pytester.runpytest("-vv", "-rA", "tests/test_p3.py", "--rootdir=tests") result.stdout.fnmatch_lines( [ "tests/test_p3.py::TestMore::test_p1 <- test_p1.py FAILED *", @@ -224,9 +230,11 @@ class TestTerminal: ] ) - def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): - a = testdir.mkpydir("a123") - a.join("test_hello123.py").write( + def test_itemreport_directclasses_not_shown_as_subclasses( + self, pytester: Pytester + ) -> None: + a = pytester.mkpydir("a123") + a.joinpath("test_hello123.py").write_text( textwrap.dedent( """\ class TestClass(object): @@ -235,14 +243,14 @@ class TestTerminal: """ ) ) - result = testdir.runpytest("-vv") + result = pytester.runpytest("-vv") assert result.ret == 0 result.stdout.fnmatch_lines(["*a123/test_hello123.py*PASS*"]) result.stdout.no_fnmatch_line("* <- *") @pytest.mark.parametrize("fulltrace", ("", "--fulltrace")) - def test_keyboard_interrupt(self, testdir, fulltrace): - testdir.makepyfile( + def test_keyboard_interrupt(self, pytester: Pytester, fulltrace) -> None: + pytester.makepyfile( """ def test_foobar(): assert 0 @@ -253,7 +261,7 @@ class TestTerminal: """ ) - result = testdir.runpytest(fulltrace, no_reraise_ctrlc=True) + result = pytester.runpytest(fulltrace, no_reraise_ctrlc=True) result.stdout.fnmatch_lines( [ " def test_foobar():", @@ -272,37 +280,37 @@ class TestTerminal: ) result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) - def test_keyboard_in_sessionstart(self, testdir): - testdir.makeconftest( + def test_keyboard_in_sessionstart(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_sessionstart(): raise KeyboardInterrupt """ ) - testdir.makepyfile( + pytester.makepyfile( """ def test_foobar(): pass """ ) - result = testdir.runpytest(no_reraise_ctrlc=True) + result = pytester.runpytest(no_reraise_ctrlc=True) assert result.ret == 2 result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) - def test_collect_single_item(self, testdir): + def test_collect_single_item(self, pytester: Pytester) -> None: """Use singular 'item' when reporting a single test item""" - testdir.makepyfile( + pytester.makepyfile( """ def test_foobar(): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["collected 1 item"]) - def test_rewrite(self, testdir, monkeypatch): - config = testdir.parseconfig() + def test_rewrite(self, pytester: Pytester, monkeypatch) -> None: + config = pytester.parseconfig() f = StringIO() monkeypatch.setattr(f, "isatty", lambda *args: True) tr = TerminalReporter(config, f) @@ -312,57 +320,57 @@ class TestTerminal: assert f.getvalue() == "hello" + "\r" + "hey" + (6 * " ") def test_report_teststatus_explicit_markup( - self, testdir: Testdir, color_mapping + self, monkeypatch: MonkeyPatch, pytester: Pytester, color_mapping ) -> None: """Test that TerminalReporter handles markup explicitly provided by a pytest_report_teststatus hook.""" - testdir.monkeypatch.setenv("PY_COLORS", "1") - testdir.makeconftest( + monkeypatch.setenv("PY_COLORS", "1") + pytester.makeconftest( """ def pytest_report_teststatus(report): return 'foo', 'F', ('FOO', {'red': True}) """ ) - testdir.makepyfile( + pytester.makepyfile( """ def test_foobar(): pass """ ) - result = testdir.runpytest("-v") + result = pytester.runpytest("-v") result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch(["*{red}FOO{reset}*"]) ) class TestCollectonly: - def test_collectonly_basic(self, testdir): - testdir.makepyfile( + def test_collectonly_basic(self, pytester: Pytester) -> None: + pytester.makepyfile( """ def test_func(): pass """ ) - result = testdir.runpytest("--collect-only") + result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines( ["", " "] ) - def test_collectonly_skipped_module(self, testdir): - testdir.makepyfile( + def test_collectonly_skipped_module(self, pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest pytest.skip("hello") """ ) - result = testdir.runpytest("--collect-only", "-rs") + result = pytester.runpytest("--collect-only", "-rs") result.stdout.fnmatch_lines(["*ERROR collecting*"]) def test_collectonly_displays_test_description( - self, testdir: Testdir, dummy_yaml_custom_test + self, pytester: Pytester, dummy_yaml_custom_test ) -> None: """Used dummy_yaml_custom_test for an Item without ``obj``.""" - testdir.makepyfile( + pytester.makepyfile( """ def test_with_description(): ''' This test has a description. @@ -371,7 +379,7 @@ class TestCollectonly: more2.''' """ ) - result = testdir.runpytest("--collect-only", "--verbose") + result = pytester.runpytest("--collect-only", "--verbose") result.stdout.fnmatch_lines( [ "", @@ -386,24 +394,24 @@ class TestCollectonly: consecutive=True, ) - def test_collectonly_failed_module(self, testdir): - testdir.makepyfile("""raise ValueError(0)""") - result = testdir.runpytest("--collect-only") + def test_collectonly_failed_module(self, pytester: Pytester) -> None: + pytester.makepyfile("""raise ValueError(0)""") + result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines(["*raise ValueError*", "*1 error*"]) - def test_collectonly_fatal(self, testdir): - testdir.makeconftest( + def test_collectonly_fatal(self, pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_collectstart(collector): assert 0, "urgs" """ ) - result = testdir.runpytest("--collect-only") + result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines(["*INTERNAL*args*"]) assert result.ret == 3 - def test_collectonly_simple(self, testdir): - p = testdir.makepyfile( + def test_collectonly_simple(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ def test_func1(): pass @@ -412,7 +420,7 @@ class TestCollectonly: pass """ ) - result = testdir.runpytest("--collect-only", p) + result = pytester.runpytest("--collect-only", p) # assert stderr.startswith("inserting into sys.path") assert result.ret == 0 result.stdout.fnmatch_lines( @@ -424,9 +432,9 @@ class TestCollectonly: ] ) - def test_collectonly_error(self, testdir): - p = testdir.makepyfile("import Errlkjqweqwe") - result = testdir.runpytest("--collect-only", p) + def test_collectonly_error(self, pytester: Pytester) -> None: + p = pytester.makepyfile("import Errlkjqweqwe") + result = pytester.runpytest("--collect-only", p) assert result.ret == 2 result.stdout.fnmatch_lines( textwrap.dedent( @@ -439,28 +447,28 @@ class TestCollectonly: ).strip() ) - def test_collectonly_missing_path(self, testdir): + def test_collectonly_missing_path(self, pytester: Pytester) -> None: """Issue 115: failure in parseargs will cause session not to have the items attribute.""" - result = testdir.runpytest("--collect-only", "uhm_missing_path") + result = pytester.runpytest("--collect-only", "uhm_missing_path") assert result.ret == 4 result.stderr.fnmatch_lines( ["*ERROR: file or directory not found: uhm_missing_path"] ) - def test_collectonly_quiet(self, testdir): - testdir.makepyfile("def test_foo(): pass") - result = testdir.runpytest("--collect-only", "-q") + def test_collectonly_quiet(self, pytester: Pytester) -> None: + pytester.makepyfile("def test_foo(): pass") + result = pytester.runpytest("--collect-only", "-q") result.stdout.fnmatch_lines(["*test_foo*"]) - def test_collectonly_more_quiet(self, testdir): - testdir.makepyfile(test_fun="def test_foo(): pass") - result = testdir.runpytest("--collect-only", "-qq") + def test_collectonly_more_quiet(self, pytester: Pytester) -> None: + pytester.makepyfile(test_fun="def test_foo(): pass") + result = pytester.runpytest("--collect-only", "-qq") result.stdout.fnmatch_lines(["*test_fun.py: 1*"]) - def test_collect_only_summary_status(self, testdir): + def test_collect_only_summary_status(self, pytester: Pytester) -> None: """Custom status depending on test selection using -k or -m. #7701.""" - testdir.makepyfile( + pytester.makepyfile( test_collect_foo=""" def test_foo(): pass """, @@ -469,41 +477,41 @@ class TestCollectonly: def test_bar(): pass """, ) - result = testdir.runpytest("--collect-only") + result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines("*== 3 tests collected in * ==*") - result = testdir.runpytest("--collect-only", "test_collect_foo.py") + result = pytester.runpytest("--collect-only", "test_collect_foo.py") result.stdout.fnmatch_lines("*== 1 test collected in * ==*") - result = testdir.runpytest("--collect-only", "-k", "foo") + result = pytester.runpytest("--collect-only", "-k", "foo") result.stdout.fnmatch_lines("*== 2/3 tests collected (1 deselected) in * ==*") - result = testdir.runpytest("--collect-only", "-k", "test_bar") + result = pytester.runpytest("--collect-only", "-k", "test_bar") result.stdout.fnmatch_lines("*== 1/3 tests collected (2 deselected) in * ==*") - result = testdir.runpytest("--collect-only", "-k", "invalid") + result = pytester.runpytest("--collect-only", "-k", "invalid") result.stdout.fnmatch_lines("*== no tests collected (3 deselected) in * ==*") - testdir.mkdir("no_tests_here") - result = testdir.runpytest("--collect-only", "no_tests_here") + pytester.mkdir("no_tests_here") + result = pytester.runpytest("--collect-only", "no_tests_here") result.stdout.fnmatch_lines("*== no tests collected in * ==*") - testdir.makepyfile( + pytester.makepyfile( test_contains_error=""" raise RuntimeError """, ) - result = testdir.runpytest("--collect-only") + result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines("*== 3 tests collected, 1 error in * ==*") - result = testdir.runpytest("--collect-only", "-k", "foo") + result = pytester.runpytest("--collect-only", "-k", "foo") result.stdout.fnmatch_lines( "*== 2/3 tests collected (1 deselected), 1 error in * ==*" ) class TestFixtureReporting: - def test_setup_fixture_error(self, testdir): - testdir.makepyfile( + def test_setup_fixture_error(self, pytester: Pytester) -> None: + pytester.makepyfile( """ def setup_function(function): print("setup func") @@ -512,7 +520,7 @@ class TestFixtureReporting: pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*ERROR at setup of test_nada*", @@ -524,8 +532,8 @@ class TestFixtureReporting: ) assert result.ret != 0 - def test_teardown_fixture_error(self, testdir): - testdir.makepyfile( + def test_teardown_fixture_error(self, pytester: Pytester) -> None: + pytester.makepyfile( """ def test_nada(): pass @@ -534,7 +542,7 @@ class TestFixtureReporting: assert 0 """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*ERROR at teardown*", @@ -546,8 +554,8 @@ class TestFixtureReporting: ] ) - def test_teardown_fixture_error_and_test_failure(self, testdir): - testdir.makepyfile( + def test_teardown_fixture_error_and_test_failure(self, pytester: Pytester) -> None: + pytester.makepyfile( """ def test_fail(): assert 0, "failingfunc" @@ -557,7 +565,7 @@ class TestFixtureReporting: assert False """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*ERROR at teardown of test_fail*", @@ -572,9 +580,9 @@ class TestFixtureReporting: ] ) - def test_setup_teardown_output_and_test_failure(self, testdir): + def test_setup_teardown_output_and_test_failure(self, pytester: Pytester) -> None: """Test for issue #442.""" - testdir.makepyfile( + pytester.makepyfile( """ def setup_function(function): print("setup func") @@ -586,7 +594,7 @@ class TestFixtureReporting: print("teardown func") """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*test_fail*", @@ -602,8 +610,8 @@ class TestFixtureReporting: class TestTerminalFunctional: - def test_deselected(self, testdir): - testpath = testdir.makepyfile( + def test_deselected(self, pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ def test_one(): pass @@ -613,14 +621,14 @@ class TestTerminalFunctional: pass """ ) - result = testdir.runpytest("-k", "test_two:", testpath) + result = pytester.runpytest("-k", "test_two:", testpath) result.stdout.fnmatch_lines( ["collected 3 items / 1 deselected / 2 selected", "*test_deselected.py ..*"] ) assert result.ret == 0 - def test_deselected_with_hookwrapper(self, testdir): - testpath = testdir.makeconftest( + def test_deselected_with_hookwrapper(self, pytester: Pytester) -> None: + pytester.makeconftest( """ import pytest @@ -631,7 +639,7 @@ class TestTerminalFunctional: config.hook.pytest_deselected(items=[deselected]) """ ) - testpath = testdir.makepyfile( + testpath = pytester.makepyfile( """ def test_one(): pass @@ -641,7 +649,7 @@ class TestTerminalFunctional: pass """ ) - result = testdir.runpytest(testpath) + result = pytester.runpytest(testpath) result.stdout.fnmatch_lines( [ "collected 3 items / 1 deselected / 2 selected", @@ -650,8 +658,10 @@ class TestTerminalFunctional: ) assert result.ret == 0 - def test_show_deselected_items_using_markexpr_before_test_execution(self, testdir): - testdir.makepyfile( + def test_show_deselected_items_using_markexpr_before_test_execution( + self, pytester: Pytester + ) -> None: + pytester.makepyfile( test_show_deselected=""" import pytest @@ -667,7 +677,7 @@ class TestTerminalFunctional: pass """ ) - result = testdir.runpytest("-m", "not foo") + result = pytester.runpytest("-m", "not foo") result.stdout.fnmatch_lines( [ "collected 3 items / 1 deselected / 2 selected", @@ -678,8 +688,8 @@ class TestTerminalFunctional: result.stdout.no_fnmatch_line("*= 1 deselected =*") assert result.ret == 0 - def test_no_skip_summary_if_failure(self, testdir): - testdir.makepyfile( + def test_no_skip_summary_if_failure(self, pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest def test_ok(): @@ -690,12 +700,12 @@ class TestTerminalFunctional: pytest.skip("dontshow") """ ) - result = testdir.runpytest() + result = pytester.runpytest() assert result.stdout.str().find("skip test summary") == -1 assert result.ret == 1 - def test_passes(self, testdir): - p1 = testdir.makepyfile( + def test_passes(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( """ def test_passes(): pass @@ -704,23 +714,26 @@ class TestTerminalFunctional: pass """ ) - old = p1.dirpath().chdir() + old = p1.parent + pytester.chdir() try: - result = testdir.runpytest() + result = pytester.runpytest() finally: - old.chdir() + os.chdir(old) result.stdout.fnmatch_lines(["test_passes.py ..*", "* 2 pass*"]) assert result.ret == 0 - def test_header_trailer_info(self, testdir, request): - testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") - testdir.makepyfile( + def test_header_trailer_info( + self, monkeypatch: MonkeyPatch, pytester: Pytester, request + ) -> None: + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") + pytester.makepyfile( """ def test_passes(): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() verinfo = ".".join(map(str, sys.version_info[:3])) result.stdout.fnmatch_lines( [ @@ -740,15 +753,17 @@ class TestTerminalFunctional: if request.config.pluginmanager.list_plugin_distinfo(): result.stdout.fnmatch_lines(["plugins: *"]) - def test_no_header_trailer_info(self, testdir, request): - testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") - testdir.makepyfile( + def test_no_header_trailer_info( + self, monkeypatch: MonkeyPatch, pytester: Pytester, request + ) -> None: + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") + pytester.makepyfile( """ def test_passes(): pass """ ) - result = testdir.runpytest("--no-header") + result = pytester.runpytest("--no-header") verinfo = ".".join(map(str, sys.version_info[:3])) result.stdout.no_fnmatch_line( "platform %s -- Python %s*pytest-%s*py-%s*pluggy-%s" @@ -763,42 +778,42 @@ class TestTerminalFunctional: if request.config.pluginmanager.list_plugin_distinfo(): result.stdout.no_fnmatch_line("plugins: *") - def test_header(self, testdir): - testdir.tmpdir.join("tests").ensure_dir() - testdir.tmpdir.join("gui").ensure_dir() + def test_header(self, pytester: Pytester) -> None: + pytester.path.joinpath("tests").mkdir() + pytester.path.joinpath("gui").mkdir() # no ini file - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["rootdir: *test_header0"]) # with configfile - testdir.makeini("""[pytest]""") - result = testdir.runpytest() + pytester.makeini("""[pytest]""") + result = pytester.runpytest() result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"]) # with testpaths option, and not passing anything in the command-line - testdir.makeini( + pytester.makeini( """ [pytest] testpaths = tests gui """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( ["rootdir: *test_header0, configfile: tox.ini, testpaths: tests, gui"] ) # with testpaths option, passing directory in command-line: do not show testpaths then - result = testdir.runpytest("tests") + result = pytester.runpytest("tests") result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"]) def test_header_absolute_testpath( - self, testdir: Testdir, monkeypatch: MonkeyPatch + self, pytester: Pytester, monkeypatch: MonkeyPatch ) -> None: """Regresstion test for #7814.""" - tests = testdir.tmpdir.join("tests") - tests.ensure_dir() - testdir.makepyprojecttoml( + tests = pytester.path.joinpath("tests") + tests.mkdir() + pytester.makepyprojecttoml( """ [tool.pytest.ini_options] testpaths = ['{}'] @@ -806,7 +821,7 @@ class TestTerminalFunctional: tests ) ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "rootdir: *absolute_testpath0, configfile: pyproject.toml, testpaths: {}".format( @@ -815,38 +830,38 @@ class TestTerminalFunctional: ] ) - def test_no_header(self, testdir): - testdir.tmpdir.join("tests").ensure_dir() - testdir.tmpdir.join("gui").ensure_dir() + def test_no_header(self, pytester: Pytester) -> None: + pytester.path.joinpath("tests").mkdir() + pytester.path.joinpath("gui").mkdir() # with testpaths option, and not passing anything in the command-line - testdir.makeini( + pytester.makeini( """ [pytest] testpaths = tests gui """ ) - result = testdir.runpytest("--no-header") + result = pytester.runpytest("--no-header") result.stdout.no_fnmatch_line( "rootdir: *test_header0, inifile: tox.ini, testpaths: tests, gui" ) # with testpaths option, passing directory in command-line: do not show testpaths then - result = testdir.runpytest("tests", "--no-header") + result = pytester.runpytest("tests", "--no-header") result.stdout.no_fnmatch_line("rootdir: *test_header0, inifile: tox.ini") - def test_no_summary(self, testdir): - p1 = testdir.makepyfile( + def test_no_summary(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( """ def test_no_summary(): assert false """ ) - result = testdir.runpytest(p1, "--no-summary") + result = pytester.runpytest(p1, "--no-summary") result.stdout.no_fnmatch_line("*= FAILURES =*") - def test_showlocals(self, testdir): - p1 = testdir.makepyfile( + def test_showlocals(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( """ def test_showlocals(): x = 3 @@ -854,7 +869,7 @@ class TestTerminalFunctional: assert 0 """ ) - result = testdir.runpytest(p1, "-l") + result = pytester.runpytest(p1, "-l") result.stdout.fnmatch_lines( [ # "_ _ * Locals *", @@ -863,8 +878,8 @@ class TestTerminalFunctional: ] ) - def test_showlocals_short(self, testdir): - p1 = testdir.makepyfile( + def test_showlocals_short(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile( """ def test_showlocals_short(): x = 3 @@ -872,7 +887,7 @@ class TestTerminalFunctional: assert 0 """ ) - result = testdir.runpytest(p1, "-l", "--tb=short") + result = pytester.runpytest(p1, "-l", "--tb=short") result.stdout.fnmatch_lines( [ "test_showlocals_short.py:*", @@ -884,8 +899,8 @@ class TestTerminalFunctional: ) @pytest.fixture - def verbose_testfile(self, testdir): - return testdir.makepyfile( + def verbose_testfile(self, pytester: Pytester) -> Path: + return pytester.makepyfile( """ import pytest def test_fail(): @@ -902,8 +917,8 @@ class TestTerminalFunctional: """ ) - def test_verbose_reporting(self, verbose_testfile, testdir): - result = testdir.runpytest( + def test_verbose_reporting(self, verbose_testfile, pytester: Pytester) -> None: + result = pytester.runpytest( verbose_testfile, "-v", "-Walways::pytest.PytestWarning" ) result.stdout.fnmatch_lines( @@ -916,12 +931,18 @@ class TestTerminalFunctional: ) assert result.ret == 1 - def test_verbose_reporting_xdist(self, verbose_testfile, testdir, pytestconfig): + def test_verbose_reporting_xdist( + self, + verbose_testfile, + monkeypatch: MonkeyPatch, + pytester: Pytester, + pytestconfig, + ) -> None: if not pytestconfig.pluginmanager.get_plugin("xdist"): pytest.skip("xdist plugin not installed") - testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") - result = testdir.runpytest( + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") + result = pytester.runpytest( verbose_testfile, "-v", "-n 1", "-Walways::pytest.PytestWarning" ) result.stdout.fnmatch_lines( @@ -929,35 +950,35 @@ class TestTerminalFunctional: ) assert result.ret == 1 - def test_quiet_reporting(self, testdir): - p1 = testdir.makepyfile("def test_pass(): pass") - result = testdir.runpytest(p1, "-q") + def test_quiet_reporting(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile("def test_pass(): pass") + result = pytester.runpytest(p1, "-q") s = result.stdout.str() assert "test session starts" not in s - assert p1.basename not in s + assert p1.name not in s assert "===" not in s assert "passed" in s - def test_more_quiet_reporting(self, testdir): - p1 = testdir.makepyfile("def test_pass(): pass") - result = testdir.runpytest(p1, "-qq") + def test_more_quiet_reporting(self, pytester: Pytester) -> None: + p1 = pytester.makepyfile("def test_pass(): pass") + result = pytester.runpytest(p1, "-qq") s = result.stdout.str() assert "test session starts" not in s - assert p1.basename not in s + assert p1.name not in s assert "===" not in s assert "passed" not in s @pytest.mark.parametrize( "params", [(), ("--collect-only",)], ids=["no-params", "collect-only"] ) - def test_report_collectionfinish_hook(self, testdir, params): - testdir.makeconftest( + def test_report_collectionfinish_hook(self, pytester: Pytester, params) -> None: + pytester.makeconftest( """ def pytest_report_collectionfinish(config, startdir, items): return ['hello from hook: {0} items'.format(len(items))] """ ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest @pytest.mark.parametrize('i', range(3)) @@ -965,25 +986,25 @@ class TestTerminalFunctional: pass """ ) - result = testdir.runpytest(*params) + result = pytester.runpytest(*params) result.stdout.fnmatch_lines(["collected 3 items", "hello from hook: 3 items"]) - def test_summary_f_alias(self, testdir): + def test_summary_f_alias(self, pytester: Pytester) -> None: """Test that 'f' and 'F' report chars are aliases and don't show up twice in the summary (#6334)""" - testdir.makepyfile( + pytester.makepyfile( """ def test(): assert False """ ) - result = testdir.runpytest("-rfF") + result = pytester.runpytest("-rfF") expected = "FAILED test_summary_f_alias.py::test - assert False" result.stdout.fnmatch_lines([expected]) assert result.stdout.lines.count(expected) == 1 - def test_summary_s_alias(self, testdir): + def test_summary_s_alias(self, pytester: Pytester) -> None: """Test that 's' and 'S' report chars are aliases and don't show up twice in the summary""" - testdir.makepyfile( + pytester.makepyfile( """ import pytest @@ -992,18 +1013,18 @@ class TestTerminalFunctional: pass """ ) - result = testdir.runpytest("-rsS") + result = pytester.runpytest("-rsS") expected = "SKIPPED [1] test_summary_s_alias.py:3: unconditional skip" result.stdout.fnmatch_lines([expected]) assert result.stdout.lines.count(expected) == 1 -def test_fail_extra_reporting(testdir, monkeypatch): +def test_fail_extra_reporting(pytester: Pytester, monkeypatch) -> None: monkeypatch.setenv("COLUMNS", "80") - testdir.makepyfile("def test_this(): assert 0, 'this_failed' * 100") - result = testdir.runpytest("-rN") + pytester.makepyfile("def test_this(): assert 0, 'this_failed' * 100") + result = pytester.runpytest("-rN") result.stdout.no_fnmatch_line("*short test summary*") - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*test summary*", @@ -1012,28 +1033,28 @@ def test_fail_extra_reporting(testdir, monkeypatch): ) -def test_fail_reporting_on_pass(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("-rf") +def test_fail_reporting_on_pass(pytester: Pytester) -> None: + pytester.makepyfile("def test_this(): assert 1") + result = pytester.runpytest("-rf") result.stdout.no_fnmatch_line("*short test summary*") -def test_pass_extra_reporting(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest() +def test_pass_extra_reporting(pytester: Pytester) -> None: + pytester.makepyfile("def test_this(): assert 1") + result = pytester.runpytest() result.stdout.no_fnmatch_line("*short test summary*") - result = testdir.runpytest("-rp") + result = pytester.runpytest("-rp") result.stdout.fnmatch_lines(["*test summary*", "PASS*test_pass_extra_reporting*"]) -def test_pass_reporting_on_fail(testdir): - testdir.makepyfile("def test_this(): assert 0") - result = testdir.runpytest("-rp") +def test_pass_reporting_on_fail(pytester: Pytester) -> None: + pytester.makepyfile("def test_this(): assert 0") + result = pytester.runpytest("-rp") result.stdout.no_fnmatch_line("*short test summary*") -def test_pass_output_reporting(testdir): - testdir.makepyfile( +def test_pass_output_reporting(pytester: Pytester) -> None: + pytester.makepyfile( """ def setup_module(): print("setup_module") @@ -1048,12 +1069,12 @@ def test_pass_output_reporting(testdir): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() s = result.stdout.str() assert "test_pass_has_output" not in s assert "Four score and seven years ago..." not in s assert "test_pass_no_output" not in s - result = testdir.runpytest("-rPp") + result = pytester.runpytest("-rPp") result.stdout.fnmatch_lines( [ "*= PASSES =*", @@ -1072,8 +1093,8 @@ def test_pass_output_reporting(testdir): ) -def test_color_yes(testdir, color_mapping): - p1 = testdir.makepyfile( +def test_color_yes(pytester: Pytester, color_mapping) -> None: + p1 = pytester.makepyfile( """ def fail(): assert 0 @@ -1082,7 +1103,7 @@ def test_color_yes(testdir, color_mapping): fail() """ ) - result = testdir.runpytest("--color=yes", str(p1)) + result = pytester.runpytest("--color=yes", str(p1)) result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ @@ -1109,7 +1130,7 @@ def test_color_yes(testdir, color_mapping): ] ) ) - result = testdir.runpytest("--color=yes", "--tb=short", str(p1)) + result = pytester.runpytest("--color=yes", "--tb=short", str(p1)) result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ @@ -1131,17 +1152,17 @@ def test_color_yes(testdir, color_mapping): ) -def test_color_no(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("--color=no") +def test_color_no(pytester: Pytester) -> None: + pytester.makepyfile("def test_this(): assert 1") + result = pytester.runpytest("--color=no") assert "test session starts" in result.stdout.str() result.stdout.no_fnmatch_line("*\x1b[1m*") @pytest.mark.parametrize("verbose", [True, False]) -def test_color_yes_collection_on_non_atty(testdir, verbose): +def test_color_yes_collection_on_non_atty(pytester: Pytester, verbose) -> None: """#1397: Skip collect progress report when working on non-terminals.""" - testdir.makepyfile( + pytester.makepyfile( """ import pytest @pytest.mark.parametrize('i', range(10)) @@ -1152,7 +1173,7 @@ def test_color_yes_collection_on_non_atty(testdir, verbose): args = ["--color=yes"] if verbose: args.append("-vv") - result = testdir.runpytest(*args) + result = pytester.runpytest(*args) assert "test session starts" in result.stdout.str() assert "\x1b[1m" in result.stdout.str() result.stdout.no_fnmatch_line("*collecting 10 items*") @@ -1220,9 +1241,9 @@ def test_getreportopt() -> None: assert getreportopt(config) == "fE" -def test_terminalreporter_reportopt_addopts(testdir): - testdir.makeini("[pytest]\naddopts=-rs") - testdir.makepyfile( +def test_terminalreporter_reportopt_addopts(pytester: Pytester) -> None: + pytester.makeini("[pytest]\naddopts=-rs") + pytester.makepyfile( """ import pytest @@ -1235,12 +1256,12 @@ def test_terminalreporter_reportopt_addopts(testdir): assert not tr.hasopt('qwe') """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*1 passed*"]) -def test_tbstyle_short(testdir): - p = testdir.makepyfile( +def test_tbstyle_short(pytester: Pytester) -> None: + p = pytester.makepyfile( """ import pytest @@ -1252,19 +1273,19 @@ def test_tbstyle_short(testdir): assert x """ ) - result = testdir.runpytest("--tb=short") + result = pytester.runpytest("--tb=short") s = result.stdout.str() assert "arg = 42" not in s assert "x = 0" not in s - result.stdout.fnmatch_lines(["*%s:8*" % p.basename, " assert x", "E assert*"]) - result = testdir.runpytest() + result.stdout.fnmatch_lines(["*%s:8*" % p.name, " assert x", "E assert*"]) + result = pytester.runpytest() s = result.stdout.str() assert "x = 0" in s assert "assert x" in s -def test_traceconfig(testdir): - result = testdir.runpytest("--traceconfig") +def test_traceconfig(pytester: Pytester) -> None: + result = pytester.runpytest("--traceconfig") result.stdout.fnmatch_lines(["*active plugins*"]) assert result.ret == ExitCode.NO_TESTS_COLLECTED @@ -1273,15 +1294,15 @@ class TestGenericReporting: """Test class which can be subclassed with a different option provider to run e.g. distributed tests.""" - def test_collect_fail(self, testdir, option): - testdir.makepyfile("import xyz\n") - result = testdir.runpytest(*option.args) + def test_collect_fail(self, pytester: Pytester, option) -> None: + pytester.makepyfile("import xyz\n") + result = pytester.runpytest(*option.args) result.stdout.fnmatch_lines( ["ImportError while importing*", "*No module named *xyz*", "*1 error*"] ) - def test_maxfailures(self, testdir, option): - testdir.makepyfile( + def test_maxfailures(self, pytester: Pytester, option) -> None: + pytester.makepyfile( """ def test_1(): assert 0 @@ -1291,7 +1312,7 @@ class TestGenericReporting: assert 0 """ ) - result = testdir.runpytest("--maxfail=2", *option.args) + result = pytester.runpytest("--maxfail=2", *option.args) result.stdout.fnmatch_lines( [ "*def test_1():*", @@ -1301,15 +1322,15 @@ class TestGenericReporting: ] ) - def test_maxfailures_with_interrupted(self, testdir): - testdir.makepyfile( + def test_maxfailures_with_interrupted(self, pytester: Pytester) -> None: + pytester.makepyfile( """ def test(request): request.session.shouldstop = "session_interrupted" assert 0 """ ) - result = testdir.runpytest("--maxfail=1", "-ra") + result = pytester.runpytest("--maxfail=1", "-ra") result.stdout.fnmatch_lines( [ "*= short test summary info =*", @@ -1320,8 +1341,8 @@ class TestGenericReporting: ] ) - def test_tb_option(self, testdir, option): - testdir.makepyfile( + def test_tb_option(self, pytester: Pytester, option) -> None: + pytester.makepyfile( """ import pytest def g(): @@ -1333,7 +1354,7 @@ class TestGenericReporting: ) for tbopt in ["long", "short", "no"]: print("testing --tb=%s..." % tbopt) - result = testdir.runpytest("-rN", "--tb=%s" % tbopt) + result = pytester.runpytest("-rN", "--tb=%s" % tbopt) s = result.stdout.str() if tbopt == "long": assert "print(6*7)" in s @@ -1347,8 +1368,8 @@ class TestGenericReporting: assert "--calling--" not in s assert "IndexError" not in s - def test_tb_crashline(self, testdir, option): - p = testdir.makepyfile( + def test_tb_crashline(self, pytester: Pytester, option) -> None: + p = pytester.makepyfile( """ import pytest def g(): @@ -1360,16 +1381,16 @@ class TestGenericReporting: assert 0, "hello" """ ) - result = testdir.runpytest("--tb=line") - bn = p.basename + result = pytester.runpytest("--tb=line") + bn = p.name result.stdout.fnmatch_lines( ["*%s:3: IndexError*" % bn, "*%s:8: AssertionError: hello*" % bn] ) s = result.stdout.str() assert "def test_func2" not in s - def test_pytest_report_header(self, testdir, option): - testdir.makeconftest( + def test_pytest_report_header(self, pytester: Pytester, option) -> None: + pytester.makeconftest( """ def pytest_sessionstart(session): session.config._somevalue = 42 @@ -1377,17 +1398,17 @@ class TestGenericReporting: return "hello: %s" % config._somevalue """ ) - testdir.mkdir("a").join("conftest.py").write( + pytester.mkdir("a").joinpath("conftest.py").write_text( """ def pytest_report_header(config, startdir): return ["line1", str(startdir)] """ ) - result = testdir.runpytest("a") - result.stdout.fnmatch_lines(["*hello: 42*", "line1", str(testdir.tmpdir)]) + result = pytester.runpytest("a") + result.stdout.fnmatch_lines(["*hello: 42*", "line1", str(pytester.path)]) - def test_show_capture(self, testdir): - testdir.makepyfile( + def test_show_capture(self, pytester: Pytester) -> None: + pytester.makepyfile( """ import sys import logging @@ -1399,7 +1420,7 @@ def pytest_report_header(config, startdir): """ ) - result = testdir.runpytest("--tb=short") + result = pytester.runpytest("--tb=short") result.stdout.fnmatch_lines( [ "!This is stdout!", @@ -1408,7 +1429,7 @@ def pytest_report_header(config, startdir): ] ) - result = testdir.runpytest("--show-capture=all", "--tb=short") + result = pytester.runpytest("--show-capture=all", "--tb=short") result.stdout.fnmatch_lines( [ "!This is stdout!", @@ -1417,29 +1438,29 @@ def pytest_report_header(config, startdir): ] ) - stdout = testdir.runpytest("--show-capture=stdout", "--tb=short").stdout.str() + stdout = pytester.runpytest("--show-capture=stdout", "--tb=short").stdout.str() assert "!This is stderr!" not in stdout assert "!This is stdout!" in stdout assert "!This is a warning log msg!" not in stdout - stdout = testdir.runpytest("--show-capture=stderr", "--tb=short").stdout.str() + stdout = pytester.runpytest("--show-capture=stderr", "--tb=short").stdout.str() assert "!This is stdout!" not in stdout assert "!This is stderr!" in stdout assert "!This is a warning log msg!" not in stdout - stdout = testdir.runpytest("--show-capture=log", "--tb=short").stdout.str() + stdout = pytester.runpytest("--show-capture=log", "--tb=short").stdout.str() assert "!This is stdout!" not in stdout assert "!This is stderr!" not in stdout assert "!This is a warning log msg!" in stdout - stdout = testdir.runpytest("--show-capture=no", "--tb=short").stdout.str() + stdout = pytester.runpytest("--show-capture=no", "--tb=short").stdout.str() assert "!This is stdout!" not in stdout assert "!This is stderr!" not in stdout assert "!This is a warning log msg!" not in stdout - def test_show_capture_with_teardown_logs(self, testdir): + def test_show_capture_with_teardown_logs(self, pytester: Pytester) -> None: """Ensure that the capturing of teardown logs honor --show-capture setting""" - testdir.makepyfile( + pytester.makepyfile( """ import logging import sys @@ -1457,30 +1478,30 @@ def pytest_report_header(config, startdir): """ ) - result = testdir.runpytest("--show-capture=stdout", "--tb=short").stdout.str() + result = pytester.runpytest("--show-capture=stdout", "--tb=short").stdout.str() assert "!stdout!" in result assert "!stderr!" not in result assert "!log!" not in result - result = testdir.runpytest("--show-capture=stderr", "--tb=short").stdout.str() + result = pytester.runpytest("--show-capture=stderr", "--tb=short").stdout.str() assert "!stdout!" not in result assert "!stderr!" in result assert "!log!" not in result - result = testdir.runpytest("--show-capture=log", "--tb=short").stdout.str() + result = pytester.runpytest("--show-capture=log", "--tb=short").stdout.str() assert "!stdout!" not in result assert "!stderr!" not in result assert "!log!" in result - result = testdir.runpytest("--show-capture=no", "--tb=short").stdout.str() + result = pytester.runpytest("--show-capture=no", "--tb=short").stdout.str() assert "!stdout!" not in result assert "!stderr!" not in result assert "!log!" not in result @pytest.mark.xfail("not hasattr(os, 'dup')") -def test_fdopen_kept_alive_issue124(testdir): - testdir.makepyfile( +def test_fdopen_kept_alive_issue124(pytester: Pytester) -> None: + pytester.makepyfile( """ import os, sys k = [] @@ -1493,12 +1514,12 @@ def test_fdopen_kept_alive_issue124(testdir): stdout.close() """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*2 passed*"]) -def test_tbstyle_native_setup_error(testdir): - testdir.makepyfile( +def test_tbstyle_native_setup_error(pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest @pytest.fixture @@ -1509,14 +1530,14 @@ def test_tbstyle_native_setup_error(testdir): pass """ ) - result = testdir.runpytest("--tb=native") + result = pytester.runpytest("--tb=native") result.stdout.fnmatch_lines( ['*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'] ) -def test_terminal_summary(testdir): - testdir.makeconftest( +def test_terminal_summary(pytester: Pytester) -> None: + pytester.makeconftest( """ def pytest_terminal_summary(terminalreporter, exitstatus): w = terminalreporter @@ -1525,7 +1546,7 @@ def test_terminal_summary(testdir): w.line("exitstatus: {0}".format(exitstatus)) """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( """ *==== hello ====* @@ -1536,18 +1557,18 @@ def test_terminal_summary(testdir): @pytest.mark.filterwarnings("default") -def test_terminal_summary_warnings_are_displayed(testdir): +def test_terminal_summary_warnings_are_displayed(pytester: Pytester) -> None: """Test that warnings emitted during pytest_terminal_summary are displayed. (#1305). """ - testdir.makeconftest( + pytester.makeconftest( """ import warnings def pytest_terminal_summary(terminalreporter): warnings.warn(UserWarning('internal warning')) """ ) - testdir.makepyfile( + pytester.makepyfile( """ def test_failure(): import warnings @@ -1555,7 +1576,7 @@ def test_terminal_summary_warnings_are_displayed(testdir): assert 0 """ ) - result = testdir.runpytest("-ra") + result = pytester.runpytest("-ra") result.stdout.fnmatch_lines( [ "*= warnings summary =*", @@ -1573,8 +1594,8 @@ def test_terminal_summary_warnings_are_displayed(testdir): @pytest.mark.filterwarnings("default") -def test_terminal_summary_warnings_header_once(testdir): - testdir.makepyfile( +def test_terminal_summary_warnings_header_once(pytester: Pytester) -> None: + pytester.makepyfile( """ def test_failure(): import warnings @@ -1582,7 +1603,7 @@ def test_terminal_summary_warnings_header_once(testdir): assert 0 """ ) - result = testdir.runpytest("-ra") + result = pytester.runpytest("-ra") result.stdout.fnmatch_lines( [ "*= warnings summary =*", @@ -1598,8 +1619,8 @@ def test_terminal_summary_warnings_header_once(testdir): @pytest.mark.filterwarnings("default") -def test_terminal_no_summary_warnings_header_once(testdir): - testdir.makepyfile( +def test_terminal_no_summary_warnings_header_once(pytester: Pytester) -> None: + pytester.makepyfile( """ def test_failure(): import warnings @@ -1607,7 +1628,7 @@ def test_terminal_no_summary_warnings_header_once(testdir): assert 0 """ ) - result = testdir.runpytest("--no-summary") + result = pytester.runpytest("--no-summary") result.stdout.no_fnmatch_line("*= warnings summary =*") result.stdout.no_fnmatch_line("*= short test summary info =*") @@ -1796,8 +1817,8 @@ class TestClassicOutputStyle: """Ensure classic output style works as expected (#3883)""" @pytest.fixture - def test_files(self, testdir): - testdir.makepyfile( + def test_files(self, pytester: Pytester) -> None: + pytester.makepyfile( **{ "test_one.py": "def test_one(): pass", "test_two.py": "def test_two(): assert 0", @@ -1809,8 +1830,8 @@ class TestClassicOutputStyle: } ) - def test_normal_verbosity(self, testdir, test_files): - result = testdir.runpytest("-o", "console_output_style=classic") + def test_normal_verbosity(self, pytester: Pytester, test_files) -> None: + result = pytester.runpytest("-o", "console_output_style=classic") result.stdout.fnmatch_lines( [ "test_one.py .", @@ -1820,8 +1841,8 @@ class TestClassicOutputStyle: ] ) - def test_verbose(self, testdir, test_files): - result = testdir.runpytest("-o", "console_output_style=classic", "-v") + def test_verbose(self, pytester: Pytester, test_files) -> None: + result = pytester.runpytest("-o", "console_output_style=classic", "-v") result.stdout.fnmatch_lines( [ "test_one.py::test_one PASSED", @@ -1833,15 +1854,15 @@ class TestClassicOutputStyle: ] ) - def test_quiet(self, testdir, test_files): - result = testdir.runpytest("-o", "console_output_style=classic", "-q") + def test_quiet(self, pytester: Pytester, test_files) -> None: + result = pytester.runpytest("-o", "console_output_style=classic", "-q") result.stdout.fnmatch_lines([".F.F.", "*2 failed, 3 passed in*"]) class TestProgressOutputStyle: @pytest.fixture - def many_tests_files(self, testdir): - testdir.makepyfile( + def many_tests_files(self, pytester: Pytester) -> None: + pytester.makepyfile( test_bar=""" import pytest @pytest.mark.parametrize('i', range(10)) @@ -1859,10 +1880,10 @@ class TestProgressOutputStyle: """, ) - def test_zero_tests_collected(self, testdir): + def test_zero_tests_collected(self, pytester: Pytester) -> None: """Some plugins (testmon for example) might issue pytest_runtest_logreport without any tests being actually collected (#2971).""" - testdir.makeconftest( + pytester.makeconftest( """ def pytest_collection_modifyitems(items, config): from _pytest.runner import CollectReport @@ -1873,12 +1894,12 @@ class TestProgressOutputStyle: config.hook.pytest_runtest_logreport(report=rep) """ ) - output = testdir.runpytest() + output = pytester.runpytest() output.stdout.no_fnmatch_line("*ZeroDivisionError*") output.stdout.fnmatch_lines(["=* 2 passed in *="]) - def test_normal(self, many_tests_files, testdir): - output = testdir.runpytest() + def test_normal(self, many_tests_files, pytester: Pytester) -> None: + output = pytester.runpytest() output.stdout.re_match_lines( [ r"test_bar.py \.{10} \s+ \[ 50%\]", @@ -1887,9 +1908,11 @@ class TestProgressOutputStyle: ] ) - def test_colored_progress(self, testdir, monkeypatch, color_mapping): + def test_colored_progress( + self, pytester: Pytester, monkeypatch, color_mapping + ) -> None: monkeypatch.setenv("PY_COLORS", "1") - testdir.makepyfile( + pytester.makepyfile( test_axfail=""" import pytest @pytest.mark.xfail @@ -1914,7 +1937,7 @@ class TestProgressOutputStyle: def test_foobar(i): raise ValueError() """, ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.re_match_lines( color_mapping.format_for_rematch( [ @@ -1927,7 +1950,7 @@ class TestProgressOutputStyle: ) # Only xfail should have yellow progress indicator. - result = testdir.runpytest("test_axfail.py") + result = pytester.runpytest("test_axfail.py") result.stdout.re_match_lines( color_mapping.format_for_rematch( [ @@ -1937,14 +1960,14 @@ class TestProgressOutputStyle: ) ) - def test_count(self, many_tests_files, testdir): - testdir.makeini( + def test_count(self, many_tests_files, pytester: Pytester) -> None: + pytester.makeini( """ [pytest] console_output_style = count """ ) - output = testdir.runpytest() + output = pytester.runpytest() output.stdout.re_match_lines( [ r"test_bar.py \.{10} \s+ \[10/20\]", @@ -1953,8 +1976,8 @@ class TestProgressOutputStyle: ] ) - def test_verbose(self, many_tests_files, testdir): - output = testdir.runpytest("-v") + def test_verbose(self, many_tests_files, pytester: Pytester) -> None: + output = pytester.runpytest("-v") output.stdout.re_match_lines( [ r"test_bar.py::test_bar\[0\] PASSED \s+ \[ 5%\]", @@ -1963,14 +1986,14 @@ class TestProgressOutputStyle: ] ) - def test_verbose_count(self, many_tests_files, testdir): - testdir.makeini( + def test_verbose_count(self, many_tests_files, pytester: Pytester) -> None: + pytester.makeini( """ [pytest] console_output_style = count """ ) - output = testdir.runpytest("-v") + output = pytester.runpytest("-v") output.stdout.re_match_lines( [ r"test_bar.py::test_bar\[0\] PASSED \s+ \[ 1/20\]", @@ -1979,28 +2002,34 @@ class TestProgressOutputStyle: ] ) - def test_xdist_normal(self, many_tests_files, testdir, monkeypatch): + def test_xdist_normal( + self, many_tests_files, pytester: Pytester, monkeypatch + ) -> None: pytest.importorskip("xdist") monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - output = testdir.runpytest("-n2") + output = pytester.runpytest("-n2") output.stdout.re_match_lines([r"\.{20} \s+ \[100%\]"]) - def test_xdist_normal_count(self, many_tests_files, testdir, monkeypatch): + def test_xdist_normal_count( + self, many_tests_files, pytester: Pytester, monkeypatch + ) -> None: pytest.importorskip("xdist") monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - testdir.makeini( + pytester.makeini( """ [pytest] console_output_style = count """ ) - output = testdir.runpytest("-n2") + output = pytester.runpytest("-n2") output.stdout.re_match_lines([r"\.{20} \s+ \[20/20\]"]) - def test_xdist_verbose(self, many_tests_files, testdir, monkeypatch): + def test_xdist_verbose( + self, many_tests_files, pytester: Pytester, monkeypatch + ) -> None: pytest.importorskip("xdist") monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - output = testdir.runpytest("-n2", "-v") + output = pytester.runpytest("-n2", "-v") output.stdout.re_match_lines_random( [ r"\[gw\d\] \[\s*\d+%\] PASSED test_bar.py::test_bar\[1\]", @@ -2025,13 +2054,13 @@ class TestProgressOutputStyle: ] ) - def test_capture_no(self, many_tests_files, testdir): - output = testdir.runpytest("-s") + def test_capture_no(self, many_tests_files, pytester: Pytester) -> None: + output = pytester.runpytest("-s") output.stdout.re_match_lines( [r"test_bar.py \.{10}", r"test_foo.py \.{5}", r"test_foobar.py \.{5}"] ) - output = testdir.runpytest("--capture=no") + output = pytester.runpytest("--capture=no") output.stdout.no_fnmatch_line("*%]*") @@ -2039,8 +2068,8 @@ class TestProgressWithTeardown: """Ensure we show the correct percentages for tests that fail during teardown (#3088)""" @pytest.fixture - def contest_with_teardown_fixture(self, testdir): - testdir.makeconftest( + def contest_with_teardown_fixture(self, pytester: Pytester) -> None: + pytester.makeconftest( """ import pytest @@ -2052,8 +2081,8 @@ class TestProgressWithTeardown: ) @pytest.fixture - def many_files(self, testdir, contest_with_teardown_fixture): - testdir.makepyfile( + def many_files(self, pytester: Pytester, contest_with_teardown_fixture) -> None: + pytester.makepyfile( test_bar=""" import pytest @pytest.mark.parametrize('i', range(5)) @@ -2068,26 +2097,28 @@ class TestProgressWithTeardown: """, ) - def test_teardown_simple(self, testdir, contest_with_teardown_fixture): - testdir.makepyfile( + def test_teardown_simple( + self, pytester: Pytester, contest_with_teardown_fixture + ) -> None: + pytester.makepyfile( """ def test_foo(fail_teardown): pass """ ) - output = testdir.runpytest() + output = pytester.runpytest() output.stdout.re_match_lines([r"test_teardown_simple.py \.E\s+\[100%\]"]) def test_teardown_with_test_also_failing( - self, testdir, contest_with_teardown_fixture - ): - testdir.makepyfile( + self, pytester: Pytester, contest_with_teardown_fixture + ) -> None: + pytester.makepyfile( """ def test_foo(fail_teardown): assert 0 """ ) - output = testdir.runpytest("-rfE") + output = pytester.runpytest("-rfE") output.stdout.re_match_lines( [ r"test_teardown_with_test_also_failing.py FE\s+\[100%\]", @@ -2096,16 +2127,16 @@ class TestProgressWithTeardown: ] ) - def test_teardown_many(self, testdir, many_files): - output = testdir.runpytest() + def test_teardown_many(self, pytester: Pytester, many_files) -> None: + output = pytester.runpytest() output.stdout.re_match_lines( [r"test_bar.py (\.E){5}\s+\[ 25%\]", r"test_foo.py (\.E){15}\s+\[100%\]"] ) def test_teardown_many_verbose( - self, testdir: Testdir, many_files, color_mapping + self, pytester: Pytester, many_files, color_mapping ) -> None: - result = testdir.runpytest("-v") + result = pytester.runpytest("-v") result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ @@ -2119,10 +2150,10 @@ class TestProgressWithTeardown: ) ) - def test_xdist_normal(self, many_files, testdir, monkeypatch): + def test_xdist_normal(self, many_files, pytester: Pytester, monkeypatch) -> None: pytest.importorskip("xdist") monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - output = testdir.runpytest("-n2") + output = pytester.runpytest("-n2") output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"]) @@ -2160,7 +2191,7 @@ def test_skip_reasons_folding() -> None: assert reason == message -def test_line_with_reprcrash(monkeypatch): +def test_line_with_reprcrash(monkeypatch: MonkeyPatch) -> None: mocked_verbose_word = "FAILED" mocked_pos = "some::nodeid" @@ -2242,9 +2273,9 @@ def test_format_session_duration(seconds, expected): assert format_session_duration(seconds) == expected -def test_collecterror(testdir): - p1 = testdir.makepyfile("raise SyntaxError()") - result = testdir.runpytest("-ra", str(p1)) +def test_collecterror(pytester: Pytester) -> None: + p1 = pytester.makepyfile("raise SyntaxError()") + result = pytester.runpytest("-ra", str(p1)) result.stdout.fnmatch_lines( [ "collected 0 items / 1 error", @@ -2259,29 +2290,29 @@ def test_collecterror(testdir): ) -def test_no_summary_collecterror(testdir): - p1 = testdir.makepyfile("raise SyntaxError()") - result = testdir.runpytest("-ra", "--no-summary", str(p1)) +def test_no_summary_collecterror(pytester: Pytester) -> None: + p1 = pytester.makepyfile("raise SyntaxError()") + result = pytester.runpytest("-ra", "--no-summary", str(p1)) result.stdout.no_fnmatch_line("*= ERRORS =*") -def test_via_exec(testdir: Testdir) -> None: - p1 = testdir.makepyfile("exec('def test_via_exec(): pass')") - result = testdir.runpytest(str(p1), "-vv") +def test_via_exec(pytester: Pytester) -> None: + p1 = pytester.makepyfile("exec('def test_via_exec(): pass')") + result = pytester.runpytest(str(p1), "-vv") result.stdout.fnmatch_lines( ["test_via_exec.py::test_via_exec <- PASSED*", "*= 1 passed in *"] ) class TestCodeHighlight: - def test_code_highlight_simple(self, testdir: Testdir, color_mapping) -> None: - testdir.makepyfile( + def test_code_highlight_simple(self, pytester: Pytester, color_mapping) -> None: + pytester.makepyfile( """ def test_foo(): assert 1 == 10 """ ) - result = testdir.runpytest("--color=yes") + result = pytester.runpytest("--color=yes") result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ @@ -2292,15 +2323,17 @@ class TestCodeHighlight: ) ) - def test_code_highlight_continuation(self, testdir: Testdir, color_mapping) -> None: - testdir.makepyfile( + def test_code_highlight_continuation( + self, pytester: Pytester, color_mapping + ) -> None: + pytester.makepyfile( """ def test_foo(): print(''' '''); assert 0 """ ) - result = testdir.runpytest("--color=yes") + result = pytester.runpytest("--color=yes") result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch(