Skip to content

Reduce pyright baseline: 173 errors, most intentional-pattern noise but some look like real bugs #1564

@thehesiod

Description

@thehesiod

Summary

uv run --with pyright pyright aiobotocore/ currently reports 173 errors. Our workflow prompts (and the new /aiobotocore-bot:pyright-delta command) acknowledge this as a long-standing baseline and only gate on delta error counts in PR-touched files. That's a pragmatic workaround, but:

  • It assumes a contributor can eyeball whether a new error is real or baseline — brittle.
  • Real bugs can hide in the noise (see suspicious categories below).
  • The baseline grows unchecked; every new override adds another incompatible-method-override error.

Current breakdown

Count Category Likely disposition
101 reportIncompatibleMethodOverride Intentional. Async methods overriding sync base methods. Fix: @typing.override + targeted # type: ignore[override], or a pyrightconfig entry excluding this rule for specific subclasses.
16 reportOptionalMemberAccess Mix. Some are "we know this isn't None because of earlier guard" (real), some could be latent bugs. Needs per-site review.
14 reportAttributeAccessIssue Mix. Some are accessing attributes pyright can't see on dynamic botocore classes; others may be typos.
9 reportArgumentType Mostly likely real — argument-type mismatches often indicate bugs.
6 reportIndexIssue Optional subscripting without check.
5 reportGeneralTypeIssues CachedProperty — missing type stub; probably a pyright limitation not a real bug.
4 reportMissingImports httpx — optional dependency; already conditional at runtime, need # type: ignore[import-untyped] or configure pyright to ignore.
3 reportPossiblyUnboundVariable waiter.py:127,139 — real bugs. acceptor is referenced outside the loop that binds it.
3 reportOptionalSubscript Optional subscripting — real or missing guards.
3 reportOptionalCall Calling Optional — real or missing guards.
3 reportCallIssue Call-signature mismatches.
2 reportPrivateImportUsage Intentional — we import private symbols from botocore to override them. # type: ignore[attr-defined] at the import sites.
2 reportIncompatibleVariableOverride Same class as the 101 overrides above, but for class variables.
1 reportInvalidTypeForm Single-instance; needs inspection.
1 reportAssignmentType Single-instance; needs inspection.

Proposed phased cleanup

  1. Silence the known-intentional noise (101 + 2 + 2 + 4 = ~109 errors). Either use typing.override on subclasses + targeted # type: ignore[override] where signatures genuinely differ, or configure pyrightconfig.json to exclude the rule for specific classes/paths. Net: baseline drops to ~64.

  2. Fix the obvious real bugswaiter.py:127,139 unbound acceptor; the reportArgumentType, reportIndexIssue, reportOptionalCall categories.

  3. Investigate the rest — categorize as real bug, missing guard, or pyright limitation. Add # type: ignore[reason] only where pyright is demonstrably wrong.

  4. Enforce via pre-commit — once the baseline is at zero (or a tightly-bounded set of explicitly-ignored cases), add a pyright hook to .pre-commit-config.yaml so errors are caught at commit time, not at review time. This is the natural end state: pyright sits alongside ruff and yamllint as a local gate, and CI re-runs the same hook for belt-and-suspenders. The /aiobotocore-bot:pyright-delta command becomes obsolete for the sync-bot flow (absolute pyright is the gate) and is retained only for ad-hoc delta inspection.

    Note: pre-commit runs per-changed-file by default. Pyright's type-checking isn't sound when run on a subset of files (cross-module type inference breaks), so the hook should run on the whole aiobotocore/ tree regardless of which files changed — pass_filenames: false + always_run: true. This is how mypy/pyright hooks are usually configured.

  5. Remove /aiobotocore-bot:pyright-delta — once step 4 lands, the command has no callers. Delete plugins/aiobotocore-bot/commands/pyright-delta.md and update .github/botocore-sync-prompt.md Step 6 to run absolute pyright via pre-commit (or directly) instead of the delta command. Also drop the pyright-delta row from docs/ai-workflows.md and plugins/aiobotocore-bot/README.md.

Why now

The new AI workflow plumbing (#1563) explicitly documents the baseline as a known limitation. Every reference to "long-standing baseline" in plugins/aiobotocore-bot/commands/pyright-delta.md is a marker that we've moved the problem rather than solving it. A focused cleanup PR per category would be tractable — none of the 14 categories is individually huge.

References

  • plugins/aiobotocore-bot/commands/pyright-delta.md — current delta-only approach
  • .github/botocore-sync-prompt.md Step 6 — sync bot runs pyright-delta, not absolute pyright
  • CLAUDE.md §"How aiobotocore overrides botocore" — async-overriding-sync is the intentional pattern driving the override-error count

Reproduce

uv run --with pyright pyright aiobotocore/ 2>&1 | tail -1
# 173 errors, 0 warnings, 0 informations

Category counts:

uv run --with pyright pyright aiobotocore/ 2>&1 \
  | grep -oE '\(report[A-Za-z]+\)' | sort | uniq -c | sort -rn

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions