Blanket 1.0: An Early Look at Larry Hastings's Deterministic Threading Tests
Larry Hastings (CPython core developer behind the Gilectomy GIL-removal work) released Blanket 1.0 around his PyCon US 2026 talk, “Conquer multithreaded Python with Blanket”. It puts the Python thread scheduler under test control, making threaded tests deterministic. The repo is 10 days old with six stars, too early for the handbook to recommend, but it lands just as PEP 703 makes free-threaded Python official for 3.14.
The problem Blanket solves
A race between two threads might fire one run in a hundred, at the mercy of the OS scheduler, leaving you to either ignore it or hand-write brittle threading.Event plumbing to force the bug out. Free-threaded Python makes it worse: code the GIL used to serialize is now genuinely concurrent, so tests that quietly passed start flaking.
What Blanket does
Blanket wraps the standard threading primitives (Lock, Event, Condition, Semaphore), then a Scenario object scripts which thread runs next through relay() and cycle():
import blanket
scenario = blanket.Scenario()
lock = scenario.Lock()
def worker(name):
with lock:
print(f"worker {name} got the lock")
A = scenario.thread(worker, 'A')
B = scenario.thread(worker, 'B')
lock_api = scenario.api(lock)
with scenario:
list(lock_api.relay(A, B))
for t in [A, B]:
t.join()relay(A, B) commits A to one lock acquisition, then B, printing worker A before worker B every run. A bytecode injector inserts the scheduling points, so the only change to the code under test is scenario.Lock() in place of threading.Lock().
Why it’s worth watching at six stars
Scanners like pytest-run-parallel and pytest-freethreaded run a test under many threads to find unknown races; Blanket goes the other way and scripts a known failing order into a deterministic regression test. Free-threaded Python needs that, and Blanket is the first library shaped right for it. If you have ever chased a flaky threaded test you could not pin down, the README is worth a read today.