Skip to content

code.InteractiveConsole leaks to stderr when stdin is non-interactive and -i isn't specified #140017

@bswck

Description

@bswck

Bug report

Bug description:

sys._baserepl() doesn't write to stdout when stdin is not a TTY:

❯ ./python <<< ''

(As clearly resembled in the code:)

if (_Py_FdIsInteractive(fp, filename)) {
res = _PyRun_InteractiveLoopObject(fp, filename, flags);
if (closeit) {
fclose(fp);
}
}
else {
res = _PyRun_SimpleFileObject(fp, filename, closeit, flags);
}

We can force it to write to stdout with the -i flag.

❯ ./python -i <<< ''
Python 3.15.0a0 (heads/main:5f91d5d9a41, Oct 12 2025, 22:21:59) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> >>> 

It's a mechanism currently used in tests:

def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
"""Run the Python REPL with the given arguments.
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
object.
"""
# To run the REPL without using a terminal, spawn python with the command
# line option '-i' and the process name set to '<stdin>'.

However, the code console family doesn't exhibit the same behavior:

❯ ./python -m code <<< ''
Python 3.15.0a0 (heads/main:5f91d5d9a41, Oct 12 2025, 22:21:59) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> >>> 
now exiting InteractiveConsole...

❯ ./python -m asyncio <<< ''
asyncio REPL 3.15.0a0 (heads/main:5f91d5d9a41, Oct 12 2025, 22:21:59) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> >>> 
exiting asyncio REPL...

The output that we're seeing here is gibberish.

The reason for that is that both of these interactive interpreters use input() for prompts.
input() writes to

  1. stdout, if stdin is a TTY or stdout is redirected
  2. stderr, if stdin is not a TTY or stderr is redirected

(The relationship of input() with stdout and stderr was widely discussed in #46221, but this issue doesn't particularly criticize that behavior).

Unless some existing pipelines rely on this existing behavior (which I doubt), perhaps we'd like to align code and friends to the original behavior and make them work with -i flag too (which will be a separate issue, preferable completed first, before this one).

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions