Simple JavaScript interpreter for Python built on top of duktape engine without any external dependencies
—
npm package installation with automatic dependency resolution, enabling JavaScript module usage within Python applications through the persistent interpreter's require() system.
Downloads and installs JavaScript packages from npmjs.org with automatic dependency resolution. Packages are installed in a CommonJS-compatible directory structure that can be used with the JSInterpreter's require() system.
def install_jspackage(package_name, version, modulesdir):
"""
Installs a JavaScript package downloaded from npmjs.org.
Parameters:
- package_name: str - Name of the npm package to install
- version: str or None - Version specifier (semver compatible) or None for latest
- modulesdir: str - Directory where to install JavaScript packages
Returns:
None - Prints installation progress to stdout
Raises:
JSPackageInstallError: When package installation fails
- Error code 2: Version not found
- Error code 3: Unable to detect download URL
Note: Currently unable to resolve conflicting dependencies
"""Usage example:
import dukpy
# Install latest version of a package
dukpy.install_jspackage('lodash', None, './js_modules')
# Install specific version
dukpy.install_jspackage('react', '16.14.0', './node_modules')
# Install package with complex name
dukpy.install_jspackage('@babel/core', '7.12.0', './js_modules')
# Use installed packages
interpreter = dukpy.JSInterpreter()
interpreter.loader.register_path('./js_modules')
result = interpreter.evaljs("""
var _ = require('lodash');
_.chunk(['a', 'b', 'c', 'd'], 2)
""")
print(result) # [['a', 'b'], ['c', 'd']]The dukpy-install command provides shell access to package installation functionality with the same capabilities as the Python API.
def main():
"""
CLI entry point for dukpy-install command.
Usage: dukpy-install [-d DESTINATION] package_name [version]
Arguments:
- package_name: Name of the npm package to install
- version: Optional version specifier
- --destination, -d: Installation directory (default: ./js_modules)
Returns:
int - Exit code (0 for success, error code for failures)
"""Command line usage:
# Install latest version
dukpy-install lodash
# Install specific version
dukpy-install react 16.14.0
# Install to custom directory
dukpy-install -d ./my_modules moment
# Install scoped package
dukpy-install @angular/core 12.0.0The package installer automatically resolves and installs all required dependencies using npm's dependency information. Dependencies are flattened into the target directory structure.
# Example of automatic dependency resolution
dukpy.install_jspackage('express', '4.17.1', './js_modules')
# This will install:
# - express@4.17.1
# - accepts@1.3.7
# - array-flatten@1.1.1
# - body-parser@1.19.0
# - cookie@0.4.0
# - cookie-signature@1.0.6
# - debug@2.6.9
# - depd@1.1.2
# ... and many more dependenciesSupports semantic versioning (semver) for flexible version specification using the semver JavaScript library for version matching.
import dukpy
# Latest version
dukpy.install_jspackage('moment', None, './js_modules')
# Exact version
dukpy.install_jspackage('moment', '2.29.1', './js_modules')
# Version range
dukpy.install_jspackage('moment', '^2.29.0', './js_modules') # 2.29.x
dukpy.install_jspackage('moment', '~2.29.1', './js_modules') # 2.29.1 - 2.29.x
dukpy.install_jspackage('moment', '>=2.28.0', './js_modules') # 2.28.0 or higherInstalled packages integrate seamlessly with the JSInterpreter's module loading system. Register the installation directory as a module search path to enable require() access.
import dukpy
# Install packages
dukpy.install_jspackage('lodash', None, './js_modules')
dukpy.install_jspackage('moment', None, './js_modules')
# Create interpreter and register module path
interpreter = dukpy.JSInterpreter()
interpreter.loader.register_path('./js_modules')
# Use packages in JavaScript
result = interpreter.evaljs("""
var _ = require('lodash');
var moment = require('moment');
var data = [
{ name: 'Alice', date: '2023-01-15' },
{ name: 'Bob', date: '2023-02-20' },
{ name: 'Charlie', date: '2023-01-10' }
];
var sorted = _.sortBy(data, function(item) {
return moment(item.date).unix();
});
_.map(sorted, 'name')
""")
print(result) # ['Charlie', 'Alice', 'Bob']class JSPackageInstallError(Exception):
"""
Exception raised when package installation fails.
Provides specific error codes for different failure types:
- Code 2: Version not found
- Code 3: Unable to detect download URL
"""
def __init__(self, msg, error_code):
"""
Initialize with error message and code.
Parameters:
- msg: str - Error description
- error_code: int - Specific error code
"""
super().__init__(msg)
self.error_code = error_codeError handling example:
import dukpy
try:
# Attempt to install non-existent version
dukpy.install_jspackage('lodash', '999.999.999', './js_modules')
except dukpy.JSPackageInstallError as e:
print(f"Installation failed: {e}")
print(f"Error code: {e.error_code}")
try:
# Attempt to install non-existent package
dukpy.install_jspackage('this-package-does-not-exist', None, './js_modules')
except dukpy.JSPackageInstallError as e:
print(f"Installation failed: {e}")
print(f"Error code: {e.error_code}")Package installation provides detailed progress information:
dukpy.install_jspackage('react', '16.14.0', './js_modules')
# Output:
# Packages going to be installed: react->16.14.0, loose-envify->1.4.0, js-tokens->4.0.0, object-assign->4.1.1
# Fetching https://registry.npmjs.org/react/-/react-16.14.0.tgz............................
# Fetching https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz............
# Fetching https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz............
# Fetching https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz............
# Installing react in ./js_modules Done!Install with Tessl CLI
npx tessl i tessl/pypi-dukpy