python-shell
Run Python scripts from Node.js with simple, efficient stdio-based inter-process communication.
Repository Health
Technical Analysis
python-shell is a Node.js library for spawning Python scripts as child processes and exchanging data with them over stdin/stdout. It wraps child_process.spawn with a mode system (text, JSON, or binary) that automatically formats outgoing messages and parses incoming ones, so a Node application can send commands to a running Python process and receive structured messages back without manually managing stream buffering or line splitting.
Beyond raw process control, it adds developer conveniences that plain child_process doesn’t: a promise-based run/runString API for one-shot script execution, syntax-checking helpers (checkSyntax/checkSyntaxFile) that validate Python code before running it, and error handling that parses Python tracebacks out of stderr into a JavaScript PythonShellError with an extended stack trace showing both the Node and Python call sites.
It has zero runtime dependencies and ships as a small, TypeScript-authored package, making it a common glue layer for Node applications that need to call into Python-only libraries or scripts (data processing, ML inference, scripting) without standing up a separate service.
What You Get
- A
PythonShellclass (extendsEventEmitter) that spawns a Python process and exposes its stdin/stdout/stderr as manageable streams - Built-in
text,json, andbinarymodes that automatically format sent messages and parse received ones per line - A
NewlineTransformerstream that splits chunked stdout/stderr into discrete newline-delimited messages, avoiding partial-JSON parsing bugs - Promise-based
PythonShell.run()andPythonShell.runString()statics for one-off script/code execution that collect all emitted messages checkSyntax()/checkSyntaxFile()helpers that validate Python source without executing it- Automatic Python traceback parsing into a
PythonShellError/PythonShellErrorWithLogswith an extended, combined Node+Python stack trace
Common Use Cases
- Calling a Python data-processing or ML script from a Node.js backend and collecting its output as JSON
- Running short one-off Python snippets via
runString()for quick calculations or environment checks - Maintaining a long-lived interactive Python process that a Node app repeatedly sends commands to via
.send()and listens to via themessageevent - Validating user- or template-generated Python code with
checkSyntax()before executing it - Surfacing Python exceptions in a Node error-handling pipeline with full traceback context attached to the thrown error
Under The Hood
Architecture
The entire library lives in a single index.ts module built around the PythonShell class, which extends EventEmitter and wraps child_process.spawn directly in its constructor. Message framing is handled by piping stdout/stderr through a NewlineTransformer (a custom Transform stream) before applying the mode-specific parser, and process termination is coordinated through a terminateIfNeeded() closure that waits for both streams to end and an exit code/signal before resolving. There is no internal layering beyond this one class plus a couple of free functions (toArray, extend) — a monolithic but narrowly scoped design where the constructor itself does spawning, stream wiring, and error-state tracking together, so changes to child_process’s stream/event contract would touch nearly the whole file at once.
Tech Stack
Written in TypeScript (es6 target, commonjs module) and distributed with zero runtime dependencies — it only uses Node’s built-in child_process, events, stream, os, path, fs, and util modules. The dev toolchain is mocha with should assertions run through ts-node, tsc for compilation, prettier for formatting, and legacy AppVeyor CI with Codecov coverage reporting rather than GitHub Actions.
Code Quality
The test suite (test/test-python-shell.ts) is extensive, covering constructor argument handling, all three IO modes, error and traceback parsing, syntax checking, and process lifecycle events against real Python fixture scripts in test/python/. Error handling is explicit: a dedicated PythonShellError type carries the parsed Python traceback and exit code rather than swallowing failures. That said, the TypeScript config doesn’t enable strict mode, several signatures fall back to any/Object, and there’s no linter configured — only prettier for formatting — and CI runs on a stale, non-GitHub-Actions pipeline, consistent with the repo’s own looking-for-maintainer topic tags.
API Design
The public surface is small and pragmatic: a promise-based run/runString pair for fire-and-forget scripts, and an instance-based new PythonShell() API with .send()/.on('message') for interactive processes, unified by a single mode option that swaps the formatter/parser pair instead of requiring separate methods per format. Getting started requires a single import and one call. The concepts (spawn wrapper, mode-based (de)serialization, traceback bridging) aren’t novel relative to other child-process wrappers, but the ergonomics around error reporting and stream-splitting are a genuine convenience over hand-rolling child_process.spawn directly.
Used by 2 apps in this directory
GrowthBook
Developer Tools · Analytics · Monitoring
Open source feature flags, A/B testing, and warehouse-native experimentation that queries your existing data infrastructure—no data movement required.
Promptfoo
AI Development
An open-source CLI and library for evaluating and red-teaming LLM applications — replace trial-and-error prompt engineering with systematic evals, vulnerability scanning, and CI/CD integration.