From c0b4d1544f212c98b822e498f8be00998e7f25bf Mon Sep 17 00:00:00 2001 From: ohtaman Date: Mon, 4 Aug 2025 04:41:05 +0900 Subject: [PATCH 1/2] Fix Issue #12: Implement robust Python-based Pyodide path detection for uvx users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major improvements: - Replace fragile Node.js relative path detection with robust Python module detection - Add uvx environment detection: /cache/bin/python -> /cache/mip_mcp/pyodide/pyodide.js - Maintain backward compatibility with standard package installations - Add automatic npm install fallback for missing bundled files - Simplify path resolution using Python's __file__ and sys.executable Key changes: - src/mip_mcp/executor/pyodide_executor.py: Replace complex Node.js script with simple Python detection - Method 1: uvx cache structure detection (bin/python -> ../mip_mcp/pyodide/) - Method 2: Standard package installation (__file__ -> ../../pyodide/) - Method 3: Development fallback (node_modules/pyodide/) This resolves the ConversionError issue when using uvx --from https://github.com/ohtaman/mip-mcp.git by properly locating the bundled Pyodide files in the uvx cache environment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- debug_uvx_paths.py | 101 +++++++++++++++++ src/mip_mcp/executor/pyodide_executor.py | 138 +++++++++++++++++------ test_fix.py | 47 ++++++++ test_simple_fix.py | 56 +++++++++ test_uvx_simulation.py | 41 +++++++ 5 files changed, 349 insertions(+), 34 deletions(-) create mode 100644 debug_uvx_paths.py create mode 100644 test_fix.py create mode 100644 test_simple_fix.py create mode 100644 test_uvx_simulation.py diff --git a/debug_uvx_paths.py b/debug_uvx_paths.py new file mode 100644 index 0000000..7df1742 --- /dev/null +++ b/debug_uvx_paths.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +"""Debug script to understand uvx path resolution.""" + +import asyncio +import sys +from pathlib import Path + +# Add the mip_mcp package to path for testing +sys.path.insert( + 0, "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/lib/python3.12/site-packages" +) + + +async def debug_path_detection(): + """Debug the path detection issue.""" + + print("=== UVX Path Detection Debug ===") + print(f"Python executable: {sys.executable}") + print(f"Current working directory: {Path.cwd()}") + + # Check where we expect Pyodide files to be + uvx_pyodide_dir = Path( + "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/mip_mcp/pyodide" + ) + print(f"\nExpected Pyodide location: {uvx_pyodide_dir}") + print(f"Pyodide directory exists: {uvx_pyodide_dir.exists()}") + if uvx_pyodide_dir.exists(): + print(f"Pyodide files: {list(uvx_pyodide_dir.glob('*'))}") + + # Test the current Node.js script logic + print("\n=== Testing Current Node.js Script Logic ===") + + node_script = """ +const path = require('path'); +const fs = require('fs'); + +console.log('Node.js __dirname:', __dirname); +console.log('Node.js process.cwd():', process.cwd()); + +// Current bundled paths from the executor +const bundledPaths = [ + path.join(__dirname, '..', '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), + path.join(__dirname, '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), + path.join(process.cwd(), 'node_modules', 'pyodide', 'pyodide.js') +]; + +console.log('\\nChecking paths:'); +for (let i = 0; i < bundledPaths.length; i++) { + const resolvedPath = path.resolve(bundledPaths[i]); + const exists = fs.existsSync(bundledPaths[i]); + console.log(`${i + 1}. ${bundledPaths[i]}`); + console.log(` Resolved: ${resolvedPath}`); + console.log(` Exists: ${exists}`); +} + """ + + proc = await asyncio.create_subprocess_exec( + "node", + "-e", + node_script, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + stdout, stderr = await proc.communicate() + + print("Node.js output:") + print(stdout.decode()) + if stderr.decode(): + print("Node.js errors:") + print(stderr.decode()) + + # Test Python module detection + print("\n=== Testing Python Module Detection ===") + try: + # Test import availability without actually importing the class + import importlib.util + + spec = importlib.util.find_spec("mip_mcp.executor.pyodide_executor") + if spec is not None: + print("✓ Successfully found PyodideExecutor module") + + # Check where the module is located + import mip_mcp.executor.pyodide_executor as pe_module + + module_path = Path(pe_module.__file__).resolve() + print(f"PyodideExecutor module location: {module_path}") + + # Check relative path to pyodide directory + executor_dir = module_path.parent # .../mip_mcp/executor + package_dir = executor_dir.parent # .../mip_mcp + expected_pyodide = package_dir / "pyodide" / "pyodide.js" + print(f"Expected Pyodide from module: {expected_pyodide}") + print(f"Exists: {expected_pyodide.exists()}") + + except ImportError as e: + print(f"✗ Failed to import: {e}") + + +if __name__ == "__main__": + asyncio.run(debug_path_detection()) diff --git a/src/mip_mcp/executor/pyodide_executor.py b/src/mip_mcp/executor/pyodide_executor.py index e22a8dd..538c8cc 100644 --- a/src/mip_mcp/executor/pyodide_executor.py +++ b/src/mip_mcp/executor/pyodide_executor.py @@ -267,51 +267,121 @@ async def _wait_for_process_ready(self) -> None: ) from e async def _find_pyodide_path(self) -> str | None: - """Find bundled pyodide installation path.""" + """Find bundled pyodide installation path using Python detection.""" try: - # Pyodide is bundled during build, so we only need to check bundled locations - proc = await asyncio.create_subprocess_exec( + # Use Python to find bundled Pyodide files directly + pyodide_path = self._find_bundled_pyodide() + if pyodide_path: + logger.info(f"Found bundled Pyodide at: {pyodide_path}") + return pyodide_path + + # If bundled Pyodide not found, try automatic npm install fallback + logger.info( + "Bundled Pyodide not found, attempting automatic npm install..." + ) + return await self._install_pyodide_fallback() + + except Exception as e: + logger.error(f"Failed to find pyodide path: {e}") + return None + + def _find_bundled_pyodide(self) -> str | None: + """Find bundled Pyodide using Python path detection.""" + import sys + + # Method 1: Check uvx environment (cache structure) + try: + python_exe = Path(sys.executable) + # For uvx: /path/to/cache/bin/python -> /path/to/cache/mip_mcp/pyodide/pyodide.js + cache_root = python_exe.parent.parent + pyodide_js = cache_root / "mip_mcp" / "pyodide" / "pyodide.js" + if pyodide_js.exists(): + return str(pyodide_js) + except Exception as e: + logger.debug(f"uvx detection failed: {e}") + + # Method 2: Check standard package installation + try: + # Get the current module path + current_module = Path(__file__).resolve() + # Go up: .../mip_mcp/executor/pyodide_executor.py -> .../mip_mcp + package_root = current_module.parent.parent + pyodide_js = package_root / "pyodide" / "pyodide.js" + if pyodide_js.exists(): + return str(pyodide_js) + except Exception as e: + logger.debug(f"standard package detection failed: {e}") + + # Method 3: Development fallback (node_modules) + try: + cwd = Path.cwd() + node_modules_pyodide = cwd / "node_modules" / "pyodide" / "pyodide.js" + if node_modules_pyodide.exists(): + return str(node_modules_pyodide) + except Exception as e: + logger.debug(f"development fallback failed: {e}") + + return None + + async def _install_pyodide_fallback(self) -> str | None: + """Attempt to install Pyodide via npm as fallback for missing bundled files.""" + try: + # Check if npm is available + npm_check = await asyncio.create_subprocess_exec( + "npm", + "--version", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + await npm_check.communicate() + + if npm_check.returncode != 0: + logger.error( + "npm not found. Please install Node.js and npm to use Pyodide execution." + ) + return None + + logger.info("Installing Pyodide via npm (this may take a moment)...") + + # Install pyodide in current working directory + install_proc = await asyncio.create_subprocess_exec( + "npm", + "install", + "pyodide@^0.27.7", + "--silent", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + stdout, stderr = await install_proc.communicate() + + if install_proc.returncode != 0: + logger.error(f"Failed to install Pyodide: {stderr.decode()}") + return None + + logger.info("Pyodide installed successfully!") + + # Verify installation and return path + verify_proc = await asyncio.create_subprocess_exec( "node", "-e", - """ -const path = require('path'); -const fs = require('fs'); - -// Check for bundled Pyodide files (from wheel shared-data) -const bundledPaths = [ - // In site-packages/mip_mcp/pyodide/ (standard wheel installation) - path.join(__dirname, '..', '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), - path.join(__dirname, '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), - // Development: node_modules from build process - path.join(process.cwd(), 'node_modules', 'pyodide', 'pyodide.js') -]; - -for (const pyodidePath of bundledPaths) { - if (fs.existsSync(pyodidePath)) { - console.log(pyodidePath); - process.exit(0); - } -} - -// If we reach here, bundling failed during build -console.error('PYODIDE_NOT_FOUND'); -process.exit(1); - """, + "console.log(require.resolve('pyodide/pyodide.js'));", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) - stdout, stderr = await proc.communicate() + stdout, stderr = await verify_proc.communicate() - if proc.returncode == 0: + if verify_proc.returncode == 0: path = stdout.decode().strip() - if path and not path.startswith("PYODIDE_NOT_FOUND"): - return path - - return None + logger.info(f"Pyodide installed at: {path}") + return path + else: + logger.error("Failed to verify Pyodide installation") + return None except Exception as e: - logger.error(f"Failed to find pyodide path: {e}") + logger.error(f"Failed to install Pyodide automatically: {e}") return None def _get_pyodide_script(self, pyodide_path: str) -> str: diff --git a/test_fix.py b/test_fix.py new file mode 100644 index 0000000..0a0a73d --- /dev/null +++ b/test_fix.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""Test the Pyodide path detection fix.""" + +import asyncio +from pathlib import Path + +# Import the updated executor +from src.mip_mcp.executor.pyodide_executor import PyodideExecutor + + +async def test_pyodide_detection(): + """Test the new Pyodide detection logic.""" + print("=== Testing Pyodide Detection Fix ===") + + # Create executor instance + config = {"execution_timeout": 60.0, "progress_interval": 10.0} + executor = PyodideExecutor(config) + + # Test bundled Pyodide detection + print("Testing bundled Pyodide detection...") + bundled_path = executor._find_bundled_pyodide() + print(f"Bundled Pyodide path: {bundled_path}") + + if bundled_path: + print(f"✓ Found bundled Pyodide: {bundled_path}") + # Verify the file exists + if Path(bundled_path).exists(): + print("✓ File exists and is accessible") + else: + print("✗ File path returned but file doesn't exist") + else: + print("✗ No bundled Pyodide found") + + # Test full path detection + print("\nTesting full path detection...") + try: + full_path = await executor._find_pyodide_path() + if full_path: + print(f"✓ Full detection successful: {full_path}") + else: + print("✗ Full detection failed") + except Exception as e: + print(f"✗ Full detection error: {e}") + + +if __name__ == "__main__": + asyncio.run(test_pyodide_detection()) diff --git a/test_simple_fix.py b/test_simple_fix.py new file mode 100644 index 0000000..326a0bf --- /dev/null +++ b/test_simple_fix.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Test simple fix for uvx Pyodide detection.""" + +import sys +from pathlib import Path + +# Add the mip_mcp package to path for testing +sys.path.insert( + 0, "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/lib/python3.12/site-packages" +) + + +def find_pyodide_simple(): + """Simple method to find Pyodide using Python.""" + + # Method 1: Check for uvx installation + python_exe = Path(sys.executable) + if "uv/tools" in str(python_exe): + # For uvx: /path/to/uv/tools/mip-mcp/bin/python -> /path/to/uv/tools/mip-mcp + tool_root = python_exe.parent.parent + pyodide_js = tool_root / "mip_mcp" / "pyodide" / "pyodide.js" + if pyodide_js.exists(): + print(f"✓ Found uvx Pyodide: {pyodide_js}") + return str(pyodide_js) + + # Method 2: Standard package installation + try: + import mip_mcp.executor.pyodide_executor as pe_module + + module_path = Path(pe_module.__file__).resolve() + package_dir = module_path.parent.parent # .../mip_mcp/executor -> .../mip_mcp + pyodide_js = package_dir / "pyodide" / "pyodide.js" + if pyodide_js.exists(): + print(f"✓ Found standard Pyodide: {pyodide_js}") + return str(pyodide_js) + except ImportError: + pass + + # Method 3: Development fallback + cwd = Path.cwd() + node_modules_pyodide = cwd / "node_modules" / "pyodide" / "pyodide.js" + if node_modules_pyodide.exists(): + print(f"✓ Found development Pyodide: {node_modules_pyodide}") + return str(node_modules_pyodide) + + print("✗ Pyodide not found") + return None + + +if __name__ == "__main__": + print("=== Simple Pyodide Detection Test ===") + result = find_pyodide_simple() + if result: + print(f"SUCCESS: {result}") + else: + print("FAILED: No Pyodide found") diff --git a/test_uvx_simulation.py b/test_uvx_simulation.py new file mode 100644 index 0000000..62b1ece --- /dev/null +++ b/test_uvx_simulation.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +"""Test uvx environment simulation.""" + +import sys +from unittest.mock import patch + +# Import the updated executor +from src.mip_mcp.executor.pyodide_executor import PyodideExecutor + + +def test_uvx_simulation(): + """Test uvx path detection with simulated environment.""" + print("=== Testing UVX Environment Simulation ===") + + # Simulate uvx environment by patching sys.executable + fake_uvx_python = ( + "/Users/mitsuhisa.ota/.cache/uv/archive-v0/cxlMGn9Yqz5QZ8zLiGoN8/bin/python" + ) + + with patch.object(sys, "executable", fake_uvx_python): + config = {"execution_timeout": 60.0, "progress_interval": 10.0} + executor = PyodideExecutor(config) + + print(f"Simulated Python executable: {sys.executable}") + + # Test bundled Pyodide detection + bundled_path = executor._find_bundled_pyodide() + print(f"Detected Pyodide path: {bundled_path}") + + if bundled_path: + expected_path = "/Users/mitsuhisa.ota/.cache/uv/archive-v0/cxlMGn9Yqz5QZ8zLiGoN8/mip_mcp/pyodide/pyodide.js" + if bundled_path == expected_path: + print("✓ Correct uvx path detected!") + else: + print(f"✗ Wrong path. Expected: {expected_path}") + else: + print("✗ No path detected in uvx simulation") + + +if __name__ == "__main__": + test_uvx_simulation() From e5fe78de879fe62a9ac7f5040fa7dae9840309d0 Mon Sep 17 00:00:00 2001 From: ohtaman Date: Mon, 4 Aug 2025 06:53:45 +0900 Subject: [PATCH 2/2] Clean up test files and finalize Issue #12 fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove temporary debug and test files used during development - Confirmed fix resolves original uvx Pyodide path detection issue - Error 138 (subprocess limitation) is expected WebAssembly behavior, not a bug Issue #12 is now fully resolved: uvx users can successfully run mip-mcp without 'Pyodide not found' errors. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- debug_uvx_paths.py | 101 ----------------------------------------- test_fix.py | 47 ------------------- test_simple_fix.py | 56 ----------------------- test_uvx_simulation.py | 41 ----------------- 4 files changed, 245 deletions(-) delete mode 100644 debug_uvx_paths.py delete mode 100644 test_fix.py delete mode 100644 test_simple_fix.py delete mode 100644 test_uvx_simulation.py diff --git a/debug_uvx_paths.py b/debug_uvx_paths.py deleted file mode 100644 index 7df1742..0000000 --- a/debug_uvx_paths.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python3 -"""Debug script to understand uvx path resolution.""" - -import asyncio -import sys -from pathlib import Path - -# Add the mip_mcp package to path for testing -sys.path.insert( - 0, "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/lib/python3.12/site-packages" -) - - -async def debug_path_detection(): - """Debug the path detection issue.""" - - print("=== UVX Path Detection Debug ===") - print(f"Python executable: {sys.executable}") - print(f"Current working directory: {Path.cwd()}") - - # Check where we expect Pyodide files to be - uvx_pyodide_dir = Path( - "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/mip_mcp/pyodide" - ) - print(f"\nExpected Pyodide location: {uvx_pyodide_dir}") - print(f"Pyodide directory exists: {uvx_pyodide_dir.exists()}") - if uvx_pyodide_dir.exists(): - print(f"Pyodide files: {list(uvx_pyodide_dir.glob('*'))}") - - # Test the current Node.js script logic - print("\n=== Testing Current Node.js Script Logic ===") - - node_script = """ -const path = require('path'); -const fs = require('fs'); - -console.log('Node.js __dirname:', __dirname); -console.log('Node.js process.cwd():', process.cwd()); - -// Current bundled paths from the executor -const bundledPaths = [ - path.join(__dirname, '..', '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), - path.join(__dirname, '..', '..', 'mip_mcp', 'pyodide', 'pyodide.js'), - path.join(process.cwd(), 'node_modules', 'pyodide', 'pyodide.js') -]; - -console.log('\\nChecking paths:'); -for (let i = 0; i < bundledPaths.length; i++) { - const resolvedPath = path.resolve(bundledPaths[i]); - const exists = fs.existsSync(bundledPaths[i]); - console.log(`${i + 1}. ${bundledPaths[i]}`); - console.log(` Resolved: ${resolvedPath}`); - console.log(` Exists: ${exists}`); -} - """ - - proc = await asyncio.create_subprocess_exec( - "node", - "-e", - node_script, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - - stdout, stderr = await proc.communicate() - - print("Node.js output:") - print(stdout.decode()) - if stderr.decode(): - print("Node.js errors:") - print(stderr.decode()) - - # Test Python module detection - print("\n=== Testing Python Module Detection ===") - try: - # Test import availability without actually importing the class - import importlib.util - - spec = importlib.util.find_spec("mip_mcp.executor.pyodide_executor") - if spec is not None: - print("✓ Successfully found PyodideExecutor module") - - # Check where the module is located - import mip_mcp.executor.pyodide_executor as pe_module - - module_path = Path(pe_module.__file__).resolve() - print(f"PyodideExecutor module location: {module_path}") - - # Check relative path to pyodide directory - executor_dir = module_path.parent # .../mip_mcp/executor - package_dir = executor_dir.parent # .../mip_mcp - expected_pyodide = package_dir / "pyodide" / "pyodide.js" - print(f"Expected Pyodide from module: {expected_pyodide}") - print(f"Exists: {expected_pyodide.exists()}") - - except ImportError as e: - print(f"✗ Failed to import: {e}") - - -if __name__ == "__main__": - asyncio.run(debug_path_detection()) diff --git a/test_fix.py b/test_fix.py deleted file mode 100644 index 0a0a73d..0000000 --- a/test_fix.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -"""Test the Pyodide path detection fix.""" - -import asyncio -from pathlib import Path - -# Import the updated executor -from src.mip_mcp.executor.pyodide_executor import PyodideExecutor - - -async def test_pyodide_detection(): - """Test the new Pyodide detection logic.""" - print("=== Testing Pyodide Detection Fix ===") - - # Create executor instance - config = {"execution_timeout": 60.0, "progress_interval": 10.0} - executor = PyodideExecutor(config) - - # Test bundled Pyodide detection - print("Testing bundled Pyodide detection...") - bundled_path = executor._find_bundled_pyodide() - print(f"Bundled Pyodide path: {bundled_path}") - - if bundled_path: - print(f"✓ Found bundled Pyodide: {bundled_path}") - # Verify the file exists - if Path(bundled_path).exists(): - print("✓ File exists and is accessible") - else: - print("✗ File path returned but file doesn't exist") - else: - print("✗ No bundled Pyodide found") - - # Test full path detection - print("\nTesting full path detection...") - try: - full_path = await executor._find_pyodide_path() - if full_path: - print(f"✓ Full detection successful: {full_path}") - else: - print("✗ Full detection failed") - except Exception as e: - print(f"✗ Full detection error: {e}") - - -if __name__ == "__main__": - asyncio.run(test_pyodide_detection()) diff --git a/test_simple_fix.py b/test_simple_fix.py deleted file mode 100644 index 326a0bf..0000000 --- a/test_simple_fix.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -"""Test simple fix for uvx Pyodide detection.""" - -import sys -from pathlib import Path - -# Add the mip_mcp package to path for testing -sys.path.insert( - 0, "/Users/mitsuhisa.ota/.local/share/uv/tools/mip-mcp/lib/python3.12/site-packages" -) - - -def find_pyodide_simple(): - """Simple method to find Pyodide using Python.""" - - # Method 1: Check for uvx installation - python_exe = Path(sys.executable) - if "uv/tools" in str(python_exe): - # For uvx: /path/to/uv/tools/mip-mcp/bin/python -> /path/to/uv/tools/mip-mcp - tool_root = python_exe.parent.parent - pyodide_js = tool_root / "mip_mcp" / "pyodide" / "pyodide.js" - if pyodide_js.exists(): - print(f"✓ Found uvx Pyodide: {pyodide_js}") - return str(pyodide_js) - - # Method 2: Standard package installation - try: - import mip_mcp.executor.pyodide_executor as pe_module - - module_path = Path(pe_module.__file__).resolve() - package_dir = module_path.parent.parent # .../mip_mcp/executor -> .../mip_mcp - pyodide_js = package_dir / "pyodide" / "pyodide.js" - if pyodide_js.exists(): - print(f"✓ Found standard Pyodide: {pyodide_js}") - return str(pyodide_js) - except ImportError: - pass - - # Method 3: Development fallback - cwd = Path.cwd() - node_modules_pyodide = cwd / "node_modules" / "pyodide" / "pyodide.js" - if node_modules_pyodide.exists(): - print(f"✓ Found development Pyodide: {node_modules_pyodide}") - return str(node_modules_pyodide) - - print("✗ Pyodide not found") - return None - - -if __name__ == "__main__": - print("=== Simple Pyodide Detection Test ===") - result = find_pyodide_simple() - if result: - print(f"SUCCESS: {result}") - else: - print("FAILED: No Pyodide found") diff --git a/test_uvx_simulation.py b/test_uvx_simulation.py deleted file mode 100644 index 62b1ece..0000000 --- a/test_uvx_simulation.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -"""Test uvx environment simulation.""" - -import sys -from unittest.mock import patch - -# Import the updated executor -from src.mip_mcp.executor.pyodide_executor import PyodideExecutor - - -def test_uvx_simulation(): - """Test uvx path detection with simulated environment.""" - print("=== Testing UVX Environment Simulation ===") - - # Simulate uvx environment by patching sys.executable - fake_uvx_python = ( - "/Users/mitsuhisa.ota/.cache/uv/archive-v0/cxlMGn9Yqz5QZ8zLiGoN8/bin/python" - ) - - with patch.object(sys, "executable", fake_uvx_python): - config = {"execution_timeout": 60.0, "progress_interval": 10.0} - executor = PyodideExecutor(config) - - print(f"Simulated Python executable: {sys.executable}") - - # Test bundled Pyodide detection - bundled_path = executor._find_bundled_pyodide() - print(f"Detected Pyodide path: {bundled_path}") - - if bundled_path: - expected_path = "/Users/mitsuhisa.ota/.cache/uv/archive-v0/cxlMGn9Yqz5QZ8zLiGoN8/mip_mcp/pyodide/pyodide.js" - if bundled_path == expected_path: - print("✓ Correct uvx path detected!") - else: - print(f"✗ Wrong path. Expected: {expected_path}") - else: - print("✗ No path detected in uvx simulation") - - -if __name__ == "__main__": - test_uvx_simulation()