Skip to content

The PDB tests fail with Bash in bracketed-paste mode: Unexpected escape sequences in stdout #8256

@hroncok

Description

@hroncok

Hello, the recent Bash update to 5.1 introduced the bracketed-paste mode by default. The tests of pytest now fail by default, however users were able to opt-in for bracketed-paste mode even in the past.

It can be reproduced on Linux even with older Bash, with:

$ echo "set enable-bracketed-paste on" > .inputrc
$ export INPUTRC=$PWD/.inputrc 
$ git diff tox.ini
-passenv = USER USERNAME COVERAGE_* PYTEST_ADDOPTS TERM
+passenv = INPUTRC USER USERNAME COVERAGE_* PYTEST_ADDOPTS TERM
$ tox -e py39-pexpect -- -k pdb -v
...
py39 inst-nodeps: .../pytest/.tox/.tmp/package/3/pytest-6.3.0.dev92+g7a5a6cb51.d20210119.tar.gz
py39 installed: argcomplete==1.12.2,attrs==20.3.0,certifi==2020.12.5,chardet==4.0.0,elementpath==2.1.1,hypothesis==6.0.2,idna==2.10,iniconfig==1.1.1,mock==4.0.3,nose==1.3.7,packaging==20.8,pexpect==4.8.0,pluggy==0.13.1,ptyprocess==0.7.0,py==1.10.0,Pygments==2.7.4,pyparsing==2.4.7,pytest @ file://.../pytest/.tox/.tmp/package/3/pytest-6.3.0.dev92%2Bg7a5a6cb51.d20210119.tar.gz,requests==2.25.1,sortedcontainers==2.3.0,toml==0.10.2,urllib3==1.26.2,xmlschema==1.4.1
py39 run-test-pre: PYTHONHASHSEED='3921388258'
py39 run-test: commands[0] | pytest -k pdb -v
============================= test session starts ==============================
platform linux -- Python 3.9.1, pytest-6.3.0.dev92+g7a5a6cb51.d20210119, py-1.10.0, pluggy-0.13.1 -- .../pytest/.tox/py39/bin/python
cachedir: .tox/py39/.pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('.../pytest/.hypothesis/examples')
rootdir: .../pytest, configfile: pyproject.toml, testpaths: testing
plugins: hypothesis-6.0.2
collecting ... collected 3057 items / 3002 deselected / 55 selected

testing/test_debugging.py::TestPDB::test_pdb_validate_usepdb_cls PASSED  [  1%]
testing/test_faulthandler.py::test_cancel_timeout_on_hook[pytest_enter_pdb] PASSED [  3%]
testing/test_debugging.py::TestPDB::test_pdb_on_fail PASSED              [  5%]
testing/test_debugging.py::TestPDB::test_pdb_on_xfail PASSED             [  7%]
testing/test_debugging.py::TestPDB::test_pdb_on_skip PASSED              [  9%]
testing/test_debugging.py::TestPDB::test_pdb_on_BdbQuit PASSED           [ 10%]
testing/test_debugging.py::TestPDB::test_pdb_on_KeyboardInterrupt PASSED [ 12%]
testing/test_debugging.py::TestPDB::test_pdb_custom_cls PASSED           [ 14%]
testing/test_debugging.py::TestPDB::test_pdb_custom_cls_invalid PASSED   [ 16%]
testing/test_debugging.py::TestPDB::test_pdb_custom_cls_without_pdb PASSED [ 18%]
testing/test_debugging.py::TestDebuggingBreakpoints::test_pdb_custom_cls PASSED [ 20%]
testing/test_debugging.py::test_pdbcls_via_local_module PASSED           [ 21%]
testing/test_debugging.py::test_pdb_wrapper_class_is_reused PASSED       [ 23%]
testing/test_unittest.py::test_pdb_teardown_called PASSED                [ 25%]
testing/test_unittest.py::test_pdb_teardown_skipped[@unittest.skip] PASSED [ 27%]
testing/test_unittest.py::test_pdb_teardown_skipped[@pytest.mark.skip] PASSED [ 29%]
testing/acceptance_test.py::test_pdb_can_be_rewritten PASSED             [ 30%]
testing/test_debugging.py::TestPDB::test_pdb_unittest_postmortem PASSED  [ 32%]
testing/test_debugging.py::TestPDB::test_pdb_unittest_skip PASSED        [ 34%]
testing/test_debugging.py::TestPDB::test_pdb_print_captured_stdout_and_stderr PASSED [ 36%]
testing/test_debugging.py::TestPDB::test_pdb_dont_print_empty_captured_stdout_and_stderr PASSED [ 38%]
testing/test_debugging.py::TestPDB::test_pdb_print_captured_logs[all] PASSED [ 40%]
testing/test_debugging.py::TestPDB::test_pdb_print_captured_logs[no] PASSED [ 41%]
testing/test_debugging.py::TestPDB::test_pdb_print_captured_logs[log] PASSED [ 43%]
testing/test_debugging.py::TestPDB::test_pdb_print_captured_logs_nologging PASSED [ 45%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_exception PASSED [ 47%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_on_collection_issue181 PASSED [ 49%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_on_internal_error PASSED [ 50%]
testing/test_debugging.py::TestPDB::test_pdb_prevent_ConftestImportFailure_hiding_exception PASSED [ 52%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_capturing_simple PASSED [ 54%]
testing/test_debugging.py::TestPDB::test_pdb_set_trace_kwargs PASSED     [ 56%]
testing/test_debugging.py::TestPDB::test_pdb_set_trace_interception PASSED [ 58%]
testing/test_debugging.py::TestPDB::test_pdb_and_capsys PASSED           [ 60%]
testing/test_debugging.py::TestPDB::test_pdb_with_caplog_on_pdb_invocation PASSED [ 61%]
testing/test_debugging.py::TestPDB::test_set_trace_capturing_afterwards PASSED [ 63%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_doctest FAILED  [ 65%]
testing/test_debugging.py::TestPDB::test_doctest_set_trace_quit PASSED   [ 67%]
testing/test_debugging.py::TestPDB::test_pdb_interaction_capturing_twice PASSED [ 69%]
testing/test_debugging.py::TestPDB::test_pdb_with_injected_do_debug FAILED [ 70%]
testing/test_debugging.py::TestPDB::test_pdb_without_capture PASSED      [ 72%]
testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[] FAILED [ 74%]
testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[-s] FAILED [ 76%]
testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[-p no:capture] FAILED [ 78%]
testing/test_debugging.py::TestPDB::test_pdb_used_outside_test PASSED    [ 80%]
testing/test_debugging.py::TestPDB::test_pdb_used_in_generate_tests PASSED [ 81%]
testing/test_debugging.py::TestPDB::test_pdb_collection_failure_is_shown PASSED [ 83%]
testing/test_debugging.py::TestPDB::test_enter_leave_pdb_hooks_are_called[False] PASSED [ 85%]
testing/test_debugging.py::TestPDB::test_enter_leave_pdb_hooks_are_called[True] PASSED [ 87%]
testing/test_debugging.py::TestPDB::test_pdb_custom_cls_with_set_trace PASSED [ 89%]
testing/test_debugging.py::TestDebuggingBreakpoints::test_sys_breakpointhook_configure_and_unconfigure[--pdb] PASSED [ 90%]
testing/test_debugging.py::TestDebuggingBreakpoints::test_environ_custom_class[--pdb] PASSED [ 92%]
testing/test_debugging.py::TestDebuggingBreakpoints::test_pdb_not_altered PASSED [ 94%]
testing/test_debugging.py::test_pdb_suspends_fixture_capturing[capfd] FAILED [ 96%]
testing/test_debugging.py::test_pdb_suspends_fixture_capturing[capsys] FAILED [ 98%]
testing/test_unittest.py::TestTrialUnittest::test_trial_pdb SKIPPED      [100%]

=================================== FAILURES ===================================
_____________________ TestPDB.test_pdb_interaction_doctest _____________________

self = <test_debugging.TestPDB object at 0x7f3de3aa8df0>
pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_interaction_doctest0')>

    def test_pdb_interaction_doctest(self, pytester: Pytester) -> None:
        p1 = pytester.makepyfile(
            """
            def function_1():
                '''
                >>> i = 0
                >>> assert i == 1
                '''
        """
        )
        child = pytester.spawn_pytest("--doctest-modules --pdb %s" % p1)
        child.expect("Pdb")
    
        assert "UNEXPECTED EXCEPTION: AssertionError()" in child.before.decode("utf8")
    
        child.sendline("'i=%i.' % i")
        child.expect("Pdb")
>       assert "\r\n'i=0.'\r\n" in child.before.decode("utf8")
E       assert "\r\n'i=0.'\r\n" in ") 'i=%i.' % i\r\n\x1b[?2004l\r'i=0.'\r\n\x1b[?2004h("
E        +  where ") 'i=%i.' % i\r\n\x1b[?2004l\r'i=0.'\r\n\x1b[?2004h(" = <built-in method decode of bytes object at 0x7f3de3a76260>('utf8')
E        +    where <built-in method decode of bytes object at 0x7f3de3a76260> = b") 'i=%i.' % i\r\n\x1b[?2004l\r'i=0.'\r\n\x1b[?2004h(".decode
E        +      where b") 'i=%i.' % i\r\n\x1b[?2004l\r'i=0.'\r\n\x1b[?2004h(" = <pexpect.pty_spawn.spawn object at 0x7f3de3aa8dc0>.before

.../pytest/testing/test_debugging.py:502: AssertionError
___________________ TestPDB.test_pdb_with_injected_do_debug ____________________

self = <test_debugging.TestPDB object at 0x7f3de4256f10>
pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_with_injected_do_debug0')>

    def test_pdb_with_injected_do_debug(self, pytester: Pytester) -> None:
        """Simulates pdbpp, which injects Pdb into do_debug, and uses
        self.__class__ in do_continue.
        """
        p1 = pytester.makepyfile(
            mytest="""
            import pdb
            import pytest
    
            count_continue = 0
    
            class CustomPdb(pdb.Pdb, object):
                def do_debug(self, arg):
                    import sys
                    import types
    
                    do_debug_func = pdb.Pdb.do_debug
    
                    newglobals = do_debug_func.__globals__.copy()
                    newglobals['Pdb'] = self.__class__
                    orig_do_debug = types.FunctionType(
                        do_debug_func.__code__, newglobals,
                        do_debug_func.__name__, do_debug_func.__defaults__,
                    )
                    return orig_do_debug(self, arg)
                do_debug.__doc__ = pdb.Pdb.do_debug.__doc__
    
                def do_continue(self, *args, **kwargs):
                    global count_continue
                    count_continue += 1
                    return super(CustomPdb, self).do_continue(*args, **kwargs)
    
            def foo():
                print("print_from_foo")
    
            def test_1():
                i = 0
                print("hello17")
                pytest.set_trace()
                x = 3
                print("hello18")
    
                assert count_continue == 2, "unexpected_failure: %d != 2" % count_continue
                pytest.fail("expected_failure")
        """
        )
        child = pytester.spawn_pytest("--pdbcls=mytest:CustomPdb %s" % str(p1))
        child.expect(r"PDB set_trace \(IO-capturing turned off\)")
>       child.expect(r"\n\(Pdb")

.../pytest/testing/test_debugging.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../pytest/.tox/py39/lib/python3.9/site-packages/pexpect/spawnbase.py:343: in expect
    return self.expect_list(compiled_pattern_list,
.../pytest/.tox/py39/lib/python3.9/site-packages/pexpect/spawnbase.py:372: in expect_list
    return exp.expect_loop(timeout)
.../pytest/.tox/py39/lib/python3.9/site-packages/pexpect/expect.py:181: in expect_loop
    return self.timeout(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pexpect.expect.Expecter object at 0x7f3de4314f70>
err = TIMEOUT('Timeout exceeded.')

    def timeout(self, err=None):
        spawn = self.spawn
    
        spawn.before = spawn._before.getvalue()
        spawn.after = TIMEOUT
        index = self.searcher.timeout_index
        if index >= 0:
            spawn.match = TIMEOUT
            spawn.match_index = index
            return index
        else:
            spawn.match = None
            spawn.match_index = None
            msg = str(spawn)
            msg += '\nsearcher: %s' % self.searcher
            if err is not None:
                msg = str(err) + '\n' + msg
    
            exc = TIMEOUT(msg)
            exc.__cause__ = None    # in Python 3.x we can use "raise exc from None"
>           raise exc
E           pexpect.exceptions.TIMEOUT: Timeout exceeded.
E           <pexpect.pty_spawn.spawn object at 0x7f3de42c36d0>
E           command: .../pytest/.tox/py39/bin/python
E           args: ['.../pytest/.tox/py39/bin/python', '-mpytest', '--basetemp=/tmp/pytest-of-churchyard/pytest-14/test_pdb_with_injected_do_debug0/temp-pexpect', '--pdbcls=mytest:CustomPdb', '/tmp/pytest-of-churchyard/pytest-14/test_pdb_with_injected_do_debug0/mytest.py']
E           buffer (last 100 chars): b'hurchyard/pytest-14/test_pdb_with_injected_do_debug0/mytest.py(34)test_1()\r\n-> x = 3\r\n\x1b[?2004h(Pdb) '
E           before (last 100 chars): b'hurchyard/pytest-14/test_pdb_with_injected_do_debug0/mytest.py(34)test_1()\r\n-> x = 3\r\n\x1b[?2004h(Pdb) '
E           after: <class 'pexpect.exceptions.TIMEOUT'>
E           match: None
E           match_index: None
E           exitstatus: None
E           flag_eof: False
E           pid: 1921178
E           child_fd: 17
E           closed: False
E           timeout: 10.0
E           delimiter: <class 'pexpect.exceptions.EOF'>
E           logfile: <_io.BufferedWriter name='/tmp/pytest-of-churchyard/pytest-14/test_pdb_with_injected_do_debug0/spawn.out'>
E           logfile_read: None
E           logfile_send: None
E           maxread: 2000
E           ignorecase: False
E           searchwindowsize: None
E           delaybeforesend: 0.05
E           delayafterclose: 0.1
E           delayafterterminate: 0.1
E           searcher: searcher_re:
E               0: re.compile(b'\\n\\(Pdb')

.../pytest/.tox/py39/lib/python3.9/site-packages/pexpect/expect.py:144: TIMEOUT
_______________ TestPDB.test_pdb_continue_with_recursive_debug[] _______________

self = <test_debugging.TestPDB object at 0x7f3de428b340>, capture_arg = ''
pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_continue_with_recursive_debug0')>

    @pytest.mark.parametrize("capture_arg", ("", "-s", "-p no:capture"))
    def test_pdb_continue_with_recursive_debug(
        self, capture_arg, pytester: Pytester
    ) -> None:
        """Full coverage for do_debug without capturing.
    
        This is very similar to test_pdb_interaction_continue_recursive in general,
        but mocks out ``pdb.set_trace`` for providing more coverage.
        """
        p1 = pytester.makepyfile(
            """
            try:
                input = raw_input
            except NameError:
                pass
    
            def set_trace():
                __import__('pdb').set_trace()
    
            def test_1(monkeypatch):
                import _pytest.debugging
    
                class pytestPDBTest(_pytest.debugging.pytestPDB):
                    @classmethod
                    def set_trace(cls, *args, **kwargs):
                        # Init PytestPdbWrapper to handle capturing.
                        _pdb = cls._init_pdb("set_trace", *args, **kwargs)
    
                        # Mock out pdb.Pdb.do_continue.
                        import pdb
                        pdb.Pdb.do_continue = lambda self, arg: None
    
                        print("===" + " SET_TRACE ===")
                        assert input() == "debug set_trace()"
    
                        # Simulate PytestPdbWrapper.do_debug
                        cls._recursive_debug += 1
                        print("ENTERING RECURSIVE DEBUGGER")
                        print("===" + " SET_TRACE_2 ===")
    
                        assert input() == "c"
                        _pdb.do_continue("")
                        print("===" + " SET_TRACE_3 ===")
    
                        # Simulate PytestPdbWrapper.do_debug
                        print("LEAVING RECURSIVE DEBUGGER")
                        cls._recursive_debug -= 1
    
                        print("===" + " SET_TRACE_4 ===")
                        assert input() == "c"
                        _pdb.do_continue("")
    
                    def do_continue(self, arg):
                        print("=== do_continue")
    
                monkeypatch.setattr(_pytest.debugging, "pytestPDB", pytestPDBTest)
    
                import pdb
                monkeypatch.setattr(pdb, "set_trace", pytestPDBTest.set_trace)
    
                set_trace()
        """
        )
        child = pytester.spawn_pytest(f"--tb=short {p1} {capture_arg}")
        child.expect("=== SET_TRACE ===")
        before = child.before.decode("utf8")
        if not capture_arg:
            assert ">>> PDB set_trace (IO-capturing turned off) >>>" in before
        else:
            assert ">>> PDB set_trace >>>" in before
        child.sendline("debug set_trace()")
        child.expect("=== SET_TRACE_2 ===")
        before = child.before.decode("utf8")
>       assert "\r\nENTERING RECURSIVE DEBUGGER\r\n" in before
E       AssertionError: assert '\r\nENTERING RECURSIVE DEBUGGER\r\n' in '\r\n\x1b[?2004hdebug set_trace()\r\n\x1b[?2004l\rENTERING RECURSIVE DEBUGGER\r\n'

.../pytest/testing/test_debugging.py:731: AssertionError
______________ TestPDB.test_pdb_continue_with_recursive_debug[-s] ______________

self = <test_debugging.TestPDB object at 0x7f3de3b846d0>, capture_arg = '-s'
pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_continue_with_recursive_debug1')>

    @pytest.mark.parametrize("capture_arg", ("", "-s", "-p no:capture"))
    def test_pdb_continue_with_recursive_debug(
        self, capture_arg, pytester: Pytester
    ) -> None:
        """Full coverage for do_debug without capturing.
    
        This is very similar to test_pdb_interaction_continue_recursive in general,
        but mocks out ``pdb.set_trace`` for providing more coverage.
        """
        p1 = pytester.makepyfile(
            """
            try:
                input = raw_input
            except NameError:
                pass
    
            def set_trace():
                __import__('pdb').set_trace()
    
            def test_1(monkeypatch):
                import _pytest.debugging
    
                class pytestPDBTest(_pytest.debugging.pytestPDB):
                    @classmethod
                    def set_trace(cls, *args, **kwargs):
                        # Init PytestPdbWrapper to handle capturing.
                        _pdb = cls._init_pdb("set_trace", *args, **kwargs)
    
                        # Mock out pdb.Pdb.do_continue.
                        import pdb
                        pdb.Pdb.do_continue = lambda self, arg: None
    
                        print("===" + " SET_TRACE ===")
                        assert input() == "debug set_trace()"
    
                        # Simulate PytestPdbWrapper.do_debug
                        cls._recursive_debug += 1
                        print("ENTERING RECURSIVE DEBUGGER")
                        print("===" + " SET_TRACE_2 ===")
    
                        assert input() == "c"
                        _pdb.do_continue("")
                        print("===" + " SET_TRACE_3 ===")
    
                        # Simulate PytestPdbWrapper.do_debug
                        print("LEAVING RECURSIVE DEBUGGER")
                        cls._recursive_debug -= 1
    
                        print("===" + " SET_TRACE_4 ===")
                        assert input() == "c"
                        _pdb.do_continue("")
    
                    def do_continue(self, arg):
                        print("=== do_continue")
    
                monkeypatch.setattr(_pytest.debugging, "pytestPDB", pytestPDBTest)
    
                import pdb
                monkeypatch.setattr(pdb, "set_trace", pytestPDBTest.set_trace)
    
                set_trace()
        """
        )
        child = pytester.spawn_pytest(f"--tb=short {p1} {capture_arg}")
        child.expect("=== SET_TRACE ===")
        before = child.before.decode("utf8")
        if not capture_arg:
            assert ">>> PDB set_trace (IO-capturing turned off) >>>" in before
        else:
            assert ">>> PDB set_trace >>>" in before
        child.sendline("debug set_trace()")
        child.expect("=== SET_TRACE_2 ===")
        before = child.before.decode("utf8")
>       assert "\r\nENTERING RECURSIVE DEBUGGER\r\n" in before
E       AssertionError: assert '\r\nENTERING RECURSIVE DEBUGGER\r\n' in '\r\n\x1b[?2004hdebug set_trace()\r\n\x1b[?2004l\rENTERING RECURSIVE DEBUGGER\r\n'

.../pytest/testing/test_debugging.py:731: AssertionError
________ TestPDB.test_pdb_continue_with_recursive_debug[-p no:capture] _________

self = <test_debugging.TestPDB object at 0x7f3de3b848e0>
capture_arg = '-p no:capture'
pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_continue_with_recursive_debug2')>

    @pytest.mark.parametrize("capture_arg", ("", "-s", "-p no:capture"))
    def test_pdb_continue_with_recursive_debug(
        self, capture_arg, pytester: Pytester
    ) -> None:
        """Full coverage for do_debug without capturing.
    
        This is very similar to test_pdb_interaction_continue_recursive in general,
        but mocks out ``pdb.set_trace`` for providing more coverage.
        """
        p1 = pytester.makepyfile(
            """
            try:
                input = raw_input
            except NameError:
                pass
    
            def set_trace():
                __import__('pdb').set_trace()
    
            def test_1(monkeypatch):
                import _pytest.debugging
    
                class pytestPDBTest(_pytest.debugging.pytestPDB):
                    @classmethod
                    def set_trace(cls, *args, **kwargs):
                        # Init PytestPdbWrapper to handle capturing.
                        _pdb = cls._init_pdb("set_trace", *args, **kwargs)
    
                        # Mock out pdb.Pdb.do_continue.
                        import pdb
                        pdb.Pdb.do_continue = lambda self, arg: None
    
                        print("===" + " SET_TRACE ===")
                        assert input() == "debug set_trace()"
    
                        # Simulate PytestPdbWrapper.do_debug
                        cls._recursive_debug += 1
                        print("ENTERING RECURSIVE DEBUGGER")
                        print("===" + " SET_TRACE_2 ===")
    
                        assert input() == "c"
                        _pdb.do_continue("")
                        print("===" + " SET_TRACE_3 ===")
    
                        # Simulate PytestPdbWrapper.do_debug
                        print("LEAVING RECURSIVE DEBUGGER")
                        cls._recursive_debug -= 1
    
                        print("===" + " SET_TRACE_4 ===")
                        assert input() == "c"
                        _pdb.do_continue("")
    
                    def do_continue(self, arg):
                        print("=== do_continue")
    
                monkeypatch.setattr(_pytest.debugging, "pytestPDB", pytestPDBTest)
    
                import pdb
                monkeypatch.setattr(pdb, "set_trace", pytestPDBTest.set_trace)
    
                set_trace()
        """
        )
        child = pytester.spawn_pytest(f"--tb=short {p1} {capture_arg}")
        child.expect("=== SET_TRACE ===")
        before = child.before.decode("utf8")
        if not capture_arg:
            assert ">>> PDB set_trace (IO-capturing turned off) >>>" in before
        else:
            assert ">>> PDB set_trace >>>" in before
        child.sendline("debug set_trace()")
        child.expect("=== SET_TRACE_2 ===")
        before = child.before.decode("utf8")
>       assert "\r\nENTERING RECURSIVE DEBUGGER\r\n" in before
E       AssertionError: assert '\r\nENTERING RECURSIVE DEBUGGER\r\n' in '\r\n\x1b[?2004hdebug set_trace()\r\n\x1b[?2004l\rENTERING RECURSIVE DEBUGGER\r\n'

.../pytest/testing/test_debugging.py:731: AssertionError
__________________ test_pdb_suspends_fixture_capturing[capfd] __________________

pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_suspends_fixture_capturing0')>
fixture = 'capfd'

    @pytest.mark.parametrize("fixture", ("capfd", "capsys"))
    def test_pdb_suspends_fixture_capturing(pytester: Pytester, fixture: str) -> None:
        """Using "-s" with pytest should suspend/resume fixture capturing."""
        p1 = pytester.makepyfile(
            """
            def test_inner({fixture}):
                import sys
    
                print("out_inner_before")
                sys.stderr.write("err_inner_before\\n")
    
                __import__("pdb").set_trace()
    
                print("out_inner_after")
                sys.stderr.write("err_inner_after\\n")
    
                out, err = {fixture}.readouterr()
                assert out =="out_inner_before\\nout_inner_after\\n"
                assert err =="err_inner_before\\nerr_inner_after\\n"
            """.format(
                fixture=fixture
            )
        )
    
        child = pytester.spawn_pytest(str(p1) + " -s")
    
        child.expect("Pdb")
        before = child.before.decode("utf8")
        assert (
            "> PDB set_trace (IO-capturing turned off for fixture %s) >" % (fixture)
            in before
        )
    
        # Test that capturing is really suspended.
        child.sendline("p 40 + 2")
        child.expect("Pdb")
>       assert "\r\n42\r\n" in child.before.decode("utf8")
E       AssertionError: assert '\r\n42\r\n' in ') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h('
E        +  where ') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h(' = <built-in method decode of bytes object at 0x7f3de4285cb0>('utf8')
E        +    where <built-in method decode of bytes object at 0x7f3de4285cb0> = b') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h('.decode
E        +      where b') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h(' = <pexpect.pty_spawn.spawn object at 0x7f3de42497c0>.before

.../pytest/testing/test_debugging.py:1225: AssertionError
_________________ test_pdb_suspends_fixture_capturing[capsys] __________________

pytester = <Pytester PosixPath('/tmp/pytest-of-churchyard/pytest-14/test_pdb_suspends_fixture_capturing1')>
fixture = 'capsys'

    @pytest.mark.parametrize("fixture", ("capfd", "capsys"))
    def test_pdb_suspends_fixture_capturing(pytester: Pytester, fixture: str) -> None:
        """Using "-s" with pytest should suspend/resume fixture capturing."""
        p1 = pytester.makepyfile(
            """
            def test_inner({fixture}):
                import sys
    
                print("out_inner_before")
                sys.stderr.write("err_inner_before\\n")
    
                __import__("pdb").set_trace()
    
                print("out_inner_after")
                sys.stderr.write("err_inner_after\\n")
    
                out, err = {fixture}.readouterr()
                assert out =="out_inner_before\\nout_inner_after\\n"
                assert err =="err_inner_before\\nerr_inner_after\\n"
            """.format(
                fixture=fixture
            )
        )
    
        child = pytester.spawn_pytest(str(p1) + " -s")
    
        child.expect("Pdb")
        before = child.before.decode("utf8")
        assert (
            "> PDB set_trace (IO-capturing turned off for fixture %s) >" % (fixture)
            in before
        )
    
        # Test that capturing is really suspended.
        child.sendline("p 40 + 2")
        child.expect("Pdb")
>       assert "\r\n42\r\n" in child.before.decode("utf8")
E       AssertionError: assert '\r\n42\r\n' in ') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h('
E        +  where ') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h(' = <built-in method decode of bytes object at 0x7f3de56e6620>('utf8')
E        +    where <built-in method decode of bytes object at 0x7f3de56e6620> = b') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h('.decode
E        +      where b') p 40 + 2\r\n\x1b[?2004l\r42\r\n\x1b[?2004h(' = <pexpect.pty_spawn.spawn object at 0x7f3de3b9abb0>.before

.../pytest/testing/test_debugging.py:1225: AssertionError
=========================== short test summary info ============================
FAILED testing/test_debugging.py::TestPDB::test_pdb_interaction_doctest - ass...
FAILED testing/test_debugging.py::TestPDB::test_pdb_with_injected_do_debug - ...
FAILED testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[]
FAILED testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[-s]
FAILED testing/test_debugging.py::TestPDB::test_pdb_continue_with_recursive_debug[-p no:capture]
FAILED testing/test_debugging.py::test_pdb_suspends_fixture_capturing[capfd]
FAILED testing/test_debugging.py::test_pdb_suspends_fixture_capturing[capsys]
========== 7 failed, 47 passed, 1 skipped, 3002 deselected in 27.89s ===========
ERROR: InvocationError for command .../pytest/.tox/py39/bin/pytest -k pdb -v (exited with code 1)
___________________________________ summary ____________________________________
ERROR:   py39: commands failed
...

Note that the escape sequences come form pexpect: pexpect/pexpect#669

However, I don't know if filtering them out there is a reasonable fix. They are part of the stdout after all.

Opening this to discuss options.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: selftestsa problem in the tests of pytest

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions