UNPKG

n8n-python-hari2

Version:
214 lines 7.93 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 path = require("path"); const fs = require("fs"); const tempy = require("tempy"); class PythonFunction { constructor() { this.description = { displayName: 'Python Function', name: 'pythonFunction', icon: 'fa:code', group: ['transform'], version: 1, description: 'Run custom Python 3.10 code which gets executed once and allows you to add, remove, change and replace items', defaults: { name: 'PythonFunction', color: '#4B8BBE', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'pythonEnvVars', required: false, }, ], properties: [ { displayName: 'Python Code', name: 'functionCode', typeOptions: { alwaysOpenEditWindow: true, rows: 10, }, type: 'string', default: ` # Code here will run only once, no matter how many input items there are. # More info and help: https://github.com/naskio/n8n-nodes-python return items `, description: 'The Python code to execute.', noDataExpression: true, }, ], }; } async execute() { var _a; let items = this.getInputData(); items = JSON.parse(JSON.stringify(items)); const functionCode = this.getNodeParameter('functionCode', 0); let pythonEnvVars = {}; try { pythonEnvVars = parseEnvFile(String(((_a = (await this.getCredentials('pythonEnvVars'))) === null || _a === void 0 ? void 0 : _a.envFileContent) || '')); } catch (_) { } let scriptPath = ''; let jsonPath = ''; try { scriptPath = await getTemporaryScriptPath(functionCode); jsonPath = await getTemporaryJsonFilePath(unwrapJsonField(items)); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not generate temporary files: ${error.message}`); } try { const execResults = await execPythonSpawn(scriptPath, jsonPath, pythonEnvVars, this.sendMessageToUI); const { error: returnedError, exitCode, items: returnedItems, } = execResults; items = wrapJsonField(returnedItems); if (returnedError !== undefined) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `exitCode: ${exitCode} ${(returnedError === null || returnedError === void 0 ? void 0 : returnedError.message) || ''}`); } if (items === undefined) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No data got returned. Always return an Array of items!'); } if (!Array.isArray(items)) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Always an Array of items has to be returned!'); } for (const item of items) { if (item.json === undefined) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'All returned items have to contain a property named "json"!'); } if (typeof item.json !== 'object') { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The json-property has to be an object!'); } if (item.binary !== undefined) { if (Array.isArray(item.binary) || typeof item.binary !== 'object') { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The binary-property has to be an object!'); } } } } catch (error) { if (this.continueOnFail()) { items = [{ json: { error: error.message } }]; } else { const stackLines = error.stack.split('\n'); if (stackLines.length > 0) { const lineParts = stackLines[1].split(':'); if (lineParts.length > 2) { const lineNumber = lineParts.splice(-2, 1); if (!isNaN(lineNumber)) { error.message = `${error.message} [Line ${lineNumber}]`; } } } throw error; } } return this.prepareOutputData(items); } } exports.PythonFunction = PythonFunction; function parseShellOutput(outputStr) { return JSON.parse(outputStr); } function execPythonSpawn(scriptPath, jsonPath, envVars, stdoutListener) { const returnData = { error: undefined, exitCode: 0, stderr: '', stdout: '', }; return new Promise((resolve, reject) => { const child = (0, child_process_1.spawn)('python3', [scriptPath, '--json_path', jsonPath, '--env_vars', JSON.stringify(envVars)], { 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) { returnData.items = parseShellOutput(returnData.stderr); } else { returnData.error = new Error(returnData.stderr); } 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) { const css = fs.readFileSync(path.resolve(__dirname, 'script.template.py'), 'utf8') || ''; return css.replace('pass', formatCodeSnippet(codeSnippet)); } async function getTemporaryScriptPath(codeSnippet) { const tmpPath = tempy.file({ extension: 'py' }); const codeStr = getScriptCode(codeSnippet); fs.writeFileSync(tmpPath, codeStr); return tmpPath; } async function getTemporaryJsonFilePath(data) { const tmpPath = tempy.file({ extension: 'json' }); const jsonStr = JSON.stringify(data); fs.writeFileSync(tmpPath, jsonStr); return tmpPath; } function unwrapJsonField(list = []) { return list.reduce((acc, item) => { if ('json' in item) { acc.push(item.json); } else { acc.push(item); } return acc; }, []); } function wrapJsonField(list = []) { return list.reduce((acc, item) => { const newItem = Object.assign({}, item); newItem.json = item; acc.push(newItem); return acc; }, []); } //# sourceMappingURL=PythonFunction.node.js.map