Skip to content

fix: resolve all pyrefly type errors and gate them in ci - #25

Merged
rasros merged 1 commit into
mainfrom
fix/pyrefly-errors
Jul 28, 2026
Merged

fix: resolve all pyrefly type errors and gate them in ci#25
rasros merged 1 commit into
mainfrom
fix/pyrefly-errors

Conversation

@rasros

@rasros rasros commented Jul 28, 2026

Copy link
Copy Markdown
Owner

23 errors to 0, fixed at the root in each case rather than suppressed. No type: ignore anywhere.

Ten errors were one real API flaw. non_dominated_sort, crowding_distance and pareto_select declared objectives: dict[int, Objectives], and dict is invariant in its value type, so a caller holding a dict[int, tuple[float, float]] could not pass it even though that tuple is a perfectly good tuple[float, ...]. All three only ever read the mapping, so they now take Mapping, which is covariant. That is a genuine widening of the API, not a workaround.

Seven were the analysis scripts being invisible. The round-trip tests import plot_run and clean_runs directly to check they still read what storage writes, but scripts/ is not an installed package. Added search-path = ["src", "scripts"] to the pyrefly config.

Two were missing assertions in tests, and the checker was right. validate returns tuple[bool, str | None] and apply_search_replace returns str | None, and both tests went straight to an in check against the possibly-None value. Now they assert non-None first, which is better test hygiene regardless of the type checker.

Two came from worker_loop over-declaring what it needs. It was annotated mp.Queue, but it only calls get on one queue and put on the other; production passes a multiprocessing queue and the tests pass a queue.Queue, and those share no base class. Replaced with a MessageQueue protocol describing exactly that surface. The methods are positional-only because the two queue classes name the argument differently (item versus obj), which otherwise fails protocol matching. multiprocessing is no longer imported there.

Two were false positives introduced by the SDK upgrade in #24. chat.completions.create and messages.create are overloaded on the stream literal to return either a response or a Stream, and building the arguments as a dict hides the literal from the checker, so it picks the streaming branch. Neither call ever enables streaming. These are the only two spots I could not fix structurally without unpicking the conditional-kwargs pattern in both providers, so they are casts with a comment explaining why. cast is a no-op at runtime.

Also added pyrefly to CI. It was configured in pyproject.toml but nothing ran it, which is exactly how it drifted to 21 errors unnoticed. Without the gate this PR just resets a counter that will climb again.

Verified beyond the checker, since two changes touch runtime paths: a real multiprocess spawn run with three workers completes and writes output (score 0.0039), confirming the protocol swap did not disturb the pickled worker entry point, and all three providers still construct. 472 tests pass, ruff clean, and the full CI gate passes locally.

The 2 remaining warnings pyrefly does not print by default are unaffected; only errors were in scope.

@rasros
rasros merged commit 0b04b4a into main Jul 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant