Fix Issue #7: Implement automatic Pyodide download for uvx users#8
Merged
Conversation
Major enhancement to resolve Pyodide initialization failures: ## Problem Solved - uvx/pipx users experienced "Pyodide module not found" errors - No mechanism to install npm dependencies during Python package installation - Manual npm install requirement created friction for users ## Solution: Hybrid Runtime Download System ### Core Features - **Automatic fallback**: Downloads pyodide from npm registry if not found locally - **Smart caching**: Stores files in ~/.cache/mip-mcp/pyodide/ for fast subsequent runs - **Universal compatibility**: Works with uvx, pip, pipx, conda, any installation method - **No npm dependency**: Users don't need Node.js/npm installed - **Robust error handling**: Clear messages with manual installation fallback ### Technical Implementation - Add _download_pyodide() method for npm registry download (12MB) - Add _extract_pyodide_package() for selective file extraction - Add _find_or_download_pyodide_path() as unified entry point - Cross-platform cache directory handling (Windows/Unix) - Async download to prevent event loop blocking - Extract only required files: pyodide.js, pyodide.asm.wasm, python_stdlib.zip, etc. ### User Experience Improvements - Fast Python package installation (no build-time npm requirements) - One-time 12MB download cached for future use - Seamless experience: uvx mip-mcp "just works" - Graceful degradation if download fails with helpful error messages ### Architecture Benefits - Maintains existing local pyodide detection (backward compatible) - No changes to build system or dependencies required - No npm requirement at install time - Better than setuptools build hooks (uvx/pipx compatible) ### Testing Results - ✅ Download from npm registry successful - ✅ All required files extracted and cached properly - ✅ Pyodide initialization successful with downloaded files - ✅ Complete MCP workflow verified: Problem generation + SCIP solving - ✅ Cache reuse working for subsequent executions Resolves #7 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Replace runtime download approach with build-time bundling for better PyPI compatibility: ## Key Changes ### Build System (pyproject.toml) - Add hatchling shared-data configuration to bundle node_modules/pyodide files - Bundle 5 essential pyodide files (~12MB total) in wheel distribution: - pyodide.js, pyodide.asm.js, pyodide.asm.wasm - pyodide-lock.json, python_stdlib.zip ### Pyodide Path Detection (pyodide_executor.py) - Add _check_bundled_pyodide() method to detect wheel-bundled files - Update _find_pyodide_path() to check bundled location first - Maintain backward compatibility with npm install workflow ## Benefits for PyPI Distribution ✅ **Self-contained wheels**: Perfect for `uv tool run mip-mcp` ✅ **Instant execution**: No runtime downloads or network dependencies ✅ **Offline capable**: Works in restricted environments/firewalls ✅ **Standard practice**: Follows industry patterns (PuLP, pyscipopt) ✅ **Clean repository**: No binary files in git (bundled only in wheels) ## Workflow Support **Development**: `npm install` → local node_modules (unchanged) **Distribution**: `uv build` → bundles pyodide in wheel → PyPI ready ## Technical Implementation - Use pkg_resources.resource_filename() for bundled file access - Bundled files stored in `mip_mcp/pyodide/` within wheel - Graceful fallback to npm-installed pyodide for development - Build process automatically includes existing node_modules files This approach provides the optimal user experience for PyPI distribution while maintaining clean development workflow and following established packaging patterns. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
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.
Summary
Resolves #7 by implementing automatic Pyodide download functionality for users installing with uvx/pipx, eliminating "Pyodide module not found" errors.
Problem Addressed
Solution: Hybrid Runtime Download System
🎯 Core Features
~/.cache/mip-mcp/pyodide/for fast subsequent runs🔧 Technical Implementation
_download_pyodide(): Downloads 12MB package from npm registry asynchronously_extract_pyodide_package(): Extracts only required files (pyodide.js, pyodide.asm.wasm, python_stdlib.zip, etc.)_find_or_download_pyodide_path(): Unified entry point with fallback logic%APPDATA%) and Unix (~/.cache) supportrun_in_executor()📈 User Experience Improvements
uvx mip-mcpnow "just works"🏗️ Architecture Benefits
Test Plan
Files Changed
src/mip_mcp/executor/pyodide_executor.py: Added download and caching functionality (+111 lines)Performance Impact
Breaking Changes
None - fully backward compatible with existing installations.
Benefits Over Alternative Solutions
Usage After This Change
This solution provides the optimal user experience while maintaining security, reliability, and broad compatibility across all Python installation methods.
🤖 Generated with Claude Code