Skip to content

Conversation

@mohsinm-dev
Copy link
Owner

@mohsinm-dev mohsinm-dev commented Nov 10, 2025

Summary

  • Fix assertion failure in io.TextIOWrapper.tell() when reading files ending with standalone \r
  • Add comprehensive test case to prevent regression
  • Add NEWS entry documenting the fix

Root Cause

The tell() optimization algorithm assumed buffered data would always be available when calculating position, but files ending with standalone \r create empty snapshots, causing assert(skip_back <= PyBytes_GET_SIZE(next_input)) to fail.

Fix

Added check to skip optimization when next_input is empty, preventing the assertion failure while maintaining correct position calculation.

Test Plan

  • Added test case test_tell_after_readline_with_cr in test_textio.py
  • Verified fix handles standalone carriage returns correctly
  • Confirmed all existing io tests still pass
  • Built CPython with debug assertions enabled

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an assertion when reporting file position while reading files that include standalone carriage return (CR) line endings, improving stability of position reporting and seek/read interactions.
  • Tests

    • Added a test that verifies reading a line with a standalone CR and subsequent tell/seek/read behavior.
    • Minor stylistic and formatting updates to tests.

…dalone carriage return

When TextIOWrapper.tell() is called after reading a line that ends with a
standalone carriage return (\r), the tell optimization algorithm incorrectly
assumes there is buffered data to search through. This causes an assertion
failure when skip_back=1 exceeds the empty buffer size.

The fix detects when next_input is empty and skips the optimization phase,
falling back to the byte-by-byte decoding method which always works correctly.
This properly handles the architectural constraint that buffer optimization
cannot function without buffered data.
…dalone carriage return

Add test case and fix assertion failure in TextIOWrapper.tell() when reading
files that end with a standalone carriage return (\r). The optimization
algorithm incorrectly assumed buffered data would always be available,
causing an assertion failure when next_input is empty.
@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Walkthrough

Adds a new test that reproduces reading a line ending with a standalone CR and exercising TextIOWrapper.tell/seek/read, updates the C tell implementation assertion to validate skip_bytes, and adds a NEWS entry documenting the bugfix for an assertion failure with \r line endings.

Changes

Cohort / File(s) Summary
Tests
Lib/test/test_io/test_textio.py
Adds test_tell_after_readline_with_cr: writes b'line1\r', reopens in text mode, reads a line asserting "line1\n", calls tell(), seeks to that position, reads remaining content and asserts it's empty.
C implementation (I/O)
Modules/_io/textio.c
In _io_TextIOWrapper_tell_impl(), changed the internal validation to assert on skip_bytes (the number of bytes used to start decoding) instead of skip_back. No API changes.
Changelog
Misc/NEWS.d/next/...gh-issue-141314.baaa28.rst
Added NEWS entry describing a bugfix: fixed an assertion failure in io.TextIOWrapper.tell() when reading files with standalone \r line endings.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Test as Test file
    participant PyAPI as TextIOWrapper (Python)
    participant CImpl as _io_TextIOWrapper_tell_impl (C)

    Test->>PyAPI: open file, readline()
    PyAPI->>CImpl: compute internal buffer/positions
    CImpl->>CImpl: compute/validate skip_bytes (was skip_back)
    Note over CImpl: assertion now checks `skip_bytes`
    CImpl-->>PyAPI: return position
    PyAPI-->>Test: tell()/seek()/read() results used by test
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect Modules/_io/textio.c change for correctness around buffer/position math and boundary cases (standalone \r).
  • Verify the new test reliably reproduces the scenario and is robust across platforms/encodings.
  • Confirm NEWS entry wording and placement.

Poem

I nibble bytes with whiskered care,
A lone CR found me in the lair,
I check the skips and count each hop,
No more assertions — hop, hop, hop! 🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly reflects the main change: fixing an assertion failure in TextIOWrapper.tell() with standalone carriage returns, which is the core issue addressed across all modified files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-textio-tell-assertion-gh-141314

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b298058 and e84d686.

📒 Files selected for processing (2)
  • Lib/test/test_io/test_textio.py (1 hunks)
  • Modules/_io/textio.c (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Modules/_io/textio.c
🔇 Additional comments (1)
Lib/test/test_io/test_textio.py (1)

689-706: Excellent regression test!

This test effectively reproduces the pythongh-141314 assertion failure scenario and verifies the fix. The test structure is clear and follows the conventions in this file.


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.

- Remove trailing whitespace
- Add missing newline at end of NEWS file
- Fix assertion to check skip_bytes instead of skip_back
- Use simpler test data b'line1\r' instead of b'line1=1\r'
- Remove unnecessary multiple CR test case
- Clean up workaround code

The assertion was checking wrong variable (skip_back vs skip_bytes).
skip_back is search step size, skip_bytes is buffer offset needing validation.
@mohsinm-dev mohsinm-dev force-pushed the fix-textio-tell-assertion-gh-141314 branch from b298058 to e84d686 Compare November 10, 2025 17:53
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.

2 participants