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
-
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.
-
Fix the obvious real bugs — waiter.py:127,139 unbound acceptor; the reportArgumentType, reportIndexIssue, reportOptionalCall categories.
-
Investigate the rest — categorize as real bug, missing guard, or pyright limitation. Add # type: ignore[reason] only where pyright is demonstrably wrong.
-
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.
-
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
Summary
uv run --with pyright pyright aiobotocore/currently reports 173 errors. Our workflow prompts (and the new/aiobotocore-bot:pyright-deltacommand) acknowledge this as a long-standing baseline and only gate on delta error counts in PR-touched files. That's a pragmatic workaround, but:Current breakdown
reportIncompatibleMethodOverride@typing.override+ targeted# type: ignore[override], or a pyrightconfig entry excluding this rule for specific subclasses.reportOptionalMemberAccessreportAttributeAccessIssuereportArgumentTypereportIndexIssuereportGeneralTypeIssuesCachedProperty— missing type stub; probably a pyright limitation not a real bug.reportMissingImportshttpx— optional dependency; already conditional at runtime, need# type: ignore[import-untyped]or configure pyright to ignore.reportPossiblyUnboundVariablewaiter.py:127,139— real bugs.acceptoris referenced outside the loop that binds it.reportOptionalSubscriptreportOptionalCallreportCallIssuereportPrivateImportUsage# type: ignore[attr-defined]at the import sites.reportIncompatibleVariableOverridereportInvalidTypeFormreportAssignmentTypeProposed phased cleanup
Silence the known-intentional noise (101 + 2 + 2 + 4 = ~109 errors). Either use
typing.overrideon subclasses + targeted# type: ignore[override]where signatures genuinely differ, or configurepyrightconfig.jsonto exclude the rule for specific classes/paths. Net: baseline drops to ~64.Fix the obvious real bugs —
waiter.py:127,139unboundacceptor; thereportArgumentType,reportIndexIssue,reportOptionalCallcategories.Investigate the rest — categorize as real bug, missing guard, or pyright limitation. Add
# type: ignore[reason]only where pyright is demonstrably wrong.Enforce via pre-commit — once the baseline is at zero (or a tightly-bounded set of explicitly-ignored cases), add a
pyrighthook to.pre-commit-config.yamlso 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-deltacommand 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.Remove
/aiobotocore-bot:pyright-delta— once step 4 lands, the command has no callers. Deleteplugins/aiobotocore-bot/commands/pyright-delta.mdand update.github/botocore-sync-prompt.mdStep 6 to run absolute pyright via pre-commit (or directly) instead of the delta command. Also drop the pyright-delta row fromdocs/ai-workflows.mdandplugins/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.mdis 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.mdStep 6 — sync bot runs pyright-delta, not absolute pyrightCLAUDE.md§"How aiobotocore overrides botocore" — async-overriding-sync is the intentional pattern driving the override-error countReproduce
Category counts: