Skip to content

🔧 build(lint): adopt simplint 0.8.0 - #254

Merged
gaborbernat merged 25 commits into
tox-dev:mainfrom
gaborbernat:simplint
Nov 8, 2026
Merged

gaborbernat merged 25 commits into
tox-dev:mainfrom
gaborbernat:simplint

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

This adopts simplint 0.8.0, a linter that reports code patterns it considers harder to read and review, and runs it through the pre-commit hooks. After this merges, the hook reports nothing on this codebase, so maintainers can rely on it for new changes. The public API of python_discovery is unchanged: the names exported from the package, their signatures and the dataclass definitions match the previous release.

The code changes make simplint report nothing, with no # simplint: ignore comments. Tests create their mocks through the mocker fixture from pytest-mock and give each mock a spec, so a misspelled attribute fails the test. Test bodies no longer branch or loop over cases; the CPython-only discovery check is its own test that is skipped on other implementations. Single-use helpers in the Windows registry fake are inlined, and annotations name the types they accept instead of object. Several ruff suppressions gained a short reason in the same comment.

The hook config orders the hooks with explicit priority values. priority means prek's hook priority tiers: hooks in a lower tier run first, and hooks in the same tier run concurrently, so a formatter and a linter that edit the same file never race.

Private modules changed some module-level names, and one of them was in an __all__. Renamed: COOKIE_LENGTH to _COOKIE_LENGTH in python_discovery._cached_py_info, PATTERN and SPECIFIER_PATTERN to _PATTERN and _SPECIFIER_PATTERN in python_discovery._py_spec, Pep514PythonInfo to _Pep514PythonInfo in python_discovery._windows._propose (dropped from its __all__), and the registry helpers in python_discovery._windows._pep514 gained a leading underscore: discover_pythons is now _discover_pythons, and enum_keys, get_value, load_exe, parse_version and process_tag follow the same pattern. fs_path_id moved within python_discovery._compat, and __version__ moved from python_discovery/__init__.py to python_discovery/_about.py; the package still exports it.

Removed: _stop_query_readers and _DEFAULT_QUERY_TIMEOUT in python_discovery._cached_py_info, _int_or_none, _MAX_VERSION_PARTS and _SINGLE_DIGIT_MAX in python_discovery._py_spec, _PRE_ORDER in python_discovery._specifier, _32BIT_POINTER_SIZE in python_discovery._py_info_collect, _VERSION_MANAGER_LAYOUTS in python_discovery._discovery, _IMPLEMENTATION_BY_ORG in python_discovery._windows._propose, and the load_arch_data, load_threaded and load_version_data helpers in python_discovery._windows._pep514. The private python_discovery._windows package no longer re-exports Pep514PythonInfo, _run, discover_pythons or propose_interpreters, and its __all__ is gone.

Some private signatures changed too. _propose_from_path, _propose_from_uv and _get_from_cache in python_discovery._discovery and python_discovery._cached_py_info no longer default all_implementations, ignore_cache or executable_args, so their callers pass them explicitly. _parse_version_parts in python_discovery._py_spec, and _extract_between_cookies and _collect_query_output in python_discovery._cached_py_info, return named tuples instead of plain tuples.

Ruff's undocumented-* rules are replaced by simplint's undocumented-public-api,
which checks only what the package exports, in reST. The docstring style is reST
because the code documents parameters with :param: fields.
Applied with `simplint check --fix --unsafe-fixes`, then the prek formatters.
The autofix added frozen=True beside **DC_KW, which already sets it, so the
module raised TypeError on import.
The autofix turned the propose_interpreters docstring into comments and kept
its :param: lines, which no tool reads. The enumeration note is the part a
reader needs.
simplint wants a reason after every suppression code. The reasons name the
constraint behind each directive; no directive changed.
Fields such as `:returns:` and `:ivar:` with no text documented nothing.
Each now states what the value is, so the reST reads on its own.
A patch without a spec accepts any call, so a renamed or re-signed target
keeps passing. The winreg patches in tests/windows stay as they are:
conftest already replaces winreg with mocks, so autospec cannot apply.
Constants that are never reassigned now say so with Final, so a type
checker rejects a later rebind.
Rows without an id get pytest's generated names, which change when the
values do. Each row now carries a stable id.
Name regex groups, fold single-use module constants into their functions,
and build text with format or f-strings where it was concatenated. Split
the cognitive-complexity hot spot in the uv matcher and document public
names that simplint asks about. The version-gate script keeps .format so
it still parses on Python 2.7.
Replace vars() reads with explicit attribute checks, bind single-letter loop
names, use an assignment expression where the value is only tested, and
upper-case the winreg mock tables so they are private constants.
Move __version__ into _about so python_discovery/__init__.py only
re-exports, and leave _windows/__init__.py as a docstring. Callers import
the Windows modules directly. Also drop the one-use helper in _py_spec,
inline the pointer-width literal in _py_info_collect, and compare pointer
size against a 64-bit integer so the gate has no magic number.
Constructor mocks now take spec= from the type they stand in for:
PyInfoCache, ContentStore, Popen and PythonInfo.

The autospec=True kwargs added to Mock and MagicMock constructors in an
earlier commit did not spec anything; they set a stray attribute and
hid the finding. Removing them here.
Return NamedTuples from the query-output, cookie-slice, version-parts and
test registry helpers so callers read fields by name. Tuple unpacking at
call sites still works, so behavior is unchanged.
Platform-dependent file names and suffixes in test_discovery are module
constants now, so the test bodies no longer branch on IS_WIN.
Host-dependent values (suffixes, threaded tags, architecture flips, case
folding) move to module constants or lookups. The missing-key cache case
gets its own test instead of a branch on the parameter.
Define each helper after its first user and move NamedTuple classes next to
the functions that return them. In test_discovery the path and env branches
become dict lookups, bool multiplication and a parametrized wrapper.
…lpers

Registry specs and parsed versions are NamedTuples, and the arch, version,
threaded and stop-reader helpers are inlined where they have one caller.
Verified on Windows 11 (tox 3.14): the Windows-only failures left are
POSIX-path assumptions in test_py_info_collect and test_py_info_extra.
Use the mocker fixture for autospec patches and the cache doubles, type the
registry and satisfies doubles, order the Windows conftest helpers after
their users, and split the alias case from the distinct-file case.
The 0.7.1 autofix renamed stop_query_reader to a private name and dropped
its __all__. Other modules import it, so simplint 0.8.0 wants it listed in
__all__ rather than private. Restoring the public name keeps it importable
as before.
Tests create mocks through the mocker fixture that pytest-mock already
provides, and every mock takes a spec so a misspelled attribute fails the
test. The winreg fake is cached because _pep514 binds winreg at import; a
fresh module per test left it patching a stale copy.
The fake registry takes str, int and None values, so the fixtures say so
instead of object. The mock values load through runpy, which returns the
module's globals, so the loader needs no Any annotation.
Each registry lookup was a factory called once from the fixture, so the
closures now sit in the fixture. A shared _key_value keeps the fixture
under the complexity limit.
The CPython-only discovery assertion becomes its own test, skipped on other
implementations, instead of an if around the assertion. The launcher probe
moves into the skip condition, and the timeout cache test calls the query
twice in a row rather than looping over two values.
@gaborbernat gaborbernat added enhancement New feature or request skip news No user-facing changelog entry needed labels Nov 8, 2026
@gaborbernat
gaborbernat merged commit 4cdf382 into tox-dev:main Nov 8, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request skip news No user-facing changelog entry needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant