← board

str/bytes surface gaps found by the 2026-08-09 differential sweep

The same sweep's one SILENT finding was split out and fixed immediately: [[bug-nilpy-startswith-endswith-ignore-a-tuple-argument]]. That split is the point — a silent wrong answer and a missing method are not the same kind of work, and bundling them buries the one that matters.

Missing, measured

call error
b.hex() DONE 2026-08-09TPyBytes.hex, pinned by test/test_nilpy_bytes_hex.npy
str.maketrans(a, b) DONE 2026-08-09pystr_maketrans, pinned by test/test_nilpy_str_translate.npy
s.translate(table) DONE 2026-08-09pystr_translate, same test
s.isascii() DONE 2026-08-09pystr_isascii, pinned by test/test_nilpy_str_isascii.npy

Second sweep, 2026-08-09 (formatting / sorting / float repr)

Two more LOUD gaps, same ticket:

call error
format(0.1, ".17f") — the BUILTIN, not str.format undefined variable (format)
sorted(xs, key=str.lower) — an UNBOUND method as a value unexpected token at .lower

The second is the more interesting one: str.lower as a first-class value is how key= is most often written for case-insensitive sorts, and it is a different question from calling "x".lower() — it needs the TYPE's method to be reachable as a value, not just through an instance. Worth checking whether the same holds for list.append, dict.get etc. before picking a fix.

Verified working in that sweep — do not re-file

% formatting with width/precision/flags (%5d %-5d %05d %.2f %e %x %X %o %c, %%), .format() positional and INDEXED ({1} {0}) with alignment and precision specs, f-strings including {n:05}, {x!r}, expressions and subscripts inside the braces, sorted with key= and with tuples (STABLE, and matching CPython's order for equal keys), and float str() at the awkward sizes (1/3, 1e-5, 1e16, 123456789.123456789, round(1.005, 2), round(2.675, 2)). 19 lines, all byte-identical to CPython.

Already working — do not re-file

Verified in the same sweep: partition, rpartition, center, zfill, expandtabs (both arities), casefold, swapcase, title, strip family with and without a chars set, removeprefix, removesuffix, split/rsplit with maxsplit, splitlines, find/rfind/index/rindex with windows, count with a window, ljust/rjust, join, replace with a count, isdigit/isalpha/isspace, % formatting, and f-string format specs (:.2f, :05d, :>4).

Notes for whoever picks this up

Gate

.npy per method diffed against CPython's own output, plus the "already working" list above staying green (test_nilpy_str_methods covers most of it).

Third sweep, 2026-08-09 — the last two str predicates, DONE

"12".isnumeric() and "AB".istitle() were the only names left failing in a full sweep of the str method surface (every other call in a 24-line probe matched CPython exactly — split/rsplit/splitlines with limits, partition, center/ljust/rjust/zfill, casefold/swapcase, removeprefix/removesuffix, expandtabs, replace with a count, index/rfind, count with a start, strip with a character set, title/capitalize, join, slicing with a step including [::-1]).

Both implemented and pinned by test/test_nilpy_str_isnumeric_istitle.npy.

istitle is the one with content: a RUN of letters must start uppercase and continue lowercase, with at least one cased character — so "A1b" is False (the run resumes after the digit and b does not start it uppercase) and a string with no letters is False rather than vacuously True.

isnumeric delegates to isdigit: over the byte range pxx strings occupy the answers are identical, and they diverge only on Unicode characters that have no representation here. Kept as its own routine so that divergence has ONE place to be fixed when wide strings arrive.

The test asserts all six related predicates per case (isnumeric, istitle, isdigit, isalnum, isupper, islower) because they share the "empty is False" and "needs a cased character" rules, and copying a neighbour is exactly how one of them ends up disagreeing.