Skip to content

Add py.typed markers for PEP 561 compliance#378

Open
aliev wants to merge 9 commits intomainfrom
add-py-typed-markers
Open

Add py.typed markers for PEP 561 compliance#378
aliev wants to merge 9 commits intomainfrom
add-py-typed-markers

Conversation

@aliev
Copy link
Member

@aliev aliev commented Feb 26, 2026

Problem

When importing vision-agents from an external project, IDEs and mypy show a warning:

Skipping analyzing "vision_agents.core.runner.http.options": module is installed, but missing library stubs or py.typed marker

Screenshot 2026-02-26 at 3 49 32 PM

This happens because none of our packages include the py.typed marker file required by PEP 561.

Changes

1. Added py.typed markers

Added empty py.typed marker files to vision_agents.core, vision_agents.testing, and all 31 plugin subpackages. Since vision_agents is an implicit namespace package, markers are placed in each regular subpackage (not at the namespace root).

Also removed misplaced py.typed files that were sitting at plugin project roots (plugins/*/py.typed) — PEP 561 requires them inside the importable package directory.

2. Fixed mypy "duplicate module" errors

Adding py.typed caused mypy to fail with:

Source file found twice under different module names:
  "aws.vision_agents.plugins.aws" and "vision_agents.plugins.aws"

This happens because py.typed makes mypy recognize vision_agents.plugins.aws as a typed namespace package. When scanning the plugins/ directory, mypy now finds the same file under two module names — one from the filesystem walk (aws.vision_agents.plugins.aws) and one from namespace package resolution (vision_agents.plugins.aws).

Fix: set MYPYPATH to include each plugin root directory (plugins/aws/, plugins/anthropic/, etc.) so mypy resolves paths relative to them, producing a single consistent module name.

3. Narrowed --exclude pattern

Changed from 'plugins/.*/tests/.*' to 'plugins/[^/]+/(tests|examples?)/' to also exclude example/examples directories at the plugin root level (e.g. plugins/aws/example/), which conflict across plugins during type checking. The pattern is scoped to top-level plugin directories only, so it does not accidentally skip packages like plugins/sample_plugin/vision_agents/plugins/example/ which is actual plugin code.

4. Centralized mypy configuration

CI and pre-commit now delegate to dev.py mypy / dev.py mypy-plugins instead of duplicating MYPYPATH setup and exclude patterns inline. The mypy configuration is defined in one place.

Testing

py.typed markers are included in built wheels

$ cd plugins/aws && uv build --wheel
$ unzip -l dist/*.whl | grep py.typed
      0  02-02-2020 00:00   ./vision_agents/plugins/aws/py.typed

$ cd agents-core && uv build --wheel
$ unzip -l dist/*.whl | grep py.typed
      0  02-02-2020 00:00   vision_agents/core/py.typed
      0  02-02-2020 00:00   vision_agents/testing/py.typed

External project no longer shows "missing py.typed" warning

Created a standalone project that depends on vision-agents and ran mypy:

$ mkdir /tmp/test-py-typed && cd /tmp/test-py-typed
$ uv init --no-workspace
$ uv add --editable /path/to/Vision-Agents/agents-core
$ uv add mypy
$ cat > check.py << 'EOF'
from vision_agents.core import Agent

a: Agent
EOF
$ uv run mypy check.py
Success: no issues found in 1 source file

No "Skipping analyzing ... missing library stubs or py.typed marker" warnings.

mypy passes for core and plugins

$ uv run dev.py mypy
Success: no issues found in 82 source files

$ uv run dev.py mypy-plugins
Success: no issues found in 115 source files

Unit tests pass (574 passed, pre-existing failures unrelated to this PR)

$ uv run dev.py check
=== 1. Ruff Linting ===        ✅
=== 2. Validate pyproject ===  ✅
=== 3. MyPy Type Checking ===  ✅
=== 4. MyPy Plugins ===        ✅
=== 5. Unit Tests ===          574 passed, 3 failed (pre-existing), 5 errors (pre-existing)

Add py.typed marker files to all packages so that mypy recognizes
inline type annotations when vision-agents is installed as a dependency.
Since vision_agents is an implicit namespace package, markers are placed
in each regular subpackage: core, testing, and all 31 plugins.
@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

CI and pre-commit mypy invocations were routed through dev.py; dev.py adds _plugin_mypypath() to build a colon-separated MYPYPATH for plugin roots, sets MYPYPATH for plugin checks, broadens the plugin exclude to plugins/[^/]+/(tests|examples?)/, and invokes mypy via callback wrappers.

Changes

Cohort / File(s) Summary
Workflow
​.github/workflows/run_tests.yml
Replaced direct uv run mypy calls with uv run dev.py mypy and uv run dev.py mypy-plugins, delegating mypy execution to the wrapper.
Pre-commit hooks
.pre-commit-config.yaml
Updated mypy hooks to call uv run --frozen dev.py mypy and uv run --frozen dev.py mypy-plugins instead of running mypy with inline flags/options.
Dev script
dev.py
Added _plugin_mypypath() to compute colon-separated MYPYPATH from plugin directories; plugin mypy invocation now sets MYPYPATH in the environment, excludes plugin `plugins/[^/]+/(tests

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Developer
  participant PreCommit as Pre-commit Hook
  participant CI as CI Workflow
  participant DevPy as dev.py
  participant FS as Filesystem
  participant Mypy as mypy

  Developer->>PreCommit: commit -> trigger mypy hook (`uv run dev.py mypy`)
  Developer->>CI: push -> CI runs (`uv run dev.py mypy-plugins`)
  PreCommit->>DevPy: invoke `dev.py mypy`
  CI->>DevPy: invoke `dev.py mypy-plugins`
  DevPy->>FS: scan plugin roots -> build MYPYPATH via `_plugin_mypypath()`
  DevPy->>Mypy: run mypy (env: MYPYPATH) with exclude `plugins/[^/]+/(tests|examples?)/`
  Mypy-->>DevPy: return type results / exit code
  DevPy-->>PreCommit: forward exit code / report
  DevPy-->>CI: forward exit code / report
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I count the plugin names like teeth beneath my tongue,
a coloned ladder threading through the dark of code,
dev.py exhales and reroutes the white-hot mypy,
tests hidden in shadowed folders gather dust,
the wrapper clasps the throat of warnings — quiet.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Add py.typed markers for PEP 561 compliance' is partially related to the changeset but does not accurately describe the main changes made. The PR primarily modifies mypy invocation configuration in dev.py, CI workflows, and pre-commit hooks to fix 'duplicate module' errors via MYPYPATH setup. Consider revising the title to reflect these primary changes, such as 'Refactor mypy configuration to use MYPYPATH for plugin resolution' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-py-typed-markers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Add plugin root directories to MYPYPATH so mypy resolves namespace
packages correctly. Also exclude example/examples directories that
conflict across plugins.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
dev.py (1)

91-94: Consider using os.pathsep for cross-platform portability.

The hardcoded colon separator works for Unix-like systems but would fail on Windows. If Windows development is ever needed, os.pathsep provides the correct separator per platform.

♻️ Suggested improvement
 def _plugin_mypypath() -> str:
     """Build MYPYPATH with all plugin root directories."""
-    return ":".join(str(p) for p in sorted(Path(PLUGINS_DIR).iterdir()) if p.is_dir())
+    return os.pathsep.join(str(p) for p in sorted(Path(PLUGINS_DIR).iterdir()) if p.is_dir())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev.py` around lines 91 - 94, Replace the hardcoded ":" join in
_plugin_mypypath with the platform-aware separator: import os and use os.pathsep
when joining plugin directories from Path(PLUGINS_DIR). Keep the current
behavior of filtering directories (p.is_dir()) and sorting, but build the string
with os.pathsep so the function is portable across Windows and Unix-like
systems.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@dev.py`:
- Around line 91-94: Replace the hardcoded ":" join in _plugin_mypypath with the
platform-aware separator: import os and use os.pathsep when joining plugin
directories from Path(PLUGINS_DIR). Keep the current behavior of filtering
directories (p.is_dir()) and sorting, but build the string with os.pathsep so
the function is portable across Windows and Unix-like systems.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f684ece and 6bd9800.

📒 Files selected for processing (36)
  • .github/workflows/run_tests.yml
  • .pre-commit-config.yaml
  • agents-core/vision_agents/core/py.typed
  • agents-core/vision_agents/testing/py.typed
  • dev.py
  • plugins/anthropic/vision_agents/plugins/anthropic/py.typed
  • plugins/aws/vision_agents/plugins/aws/py.typed
  • plugins/cartesia/vision_agents/plugins/cartesia/py.typed
  • plugins/decart/vision_agents/plugins/decart/py.typed
  • plugins/deepgram/vision_agents/plugins/deepgram/py.typed
  • plugins/elevenlabs/vision_agents/plugins/elevenlabs/py.typed
  • plugins/fast_whisper/vision_agents/plugins/fast_whisper/py.typed
  • plugins/fish/vision_agents/plugins/fish/py.typed
  • plugins/gemini/vision_agents/plugins/gemini/py.typed
  • plugins/getstream/vision_agents/plugins/getstream/py.typed
  • plugins/heygen/vision_agents/plugins/heygen/py.typed
  • plugins/huggingface/vision_agents/plugins/huggingface/py.typed
  • plugins/inworld/vision_agents/plugins/inworld/py.typed
  • plugins/kokoro/vision_agents/plugins/kokoro/py.typed
  • plugins/lemonslice/vision_agents/plugins/lemonslice/py.typed
  • plugins/mistral/vision_agents/plugins/mistral/py.typed
  • plugins/moondream/vision_agents/plugins/moondream/py.typed
  • plugins/nvidia/vision_agents/plugins/nvidia/py.typed
  • plugins/openai/vision_agents/plugins/openai/py.typed
  • plugins/openrouter/vision_agents/plugins/openrouter/py.typed
  • plugins/pocket/vision_agents/plugins/pocket/py.typed
  • plugins/qwen/vision_agents/plugins/qwen/py.typed
  • plugins/roboflow/vision_agents/plugins/roboflow/py.typed
  • plugins/sample_plugin/vision_agents/plugins/example/py.typed
  • plugins/smart_turn/vision_agents/plugins/smart_turn/py.typed
  • plugins/turbopuffer/vision_agents/plugins/turbopuffer/py.typed
  • plugins/twilio/vision_agents/plugins/twilio/py.typed
  • plugins/ultralytics/vision_agents/plugins/ultralytics/py.typed
  • plugins/vogent/vision_agents/plugins/vogent/py.typed
  • plugins/wizper/vision_agents/plugins/wizper/py.typed
  • plugins/xai/vision_agents/plugins/xai/py.typed

These py.typed files were placed at plugins/*/py.typed (the plugin
project root), not inside the actual Python packages. PEP 561 requires
the marker to be inside the importable package directory. The correct
markers at plugins/*/vision_agents/plugins/*/py.typed were already
added in 48efaae.
CI and pre-commit now delegate to `dev.py mypy` and `dev.py mypy-plugins`
instead of duplicating MYPYPATH setup and --exclude patterns inline.
Also fix step numbering (was two "4", now 1-2-3-4-5).
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dev.py`:
- Around line 91-94: The _plugin_mypypath function currently joins plugin dirs
with a hardcoded ":" which breaks on Windows; update _plugin_mypypath to use
os.pathsep when joining Path(PLUGINS_DIR).iterdir() entries (keep the sorting
and is_dir filter) so MYPYPATH is built platform‑independently; import os if
needed and ensure the returned string uses os.pathsep instead of ":".

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 187d078 and 3aa73f3.

📒 Files selected for processing (1)
  • dev.py

The broad pattern `/(tests|examples?)/` was excluding
plugins/sample_plugin/vision_agents/plugins/example/ which is actual
plugin code. Narrowed to `plugins/[^/]+/(tests|examples?)/` so only
top-level test and example directories within each plugin are skipped.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Free Tier Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@GetStream GetStream deleted a comment from coderabbitai bot Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant