Beartype Pyinstaller Repro
Reproduction case for beartype import errors with PyInstaller and fastmcp
Ask AI about Beartype Pyinstaller Repro
Powered by Claude Β· Grounded in docs
I know everything about Beartype Pyinstaller Repro. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Beartype PyInstaller Reproduction & Fix
This project demonstrates and fixes a module import error when using fastmcp (which depends on py-key-value-aio that uses beartype) with PyInstaller.
Issue
When packaging a FastMCP server with PyInstaller, the bundled executable fails at runtime with ModuleNotFoundError for modules imported after beartype is initialized.
Root Cause: When py-key-value-aio imports, it calls beartype_this_package() which installs beartype's import hook via add_beartype_pathhook(). This hook:
- Prepends a custom
FileFindertosys.path_hooks - Clears
sys.path_importer_cache - Uses
SourceFileLoaderwhich expects.pysource files
In PyInstaller's frozen environment, there are no source files - only compiled bytecode in a PYZ archive. When beartype's hook takes precedence over PyInstaller's PyiFrozenFinder, all subsequent imports fail.
β The Fix
A PyInstaller runtime hook patches beartype's add_beartype_pathhook to skip installation in frozen environments. See hooks/pyi_rth_beartype.py.
The key insight: we must patch two locations because clawpkgmain.py does from ... import add_beartype_pathhook, creating a local binding that survives module-level patches.
Project Structure
beartype_pyinstaller_repro/
βββ src/
β βββ beartype_pyinstaller_repro/
β βββ __init__.py
β βββ server.py # FastMCP server with Fibonacci tool
βββ tests/
β βββ test_integration.py # Integration tests
βββ server.py # Entry point for PyInstaller
βββ server.spec # PyInstaller configuration
βββ pyproject.toml # Project configuration
βββ Makefile # Build commands
Setup
Prerequisites
- Python 3.12+
- uv package manager
Installation
# Install dependencies
uv sync
Building
Build the PyInstaller executable:
make build
Or manually:
uv run pyinstaller server.spec
The executable will be created at dist/server (or dist/server.exe on Windows).
Running Tests
Direct Import Test (Baseline)
This test verifies that the server works correctly when run directly:
uv run pytest tests/test_integration.py::test_direct_import -v
This should pass, demonstrating that the code works fine outside of PyInstaller.
PyInstaller Executable Test
This test runs the bundled executable and checks for import errors:
# First build the executable
make build
# Then run the integration test
uv run pytest tests/test_integration.py::test_pyinstaller_executable_imports -v
This test is expected to fail (or detect the import error), demonstrating the bug.
Run All Tests
uv run pytest tests/ -v
Reproducing the Issue
-
Install dependencies:
uv sync -
Build the executable:
make build -
Run the executable directly:
./dist/serverYou should see a
ModuleNotFoundErrororImportError. The error may mentiondiskcacheor other modules, but the root cause is beartype initialization breaking subsequent imports in the PyInstaller bundle. -
Compare with direct execution:
uv run python server.pyThis should work fine, demonstrating that the issue is specific to the PyInstaller bundle.
CI/CD
GitHub Actions CI is configured to:
- Run
rufffor code quality checks - Run pytest tests
- Build the PyInstaller executable
- Run integration tests
See .github/workflows/ci.yml for details.
Dependencies
fastmcp- FastMCP framework for building MCP serverspyinstaller- Python application bundlerpytest- Testing frameworkruff- Fast Python linter
The issue stems from fastmcp's dependency on py-key-value-aio, which initializes beartype when imported. In PyInstaller bundles, after beartype is initialized, the Python import system breaks and all subsequent imports fail with ModuleNotFoundError, even for modules that are actually included in the bundle.
Expected Behavior (with fix)
- β Direct execution: Works correctly
- β Direct import test: Passes
- β PyInstaller bundle: Works with runtime hook fix
Using the Fix in Your Project
To use this fix in your own PyInstaller project:
-
Copy the runtime hook (
hooks/pyi_rth_beartype.py) to your project -
Add it to your spec file:
runtime_hooks=['path/to/pyi_rth_beartype.py'], -
Or via command line:
pyinstaller --runtime-hook=path/to/pyi_rth_beartype.py your_app.py
Related Issues
Technical Details
See docs/INVESTIGATION.md for a detailed analysis of the root cause and various fix approaches considered.
