From 6954b3b0dcca48157b744d1c35cb9ac14146759b Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Thu, 12 Mar 2020 14:56:57 +0200 Subject: [PATCH] Assume os.dup is always available The commit which added the checks for os.dup a15afb5e4879d68033a723129e6 suggests it was done for Jython. But pytest doesn't support Jython anymore (Jython is Python 2 only). Furthermore, it looks like the faulthandler plugin (bundled in pytest and enabled by default) uses os.dup() unprotected and there have not been any complaints. So seems better to just remove these checks, and only add if someone with a legitimate use case complains. --- changelog/6903.breaking.rst | 2 ++ src/_pytest/capture.py | 10 +------- testing/test_capture.py | 50 +------------------------------------ 3 files changed, 4 insertions(+), 58 deletions(-) create mode 100644 changelog/6903.breaking.rst diff --git a/changelog/6903.breaking.rst b/changelog/6903.breaking.rst new file mode 100644 index 000000000..a074a4ffe --- /dev/null +++ b/changelog/6903.breaking.rst @@ -0,0 +1,2 @@ +The ``os.dup()`` function is now assumed to exist. We are not aware of any +supported Python 3 implementations which do not provide it. diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 5f29c5ca2..2af207e21 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -34,7 +34,7 @@ def pytest_addoption(parser): group._addoption( "--capture", action="store", - default="fd" if hasattr(os, "dup") else "sys", + default="fd", metavar="method", choices=["fd", "sys", "no", "tee-sys"], help="per-test capturing method: one of fd|sys|no|tee-sys.", @@ -304,10 +304,6 @@ def capfd(request): calls, which return a ``(out, err)`` namedtuple. ``out`` and ``err`` will be ``text`` objects. """ - if not hasattr(os, "dup"): - pytest.skip( - "capfd fixture needs os.dup function which is not available in this system" - ) capman = request.config.pluginmanager.getplugin("capturemanager") with capman._capturing_for_request(request) as fixture: yield fixture @@ -321,10 +317,6 @@ def capfdbinary(request): calls, which return a ``(out, err)`` namedtuple. ``out`` and ``err`` will be ``byte`` objects. """ - if not hasattr(os, "dup"): - pytest.skip( - "capfdbinary fixture needs os.dup function which is not available in this system" - ) capman = request.config.pluginmanager.getplugin("capturemanager") with capman._capturing_for_request(request) as fixture: yield fixture diff --git a/testing/test_capture.py b/testing/test_capture.py index a3e558560..a2b100fda 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -23,11 +23,6 @@ from _pytest.config import ExitCode # pylib 1.4.20.dev2 (rev 13d9af95547e) -needsosdup = pytest.mark.skipif( - not hasattr(os, "dup"), reason="test needs os.dup, not available on this platform" -) - - def StdCaptureFD(out=True, err=True, in_=True): return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture) @@ -41,22 +36,7 @@ def TeeStdCapture(out=True, err=True, in_=True): class TestCaptureManager: - def test_getmethod_default_no_fd(self, monkeypatch): - from _pytest.capture import pytest_addoption - from _pytest.config.argparsing import Parser - - parser = Parser() - pytest_addoption(parser) - default = parser._groups[0].options[0].default - assert default == "fd" if hasattr(os, "dup") else "sys" - parser = Parser() - monkeypatch.delattr(os, "dup", raising=False) - pytest_addoption(parser) - assert parser._groups[0].options[0].default == "sys" - - @pytest.mark.parametrize( - "method", ["no", "sys", pytest.param("fd", marks=needsosdup)] - ) + @pytest.mark.parametrize("method", ["no", "sys", "fd"]) def test_capturing_basic_api(self, method): capouter = StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin @@ -86,7 +66,6 @@ class TestCaptureManager: finally: capouter.stop_capturing() - @needsosdup def test_init_capturing(self): capouter = StdCaptureFD() try: @@ -512,7 +491,6 @@ class TestCaptureFixture: result = testdir.runpytest(p) result.stdout.fnmatch_lines(["xxx42xxx"]) - @needsosdup def test_stdfd_functional(self, testdir): reprec = testdir.inline_runsource( """\ @@ -526,7 +504,6 @@ class TestCaptureFixture: ) reprec.assertoutcome(passed=1) - @needsosdup def test_capfdbinary(self, testdir): reprec = testdir.inline_runsource( """\ @@ -565,7 +542,6 @@ class TestCaptureFixture: result = testdir.runpytest(p) result.stdout.fnmatch_lines(["*test_partial_setup_failure*", "*1 error*"]) - @needsosdup def test_keyboardinterrupt_disables_capturing(self, testdir): p = testdir.makepyfile( """\ @@ -700,20 +676,6 @@ def test_setup_failure_does_not_kill_capturing(testdir): result.stdout.fnmatch_lines(["*ValueError(42)*", "*1 error*"]) -def test_fdfuncarg_skips_on_no_osdup(testdir): - testdir.makepyfile( - """ - import os - if hasattr(os, 'dup'): - del os.dup - def test_hello(capfd): - pass - """ - ) - result = testdir.runpytest_subprocess("--capture=no") - result.stdout.fnmatch_lines(["*1 skipped*"]) - - def test_capture_conftest_runtest_setup(testdir): testdir.makeconftest( """ @@ -865,7 +827,6 @@ def tmpfile(testdir) -> Generator[BinaryIO, None, None]: f.close() -@needsosdup def test_dupfile(tmpfile) -> None: flist = [] # type: List[TextIO] for i in range(5): @@ -924,8 +885,6 @@ def lsof_check(): class TestFDCapture: - pytestmark = needsosdup - def test_simple(self, tmpfile): fd = tmpfile.fileno() cap = capture.FDCapture(fd) @@ -1169,7 +1128,6 @@ class TestTeeStdCapture(TestStdCapture): class TestStdCaptureFD(TestStdCapture): - pytestmark = needsosdup captureclass = staticmethod(StdCaptureFD) def test_simple_only_fd(self, testdir): @@ -1212,8 +1170,6 @@ class TestStdCaptureFD(TestStdCapture): class TestStdCaptureFDinvalidFD: - pytestmark = needsosdup - def test_stdcapture_fd_invalid_fd(self, testdir): testdir.makepyfile( """ @@ -1269,7 +1225,6 @@ def test_capsys_results_accessible_by_attribute(capsys): assert capture_result.err == "eggs" -@needsosdup @pytest.mark.parametrize("use", [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: @@ -1285,7 +1240,6 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): assert capfile2 == capfile -@needsosdup def test_close_and_capture_again(testdir): testdir.makepyfile( """ @@ -1310,8 +1264,6 @@ def test_close_and_capture_again(testdir): @pytest.mark.parametrize("method", ["SysCapture", "FDCapture", "TeeSysCapture"]) def test_capturing_and_logging_fundamentals(testdir, method): - if method == "StdCaptureFD" and not hasattr(os, "dup"): - pytest.skip("need os.dup") # here we check a fundamental feature p = testdir.makepyfile( """