mcard-js
Version:
MCard - Content-addressable storage with cryptographic hashing, handle resolution, and vector search for Node.js and browsers
100 lines (94 loc) • 3.06 kB
JavaScript
/**
* Python runtime executor.
*
* Executes Python code via subprocess with automatic entry point detection.
*/
import * as fs from 'fs';
import * as path from 'path';
import * as util from 'util';
import { execFile, parseOutput } from './base.js';
import { findProjectRoot } from '../FileSystemUtils.js';
const writeFile = util.promisify(fs.writeFile);
const unlink = util.promisify(fs.unlink);
export class PythonRuntime {
async execute(code, context, config) {
const entryPoint = config.entry_point || 'add';
const contextStr = JSON.stringify(context);
const projectRoot = findProjectRoot();
const wrapper = this.createWrapper(code, entryPoint);
const tmpFile = path.resolve(process.cwd(), `tmp_${Date.now()}.py`);
await writeFile(tmpFile, wrapper);
try {
const { stdout, stderr } = await execFile('python3', [tmpFile, contextStr], {
cwd: projectRoot,
env: {
...process.env,
PYTHONPATH: `${projectRoot}${path.delimiter}${process.env.PYTHONPATH || ''}`
}
});
if (stderr)
console.error('[Python Stderr]', stderr);
return parseOutput(stdout);
}
catch (error) {
const stderr = error.stderr ? `\nStderr: ${error.stderr.toString()}` : '';
const stdout = error.stdout ? `\nStdout: ${error.stdout.toString()}` : '';
throw new Error(`Python execution failed: ${error.message}${stderr}${stdout}`);
}
finally {
await unlink(tmpFile);
}
}
/**
* Create Python wrapper script with entry point invocation.
*/
createWrapper(code, entryPoint) {
return `
import sys
import json
try:
context = json.loads(sys.argv[1])
target = context
if isinstance(target, str):
target = target.encode('utf-8')
except:
context = {}
target = {}
pass
${code}
def _is_arg_error(e):
msg = str(e).lower()
return 'positional argument' in msg or 'required argument' in msg or 'takes' in msg and 'argument' in msg
try:
fn = None
if '${entryPoint}' in dir():
fn = ${entryPoint}
elif '${entryPoint}' in globals():
fn = globals()['${entryPoint}']
if fn is not None:
try:
res = fn(context)
except TypeError as e:
if not _is_arg_error(e):
raise
try:
res = fn(target)
except TypeError as e2:
if not _is_arg_error(e2):
raise
res = fn()
print(json.dumps(res))
else:
if 'result' in dir() or 'result' in globals():
print(json.dumps(result if 'result' in dir() else globals().get('result')))
else:
print(json.dumps(None))
except Exception as e:
print(json.dumps({"error": str(e)}))
sys.exit(1)
`;
}
}
//# sourceMappingURL=python.js.map