CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-python-shell

Run Python scripts from Node.js with efficient inter-process communication through stdio

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utilities.mddocs/

Utilities

Utility functions for Python environment management, syntax checking, version detection, and stream processing. These functions provide helpful tools for working with Python environments and validating code before execution.

Capabilities

Syntax Checking

Validate Python code syntax without executing it, useful for code validation and error prevention.

Check Code String Syntax

Validates Python code syntax from a string without execution.

/**
 * Checks syntax of Python code string without executing
 * Creates temporary file for syntax validation
 * @param code - Python code string to validate
 * @returns Promise that resolves if syntax is valid, rejects with error details if invalid
 */
static async checkSyntax(code: string): Promise<void>;

Usage Examples:

import { PythonShell } from "python-shell";

// Valid syntax
try {
  await PythonShell.checkSyntax('print("Hello, World!")');
  console.log('Syntax is valid');
} catch (error) {
  console.error('Syntax error:', error.message);
}

// Invalid syntax
try {
  await PythonShell.checkSyntax('print("Missing closing quote');
} catch (error) {
  console.error('Syntax error detected:', error.stderr);
  // Error contains Python compiler error message
}

// Complex code validation
const pythonCode = `
import json
import sys

def process_data(data):
    if not isinstance(data, list):
        raise ValueError("Data must be a list")
    return [x * 2 for x in data if x > 0]

if __name__ == "__main__":
    data = json.loads(sys.argv[1])
    result = process_data(data)
    print(json.dumps(result))
`;

try {
  await PythonShell.checkSyntax(pythonCode);
  console.log('Complex code syntax is valid');
} catch (error) {
  console.error('Syntax issues found:', error.stderr);
}

Check File Syntax

Validates Python file syntax without execution.

/**
 * Checks syntax of Python file without executing
 * Uses py_compile module for validation
 * @param filePath - Path to Python file to validate
 * @returns Promise that resolves if syntax is valid, rejects with error details if invalid
 */
static async checkSyntaxFile(filePath: string): Promise<void>;

Usage Examples:

import { PythonShell } from "python-shell";
import { promises as fs } from 'fs';

// Check individual file
try {
  await PythonShell.checkSyntaxFile('./scripts/data_processor.py');
  console.log('File syntax is valid');
} catch (error) {
  console.error('File has syntax errors:', error.stderr);
}

// Batch validate multiple files
const scriptFiles = [
  './scripts/processor.py',
  './scripts/validator.py', 
  './scripts/exporter.py'
];

const results = await Promise.allSettled(
  scriptFiles.map(file => PythonShell.checkSyntaxFile(file))
);

results.forEach((result, index) => {
  if (result.status === 'fulfilled') {
    console.log(`${scriptFiles[index]}: Valid syntax`);
  } else {
    console.error(`${scriptFiles[index]}: Syntax error -`, result.reason.stderr);
  }
});

// Validate before execution
async function safeExecute(scriptPath: string, options?: Options) {
  try {
    await PythonShell.checkSyntaxFile(scriptPath);
    return await PythonShell.run(scriptPath, options);
  } catch (syntaxError) {
    throw new Error(`Cannot execute ${scriptPath}: ${syntaxError.stderr}`);
  }
}

Python Version Detection

Get information about Python installations and versions.

Get Python Version (Async)

Asynchronously gets Python version information.

/**
 * Gets Python version information asynchronously
 * @param pythonPath - Optional path to specific Python executable
 * @returns Promise resolving to object with stdout and stderr from version command
 */
static getVersion(pythonPath?: string): Promise<{stdout: string, stderr: string}>;

Usage Examples:

import { PythonShell } from "python-shell";

// Get default Python version
try {
  const version = await PythonShell.getVersion();
  console.log('Python version:', version.stdout.trim());
  // Output: "Python 3.9.7"
} catch (error) {
  console.error('Python not found or error getting version:', error.message);
}

// Check specific Python installation
try {
  const version = await PythonShell.getVersion('/usr/bin/python3.10');
  console.log('Python 3.10 version:', version.stdout.trim());
} catch (error) {
  console.error('Python 3.10 not found:', error.message);
}

// Check multiple Python versions
const pythonPaths = ['python', 'python3', 'python3.9', 'python3.10'];
const versionChecks = pythonPaths.map(async (path) => {
  try {
    const version = await PythonShell.getVersion(path);
    return { path, version: version.stdout.trim(), available: true };
  } catch (error) {
    return { path, error: error.message, available: false };
  }
});

const results = await Promise.all(versionChecks);
results.forEach(result => {
  if (result.available) {
    console.log(`${result.path}: ${result.version}`);
  } else {
    console.log(`${result.path}: Not available - ${result.error}`);
  }
});

Get Python Version (Sync)

Synchronously gets Python version information.

/**
 * Gets Python version information synchronously
 * @param pythonPath - Optional path to specific Python executable  
 * @returns Python version string
 */
static getVersionSync(pythonPath?: string): string;

Usage Examples:

import { PythonShell } from "python-shell";

// Get default Python version synchronously
try {
  const version = PythonShell.getVersionSync();
  console.log('Python version:', version.trim());
} catch (error) {
  console.error('Error getting Python version:', error.message);
}

// Check specific Python executable
try {
  const version = PythonShell.getVersionSync('./venv/bin/python');
  console.log('Virtual environment Python:', version.trim());
} catch (error) {
  console.error('Virtual environment Python not found');
}

// Version comparison utility
function comparePythonVersions() {
  try {
    const systemVersion = PythonShell.getVersionSync('python');
    const python3Version = PythonShell.getVersionSync('python3');
    
    console.log('System Python:', systemVersion.trim());
    console.log('Python3:', python3Version.trim());
    
    // Extract version numbers for comparison
    const systemMatch = systemVersion.match(/Python (\d+\.\d+\.\d+)/);
    const python3Match = python3Version.match(/Python (\d+\.\d+\.\d+)/);
    
    if (systemMatch && python3Match) {
      console.log('System version number:', systemMatch[1]);
      console.log('Python3 version number:', python3Match[1]);
    }
  } catch (error) {
    console.error('Error comparing versions:', error.message);
  }
}

Get Python Path

Gets the currently configured Python executable path.

/**
 * Gets the current Python path configuration
 * Returns either defaultOptions.pythonPath or defaultPythonPath
 * @returns Current Python executable path
 */
static getPythonPath(): string;

Usage Examples:

import { PythonShell } from "python-shell";

// Get current Python path
const currentPath = PythonShell.getPythonPath();
console.log('Current Python path:', currentPath);
// Default: "python3" on Unix, "python" on Windows

// After setting custom default
PythonShell.defaultOptions = { pythonPath: '/usr/bin/python3.9' };
const customPath = PythonShell.getPythonPath();
console.log('Custom Python path:', customPath); // "/usr/bin/python3.9"

// Utility to validate current Python setup
async function validatePythonSetup() {
  const pythonPath = PythonShell.getPythonPath();
  console.log('Using Python executable:', pythonPath);
  
  try {
    const version = await PythonShell.getVersion(pythonPath);
    console.log('Version:', version.stdout.trim());
    
    // Test basic functionality
    await PythonShell.checkSyntax('print("Hello")');
    console.log('Python setup is working correctly');
  } catch (error) {
    console.error('Python setup has issues:', error.message);
  }
}

Stream Processing Utilities

Utility class for processing streams with custom delimiters.

NewlineTransformer

Stream transformer that splits data into chunks separated by newlines.

/**
 * Stream transformer for splitting data by newlines
 * Used internally as default stdout/stderr splitter
 */
class NewlineTransformer extends Transform {
  /**
   * Transform stream chunks, splitting by newlines
   * @param chunk - Input data chunk
   * @param encoding - Character encoding  
   * @param callback - Completion callback
   */
  _transform(chunk: any, encoding: string, callback: TransformCallback): void;
  
  /**
   * Flush remaining data when stream ends
   * @param done - Completion callback
   */
  _flush(done: TransformCallback): void;
}

Usage Examples:

import { PythonShell, NewlineTransformer } from "python-shell";
import { Transform } from 'stream';

// Using NewlineTransformer for custom streams
const customPipe = someReadableStream;
const newlineTransformer = new NewlineTransformer();

customPipe
  .pipe(newlineTransformer)
  .on('data', (line) => {
    console.log('Received line:', line.toString());
  });

// Custom splitter for special delimiters
class CustomSplitter extends Transform {
  private buffer = '';
  
  _transform(chunk: any, encoding: string, callback: TransformCallback) {
    this.buffer += chunk.toString();
    const parts = this.buffer.split('||'); // Custom delimiter
    this.buffer = parts.pop() || '';
    
    parts.forEach(part => this.push(part));
    callback();
  }
  
  _flush(callback: TransformCallback) {
    if (this.buffer) this.push(this.buffer);
    callback();
  }
}

// Use custom splitter with PythonShell
const customSplitter = new CustomSplitter();
const pyshell = new PythonShell('script.py', {}, customSplitter);

// Advanced stream processing with multiple custom pipes
const options = {
  stdio: ['pipe', 'pipe', 'pipe', 'pipe'] // stdin, stdout, stderr, custom
};

const pyshell = new PythonShell('advanced_script.py', options);
const customStream = pyshell.childProcess.stdio[3];

if (customStream) {
  customStream
    .pipe(new NewlineTransformer())
    .on('data', (customData) => {
      console.log('Custom stream data:', customData.toString());
    });
}

Environment Validation Utility

Combined utility function for comprehensive Python environment validation:

// Example comprehensive validation function
async function validatePythonEnvironment(options?: Options) {
  const pythonPath = options?.pythonPath || PythonShell.getPythonPath();
  
  console.log('Validating Python environment...');
  console.log('Python path:', pythonPath);
  
  try {
    // Check if Python is accessible
    const version = await PythonShell.getVersion(pythonPath);
    console.log('✓ Python version:', version.stdout.trim());
    
    // Test syntax checking
    await PythonShell.checkSyntax('import sys; print("Hello")');
    console.log('✓ Syntax checking works');
    
    // Test basic execution
    const result = await PythonShell.runString('print("test")', { pythonPath });
    console.log('✓ Basic execution works:', result);
    
    // Test with provided options
    if (options?.pythonOptions) {
      const testResult = await PythonShell.runString('print("options test")', options);
      console.log('✓ Custom options work:', testResult);
    }
    
    console.log('✓ Python environment validation complete');
    return true;
    
  } catch (error) {
    console.error('✗ Python environment validation failed:', error.message);
    return false;
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-python-shell

docs

configuration.md

index.md

interactive-shell.md

script-execution.md

utilities.md

tile.json