Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix TextIOWrapper assertion typo and simplify test
- 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.
  • Loading branch information
mohsinm-dev committed Nov 10, 2025
commit e84d686fd0b07eebd9a0b6e499095e4dcf0af2c8
43 changes: 2 additions & 41 deletions Lib/test/test_io/test_textio.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,60 +689,21 @@ def test_multibyte_seek_and_tell(self):
def test_tell_after_readline_with_cr(self):
Comment thread
sergey-miryanov marked this conversation as resolved.
# Test for gh-141314: TextIOWrapper.tell() assertion failure
# when dealing with standalone carriage returns
data = b'line1=1\r'
data = b'line1\r'
with self.open(os_helper.TESTFN, "wb") as f:
f.write(data)

with self.open(os_helper.TESTFN, "r") as f:
# Read line that ends with \r
line = f.readline()
self.assertEqual(line, "line1=1\n")
self.assertEqual(line, "line1\n")
# This should not cause an assertion failure
pos = f.tell()
# Verify we can seek back to this position
f.seek(pos)
remaining = f.read()
self.assertEqual(remaining, "")

def test_tell_after_readline_with_multiple_cr(self):
# Test for gh-141314: TextIOWrapper.tell() assertion failure
# when dealing with multiple standalone carriage returns
test_cases = [
(b'line1\r\rline2\r', ['line1\n', '\n', 'line2\n']),
(b'line1\r\r\rline2\r', ['line1\n', '\n', '\n', 'line2\n']),
(b'line1\rline2\rline3\r', ['line1\n', 'line2\n', 'line3\n']),
(b'\r\rdata\r', ['\n', '\n', 'data\n']),
]

for data, expected_lines in test_cases:
with self.subTest(data=data):
with self.open(os_helper.TESTFN, "wb") as f:
f.write(data)

with self.open(os_helper.TESTFN, "r") as f:
# Read all lines and call tell() after each
lines_read = []
positions = []
while True:
pos_before = f.tell()
line = f.readline()
if not line:
break
lines_read.append(line)
# This should not cause an assertion failure
pos_after = f.tell()
positions.append((pos_before, pos_after))

# Verify lines read correctly
self.assertEqual(lines_read, expected_lines)

# Verify we can seek back to each position
f.seek(0)
for i, (pos_before, pos_after) in enumerate(positions):
f.seek(pos_before)
line = f.readline()
self.assertEqual(line, expected_lines[i])
self.assertEqual(f.tell(), pos_after)

def test_seek_with_encoder_state(self):
f = self.open(os_helper.TESTFN, "w", encoding="euc_jis_2004")
Expand Down
11 changes: 3 additions & 8 deletions Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2844,14 +2844,9 @@ _io_TextIOWrapper_tell_impl(textio *self)
/* Fast search for an acceptable start point, close to our
current pos */
skip_bytes = (Py_ssize_t) (self->b2cratio * chars_to_skip);
/* Skip the optimization if next_input is empty */
if (PyBytes_GET_SIZE(next_input) == 0) {
skip_bytes = 0;
} else {
skip_back = 1;
assert(skip_back <= PyBytes_GET_SIZE(next_input));
input = PyBytes_AS_STRING(next_input);
}
skip_back = 1;
assert(skip_bytes <= PyBytes_GET_SIZE(next_input));
input = PyBytes_AS_STRING(next_input);
while (skip_bytes > 0) {
/* Decode up to temptative start point */
if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
Expand Down
Loading