Node.js library that enables seamless integration of Python libraries into JavaScript applications
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive error handling system that maps Python exceptions to JavaScript errors with full traceback information and proper error type mapping.
All Python exceptions thrown from pymport operations are mapped to JavaScript errors with additional Python-specific information.
/**
* Extended error type that includes Python exception information
* Inherits from standard JavaScript Error, TypeError, or RangeError
*/
type PythonError = (Error | TypeError | RangeError) & {
/**
* Python exception type as PyObject (e.g., ValueError, KeyError)
*/
pythonType: PyObject;
/**
* Python exception value/message as PyObject
*/
pythonValue: PyObject;
/**
* Python traceback information as PyObject
*/
pythonTrace: PyObject;
};Standard JavaScript try-catch blocks work with Python exceptions, with additional Python context available.
Usage Examples:
import { pymport, proxify } from 'pymport';
const builtins = pymport('builtins');
try {
// This will raise a Python ValueError
const result = builtins.get('int').call('not_a_number');
} catch (error) {
// Check if it's a Python error
if (error.pythonType) {
console.log('Python Exception Type:', error.pythonType.toString());
console.log('Python Exception Value:', error.pythonValue.toString());
console.log('JavaScript Error Message:', error.message);
// Check specific Python exception types
const pythonTypeName = error.pythonType.get('__name__').toString();
if (pythonTypeName === 'ValueError') {
console.log('Handling ValueError specifically');
}
}
}Python exceptions are mapped to appropriate JavaScript error types while preserving Python-specific information.
ValueError (TypeError in JS):
try {
const int = builtins.get('int');
int.call('abc'); // Invalid literal for int()
} catch (error) {
console.log(error instanceof TypeError); // true
console.log(error.pythonType.get('__name__').toString()); // 'ValueError'
}KeyError (Error in JS):
try {
const dict = PyObject.dict({ a: 1, b: 2 });
dict.item('nonexistent_key');
} catch (error) {
console.log(error instanceof Error); // true
console.log(error.pythonType.get('__name__').toString()); // 'KeyError'
console.log(error.message); // "'nonexistent_key'"
}IndexError (RangeError in JS):
try {
const list = PyObject.list([1, 2, 3]);
list.item(10); // Index out of range
} catch (error) {
console.log(error instanceof RangeError); // true
console.log(error.pythonType.get('__name__').toString()); // 'IndexError'
}AttributeError (Error in JS):
try {
const obj = PyObject.string('hello');
obj.get('nonexistent_method');
} catch (error) {
console.log(error instanceof Error); // true
console.log(error.pythonType.get('__name__').toString()); // 'AttributeError'
}Asynchronous operations return Promise rejections with the same Python error information.
Usage Examples:
import { pymport, proxify } from 'pymport';
const asyncFunction = proxify(pymport('asyncio')).sleep;
try {
// Async operations that may fail
const result = await asyncFunction.callAsync(-1); // Invalid argument
} catch (error) {
if (error.pythonType) {
console.log('Async Python Error:', error.pythonType.toString());
console.log('Traceback:', error.pythonTrace.toString());
}
}
// Promise-based error handling
asyncFunction.callAsync('invalid')
.then(result => {
console.log('Success:', result);
})
.catch(error => {
if (error.pythonTrace) {
console.log('Python traceback available');
}
});Errors in Python context managers (with statements) are properly handled with cleanup.
Usage Examples:
import { pymport } from 'pymport';
const builtins = pymport('builtins');
const open = builtins.get('open');
try {
const file = open.call('nonexistent.txt', 'r');
file.with((f) => {
// This will fail due to file not existing
return f.get('read').call();
});
} catch (error) {
// File is automatically closed even on error
if (error.pythonType) {
const exceptionName = error.pythonType.get('__name__').toString();
if (exceptionName === 'FileNotFoundError') {
console.log('File not found, creating default...');
}
}
}
// Custom context manager error handling
const customContext = pyval('some_custom_context_manager()');
try {
customContext.with((ctx) => {
throw new Error('JavaScript error in context');
});
} catch (error) {
// Context manager's __exit__ method is called with error info
console.log('Error handled by context manager');
}Errors from Python function calls include detailed parameter and call information.
Usage Examples:
const np = proxify(pymport('numpy'));
try {
// Invalid array creation
const arr = np.array('not_an_array');
} catch (error) {
console.log('Function call failed:', error.message);
if (error.pythonTrace) {
// Get detailed traceback
const traceStr = error.pythonTrace.toString();
console.log('Full Python traceback:');
console.log(traceStr);
}
}
try {
// Invalid reshape operation
const arr = np.array([1, 2, 3]);
arr.reshape(2, 3); // Can't reshape 3 elements to 2x3
} catch (error) {
const errorType = error.pythonType.get('__name__').toString();
if (errorType === 'ValueError') {
console.log('Reshape dimension mismatch');
}
}Module import failures provide clear error information.
Usage Examples:
import { pymport } from 'pymport';
try {
const nonexistent = pymport('nonexistent_module');
} catch (error) {
if (error.pythonType) {
const errorType = error.pythonType.get('__name__').toString();
if (errorType === 'ModuleNotFoundError') {
console.log('Module not found. Install with: npx pympip install module_name');
}
}
}
try {
// Module exists but has syntax errors
const broken = pymport('broken_syntax_module');
} catch (error) {
if (error.pythonType) {
const errorType = error.pythonType.get('__name__').toString();
if (errorType === 'SyntaxError') {
console.log('Python module has syntax errors');
console.log('Error details:', error.pythonValue.toString());
}
}
}Common patterns for handling and recovering from Python errors.
Usage Examples:
// Retry with different parameters
function safeArrayCreation(data, dtype = null) {
const np = proxify(pymport('numpy'));
try {
return np.array(data, dtype ? { dtype } : {});
} catch (error) {
if (error.pythonType?.get('__name__').toString() === 'ValueError') {
console.log('Retrying without dtype specification...');
try {
return np.array(data);
} catch (retryError) {
console.log('Array creation failed completely');
throw retryError;
}
}
throw error;
}
}
// Graceful degradation
function getModuleOrFallback(primaryModule, fallbackModule) {
try {
return pymport(primaryModule);
} catch (error) {
if (error.pythonType?.get('__name__').toString() === 'ModuleNotFoundError') {
console.log(`${primaryModule} not available, using ${fallbackModule}`);
return pymport(fallbackModule);
}
throw error;
}
}
// Error logging and monitoring
function withErrorLogging(operation) {
try {
return operation();
} catch (error) {
if (error.pythonTrace) {
// Log Python-specific error details
console.error('Python Error Details:', {
type: error.pythonType.toString(),
value: error.pythonValue.toString(),
traceback: error.pythonTrace.toString(),
jsMessage: error.message,
jsStack: error.stack
});
}
throw error;
}
}Install with Tessl CLI
npx tessl i tessl/npm-pymport