TypeScript wrapper for Python libraries with full type safety.
⚠️ Experimental — APIs may change before v1.0.0. See the releases page for breaking changes.
- Full Type Safety - TypeScript definitions generated from Python source analysis
- Multi-Runtime - Node.js (subprocess) and browsers (Pyodide)
- Rich Data Types - numpy, pandas, scipy, torch, sklearn, and stdlib types
- Efficient Serialization - Apache Arrow binary format with JSON fallback
| Feature | tywrap | pythonia | node-calls-python | pymport |
|---|---|---|---|---|
| Auto-generated TypeScript types | ✅ | ❌ | ❌ | ❌ |
| Browser / WASM (Pyodide) | ✅ | ❌ | ❌ | ❌ |
| numpy / pandas type mappings | ✅ | ❌ | ❌ | ❌ |
| Node.js + Bun + Deno | All three | Node only | Node only | Node only |
| Apache Arrow binary transport | ✅ | ❌ | ❌ | ❌ |
-
Node.js 20+ (or Bun 1.1+ / Deno 1.46+)
-
Python 3.10+ with
tywrap-ir:pip install tywrap-ir
npm install tywrap
pip install tywrap-ir # Python component for code generation
npx tywrap init # Create config (and package.json scripts if present)
npx tywrap generate # Generate wrappersFor CI (or to verify a dependency upgrade didn’t change the generated surface):
npx tywrap generate --checkimport { NodeBridge } from 'tywrap/node';
import { setRuntimeBridge } from 'tywrap/runtime';
import * as math from './generated/math.generated.js';
const bridge = new NodeBridge({ pythonPath: 'python3' });
setRuntimeBridge(bridge);
const result = await math.sqrt(16); // 4If tywrap saves you time, a ⭐ on GitHub helps others find it.
import { NodeBridge } from 'tywrap/node';
const bridge = new NodeBridge({
pythonPath: 'python3',
virtualEnv: './venv',
timeoutMs: 30000,
});NodeBridge is the default, correctness-first bridge. OptimizedNodeBridge is a
performance-focused prototype (process pooling + optional caching) and is not a
drop-in replacement yet. See ROADMAP.md for the unification plan.
Both bridges share a common JSONL core for protocol validation and timeouts.
By default, NodeBridge inherits only PATH/PYTHON*/TYWRAP_* from process.env
to keep the subprocess environment minimal. Set inheritProcessEnv: true if you
need the full environment.
You can cap payload sizes with TYWRAP_CODEC_MAX_BYTES (responses) and
TYWRAP_REQUEST_MAX_BYTES (requests) to keep JSONL traffic bounded.
import { PyodideBridge } from 'tywrap/pyodide';
const bridge = new PyodideBridge({
indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.28.0/full/',
});
await bridge.init();import { NodeBridge } from 'npm:tywrap'; // Deno
import { NodeBridge } from 'tywrap'; // Bun// tywrap.config.ts
import { defineConfig } from 'tywrap';
export default defineConfig({
pythonModules: {
pandas: {
runtime: 'node',
typeHints: 'strict',
classes: ['DataFrame'],
functions: ['read_csv'],
},
numpy: {
runtime: 'node',
typeHints: 'strict',
alias: 'np',
},
},
output: { dir: './src/generated' },
});See Configuration Guide for all options.
| Python | TypeScript | Notes |
|---|---|---|
numpy.ndarray |
Uint8Array / array |
Arrow or JSON |
pandas.DataFrame |
Arrow Table / object[] |
Arrow or JSON |
scipy.sparse.* |
SparseMatrix |
CSR, CSC, COO |
torch.Tensor |
TorchTensor |
CPU only |
sklearn estimator |
SklearnEstimator |
Params only |
datetime, Decimal, UUID, Path |
string |
Standard formats |
For Arrow encoding with numpy/pandas:
import { registerArrowDecoder } from 'tywrap';
import { tableFromIPC } from 'apache-arrow';
registerArrowDecoder(bytes => tableFromIPC(bytes));npm install
npm testSee CONTRIBUTING.md for guidelines.
MIT © tywrap contributors