Skip to content

Add verify_pyi script to validate .pyi stubs in distributions - #6961

Open
masenf wants to merge 2 commits into
mainfrom
claude/post-build-pyi-checking-0xemkc
Open

Add verify_pyi script to validate .pyi stubs in distributions#6961
masenf wants to merge 2 commits into
mainfrom
claude/post-build-pyi-checking-0xemkc

Conversation

@masenf

@masenf masenf commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Type of change

  • New feature (non-breaking change which adds functionality)

Description

Adds a new scripts/verify_pyi.py script that validates built distributions (wheels and sdists) contain the .pyi type stub files they are expected to generate. This script is run by the publish workflow's post-build hook (.github/scripts/publish/post_build.sh) to prevent releasing packages without type information.

Why this matters: Reflex generates type stubs at build time (via scripts/hatch_build.py for the root package and the hatch-reflex-pyi hook for component packages). Since *.pyi files are gitignored, only the build process creates them. A build that silently fails to generate stubs would ship a release with no type information, which is not recoverable since PyPI versions are immutable.

How it works:

  • Reads each package's pyproject.toml to determine if it generates stubs (by checking for the reflex-pyi hook or *.pyi artifact declarations)
  • For packages that should generate stubs, verifies every built artifact (wheel and sdist) contains at least one .pyi file
  • Fails the build if any artifact is missing stubs, preventing the release from proceeding to the approval gate

Changes:

  • scripts/verify_pyi.py: New script with functions to read build configuration, detect stub-generating packages, count stubs in artifacts, and validate distributions
  • tests/units/test_verify_pyi.py: Comprehensive unit tests covering all code paths, including edge cases (empty dist dirs, mixed build matrices, non-distribution files)
  • .github/scripts/publish/post_build.sh: Updated to call the new verification script instead of the previous reflex-only check
  • pyproject.toml: Added linting exception for the new script's use of print()

Testing

  • Added 233 lines of comprehensive unit tests in tests/units/test_verify_pyi.py
  • Tests cover: configuration parsing, stub detection logic, artifact inspection, error cases, and real package detection
  • Tests validate both synthetic test cases and real packages in the repository (reflex and component packages)
  • All tests pass with the implementation

Checklist

  • Tests pass with adequate coverage
  • Code follows project conventions (Google-style docstrings, concise implementation)
  • Linting configured appropriately for the new script

https://claude.ai/code/session_01NwKbDTae52hrg5HY63whHb

Review in cubic

post_build.sh only checked the reflex wheel, so a component package whose
build silently produced no stubs could be published with no type
information — a release that is not recoverable, since a version can only
be uploaded to PyPI once. The check now covers every package whose build
generates stubs: reflex itself and the 14 packages driven by the
hatch-reflex-pyi hook.

Which packages those are is read out of the package's own pyproject rather
than listed anywhere, so one that starts or stops generating stubs is
covered without touching the check. Either signal is enough: declaring the
hook, or declaring *.pyi as a build artifact (how the root package's custom
hook is recognized). Reading them independently is what catches a package
that generates stubs but never declares them — *.pyi is gitignored, so
hatchling leaves the generated files out of the artifact unless listed.

Also widens what is inspected. Sdists are checked alongside wheels, since a
stubless sdist rebuilds without stubs wherever reflex-base is unavailable.
And every artifact must carry stubs rather than just one: the old
`unzip -l "$DIST_DIR"/*.whl` passed a second wheel to unzip as a member
pattern instead of listing it, so a build matrix leg that lost its stubs
went unnoticed.

Verified against real builds of all 15 packages (wheel and sdist each), a
package that generates no stubs, and a stub-stripped wheel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwKbDTae52hrg5HY63whHb
@masenf
masenf requested a review from a team as a code owner August 27, 2026 22:15
@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a release-time validator that checks generated Python type stubs are present in wheel and source distributions before publication.

  • Replaces the Reflex-only shell check with a package-aware Python verifier.
  • Detects stub-generating packages from Hatch build configuration.
  • Adds unit coverage for configuration parsing, archive inspection, missing artifacts, and repository package classifications.
  • Adds the verifier’s lint exception for console output.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
scripts/verify_pyi.py Adds package-configuration detection and wheel/sdist inspection that fails the release hook when expected stubs are absent.
.github/scripts/publish/post_build.sh Replaces the package-specific unzip check with the new verifier and explicitly requires the package build directory.
tests/units/test_verify_pyi.py Covers stub-generation detection, archive counting, success and failure paths, mixed artifacts, and real repository package configurations.
pyproject.toml Permits intentional print calls in the command-line verification script.

Reviews (2): Last reviewed commit: "Provision the tomllib backport for the ...." | Re-trigger Greptile

@codspeed-hq

codspeed-hq Bot commented Aug 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 27 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing claude/post-build-pyi-checking-0xemkc (9980b98) with main (3d2b539)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/verify_pyi.py
The 3.10 fallback could not work as written: the hook ran the verifier with
`uv run --no-project`, which resolves none of the project's dependencies, so
`import tomli` raised ModuleNotFoundError on any interpreter below 3.11
rather than falling back.

Declare the backport as inline script metadata and run the verifier with
`uv run --script`, which provisions it from the script's own dependencies.
Matches scripts/check_min_deps.py, which carries the same block for the same
reason. `--no-config` keeps the ephemeral resolution clear of the workspace's
uv settings.

The publish job runs 3.14, where tomllib is stdlib and the block resolves to
no dependencies at all, so the release path installs nothing new.

Verified by running the hook against a real build on 3.10 (reproduced the
ModuleNotFoundError first), on 3.14 and with no UV_PYTHON set, across the
pass, skip and stub-stripped-wheel paths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwKbDTae52hrg5HY63whHb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants