Skip to content

test_pyrepl and test_shelve fail on FreeBSD16 #144423

Closed

Description

@vstinner

FreeeBSD16 buildbot: https://buildbot.python.org/#/builders/1857/builds/23

test_shelve failure:

ERROR: test_custom_serializer_and_deserializer (test.test_shelve.TestCase.test_custom_serializer_and_deserializer) (proto=5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/test_shelve.py", line 205, in test_custom_serializer_and_deserializer
    s["bytearray_data"] = bytearray_data
    ~^^^^^^^^^^^^^^^^^^
  File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/shelve.py", line 137, in __setitem__
    self.dict[key.encode(self.keyencoding)] = serialized_value
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: dbm mappings have bytes or string elements only

test_pyrepl failure:

FAIL: test_no_newline (test.test_pyrepl.test_pyrepl.TestMain.test_no_newline)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/support/__init__.py", line 3048, in wrapper
    return func(*args, **kwargs)
  File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/test_pyrepl/test_pyrepl.py", line 1952, in test_no_newline
    self.assertIn(expected_output_sequence, basic_output)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 'Something pretty long>>> exit()' not found in 'print(\'Something pretty long\', end=\'\')\r\nexit()\r\nPython 3.15.0a5+ (heads/main:bb917d83b16, Feb  3 2026, 13:51:15) [Clang 19.1.7 (https://github.com/llvm/llvm-project.git llvmorg-19.1.7-0-gcd7080 on freebsd\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> Something pretty long>>> '

Activity

  1. vstinner commented on Feb 3, 2026

    @vstinner
    MemberAuthor
  2. furkanonder commented on Feb 3, 2026

    @furkanonder
    Contributor

    test_shelve failure:

    ERROR: test_custom_serializer_and_deserializer (test.test_shelve.TestCase.test_custom_serializer_and_deserializer) (proto=5)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/test_shelve.py", line 205, in test_custom_serializer_and_deserializer
        s["bytearray_data"] = bytearray_data
        ~^^^^^^^^^^^^^^^^^^
      File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/shelve.py", line 137, in __setitem__
        self.dict[key.encode(self.keyencoding)] = serialized_value
        ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    TypeError: dbm mappings have bytes or string elements only
    

    The test's custom serializer returns a bytearray directly when protocol == 5, but DBM backends (ndbm, gdbm, etc.) only accept bytes or str, not bytearray. This fails on FreeBSD (ndbm), WSL/Linux (gdbm), and potentially other platforms depending on which DBM backend is available.

    I've created a fix that addresses this by converting bytearray to bytes in the test serializer before returning.
    CC: @picnixz

  3. self-assigned this
    on Feb 3, 2026
  4. furkanonder commented on Feb 3, 2026

    @furkanonder
    Contributor

    test_pyrepl failure:

    FAIL: test_no_newline (test.test_pyrepl.test_pyrepl.TestMain.test_no_newline)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/support/__init__.py", line 3048, in wrapper
        return func(*args, **kwargs)
      File "/var/db/buildbot/buildarea/3.x.opsec-fbsd16/build/Lib/test/test_pyrepl/test_pyrepl.py", line 1952, in test_no_newline
        self.assertIn(expected_output_sequence, basic_output)
        ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AssertionError: 'Something pretty long>>> exit()' not found in 'print(\'Something pretty long\', end=\'\')\r\nexit()\r\nPython 3.15.0a5+ (heads/main:bb917d83b16, Feb  3 2026, 13:51:15) [Clang 19.1.7 (https://github.com/llvm/llvm-project.git llvmorg-19.1.7-0-gcd7080 on freebsd\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> Something pretty long>>> '
    

    The failure looks like a timing/race condition that fails on slow platforms like buildbots. It also occurred for a while on the RISC-V buildbot, but now doesn't show up consistently. It looks like a flaky test.

    The test sends two commands (print(...) and exit()) together via pty. I think the commands are echoed by the pty before the REPL has fully processed the first command, causing the output to appear in a different order.

    Reproducer

    import os, pty, select, subprocess, sys
    
    def run_test_without_fix():
        master_fd, slave_fd = pty.openpty()
        proc = subprocess.Popen(
            [sys.executable, "-i", "-u", "-I"],
            stdin=slave_fd, stdout=slave_fd, stderr=slave_fd,
            text=True, close_fds=True,
            env={**os.environ, "PYTHON_BASIC_REPL": "1", "TERM": "dumb"},
        )
        os.close(slave_fd)
    
        # Send all commands at once
        os.write(master_fd, b"print('Something pretty long', end='')\nexit()\n")
    
        output = []
        while select.select([master_fd], [], [], 15)[0]:
            try:
                data = os.read(master_fd, 1024).decode()
                if not data: break
                output.append(data)
            except OSError: break
    
        os.close(master_fd)
        proc.wait()
        return "".join(output)
    
    
    def run_test_with_fix():
        master_fd, slave_fd = pty.openpty()
        proc = subprocess.Popen(
            [sys.executable, "-i", "-u", "-I"],
            stdin=slave_fd, stdout=slave_fd, stderr=slave_fd,
            text=True, close_fds=True,
            env={**os.environ, "PYTHON_BASIC_REPL": "1", "TERM": "dumb"},
        )
        os.close(slave_fd)
    
        output = []
    
        # Wait for initial prompt
        while select.select([master_fd], [], [], 15)[0]:
            data = os.read(master_fd, 1024).decode()
            output.append(data)
            if ">>> " in "".join(output): break
    
        prompt_count = "".join(output).count(">>> ")
    
        # Send first command
        os.write(master_fd, b"print('Something pretty long', end='')\n")
    
        # Wait for command to complete (new prompt appears)
        while select.select([master_fd], [], [], 15)[0]:
            data = os.read(master_fd, 1024).decode()
            output.append(data)
            combined = "".join(output)
            if combined.count(">>> ") > prompt_count and "Something pretty long" in combined:
                break
    
        # now send exit
        os.write(master_fd, b"exit()\n")
    
        while select.select([master_fd], [], [], 5)[0]:
            try:
                data = os.read(master_fd, 1024).decode()
                if not data: break
                output.append(data)
            except OSError: break
    
        os.close(master_fd)
        proc.wait()
        return "".join(output)
    
    
    expected = "Something pretty long>>> exit()"
    
    print("Without fix:", "PASS" if expected in run_test_without_fix() else "FAIL")
    print("With fix:   ", "PASS" if expected in run_test_with_fix() else "FAIL")

    Output on x86:

    Without fix: PASS
    With fix:    PASS
    

    Output on RISC-V:

    Without fix: FAIL
    With fix:    PASS
    

    The potential fix for the test could wait for the initial >>> prompt before sending commands, and send commands one at a time waiting for each prompt. I'm working on a fix for this.
    CC: @ambv

  5. chris-eibl commented on Feb 3, 2026

    @chris-eibl
    Member

    Thanks for the pyrepl failure analysis! It is also tracked in #143394.

  6. vstinner commented on Mar 26, 2026

    @vstinner
    MemberAuthor

    test_shelve has been fixed in the meanwhile by #137879.

  7. furkanonder commented on Mar 31, 2026

    @furkanonder
    Contributor

    @vstinner The test is only passing when the GNU readline is enabled in the CPython build. (see:#143394 (comment))

  8. chris-eibl commented on Apr 3, 2026

    @chris-eibl
    Member

    @vstinner has fixed test_no_newline(#147973), so I think we can close here, too?

  9. vstinner commented on Apr 3, 2026

    @vstinner
    MemberAuthor

    I would prefer to check that all tests now pass on FreeBSD 16, but the FreeBSD 16 buildbot worker is offline for 1 month. I wrote to the worker owner to ask if he can check what's going on.

    In the meanwhile, I'm ok to close this issue.

  10. opsec commented on Aug 6, 2026

    @opsec

    The FreeBSD 16 buildbot is back with a much newer version of FreeBSD 16. Let's see if it works out.

  11. vstinner commented on Aug 6, 2026

    @vstinner
    MemberAuthor

    @opsec: Oh that's great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

OS-freebsdtestsTests 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