Package Exports
- python-bundle
Readme
python-bundle
✨ Features
- Portable Python 3.12 via Miniforge (auto-download on install)
- Built-in pip for Python package management
- Supports CommonJS & ESM (
require&import) - No system Python dependency (ideal for Pterodactyl, Docker, serverless)
- Stream & Interactive modes for real-time output & user input
- Four main methods:
execPython,runScript,runCode,pipInstall - Stdin support for passing input to Python scripts
🚀 Installation
npm install python-bundleNote: Runs
postinstallhook to download Miniforge intovendor/python.
🛠️ API Reference
Import the module:
CommonJS
const { pipInstall, runScript, runCode, execPython } = require('python-bundle');ESM
import { pipInstall, runScript, runCode, execPython } from 'python-bundle';execPython(args, options)
Execute any Python command with optimizations enabled (-O flag).
Parameters:
args(string[]): CLI arguments for Python (e.g.['-c', 'print("Hi")'])options(object):cwd(string): Working directory (default:process.cwd())stream(boolean): Pipe output to console in real-time (default:false)stdin(string): Input string to send to stdininteractive(boolean): Note: Not supported inexecPython(userunScriptinstead)
Returns: Promise<string | void>
- Resolves with output string when
stream: false - Resolves with
undefinedwhenstream: true - Rejects with error on non-zero exit code
Example:
// Execute inline code with stdin input
await execPython(
['-c', 'import sys; print(sys.stdin.read().upper())'],
{
stdin: 'hello world',
stream: true
}
);runScript(scriptPath, args, options)
Run a Python .py file with two execution modes.
Parameters:
scriptPath(string): Path to Python scriptargs(string[]): Arguments passed to script (default:[])options(object):cwd(string): Working directory (default:process.cwd())stream(boolean): Pipe output to console in real-timestdin(string): Input string for non-interactive modeinteractive(boolean): Enable interactive mode (returns ChildProcess)
Returns:
Promise<string | void>when non-interactiveChildProcesswheninteractive: true
Non-interactive Example:
// Run script with arguments and capture output
const output = await runScript('script.py', ['args1'], {
cwd: './scripts'
});Interactive Example:
// Run interactively and manage process directly
const child = runScript('script.py', [], { interactive: true });
child.stdout.on('data', data => process.stdout.write(data));
child.stderr.on('data', data => process.stderr.write(data));
child.stdin.write('user input\n');
child.on('exit', code => {
console.log(`Process exited with code ${code}`);
});runCode(codeString, options)
Execute inline Python code block.
Parameters:
codeString(string): Python source codeoptions(object): Same asexecPython
Returns: Promise<string | void>
Same behavior as execPython
Example:
// Execute code with stdin and stream output
await runCode(
`import sys, json;
data = json.load(sys.stdin);
print(data['message'])`,
{
stdin: JSON.stringify({ message: "Hello from stdin!" }),
stream: true
}
);pipInstall(packages, options)
Install Python packages via pip.
Parameters:
packages(string[]): Package names to installoptions(object):cwd(string): Working directorystream(boolean): Show live installation output
Returns: Promise<void>
Example:
// Install multiple packages with live output
await pipInstall(['numpy', 'pandas', 'scikit-learn'], {
stream: true
});📁 Project Structure
After installation:
your-project/
├── node_modules/
│ └── python-bundle/
│ ├── vendor/
│ │ └── python/ # Portable Python
│ │ ├── bin/
│ │ │ └── python # Python binary
│ │ └── ... # Python environment
│ └── index.js # Module entry point
├── scripts/
│ └── your_script.py # Your Python scripts
└── main.js # Your Node.js code🔧 Usage Examples
1. Basic Usage (CommonJS)
// JavaScript
const { runScript, pipInstall } = require('python-bundle');
(async () => {
// Install Flask
await pipInstall(['flask'], { stream: true });
// Run Python web server
await runScript('web_server.py', ['3000'], { stream: true });
})();# web_server.py (Python)
from flask import Flask
import sys
app = Flask(__name__)
port = 3000 if len(sys.argv) < 2 else int(sys.argv[1])
@app.route('/')
def home():
return "Hello from Python bundle!"
if __name__ == '__main__':
print(f"Starting server on port {port}")
app.run(port=port)2. Advanced Usage (ESM)
// JavaScript
import { runCode, pipInstall } from 'python-bundle';
// Install NumPy
await pipInstall(['numpy'], { stream: true });
// Run data processing code
await runCode(`
import numpy as np
arr = np.array([1, 2, 3, 4])
print(f"Mean: {np.mean(arr)}")
print(f"Sum: {np.sum(arr)}")
`, { stream: true });3. Interactive Script Handling
// JavaScript
const { runScript } = require('python-bundle');
// Start calculator process
const calc = runScript('calculator.py', [], { interactive: true });
calc.stdout.on('data', data => {
process.stdout.write(data);
if (data.includes('Enter operation')) {
calc.stdin.write('add\n');
}
if (data.includes('Enter first number')) {
calc.stdin.write('15\n');
}
if (data.includes('Enter second number')) {
calc.stdin.write('25\n');
}
});
calc.on('exit', () => console.log('Calculation complete!'));# calculator.py (Python)
print("Simple Calculator")
while True:
try:
op = input("Enter operation (add/sub/mul/div): ")
num1 = float(input("Enter first number: "))
num2 = float(input("Enter second number: "))
if op == 'add': result = num1 + num2
elif op == 'sub': result = num1 - num2
elif op == 'mul': result = num1 * num2
elif op == 'div': result = num1 / num2
else:
print("Invalid operation")
continue
print(f"Result: {result}")
break
except ValueError:
print("Please enter valid numbers!")
except ZeroDivisionError:
print("Cannot divide by zero!")4. File Processing Example
// JavaScript
const { runScript } = require('python-bundle');
// Process CSV file
await runScript('csv_processor.py', ['input.csv', 'output.json'], {
stream: true,
cwd: './data'
});# csv_processor.py (Python)
import csv
import json
import sys
if len(sys.argv) < 3:
print("Usage: python csv_processor.py <input.csv> <output.json>")
exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
data = []
with open(input_file, 'r') as f:
reader = csv.DictReader(f)
for row in reader:
data.append(row)
print(f"Processed {len(data)} records")
with open(output_file, 'w') as f:
json.dump(data, f, indent=2)⚠️ Troubleshooting
Interactive Mode Requirements
Use{ interactive: true }only withrunScript(), not withexecPython()orrunCode()Stdin Handling
Non-interactive mode: usestdinoption
Interactive mode: write tochild.stdindirectlyPython Optimizations
All executions run with-Oflag. Disable optimizations by modifying source if neededPath Handling
Use absolute paths or relative tooptions.cwdfor scriptsPermission Issues
On Linux systems:chmod +x node_modules/python-bundle/vendor/python/bin/pythonEnvironment Conflicts
Module setsPYTHONHOMEautomatically. Unset this variable if you encounter conflicts
📄 License
MIT © 2025 RelixOfficial
Maintained with ❤️ by RelixTeam. PRs and contributions are welcome!