◐ Shell
reader mode source ↗
Skip to content

_WindowsConsoleIO #7151

Merged
youknowone merged 2 commits into
RustPython:mainfrom
youknowone:winconsoleio
Feb 15, 2026
Merged

_WindowsConsoleIO #7151
youknowone merged 2 commits into
RustPython:mainfrom
youknowone:winconsoleio

Conversation

@youknowone

@youknowone youknowone commented Feb 15, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Windows console I/O: console-aware stdin/stdout/stderr with UTF-8 defaults, a Windows console-backed IO type, and a test console integration for simulating console input/output.
    • Unified IO buffering: larger default buffer size to improve throughput.
  • Chores

    • Updated spell-check dictionary with additional Python/console tokens.

@coderabbitai

coderabbitai Bot commented Feb 15, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds Windows console I/O: introduces DEFAULT_BUFFER_SIZE, a new winconsoleio/WindowsConsoleIO surface with console detection and UTF-8 console defaults, a PyO3 _testconsole module for injecting console input on Windows, and a windows-sys feature flag for Win32 console APIs.

Changes

Cohort / File(s) Summary
Spell Check & Cargo
\.cspell.dict/cpython.txt, crates/stdlib/Cargo.toml
Added console-related dictionary tokens and added Win32_System_Console to the windows-sys features.
Test Console Module
crates/stdlib/src/_testconsole.rs, crates/stdlib/src/lib.rs
New PyO3 _testconsole module exposing write_input() and a read_output() stub; module registered under cfg(all(feature = "host_env", windows)).
Core IO & Buffering
crates/vm/src/stdlib/io.rs
Introduced DEFAULT_BUFFER_SIZE = 128 * 1024; added winconsoleio module and WindowsConsoleIO type, console detection (pyio_get_console_type), console-aware UTF-8 defaults, and replaced literal 8*1024 with the new constant across IO initialization.

Sequence Diagram(s)

sequenceDiagram
    actor Python
    participant io_open as io.open()
    participant console_check as ConsoleDetection
    participant winconsoleio as WindowsConsoleIO
    participant fileio as FileIO
    participant py_obj as PythonFileObject

    Python->>io_open: open(path, mode)
    io_open->>console_check: is_console(fileno)?
    alt Console detected
        console_check-->>io_open: true
        io_open->>winconsoleio: create WindowsConsoleIO
        winconsoleio->>winconsoleio: set UTF-8 default, use DEFAULT_BUFFER_SIZE
        winconsoleio-->>py_obj: return console-backed file object
    else Regular file
        console_check-->>io_open: false
        io_open->>fileio: create FileIO (uses DEFAULT_BUFFER_SIZE)
        fileio-->>py_obj: return file object
    end
Loading
sequenceDiagram
    actor Python
    participant write_input as _testconsole::write_input
    participant fileno as file.fileno()
    participant handle as Win32HANDLE
    participant conv as UTF16Conversion
    participant winapi as WriteConsoleInputW
    participant error as OS_Error

    Python->>write_input: write_input(file, bytes)
    write_input->>fileno: call fileno()
    fileno-->>handle: get HANDLE
    write_input->>handle: validate HANDLE != INVALID_HANDLE_VALUE
    alt Valid handle
        write_input->>conv: bytes -> UTF-16LE Vec<u16>
        conv->>conv: build INPUT_RECORD KEY_EVENT array
        conv-->>winapi: call WriteConsoleInputW (loop until all written)
        winapi-->>Python: success
    else Invalid handle
        handle-->>error: INVALID_HANDLE_VALUE
        error-->>Python: raise exception
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • ShaharNaveh

Poem

🐰 I hopped to the console with bytes in a paw,
UTF‑16 whispers and a buffer to draw,
INPUT_RECORD taps in a tiny parade,
WindowsConsoleIO hums where keys are made,
A little rabbit cheers — the console's well played!

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title '_WindowsConsoleIO' refers to a key component being added, but it is too narrow and does not capture the full scope of the change which includes multiple files, buffer size consolidation, and comprehensive Windows console I/O integration. Expand the title to better reflect the main objective, such as 'Add Windows console I/O support with unified buffer sizing' or similar to clarify the scope beyond just the module name.
Docstring Coverage ⚠️ Warning Docstring coverage is 70.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone youknowone force-pushed the winconsoleio branch 3 times, most recently from 8b37b4a to 5e4c233 Compare February 15, 2026 07:34
@youknowone youknowone marked this pull request as ready for review February 15, 2026 07:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hide comment

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@crates/vm/src/stdlib/io.rs`:
- Line 32: DEFAULT_BUFFER_SIZE was changed to 128 KiB and is now exported as
io.DEFAULT_BUFFER_SIZE and used for _blksize; confirm whether this divergence
from CPython's 8 KiB is intentional. Either revert DEFAULT_BUFFER_SIZE to 8 *
1024 (update the constant DEFAULT_BUFFER_SIZE) to preserve CPython
compatibility, or keep 128 * 1024 but add a clear comment and public
documentation where io.DEFAULT_BUFFER_SIZE and _blksize are defined/exported
(referencing the DEFAULT_BUFFER_SIZE constant and the _blksize export)
explaining the rationale for the larger buffer size.
- Around line 5991-6029: The mode-parsing loop currently accepts '+'/'a'/'b'/'x'
but silently ignores them; change the match in the parsing loop (the code
handling mode_str, rwa, readable, writable, console_type) so that encountering
unsupported flags ('+', 'a', 'x' — and any other non-rc/w characters) returns an
explicit vm.new_value_error (include the offending flag and mode_str in the
message) instead of falling through; leave handling for 'r' and 'w' as-is and
ensure the final rwa check remains to error when neither read nor write is
selected.
- Around line 6593-6611: The WideCharToMultiByte calls in read() (and the
similar call in readall()) currently ignore a 0 return and silently drop data;
update both functions to check if WideCharToMultiByte returns 0 and, on failure,
retrieve the Windows error code (GetLastError) and return an appropriate VM I/O
error instead of continuing — use the same error-building mechanism used
elsewhere in this module (e.g., the VM context I/O error helper) so callers get
a clear failure instead of truncated data. Ensure you reference the
WideCharToMultiByte result variable (u8n) and bail out with a descriptive error
containing the GetLastError value when u8n == 0 in both read() and readall().
- Around line 6646-6673: The initial MultiByteToWideChar call in write()
currently treats wlen == 0 as Ok(0); change this to propagate the Windows error
the same way the second call does: when the first MultiByteToWideChar returns 0,
return Err(std::io::Error::last_os_error().into_pyexception(vm)) so callers
receive the OS error instead of a successful 0 length; update the branch
handling the first wlen check around the MultiByteToWideChar invocation
accordingly (refer to MultiByteToWideChar and the surrounding write() logic).

@youknowone

Copy link
Copy Markdown
Member Author

reviews need to be checked

Add _WindowsConsoleIO class to _io module with ReadConsoleW/WriteConsoleW support.
Add _testconsole stdlib module with write_input for console input simulation.
Integrate console detection in io_open to use _WindowsConsoleIO for console handles.
@github-actions

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] lib: cpython/Lib/io.py
[x] lib: cpython/Lib/_pyio.py
[ ] test: cpython/Lib/test/test_io.py (TODO: 25)
[x] test: cpython/Lib/test/test_bufio.py
[x] test: cpython/Lib/test/test_fileio.py (TODO: 1)
[ ] test: cpython/Lib/test/test_memoryio.py (TODO: 29)

dependencies:

  • io

dependent tests: (89 tests)

  • io: test__colorize test_android test_argparse test_ast test_asyncio test_bufio test_builtin test_bz2 test_calendar test_cmd test_cmd_line_script test_codecs test_compileall test_compiler_assemble test_concurrent_futures test_configparser test_contextlib test_csv test_dbm_dumb test_dis test_email test_enum test_file test_fileinput test_fileio test_ftplib test_getpass test_gzip test_hashlib test_httplib test_httpservers test_importlib test_inspect test_io test_json test_largefile test_logging test_lzma test_mailbox test_marshal test_memoryio test_memoryview test_mimetypes test_optparse test_pathlib test_pickle test_pickletools test_plistlib test_pprint test_print test_pty test_pulldom test_pydoc test_pyexpat test_regrtest test_robotparser test_shlex test_shutil test_site test_smtplib test_socket test_socketserver test_subprocess test_support test_sys test_tarfile test_tempfile test_threadedtempfile test_timeit test_tokenize test_traceback test_typing test_unittest test_univnewlines test_urllib test_urllib2 test_uuid test_wave test_winconsoleio test_wsgiref test_xml_dom_xmlbuilder test_xml_etree test_xml_etree_c test_xmlrpc test_zipapp test_zipfile test_zipimport test_zoneinfo test_zstd

[x] test: cpython/Lib/test/test_winconsoleio.py

dependencies:

dependent tests: (no tests depend on winconsoleio)

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hide comment

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/vm/src/stdlib/io.rs`:
- Around line 6111-6114: The code currently forces fd-backed consoles to never
close the fd by unconditionally calling zelf.closefd.store(false); instead honor
the closefd parameter passed to the console initializer (or constructor) so
io.open(closefd=...) semantics are respected: locate the initializer that sets
zelf.closefd (the branch that handles "opened by fd") and change it to store the
provided closefd value (or leave the existing value) rather than overriding it;
ensure any callers that construct from an fd accept and forward a closefd
boolean so explicit user requests to close the fd are honored.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hide comment

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/vm/src/stdlib/io.rs`:
- Around line 6298-6307: In copy_from_buf the implementation uses a 0 byte as a
sentinel (buf[0] != 0) which incorrectly drops valid NUL bytes and can stall
data; change the buffering to track an explicit length or index instead of
sentinel bytes (e.g., maintain a separate usize field like "len" or use a small
VecDeque) and update the logic in copy_from_buf and any producers/consumers that
mutate the SMALLBUF so they push/pop based on length rather than shifting until
a 0; locate and modify the copy_from_buf function and any associated SMALLBUF
management code to read from buf[0..len], shift or pop properly, and decrement
len (or use VecDeque::pop_front) so NUL bytes are preserved and buffer state is
explicit.

Hide details View details @youknowone youknowone merged commit 243beb6 into RustPython:main Feb 15, 2026
14 checks passed
@youknowone youknowone deleted the winconsoleio branch February 15, 2026 16:51
youknowone added a commit to youknowone/RustPython that referenced this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant