Skip to content

Commit 3faea86

Browse files
jbrockmendelclaude
andcommitted
CLN: correct issue refs and comments on the read_csv token-length helper
Comment-only follow-ups from reviewing the branch: - The embedded-NUL comment and test cited GH#66277, the perf issue, and briefly GH#19886, which this branch does not fix (three of that issue's four reported cases still fail). Both now cite GH#66415, matching the whatsnew entry for the fix. - The helper's precondition named coliter_next; its only caller uses coliter_next_with_idx, so the precondition is now checkable. - The test comment explained the wrong thing about the two columns: "a" covers the words[token_idx + 1] branch and "b" the stream-end branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 1623192 commit 3faea86

2 files changed

Lines changed: 11 additions & 9 deletions

File tree

pandas/_libs/parsers.pyx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,7 +2571,7 @@ cdef _string_pyarrow_utf8(parser_t *parser, int64_t col,
25712571
continue
25722572

25732573
# Not strlen: an embedded NUL is a data byte here, so strlen would
2574-
# truncate the field at it (GH#66277).
2574+
# truncate the field at it (GH#66415).
25752575
wlen = _token_len_words(parser, token_idx, word)
25762576

25772577
if not large and total_bytes + wlen > <Py_ssize_t>INT32_MAX:
@@ -3062,11 +3062,11 @@ cdef inline int64_t _token_len_words(parser_t *parser, int64_t token_idx,
30623062
# rather than `word_starts`. The tokenizer keeps the two in lockstep
30633063
# (words[i] == stream + word_starts[i], rebased whenever the stream
30643064
# reallocs), so the result is identical; what differs is which array the
3065-
# loop touches. coliter_next already loaded words[token_idx] to produce
3066-
# `word`, so the boundary comes off a cache line the loop has in hand
3067-
# instead of streaming a second metadata array alongside the first.
3068-
# `word` must be the unmodified coliter_next result for `token_idx`;
3069-
# an adjusted pointer would silently yield a wrong length.
3065+
# loop touches. coliter_next_with_idx already loaded words[token_idx] to
3066+
# produce `word`, so the boundary comes off a cache line the loop has in
3067+
# hand instead of streaming a second metadata array alongside the first.
3068+
# `word` must be the unmodified coliter_next_with_idx result for
3069+
# `token_idx`; an adjusted pointer would silently yield a wrong length.
30703070
# Only the pyarrow string path uses this: rewriting _token_len itself to
30713071
# this form regressed long-token ints ~6% (GH#66277), so the numeric
30723072
# callers keep the word_starts version.

pandas/tests/io/parser/test_c_parser_only.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -858,10 +858,12 @@ def test_block_lane_nrows_short_row_near_stream_capacity(c_parser_only):
858858
@pytest.mark.parametrize("kwargs", [{}, {"dtype_backend": "pyarrow"}])
859859
@pytest.mark.parametrize("prefix_len", [1, 200])
860860
def test_embedded_nul_byte_roundtrip(c_parser_only, kwargs, prefix_len):
861-
# GH#19886: the pyarrow string fast path computed token lengths with
861+
# GH#66415: the pyarrow string fast path computed token lengths with
862862
# strlen, so a quoted field with an embedded NUL byte was truncated at the
863-
# NUL. Column "b" is the last token in the stream, so its length comes
864-
# from the stream end rather than from the next token's start.
863+
# NUL. Column "a" takes its length from the next token's start and column
864+
# "b", last in the stream, from the stream end, covering both branches of
865+
# the length helper; the two prefix_len values keep a length-capped scan
866+
# from passing by accident.
865867
pytest.importorskip("pyarrow")
866868
parser = c_parser_only
867869
value = b"x" * prefix_len + b"\x00y"

0 commit comments

Comments
 (0)