UNPKG

@zgxsuerwtmrhjzt/n8n-nodes-python-raw

Version:

Run Python scripts in n8n with raw output (exitCode, stdout, stderr) - Fork of naskio/n8n-nodes-python

217 lines (211 loc) 7.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PythonFunction = void 0; const n8n_workflow_1 = require("n8n-workflow"); const child_process_1 = require("child_process"); const fs = require("fs"); const tempy = require("tempy"); class PythonFunction { constructor() { this.description = { displayName: 'Python Function (Raw)', name: 'pythonFunctionRaw', icon: 'fa:code', group: ['transform'], version: 1, description: 'Run custom Python script once and return raw output (exitCode, stdout, stderr)', defaults: { name: 'PythonFunctionRaw', color: '#4B8BBE', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'pythonEnvVars', required: false, }, ], properties: [ { displayName: 'Python Code', name: 'functionCode', typeOptions: { alwaysOpenEditWindow: true, rows: 15, }, type: 'string', default: `# This script runs once and receives input data as 'input_items' variable # Available variables: # - input_items: list of all input data # - env_vars: dict of environment variables import json import sys # Your Python code here print("Input items count:", len(input_items)) for i, item in enumerate(input_items): print(f"Item {i}: {item}") # Example: process data and print results result = {"processed_count": len(input_items), "status": "success"} print(json.dumps(result)) # Exit with success sys.exit(0) `, description: 'Pure Python script that will be executed once. Input data available as input_items variable.', noDataExpression: true, }, { displayName: 'Python Executable', name: 'pythonPath', type: 'string', default: 'python3', description: 'Path to Python executable (python3, python, or full path)', }, ], }; } async execute() { var _a; let items = this.getInputData(); items = JSON.parse(JSON.stringify(items)); const functionCode = this.getNodeParameter('functionCode', 0); const pythonPath = this.getNodeParameter('pythonPath', 0); let pythonEnvVars = {}; try { pythonEnvVars = parseEnvFile(String(((_a = (await this.getCredentials('pythonEnvVars'))) === null || _a === void 0 ? void 0 : _a.envFileContent) || '')); } catch (_) { } let scriptPath = ''; try { scriptPath = await getTemporaryScriptPath(functionCode, unwrapJsonField(items), pythonEnvVars); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not generate temporary script file: ${error.message}`); } try { const execResults = await execPythonSpawn(scriptPath, pythonPath, this.sendMessageToUI); const { error: returnedError, exitCode, stdout, stderr, } = execResults; const resultItem = { json: { exitCode: exitCode, stdout: stdout, stderr: stderr, success: exitCode === 0, error: returnedError ? returnedError.message : null, inputItemsCount: items.length, executedAt: new Date().toISOString(), } }; if (returnedError !== undefined && !this.continueOnFail()) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Python script failed with exit code ${exitCode}: ${returnedError.message}`); } return this.prepareOutputData([resultItem]); } catch (error) { if (this.continueOnFail()) { const errorItem = { json: { exitCode: -1, stdout: '', stderr: error.message || String(error), success: false, error: error.message || String(error), inputItemsCount: items.length, executedAt: new Date().toISOString(), } }; return this.prepareOutputData([errorItem]); } else { throw error; } } } } exports.PythonFunction = PythonFunction; function execPythonSpawn(scriptPath, pythonPath, stdoutListener) { const returnData = { error: undefined, exitCode: 0, stderr: '', stdout: '', }; return new Promise((resolve, reject) => { const child = child_process_1.spawn(pythonPath, [scriptPath], { cwd: process.cwd(), }); child.stdout.on('data', data => { returnData.stdout += data.toString(); if (stdoutListener) { stdoutListener(data.toString()); } }); child.stderr.on('data', data => { returnData.stderr += data.toString(); }); child.on('error', (error) => { returnData.error = error; resolve(returnData); }); child.on('close', code => { returnData.exitCode = code || 0; if (code !== 0) { returnData.error = new Error(`Process exited with code ${code}`); } resolve(returnData); }); }); } function parseEnvFile(envFileContent) { if (!envFileContent || envFileContent === '') { return {}; } const envLines = envFileContent.split('\n'); const envVars = {}; for (const line of envLines) { const parts = line.split('='); if (parts.length === 2) { envVars[parts[0]] = parts[1]; } } return envVars; } function formatCodeSnippet(code) { return code .replace(/\n/g, '\n\t') .replace(/\r/g, '\n\t') .replace(/\r\n\t/g, '\n\t') .replace(/\r\n/g, '\n\t'); } function getScriptCode(codeSnippet, data, envVars) { const script = `#!/usr/bin/env python3 # Auto-generated script for n8n Python Function (Raw) import json import sys # Input data and environment variables input_items = ${JSON.stringify(data)} env_vars = ${JSON.stringify(envVars)} # User code starts here ${codeSnippet} `; return script; } async function getTemporaryScriptPath(codeSnippet, data, envVars) { const tmpPath = tempy.file({ extension: 'py' }); const codeStr = getScriptCode(codeSnippet, data, envVars); fs.writeFileSync(tmpPath, codeStr); return tmpPath; } function unwrapJsonField(list = []) { return list.reduce((acc, item) => { if ('json' in item) { acc.push(item.json); } else { acc.push(item); } return acc; }, []); } //# sourceMappingURL=PythonFunction.node.js.map