CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pyodide

Python distribution for the browser and Node.js based on WebAssembly that enables running Python code with full JavaScript interoperability

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

package-management.mddocs/

Package Management

Install and manage Python packages in the Pyodide environment with automatic dependency resolution and progress tracking.

Loading Packages

loadPackage

Install Python packages from the Pyodide package repository.

function loadPackage(
  packages: string | string[],
  options?: {
    messageCallback?: (message: string) => void;
    errorCallback?: (message: string) => void;
    checkIntegrity?: boolean;
  }
): Promise<PackageData[]>;

Parameters:

  • packages - Package name(s) to install
  • options.messageCallback - Callback for progress messages
  • options.errorCallback - Callback for error/warning messages
  • options.checkIntegrity - Verify package integrity (default: true)

Returns: Promise resolving to array of installed package metadata

loadPackagesFromImports

Automatically detect and install packages based on import statements in Python code.

function loadPackagesFromImports(
  code: string,
  options?: {
    messageCallback?: (message: string) => void;
    errorCallback?: (message: string) => void;
    checkIntegrity?: boolean;
  }
): Promise<PackageData[]>;

Parameters:

  • code - Python code to analyze for imports
  • options - Same as loadPackage

Returns: Promise resolving to array of installed package metadata

Package Registry

loadedPackages

Access information about currently loaded packages.

const loadedPackages: Map<string, PackageData>;

Usage Examples

Basic Package Installation

// Install single package
await pyodide.loadPackage("numpy");

// Install multiple packages
await pyodide.loadPackage(["pandas", "matplotlib", "scipy"]);

// Use installed packages
pyodide.runPython(`
    import numpy as np
    import pandas as pd
    
    data = np.array([1, 2, 3, 4, 5])
    df = pd.DataFrame({"values": data})
    print(df.describe())
`);

Progress Tracking

await pyodide.loadPackage(["scipy", "scikit-learn"], {
  messageCallback: (msg) => {
    console.log(`Download: ${msg}`);
  },
  errorCallback: (msg) => {
    console.warn(`Warning: ${msg}`);
  }
});

Auto-loading from Import Analysis

const pythonCode = `
    import numpy as np
    import pandas as pd
    from sklearn.linear_model import LinearRegression
    import matplotlib.pyplot as plt
`;

// Automatically detect and install required packages
const installedPackages = await pyodide.loadPackagesFromImports(pythonCode);
console.log("Installed packages:", installedPackages.map(pkg => pkg.name));

// Now run the code
pyodide.runPython(pythonCode);
pyodide.runPython(`
    # Packages are now available
    X = np.array([[1], [2], [3], [4]])
    y = np.array([2, 4, 6, 8])
    model = LinearRegression().fit(X, y)
    print(f"Slope: {model.coef_[0]}")
`);

Custom Progress UI

let progressDiv = document.getElementById('progress');

await pyodide.loadPackage(["tensorflow", "keras"], {
  messageCallback: (msg) => {
    // Parse download progress
    if (msg.includes("Downloading")) {
      const match = msg.match(/(\d+)\/(\d+)/);
      if (match) {
        const [, current, total] = match;
        const percent = (current / total) * 100;
        progressDiv.innerHTML = `Installing packages: ${percent.toFixed(1)}%`;
      }
    }
  },
  errorCallback: (msg) => {
    console.error("Package installation warning:", msg);
  }
});

progressDiv.innerHTML = "Installation complete!";

Package Information

// Load package and examine metadata
const packageData = await pyodide.loadPackage("networkx");
console.log("Package info:", packageData[0]);

// Check all loaded packages
console.log("Currently loaded packages:");
for (const [name, data] of pyodide.loadedPackages) {
  console.log(`${name} v${data.version} (${data.package_type})`);
}

// Check if specific package is loaded
if (pyodide.loadedPackages.has("numpy")) {
  const numpyInfo = pyodide.loadedPackages.get("numpy");
  console.log(`NumPy version: ${numpyInfo.version}`);
}

Error Handling

try {
  await pyodide.loadPackage("nonexistent-package");
} catch (error) {
  if (error.message.includes("not found")) {
    console.error("Package not available in Pyodide repository");
  } else {
    console.error("Installation failed:", error.message);
  }
}

// Handle import analysis errors
try {
  const packages = await pyodide.loadPackagesFromImports(`
    import some_package_that_doesnt_exist
  `);
} catch (error) {
  console.log("Some imports couldn't be resolved, continuing...");
}

Installing from Initialization

// Load packages during Pyodide initialization for better performance
const pyodide = await loadPyodide({
  packages: ["numpy", "pandas", "matplotlib"]
});

// Packages are immediately available
pyodide.runPython(`
    import numpy as np
    print("NumPy version:", np.__version__)
`);

Batch Installation with Dependencies

// Install packages with complex dependency trees
const scientificStack = [
  "numpy", 
  "scipy", 
  "pandas", 
  "matplotlib", 
  "scikit-learn",
  "networkx",
  "sympy"
];

console.log("Installing scientific Python stack...");
const results = await pyodide.loadPackage(scientificStack, {
  messageCallback: (msg) => {
    if (msg.includes("Installing")) {
      console.log(msg);
    }
  }
});

console.log(`Successfully installed ${results.length} packages`);

// Verify installation
pyodide.runPython(`
    import sys
    installed = [pkg.split('.')[0] for pkg in sys.modules.keys() 
                 if not pkg.startswith('_')]
    print(f"Available modules: {len(set(installed))}")
`);

Working with MicroPip

// Use Python's micropip for additional packages
await pyodide.loadPackage("micropip");

pyodide.runPython(`
    import micropip
    
    # Install pure Python packages from PyPI
    await micropip.install("requests")
    await micropip.install("beautifulsoup4")
    
    # Use installed packages
    import requests
    from bs4 import BeautifulSoup
    print("Additional packages installed via micropip")
`);

Package Data Structure

interface PackageData {
  name: string;           // Package name
  version: string;        // Package version
  channel: string;        // Distribution channel
  file_name: string;      // Archive filename
  install_dir: string;    // Installation directory
  sha256: string;         // File integrity hash
  package_type: string;   // Package type (e.g., "package")
  imports: string[];      // Importable module names
  depends: string[];      // Package dependencies
}

Advanced Package Management

Custom Package Sources

// Load from custom lock file with different package sources
const customLockFile = await fetch("/custom-pyodide-lock.json")
  .then(r => r.json());

const pyodide = await loadPyodide({
  lockFileContents: customLockFile,
  packageBaseUrl: "https://custom-packages.example.com/"
});

await pyodide.loadPackage("custom-package");

Package Installation Hooks

const originalLoadPackage = pyodide.loadPackage;

// Wrap loadPackage with custom logic
pyodide.loadPackage = async function(packages, options = {}) {
  console.log(`Installing packages: ${Array.isArray(packages) ? packages.join(", ") : packages}`);
  
  const startTime = Date.now();
  const result = await originalLoadPackage.call(this, packages, {
    ...options,
    messageCallback: (msg) => {
      console.log(`[${Date.now() - startTime}ms] ${msg}`);
      options.messageCallback?.(msg);
    }
  });
  
  console.log(`Installation completed in ${Date.now() - startTime}ms`);
  return result;
};

Install with Tessl CLI

npx tessl i tessl/npm-pyodide

docs

advanced-features.md

code-execution.md

ffi.md

file-system.md

index.md

interoperability.md

io-streams.md

package-management.md

runtime-loading.md

tile.json