One function

JSONLIterator in mahmoud/boltons

The author described this change as jsonutils: fix JSONLIterator nontermination at EOF and negative rel_seek. It counts as a record because the check below fails on the code as it stood at 435774ef8 and passes on f1034b07d, with nothing else changed between the two runs.

Fix saved2026-08-06
Sharing licenceBSD-2-Clause · LICENSE
Change size+7 5

What the code was meant to do, written into the code itself as a docstring

The `JSONLIterator` is used to iterate over JSON-encoded objects stored in the `JSON Lines format`_ (one object per line). Most notably it has the ability to efficiently read from the bottom of files, making it very effective for reading in simple append-only JSONL use cases. It also has the ability to start from anywhere in the file and ignore corrupted lines. Args: file_obj (file): An open file object. ignore_errors (bool): Whether to skip over lines that raise an error on deserialization (:func:`json.loads`). reverse (bool): Controls the direction of the iteration. Defaults to `False`. If set to `True` and *rel_seek* is unset, seeks to the end of the file before iteration begins. rel_seek (float): Used to preseek the start position of iteration. Set to 0.0 for the start of the file, 1.0 for the end, and anything in between. .. _JSON Lines format: http://jsonlines.org/

The change

3434 raise ValueError("'rel_seek' expected a float between"
3535 " -1.0 and 1.0, not %r" % rel_seek)
3636 elif rel_seek < 0:
37- rel_seek = 1.0 - rel_seek
37+ rel_seek = 1.0 + rel_seek
3838 self._rel_seek = rel_seek
3939 self._blocksize = 4096
4040 if rel_seek is not None:
5858 cur_pos = fo.tell()
5959 while '\n' not in cur:
6060 cur = fo.read(bsize)
61+ if not cur:
62+ # no newline until EOF; a partial trailing line was
63+ # never yieldable from a mid-line seek anyway
64+ fo.seek(0, os.SEEK_END)
65+ return
6166 total_read += bsize
62- try:
63- newline_offset = cur.index('\n') + total_read - bsize
64- except ValueError:
65- raise # TODO: seek to end?
67+ newline_offset = cur.index('\n') + total_read - bsize
6668 fo.seek(cur_pos + newline_offset)
6769
6870 def _init_rel_seek(self):

The check that tells the two apart

failpass·tests/test_jsonutils.py::test_jsonl_iterator_mid_last_line_seek_terminates

Check file tests/test_jsonutils.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before it435774ef8b10c1355bf77483a837945034011754
Broken version dated2026-08-06
Moduleboltons.jsonutils
Units changedJSONLIterator
Fingerprint76ad3601e9b14a72
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.

Other bugs found in mahmoud/boltons