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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions