| type | Report | ||||
|---|---|---|---|---|---|
| title | Type checker findings | ||||
| description | What introducing multiple type checkers found in v2.0.2, and what v2.1 changed in response (bugs, design, minor). | ||||
| tags |
|
||||
| timestamp | 2026-10-09 00:00:00 UTC |
What v2.1 changed in response to type checker findings on v2.0.2.
| Checker | Version | v2.0.2 | v2.1 | Actionable | Bugs | Design | Minor |
|---|---|---|---|---|---|---|---|
| ty | 0.0.85 | 51 | 0 | 51 | 0 | 5 | 6 |
| pyrefly | 1.3.2 | 96 | 0 | 96 | 1 | 6 | 7 |
| pyright | 1.1.414 | 93 | 0 | 93 | 1 | 6 | 8 |
| mypy | 2.4.0 | 32 | 0 | 32 | 0 | 3 | 4 |
| basedpyright | 1.40.2 | 2,979 | 2,576 | 646 | 1 | 6 | 8 |
| zuban | 0.10.0 | 38 | 0 | 38 | 2 | 4 | 5 |
- v2.0.2, v2.1: findings on that release's
src/andtests/, both checked with v2.1's settings (tox.ini,pyproject.toml). "v2.0.2" is commitc298694: v2.0.2 plus the component bumps that preceded this work. - Actionable: v2.0.2 findings resolved by a change in v2.1.
- Bugs, Design, Minor: how many of the changes listed under Bug fixes, Design and Minor the checker spotted.
- basedpyright counts include its warnings: 110 errors + 2,869 warnings on v2.0.2, 5 + 2,571 on
v2.1. Its 5 remaining errors are import cycles (
__init__↔versions↔cpython↔inspector). basedpyright is available locally (tox -e basedpyright), see CI/CD for which checkers gate CI. - v2.1's zeros need runez 5.10.1, which fixed an annotation portable-python tripped on (see Fixed in runez).
- v2.0.2 had 3
# type:comments, v2.1 has none.
A checker pointed at code that misbehaved.
- With
cpython-use-github: true, a failed GitHub API call (rate limiting, network error) crashed with aTypeError:RestClient.get()returnsNoneon failure, and the response was iterated as-is [zuban, onceget_available_versions()had a return annotation: mypy-style checkers skip the body of unannotated functions] - When
bin/pythoncouldn't be found aftermake install, a configuredcpython-validate-scriptorcpython-additional-packagesranNoneas the python executable before the "Can't find bin/python" check happened:bin_pythonis now always aPath, and aborts with that message on first use [pyrefly, pyright, basedpyright, zuban]
portable-python's invariants are now stated in its types, and enforced where they used to be assumed.
BuildSetuptakes aPythonSpec, the newrequired_python_spec()turns CLI text (orNone/"latest") into one, with a clear error when it isn't a fullX.Y.Zversion [ty, pyrefly, pyright, basedpyright]VersionFamilyis an ABC (get_available_versions()andget_builder()are abstract):latestis always aVersion, aborting with "Could not determine latest cpython version" instead of the puzzling "Invalid python spec: None", andavailable_versionsis always a dict [all six]Folders:build,destdir,sourcesandppp-markerare required (clear error when not configured), onlydistandlogsare optional, and folders arePaths [pyrefly, pyright, basedpyright, zuban]PPG.family()always aborts for an unknown family (itsfatal=parameter is gone) [all six]m_telltaleis a plainstr(several files are space-separated), instead of a mix ofstrandClassVar[list][all six]- Library tracking:
Trackableis an ABC declaringrelative_pathandtracked_category,LibTypemoved totracking.py(the only enumTrackerwas ever used with), andTracker.report()no longer overridesrepresented()with a different return type [ty, pyrefly, pyright, basedpyright]
portable-python tripped on this runez annotation, fixed in runez 5.10.1 rather than worked around.
to_path(None)returnsNone: it always did at runtime, but runez 5.10.0's annotation only allowedstr | Path[all six]
A checker flagged code that turned out not to be needed.
- The
__main__block ofcli.pyre-importedmainfrom its own module [ty, pyrefly, zuban]
The checker was right, the fix changes little in practice.
- Attributes say what they hold, including
None(ModuleBuilder.m_*,parent_module,ModuleCollection,_bin_python,BuildSetup.build_context, ...) [all six] - Base class methods declare their return type, so overrides agree (
url,auto_select_reason(),candidate_modules(),get_problem(),xenv_LDFLAGS()) [all six] config.py:ConfigSource.get_value()walks the key in a loop,SingleFileMatchsets its attributes in__init__, andis_match()returns abool[all six]# type:comments became annotations [pyrefly, pyright, basedpyright, zuban]- Inspector: report lists hold strings,
relative_path()returns astr, nox and x.ychains [pyrefly, mypy, zuban] - Version listing checks
v.patchtruthiness instead ofv.patch > 0[ty, pyrefly, pyright, basedpyright] - Tests: no poking at
Config._sources, the mock's patcher is created in__init__[ty, pyrefly, pyright, basedpyright] runez.ActivateColorsinstead ofrunez.colors.ActivateColors[pyright, basedpyright]recompresstakes family and version from a spec only when the path names one [pyright, basedpyright]run_make(cpu_count=...)is annotated [ty]
- Folder paths containing a space are refused by portable-python itself, with the reason spelled out ("escapes too complex with makefiles, shell scripts etc"), instead of relying on a niche runez helper
- New tests: missing
bin/python, python.org listing no versions, folder path with a space