Adopt the fleet Python lint/type config for the hub's utility scripts - #388
Merged
Conversation
The hub's stdlib-only utility scripts (spec/, host-setup/) had no ruff or type-checker config, so Pylance ran in a strict default and flagged unknown types on JSON-loaded data. Add a config-only pyproject.toml mirroring the fleet's Python style - ruff (py313, line-length 100, isort) and pyright standard mode - the "uvx scripts" profile (no [project], no uv.lock). Under standard mode the unknown-type noise is gone; the real errors that remain are three genuine "possibly None" accesses, fixed minimally: - annotate gh() -> Any (it returns parsed JSON, which is Any) - clears every gh-result Optional access at once; - annotate the _HISTORY_CACHE dict; - narrow `item` (dict | None) in the interface/verbatim dispatch branches, which only run when item is non-None. ruff and pyright are both clean; audit --selftest and validate.py are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request adopts the fleet-wide Python lint and type-check configuration for the hub's stdlib-only utility scripts and adjusts spec/audit.py annotations to reduce type-checker noise around JSON-shaped data.
Changes:
- Add a config-only
pyproject.tomlwith Ruff (py313 + import sorting) and Pyright (standard mode) settings scoped tospec/andhost-setup/. - Update
spec/audit.pytyping (notablygh() -> Anyand additional narrowing) to align with the new type-checking baseline.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| spec/audit.py | Adds/adjusts type annotations to reduce Pyright findings and narrow Optional paths. |
| pyproject.toml | Introduces Ruff and Pyright configuration for hub utility-script linting/type checking. |
…#388) - gh() also returns None on an empty response body, not only a 404; say so. - Type _HISTORY_CACHE as dict[str, list[str]] (rel_path -> past revision contents) instead of a bare dict. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
spec/audit.py:64
- The gh() implementation can return None (404 when ok404, or an empty response body), so the return annotation should include None. Using -> Any makes the type hint contradict both the docstring and the actual return value, and it can hide real None-handling bugs at call sites.
def gh(path, ok404=False) -> Any:
"""GET a REST path via gh, returning parsed JSON, or None on a 404 (when ok404) or an empty response body.
#388) Per the Scripts-profile decision (mypy is the CODESTYLE-mandated type checker; pyright/pylance is editor-only): - pyproject.toml: add [tool.mypy] (the gate, clean) alongside [tool.pyright] standard (tames Pylance) and [tool.ruff]. Config only, the Scripts profile. - CODESTYLE.md Scripts profile: state that the pyproject may carry a [tool.pyright] editor block (the same mypy-gate/pyright-editor split the Project profile uses). - CODESTYLE.md: correct the tool-pinning guidance. A uvx <tool>@<ver> pin in a run: step is not Dependabot-trackable, so CI runs uvx ruff@latest / mypy@latest per the fleet rule (pin only what Dependabot auto-updates, else run latest, never a manual pin that goes stale). Also recast two clause-joining semicolons in the edited bullet. - audit.py: reword the _HISTORY_CACHE comment for grammar (Copilot). ruff, mypy, and pyright are all clean; audit --selftest unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The interface/verbatim dispatch guarded with `if item and ...`, relying on dict truthiness. Use an explicit `is not None` - it is what narrows item for the type checker and reads as intent, not an empty-dict edge case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
spec/audit.py:64
- gh() can return None (404/empty body), but the return annotation is Any. That prevents pyright/mypy from helping catch accidental None dereferences at new call sites and makes the signature less self-documenting than the docstring. Consider annotating the real return type (Any | None) and using an explicit cast/assert at the specific call sites where you intentionally treat the JSON as unchecked.
def gh(path, ok404=False) -> Any:
"""GET a REST path via gh, returning parsed JSON, or None on a 404 (when ok404) or an empty response body.
CODESTYLE now says CI runs uvx ruff@latest / mypy@latest (a uvx run-step pin is not Dependabot-trackable), but spec/project-types.json python.scripts.uvx still asserted "CI pins exact tool versions". The spec audits downstream repos, so update the assertion to match the latest-not-pinned rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AGENTS.md bans file-header summary comment blocks. Replace the three-line summary with a single terse note for the one non-obvious point - why there is no [project] (the Scripts profile). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The hub's stdlib-only utility scripts (
spec/,host-setup/) had no ruff or type-checker config, so Pylance ran in a strict default and flagged unknown types on JSON-loaded data (entry: Unknown, etc.). This adopts the fleet's Python style.Changes
pyproject.toml(new, config-only — the "uvx scripts" profile: no[project], nouv.lock):[tool.ruff](py313, line-length 100, isort) +[tool.pyright](standardmode,includespec + host-setup). Mirrors finmod.spec/audit.py: annotategh() -> Any(it returns parsed JSON, which isAny) — this clears every gh-result Optional access at once; annotate the_HISTORY_CACHEdict; narrowitem(dict | None) in the interface/verbatim dispatch branches, which only run whenitemis non-None.Why standard mode
finmod uses
typeCheckingMode = "standard", which does not report unknown types — so the Pylance noise vanishes with the config, no hand-annotating JSON data. The genuine "possibly None" errors (3 after the config) are fixed above.Verification
uvx ruff checkanduvx pyrightare both clean (0 errors).spec/audit.py --selftestandspec/validate.pyare unchanged — the annotations carry no behavior.Note:
line-length = 100drives the ruff formatter only; E501 is not in ruff's select, so the scripts' intentionally-long finding strings are not reflowed.🤖 Generated with Claude Code