Skip to content

Readline-reliant tests are not isolated from personal init files #142353

@johnslavik

Description

@johnslavik

Bug description

This example test uses \x08 to simulate backspace:

cpython/Lib/test/test_pdb.py

Lines 4973 to 4991 in 61823a5

def test_multiline_auto_indent(self):
script = textwrap.dedent("""
import pdb; pdb.Pdb().set_trace()
""")
input = b"def f(x):\n"
input += b"if x > 0:\n"
input += b"x += 1\n"
input += b"return x\n"
# We need to do backspaces to remove the auto-indentation
input += b"\x08\x08\x08\x08else:\n"
input += b"return -x\n"
input += b"\n"
input += b"f(-21-21)\n"
input += b"c\n"
output = run_pty(script, input)
self.assertIn(b'42', output)

With a GNU readline backend (e.g. on Linux), somebody's ~/.inputrc could break this heuristic and cause the test to fail.

To reproduce:

# remap \x08
echo '"\C-h": backward-kill-word' >| ${TMP_INPUTRC:=$(mktemp)}

# run test
INPUTRC=$TMP_INPUTRC ./python -m test test_pdb -m test_multiline_auto_indent

# cleanup
rm -fv $TMP_INPUTRC
======================================================================
FAIL: test_multiline_auto_indent (Lib.test.test_pdb.PdbTestReadline.test_multiline_auto_indent)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/bswck/Python/cpython/Lib/test/test_pdb.py", line 4991, in test_multiline_auto_indent
    self.assertIn(b'42', output)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^
AssertionError: b'42' not found in bytearray(b"def f(x):\r\nif x > 0:\r\nx += 1\r\nreturn x\r\n^H^H^H^Helse:\r\nreturn -x\r\n\r\nf(-21-21)\r\nc\r\n> <string>(2)<module>()\r\n(Pdb) def f(x):\r\n...       if x > 0:\r\n...           x += 1\r\n...           return x\r\n...           \r\x1b[C\x1b[C\x1b[C\x1b[C\x1b[C\x1b[C\x1b[Kelse:\r\n*** SyntaxError: invalid syntax\r\n(Pdb) return -x\r\n*** Invalid argument: -x\r\n      Usage: r(eturn)\r\n(Pdb) \r\n*** Invalid argument: -x\r\n      Usage: r(eturn)\r\n(Pdb) f(-21-21)\r\n*** NameError: name 'f' is not defined\r\n(Pdb) c\r\n")

----------------------------------------------------------------------
Ran 1 test in 0.244s

FAILED (failures=1)
removed '/tmp/tmp.VXGud3AbMo'

If INPUTRC (or EDITRC if libedit is used1) points to a clean file, the default Readline keybinds in tests always work:

❯ INPUTRC=/dev/null ./python -m test test_pdb -m test_multiline_auto_indent
Using random seed: 4048417429
0:00:00 load avg: 0.81 Run 1 test sequentially in a single process
0:00:00 load avg: 0.81 [1/1] test_pdb
0:00:00 load avg: 0.81 [1/1] test_pdb passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 509 ms
Total tests: run=1 (filtered)
Total test files: run=1/1 (filtered)
Result: SUCCESS

Scope

This issue is relevant to PTY tests only:

  • input() uses readline only if stdin a TTY
  • code.InteractiveConsole uses input() in general
  • pdb interactive mode isn't tested outside of PTY
  • the new REPL requires stdin to be a TTY (because it emulates readline), falls back to basic REPL otherwise
  • the basic REPL doesn't use readline

Resolution

To avoid looking into $HOME/.inputrc or /etc/inputrc (or $PWD/.editrc or $HOME/.editrc1) which can cause test pollution, we could ensure that INPUTRC (and EDITRC?1) environment variables are set to a path of an empty file in the proper test setup code.

The most tempting idea I have is to add a flag parameter like readline= to run_pty() that would create the proper environment dict if env is None.

CC @ZeroIntensity (mentorship) type-bug, tests, 3.13, 3.14, 3.15

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Footnotes

  1. I have not confirmed these libedit specifics -- only found them. I couldn't find any documentation on EDITRC anywhere. 2 3

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14bugs and security fixes3.15new features, bugs and security fixestestsTests in the Lib/test dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions