Repository navigation
Typed Python stubs: mypy-protobuf .pyi + hash-locked generators (#158) - #164
Merged
Merged
Conversation
…#158) generate-python-stubs.yml now runs --mypy_out / --mypy_grpc_out alongside the existing generators, so every synced *_pb2.py and *_pb2_grpc.py gets a typed .pyi. The .py output is byte-identical to what dp-python-lib has. - Pin grpcio-tools 1.84.0 and mypy-protobuf 5.1.0 in tools/python-stubs-requirements.in, compiled with pip-compile --generate-hashes into a lock the workflow installs with --require-hashes. - Widen the import fixup to *.pyi and add a guard step that fails the run on any surviving absolute import of a generated module, or any module without a stub. - Upload out/python as the python-stubs artifact on every run; the dry-run summary lists .py and .pyi with separate counts. - python-stubs.md: new generation commands, widened fixup, and a Type checking section. - NEXT.md: #158 section, plus a Cutting-the-release gate to check dp-python-lib against the dry-run artifact before tagging. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01We3Lmjj8XNLK1zpHRr1AwQ
Contributor
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Workflow-level verification remains pending, and regeneration instructions are inconsistent.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Adds reproducible, hash-locked mypy-protobuf generation and publishes typed Python stubs.
Changes:
- Pins and hash-locks generator dependencies.
- Generates and validates
.pyistubs, then uploads them as an artifact. - Updates documentation, release notes, and repository guidance.
| File | Summary |
|---|---|
tools/python-stubs-requirements.txt |
Hash-locked dependencies. Nit (2 votes): reconcile the --no-index regeneration command with the .in instructions. |
tools/python-stubs-requirements.in |
Defines generator pins and regeneration guidance. |
doc/release-notes/NEXT.md |
Adds release and cross-repository sequencing guidance. |
doc/cookbook/python-stubs.md |
Documents stub generation and type checking. |
CLAUDE.md |
Updates the tools directory documentation. |
.github/workflows/generate-python-stubs.yml |
Generates, validates, and uploads typed stubs. Moderate (1 vote): complete the pending dry_run: true workflow and downstream verification. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- python-stubs-requirements.in: explain that pip-tools itself writes `--no-index` into the .txt header; the .in command is authoritative. A clean regeneration with it reproduces the committed lock byte for byte. - NEXT.md: don't assert the .py modules match the previous sync, which a later proto change would silently falsify; make the dp-python-lib release gate unconditional. - Guard step: also catch absolute imports of *_pb2_grpc modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01We3Lmjj8XNLK1zpHRr1AwQ
This was referenced Sep 24, 2026
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.

Implements #158 (step 2 of the plan's cross-repo sequencing). Step 1, the dp-python-lib preparation PR osprey-dcs/dp-python-lib#60, has already merged.
Changes
generate-python-stubs.ymlpip install --require-hashes) instead of unversionedgrpcio grpcio-tools protobuf. The unhashedpip install --upgrade pipis dropped too.--mypy_out/--mypy_grpc_out, and widens the import fixupfindto*.pyi.import x_pb2/from x_pb2 import), or if any.pyhas no matching.pyi, or if nothing was generated.out/pythonas thepython-stubsartifact on every run, usingrelease.yml's pinnedupload-artifactSHA. The dry-run summary counts.pyand.pyiseparately.tools/python-stubs-requirements.in/.txt: pinsgrpcio-tools==1.84.0andmypy-protobuf==5.1.0. The.txtispip-compile --generate-hashes --allow-unsafeoutput.--allow-unsafeis needed because grpcio-tools depends on setuptools. The.inheader records the regeneration command, the dp-python-lib coordination rule, and why the file is not Dependabot-managed.doc/cookbook/python-stubs.md: updated publishing steps, generation commands, and fixup, plus a new Type checking section.doc/release-notes/NEXT.md: a Generate typed Python stubs (.pyi) in generate-python-stubs.yml #158 section, plus a new first item in "Cutting the release". It confirms dp-python-lib#60 is still merged, then checks dp-python-lib (mypy src/and its snippet checker) against the dry-run artifact before tagging.CLAUDE.md: thetools/layout line.Verified locally
A fresh venv installs the lock under
--require-hashes, and generates with the lock plus the workflow's flags. Against that output:mypy src/and the snippet checker);.pyfiles are byte-identical to dp-python-libmain.Every locked package supports Python 3.11 and has a linux x86_64 wheel. The recorded hashes match PyPI. The lock was compiled on 3.12 and the workflow runs 3.11, and no environment markers are involved.
The guard step, extracted from the workflow and run under bash, gave:
import common_pb2 asin a.pyifrom common_pb2 import …import common_pb2_grpc.pyimvn packageandtools/check-cookbook-snippets.pypass. actionlint's only findings are three SC2086 infos already present onmain(the "Determine sync mode" step).Dry run on this branch (plan work-breakdown step 7)
Run 36068796341 was dispatched from this branch with
dry_run: true. It succeeded, and every dp-python-lib step was skipped. Checks on its output:The
python-stubsartifact downloads, with 10.pyand 10.pyifiles. It is byte-identical to the local locked output above.All 10
.pyfiles are byte-identical to dp-python-libmain.Every
.pyiimport between generated modules is relative (from . import …), with zero absolute ones.dp-python-lib
origin/main(f856b94, which includes rename bidirectional streaming ingestion method #60), with the artifact's.pyifiles dropped in:mypy src/exclude+follow_imports = "skip")The plan expected only zero
name-defined/attr-definedhere. The hand-written errors are gone as well, because rename bidirectional streaming ingestion method #60 fixed them. The unsuppressed result is clean partly because_stubis stillAnyin dp-python-lib. Typing it is step 5.Nothing reaches dp-python-lib until the next
rel-*tag (step 4). The new first item inNEXT.md's "Cutting the release" repeats this check before that tag is pushed.🤖 Generated with Claude Code
https://claude.ai/code/session_01We3Lmjj8XNLK1zpHRr1AwQ