Python: Add the missing py.typed markers, and check for them going forward - #8823
fei (feiiiiii5) wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The package markers are complete and correctly located; the remaining documentation precision issue is non-blocking.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds PEP 561 markers to 18 typed Python packages and documents a consistency check for future packages.
Changes:
- Adds missing
py.typedmarkers. - Adds package-management guidance for keeping markers and classifiers aligned.
| File | Description |
|---|---|
python/.github/skills/python-package-management/SKILL.md |
Documents marker validation. |
python/packages/a2a/agent_framework_a2a/py.typed |
Marks A2A as typed. |
python/packages/anthropic/agent_framework_anthropic/py.typed |
Marks Anthropic as typed. |
python/packages/azure-contentunderstanding/agent_framework_azure_contentunderstanding/py.typed |
Marks Content Understanding as typed. |
python/packages/azure-cosmos-memory/agent_framework_azure_cosmos_memory/py.typed |
Marks Cosmos memory as typed. |
python/packages/bedrock/agent_framework_bedrock/py.typed |
Marks Bedrock as typed. |
python/packages/claude/agent_framework_claude/py.typed |
Marks Claude as typed. |
python/packages/copilotstudio/agent_framework_copilotstudio/py.typed |
Marks Copilot Studio as typed. |
python/packages/declarative/agent_framework_declarative/py.typed |
Marks Declarative as typed. |
python/packages/devui/agent_framework_devui/py.typed |
Marks DevUI as typed. |
python/packages/foundry/agent_framework_foundry/py.typed |
Marks Foundry as typed. |
python/packages/foundry_hosting/agent_framework_foundry_hosting/py.typed |
Marks Foundry hosting as typed. |
python/packages/github_copilot/agent_framework_github_copilot/py.typed |
Marks GitHub Copilot as typed. |
python/packages/hosting/agent_framework_hosting/py.typed |
Marks Hosting as typed. |
python/packages/hosting-responses/agent_framework_hosting_responses/py.typed |
Marks Responses hosting as typed. |
python/packages/hosting-telegram/agent_framework_hosting_telegram/py.typed |
Marks Telegram hosting as typed. |
python/packages/mem0/agent_framework_mem0/py.typed |
Marks Mem0 as typed. |
python/packages/purview/agent_framework_purview/py.typed |
Marks Purview as typed. |
python/packages/redis/agent_framework_redis/py.typed |
Marks Redis as typed. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
|
Good catch — reworded in bdb73ee. PEP 561 only makes the marker the signal; what a checker does with an untyped import afterwards is its own business, so the skill now states the portable guarantee (without the marker the package is not treated as typed, so the API falls back to the checker's untyped-import behaviour) instead of promising |
|
fei (@feiiiiii5) thanks for taking a look at this, we do need to fix some typing issues now that did not get flagged before, see the failing check |
|
Thanks for the pointer — I agree they need fixing, and they are all in test files that nothing type-checked before the markers landed. Reading the job log, all 18 are under Three of them look different from a plain missing fix: Both I could not reproduce the job locally: Two questions so I take the right next step:
I will pick this back up as soon as a sync completes and run the same |
Head branch was pushed to by a user without write access
|
Fixed all 18 in Monkeypatching → bedrock → import from the package (3 errors).
Suppression codes (4 errors). The How I verified, since the CI job fans out over many checkers:
One unrelated thing worth flagging: |
18 packages declare `Typing :: Typed` but ship no py.typed, so the promise never reaches anyone who installs them: PEP 561 keeps it through the marker file inside the package directory, and without it a type checker must treat the whole package as untyped. Verified on the published wheel, not just the tree - agent_framework_foundry 1.13.1 carried the classifier and not the file, so `from agent_framework.foundry import FoundryChatClient` resolved to `Any` while `from agent_framework import Agent`, from a package that does ship the marker, resolved to a full signature. flit already ships whatever is in the package directory, so the marker is not being excluded by configuration - it was simply absent. Adding the file is the whole change. The package management skill now checks the two against each other, since a new package can repeat the same mismatch.
The skill said a package that declares `Typing :: Typed` without shipping `py.typed` "resolves to Any for every type checker", but PEP 561 only makes the marker the signal; what a checker then does with an untyped import is its own business. State the portable guarantee instead: without the marker the package is not treated as typed, so its API falls back to the checker's untyped-import behaviour rather than the inline annotations.
Adding the markers makes mypy check these packages' tests instead of skipping them, which surfaced 18 errors across five packages. All of them are in test files, and each is fixed the way the surrounding code already does it: - module and method monkeypatching moves to monkeypatch.setattr, the idiom used elsewhere in these tests, so mypy no longer sees an assignment to a type or a method. The assertions now target the mock directly instead of reading it back off the patched object. - bedrock imports BedrockChatClient and BedrockSettings from the package instead of the private _chat_client module; both are in __all__ and the same test file already imported BedrockChatClient publicly. - _redis_result gains an overload pair. Awaitable[_T] | _T left mypy unable to solve the TypeVar from a coroutine argument; the overloads let it infer, so the test needs no cast. - the two default_options arguments and four async-for loops get mypy's error code added to the per-checker suppressions already on those lines. Verified with the repo's own five gating checkers (mypy, zuban, pyrefly, ty, pyright) on Python 3.11 for all five packages, and the affected test suites pass: 1927 passed, 454 skipped.
d0e88ec to
65a74a1
Compare
|
Rebased onto the current Re-verified after the rebase rather than assuming the resolution was right:
Now 27 files (the 18 |

Motivation & Context
18 packages declare
Typing :: Typedbut ship nopy.typed, so the promise never reaches anyone who installs them. Reported in #8820; eavanvalkenburg confirmed it was an oversight and asked for a PR, plus a check so agents catch it themselves.PEP 561 keeps that classifier through the marker file inside the package directory. Without it a type checker must treat the whole package as untyped. I checked the published artifact rather than the tree:
agent_framework_foundry1.13.1 on PyPI carriesClassifier: Typing :: Typedin its METADATA and nopy.typedin the wheel, sofrom agent_framework.foundry import FoundryChatClientresolved toAnywhilefrom agent_framework import Agent— fromcore, which does ship the marker — resolved to a full signature. Same import style, silently different results.foundryis what the rootREADME.mdquickstart imports.The 18:
a2a,anthropic,azure-contentunderstanding,azure-cosmos-memory,bedrock,claude,copilotstudio,declarative,devui,foundry,foundry_hosting,github_copilot,hosting,hosting-responses,hosting-telegram,mem0,purview,redis. The other 23 of the 38 declaring packages already have the marker.Description & Review Guide
py.typedfiles, one per affected package, plus one checklist item in the Python package management skill. No code, no annotations, no packaging configuration.How this was verified.
uv build --wheel --package agent-framework-foundryon this branch putspy.typedin the wheel; installing that wheel into a clean venv and running mypy overnow reveals the full
__init__signature —project_endpoint: str | None = ..., model: str | None = ..., credential: ... , allow_preview: bool | None = ...,— where the published 1.13.1 wheel givesAny.What I have not done. I have not type-checked these 18 packages, so I cannot say whether any has annotations that do not hold up.
py.typedonly makes annotations that are already there visible; it adds none, and some of these may surface further errors downstream once the marker lands. That is a maintainer's call, and why I asked about batching in #8820.The skill's check reports nothing on this branch and all 18 on
main:Related Issue
Fixes #8820
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.