Skip to content

test_builtin.PtyTests fail on non-ASCII characters if the readline module is loaded #58094

Closed

Description

@nadeemvawda
BPO 13886
Nosy @doko42, @vstinner, @ezio-melotti, @akheron, @vadmium, @serhiy-storchaka, @miss-islington, @iritkatriel
PRs
  • bpo-13886: Fix test_builtin.PtyTests tests when readline is loaded #7133
  • bpo-13886: Skip PTY non-ASCII tests if readline is loaded #30631
  • [3.10] bpo-13886: Skip PTY non-ASCII tests if readline is loaded (GH-30631) #30634
  • [3.9] bpo-13886: Skip PTY non-ASCII tests if readline is loaded (GH-30631) #30635
  • Files
  • rl-locale.diff: Fix readline to not discard chars that can't be decoded with sys.stdin.encoding
  • rl-test.diff: Ensure that input() tty tests always use readline
  • input-readline.patch
  • input-readline.v2.patch: stderr=DEVNULL
  • input-readline.v3.patch
  • input-readline.v4.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2022-01-17.13:48:59.793>
    created_at = <Date 2012-01-27.10:23:39.123>
    labels = ['type-bug', 'tests', '3.9', '3.10', '3.11']
    title = 'test_builtin.PtyTests fail on non-ASCII characters if the readline module is loaded'
    updated_at = <Date 2022-01-17.13:48:59.792>
    user = 'https://bugs.python.org/nadeemvawda'

    bugs.python.org fields:

    activity = <Date 2022-01-17.13:48:59.792>
    actor = 'vstinner'
    assignee = 'nadeem.vawda'
    closed = True
    closed_date = <Date 2022-01-17.13:48:59.793>
    closer = 'vstinner'
    components = ['Tests']
    creation = <Date 2012-01-27.10:23:39.123>
    creator = 'nadeem.vawda'
    dependencies = []
    files = ['24337', '24338', '41653', '45771', '46296', '46340']
    hgrepos = []
    issue_num = 13886
    keywords = ['patch']
    message_count = 41.0
    messages = ['152080', '152082', '164253', '180732', '180766', '180767', '180769', '180770', '180837', '181200', '181201', '181205', '181207', '181208', '191272', '211077', '258517', '258564', '282399', '282496', '283932', '283961', '285539', '285810', '303770', '303772', '317353', '317757', '318018', '410714', '410715', '410759', '410761', '410766', '410767', '410772', '410774', '410777', '410782', '410784', '410786']
    nosy_count = 11.0
    nosy_names = ['doko', 'vstinner', 'nadeem.vawda', 'ezio.melotti', 'Arfrever', 'python-dev', 'petri.lehtinen', 'martin.panter', 'serhiy.storchaka', 'miss-islington', 'iritkatriel']
    pr_nums = ['7133', '30631', '30634', '30635']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue13886'
    versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

    Activity

    1. nadeemvawda commented on Jan 27, 2012

      nadeemvawdamannequin
      MannequinAuthor

      I've recently come across a strange failure in the tests for the input()
      built-in function:

          $ ./python -E -m test -v test_readline test_builtin
      [... snip ...]
      
      \======================================================================
      FAIL: test_input_tty_non_ascii (test.test_builtin.BuiltinTest)
      \----------------------------------------------------------------------
      
          Traceback (most recent call last):
            File "/home/nadeem/src/cpython/def/Lib/test/test_builtin.py", line 1079, in test_input_tty_non_ascii
              self.check_input_tty("prompté", b"quux\xe9", "utf-8")
            File "/home/nadeem/src/cpython/def/Lib/test/test_builtin.py", line 1070, in check_input_tty
              self.assertEqual(input_result, expected)
          AssertionError: 'quux' != 'quux\udce9'
          - quux
          + quux\udce9
          ?     +
      \======================================================================
      FAIL: test_input_tty_non_ascii_unicode_errors (test.test_builtin.BuiltinTest)
      \----------------------------------------------------------------------
      
          Traceback (most recent call last):
            File "/home/nadeem/src/cpython/def/Lib/test/test_builtin.py", line 1083, in test_input_tty_non_ascii_unicode_errors
              self.check_input_tty("prompté", b"quux\xe9", "ascii")
            File "/home/nadeem/src/cpython/def/Lib/test/test_builtin.py", line 1070, in check_input_tty
              self.assertEqual(input_result, expected)
          AssertionError: 'quux' != 'quux\udce9'
          - quux
          + quux\udce9
          ?     +

      The failure only manifests itself if the readline module is loaded before
      test_builtin runs (hence the presence of test_readline above). It will
      not occur if regrtest is run with either of the -j or -W flags (which is
      why it hasn't been seen on the buildbots).

      The problem seems to be that readline assumes that its input should use
      the locale encoding, and silently strips out any undecodable chars. This
      breaks the tests mentioned above, since they set up sys.stdin to use the
      surrogateescape error handler, expecting invalid characters to be escaped
      rather than discarded.

      This problem doesn't crop up if readline is *not* loaded, because in that
      case PyOS_Readline() falls back to a stdio-based implementation
      (PyOS_StdioReadline()) that preserves invalid characters, allowing them
      to be handled properly by sys.stdin's encoding and error handler.

      I have been able to fix the test failures with the attached patch, which
      stops readline from eating invalid characters, making it consistent with
      the stdio-based fallback. Can someone with more knowledge of readline
      and/or locale issues advise whether the change is a good idea?

    2. nadeemvawda commented on Jan 27, 2012

      nadeemvawdamannequin
      MannequinAuthor

      Here's another patch that ensures the test always exercises the GNU
      readline code path (rather than the stdio fallback). This will cause the
      failure to occur when running just test_builtin (no need to also run
      test_readline before it).

      Ideally we'd want to test both code paths, but I'm not sure how to
      accomplish that reliably, short of running the test in a subprocess.

    3. akheron commented on Jun 28, 2012

      @akheron
      Member

      I had exactly the same error on 3.3b1 when running the test suite with randomized order.

    4. ezio-melotti commented on Jan 27, 2013

      @ezio-melotti
      Member

      This problem still exists on 3.4.
      The attached patch seems to solve it.

    5. python-dev commented on Jan 27, 2013

      python-devmannequin
      Mannequin

      New changeset cf0f450b3299 by Nadeem Vawda in branch '3.2':
      Issue bpo-13886: Fix input() to not strip out supposedly-invalid input bytes.
      http://hg.python.org/cpython/rev/cf0f450b3299

    6. python-dev commented on Jan 27, 2013

      python-devmannequin
      Mannequin

      New changeset 5c8732049dd5 by Nadeem Vawda in branch '3.3':
      Issue bpo-13886: Fix input() to not strip out supposedly-invalid input bytes.
      http://hg.python.org/cpython/rev/5c8732049dd5

    7. python-dev commented on Jan 27, 2013

      python-devmannequin
      Mannequin

      New changeset 9774721bfc32 by Nadeem Vawda in branch 'default':
      Issue bpo-13886: Fix input() to not strip out supposedly-invalid input bytes.
      http://hg.python.org/cpython/rev/9774721bfc32

    8. python-dev commented on Jan 27, 2013

      python-devmannequin
      Mannequin

      New changeset 12223782031f by Nadeem Vawda in branch '2.7':
      Issue bpo-13886: Fix input() to not strip out supposedly-invalid input bytes.
      http://hg.python.org/cpython/rev/12223782031f

    9. self-assigned this
      on Jan 27, 2013
    10. akheron commented on Jan 28, 2013

      @akheron
      Member
      • setlocale(LC_CTYPE, "");
        + setlocale(LC_CTYPE, "C");

      This looks dangerous to me. Are you sure readline's behavior doesn't change because of this?

    11. nadeemvawda commented on Feb 2, 2013

      nadeemvawdamannequin
      MannequinAuthor

      You're right; it breaks backspacing over multibyte characters. I should
      have tested it more carefully before committing. I'll revert the changes.

    12. 26 remaining items

    13. iritkatriel commented on Jan 16, 2022

      @iritkatriel
      Member

      See also bpo-44887.

    14. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      On Fedora 35, I still reproduce the initial issue on the main branch of Python:

      $ ./python -E -m test -v test_readline test_builtin
      (...)

      ======================================================================
      FAIL: test_input_tty_non_ascii (test.test_builtin.PtyTests)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2095, in test_input_tty_non_ascii
          self.check_input_tty("prompté", b"quux\xe9", "utf-8")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2086, in check_input_tty
          self.assertEqual(input_result, expected)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      AssertionError: 'quux' != 'quux\udce9'
      - quux
      + quux\udce9
      ?     +

      ======================================================================
      FAIL: test_input_tty_non_ascii_unicode_errors (test.test_builtin.PtyTests)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2099, in test_input_tty_non_ascii_unicode_errors
          self.check_input_tty("prompté", b"quux\xe9", "ascii")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2086, in check_input_tty
          self.assertEqual(input_result, expected)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      AssertionError: 'quux' != 'quux\udce9'
      - quux
      + quux\udce9
      ?     +
      (...)

      Fedora 35 uses readline 8.1:

      $ ldd $(./python -c 'import readline; print(readline.__file__)')
      	...
      	libreadline.so.8 => /lib64/libreadline.so.8 (0x00007fd00e553000)
      	...
      $ rpm -qf /lib64/libreadline.so.8
      readline-8.1-3.fc35.x86_64
      
      $ make pythoninfo|grep readline
      readline._READLINE_LIBRARY_VERSION: 8.1
      readline._READLINE_RUNTIME_VERSION: 0x801
      readline._READLINE_VERSION: 0x801
    15. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      Oh, the test_builtin.test_input_tty_non_ascii() fails just if test_readline is loaded previously:

      $ ./python -E -m test -m test.test_builtin.PtyTests.test_input_tty_non_ascii -v test_readline test_builtin
      == CPython 3.11.0a4+ (heads/main:7f4b69b9076, Jan 17 2022, 12:28:15) [GCC 11.2.1 20211203 (Red Hat 11.2.1-7)]
      == Linux-5.15.12-200.fc35.x86_64-x86_64-with-glibc2.34 little-endian
      == cwd: /home/vstinner/python/main/build/test_python_49429æ
      == CPU count: 8
      == encodings: locale=UTF-8, FS=utf-8
      0:00:00 load avg: 0.48 Run tests sequentially
      0:00:00 load avg: 0.48 [1/2] test_readline

      Ran 0 tests in 0.000s

      OK
      0:00:00 load avg: 0.48 [2/2] test_builtin -- test_readline ran no tests
      test_input_tty_non_ascii (test.test_builtin.PtyTests) ... FAIL

      ======================================================================
      FAIL: test_input_tty_non_ascii (test.test_builtin.PtyTests)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2095, in test_input_tty_non_ascii
          self.check_input_tty("prompté", b"quux\xe9", "utf-8")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2086, in check_input_tty
          self.assertEqual(input_result, expected)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      AssertionError: 'quux' != 'quux\udce9'
      - quux
      + quux\udce9
      ?     +

      Ran 1 test in 0.013s

      FAILED (failures=1)
      test test_builtin failed
      test_builtin failed (1 failure)

      == Tests result: FAILURE ==

      1 test failed:
      test_builtin

      1 test run no tests:
      test_readline

      Total duration: 559 ms
      Tests result: FAILURE

      In just, just importing readline is enough to make the test fails:

      $ git diff Lib/test/test_builtin.py
      diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
      index 6dc4fa55502..20d3d33d9fb 100644
      --- a/Lib/test/test_builtin.py
      +++ b/Lib/test/test_builtin.py
      @@ -1,3 +1,5 @@
      +import readline
      +
       # Python test set -- built-in functions
       
       import ast
      $ ./python -E -m test -m test.test_builtin.PtyTests.test_input_tty_non_ascii -v test_builtin
      (...)

      ======================================================================
      FAIL: test_input_tty_non_ascii (test.test_builtin.PtyTests)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2097, in test_input_tty_non_ascii
          self.check_input_tty("prompté", b"quux\xe9", "utf-8")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/home/vstinner/python/main/Lib/test/test_builtin.py", line 2088, in check_input_tty
          self.assertEqual(input_result, expected)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      AssertionError: 'quux' != 'quux\udce9'
      - quux
      + quux\udce9
      ?     +

      (...)

    16. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      Since nobody managed to fix this issue in 10 years and the test still fails if the readline module is loaded, I wrote python/issues-test-cpython#30631 to skip the test if the readline module is loaded.

    17. changed the title [-]readline-related test_builtin failure[/-] [+]test_builtin.PtyTests fail on non-ASCII characters if the readline module is loaded[/+] on Jan 17, 2022
    18. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      rl-locale.diff changes the readline implementation of the PyOS_Readline() to set LC_CTYPE locale to "C": setlocale(LC_CTYPE, "C"), rather to the user preferred locale: setlocale(LC_CTYPE, ""). IMO it's a bad idea. Python made great progress in Unicode support, readline has a good Unicode support, and in most cases, it just works like a charm. This change looks a hack just to get these 2 specific tests to pass, but it breaks any other usage of readline.

      rl-test.diff skips the test if the readline module can be imported, and it always import the readline module. It's different than that python/issues-test-cpython#30631 which only checks if the readline module is currently imported: my change doesn't import readline in test_builtin.

      "input-readline*.patch" patches and #51382 spawn a fresh Python process to make sure that the readline is not imported or to import readline explicitly. They are better than my fix, but they are more complicated. It seems likle these changes also fix test_input_tty_non_ascii() but I don't understand how.

    19. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      I marked bpo-41034 "test_builtin: PtyTests fail when run twice" as a duplicate of this issue. Moreover, I tested manually: my change python/issues-test-cpython#30631 fix the "./python -m test -R 3:3 test_builtin" command.

    20. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      New changeset ad6e640 by Victor Stinner in branch 'main':
      bpo-13886: Skip PTY non-ASCII tests if readline is loaded (GH-30631)
      ad6e640

    21. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      With my change, the two following commands now pass successfully:

      • ./python -m test test_readline test_builtin
      • ./python -m test -R 3:3 test_builtin
    22. miss-islington commented on Jan 17, 2022

      @miss-islington
      Contributor

      New changeset 1345b46 by Miss Islington (bot) in branch '3.10':
      bpo-13886: Skip PTY non-ASCII tests if readline is loaded (GH-30631)
      1345b46

    23. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      New changeset 0fbb9af by Miss Islington (bot) in branch '3.9':
      bpo-13886: Skip PTY non-ASCII tests if readline is loaded (GH-30631) (GH-30635)
      0fbb9af

    24. vstinner commented on Jan 17, 2022

      @vstinner
      Member

      Ok, the initial issue is now fixed: the test pass.

      If someone wants to write test input() with non-ASCII input and readline, I suggest to open a new issue and add the test in the test_readline module instead.

    25. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.10 (EOL)end of life3.11only security fixes3.9 (EOL)end of lifetestsTests 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