Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
hroncok opened this issue Jan 19, 2021 · 4 comments
Labels
type: selftests a problem in the tests of pytest

Comments

@hroncok
Copy link
Member

hroncok commented Jan 19, 2021

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.

@hroncok hroncok added the type: selftests a problem in the tests of pytest label Jan 19, 2021
@hroncok
Copy link
Member Author

hroncok commented Jan 20, 2021

In the meantime, we can workaround the failures in Fedora with the reverse:

echo "set enable-bracketed-paste off" > .inputrc
export INPUTRC=$PWD/.inputrc 

@bluetech
Copy link
Member

@hroncok Was this fixed in cpython? At least, this doesn't reproduce for me on bash 5.1.8 (bracket mode enabled), python 3.9.7.

@hroncok
Copy link
Member Author

hroncok commented Nov 15, 2021

Yeah, it might have been fixed by python/cpython#24108 -- I am unable to check now.

@hroncok
Copy link
Member Author

hroncok commented Nov 15, 2021

However, only on 3.8+.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: selftests a problem in the tests of pytest
Projects
None yet
Development

No branches or pull requests

2 participants