mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
refactor: Replace Pyodide with native Python with env flag is enabled (#19403)
This commit is contained in:
@@ -69,4 +69,19 @@ export class TaskRunnersConfig {
|
||||
*/
|
||||
@Env('N8N_RUNNERS_INSECURE_MODE')
|
||||
insecureMode: boolean = false;
|
||||
|
||||
/**
|
||||
* Whether to enable the Python task runner (beta). This will replace the
|
||||
* Pyodide option with the native Python option in the Code node. Expects a
|
||||
* Python task runner to be available, typically in a sidecar container.
|
||||
*
|
||||
* Actions required:
|
||||
* - Any Code node set to the legacy `python` parameter will need to be manually
|
||||
* updated to use the new `pythonNative` parameter.
|
||||
* - Any Code node script relying on Pyodide syntax is likely to need to be manually
|
||||
* adjusted to account for breaking changes:
|
||||
* https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/#python-native-beta
|
||||
*/
|
||||
@Env('N8N_NATIVE_PYTHON_RUNNER')
|
||||
isNativePythonRunnerEnabled: boolean = false;
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ describe('GlobalConfig', () => {
|
||||
taskTimeout: 300,
|
||||
heartbeatInterval: 30,
|
||||
insecureMode: false,
|
||||
isNativePythonRunnerEnabled: false,
|
||||
},
|
||||
sentry: {
|
||||
backendDsn: '',
|
||||
|
||||
@@ -132,7 +132,8 @@ export class FrontendService {
|
||||
versionCli: N8N_VERSION,
|
||||
concurrency: this.globalConfig.executions.concurrency.productionLimit,
|
||||
isNativePythonRunnerEnabled:
|
||||
this.globalConfig.taskRunners.enabled && process.env.N8N_NATIVE_PYTHON_RUNNER === 'true',
|
||||
this.globalConfig.taskRunners.enabled &&
|
||||
this.globalConfig.taskRunners.isNativePythonRunnerEnabled,
|
||||
authCookie: {
|
||||
secure: this.globalConfig.auth.cookie.secure,
|
||||
},
|
||||
|
||||
@@ -118,7 +118,7 @@ export class TaskRunnerModule {
|
||||
|
||||
await this.jsRunnerProcess.start();
|
||||
|
||||
if (process.env.N8N_NATIVE_PYTHON_RUNNER === 'true') {
|
||||
if (this.runnerConfig.isNativePythonRunnerEnabled) {
|
||||
const { PyTaskRunnerProcess } = await import('@/task-runners/task-runner-process-py');
|
||||
this.pyRunnerProcess = Container.get(PyTaskRunnerProcess);
|
||||
this.pyRunnerProcessRestartLoopDetector = new TaskRunnerProcessRestartLoopDetector(
|
||||
|
||||
@@ -111,9 +111,9 @@ function operationsCategory(nodeTypeDescription: INodeTypeDescription): ActionTy
|
||||
nodeTypeDescription,
|
||||
);
|
||||
if (customParsedItems) {
|
||||
// temporary filter until native Python runner is GA
|
||||
// temporary until native Python runner is GA
|
||||
return useSettingsStore().isNativePythonRunnerEnabled
|
||||
? customParsedItems
|
||||
? customParsedItems.filter((item) => item.actionKey !== 'language_python')
|
||||
: customParsedItems.filter((item) => item.actionKey !== 'language_pythonNative');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,9 +241,13 @@ const parameterOptions = computed(() => {
|
||||
const options = hasRemoteMethod.value ? remoteParameterOptions.value : props.parameter.options;
|
||||
const safeOptions = (options ?? []).filter(isValidParameterOption);
|
||||
|
||||
// temporary filter until native Python runner is GA
|
||||
if (props.parameter.name === 'language' && !settingsStore.isNativePythonRunnerEnabled) {
|
||||
return safeOptions.filter((o) => o.value !== 'pythonNative');
|
||||
// temporary until native Python runner is GA
|
||||
if (props.parameter.name === 'language') {
|
||||
if (settingsStore.isNativePythonRunnerEnabled) {
|
||||
return safeOptions.filter((o) => o.value !== 'python');
|
||||
} else {
|
||||
return safeOptions.filter((o) => o.value !== 'pythonNative');
|
||||
}
|
||||
}
|
||||
|
||||
return safeOptions;
|
||||
|
||||
@@ -123,19 +123,22 @@ export class Code implements INodeType {
|
||||
? (this.getNodeParameter('language', 0) as CodeNodeLanguageOption)
|
||||
: 'javaScript';
|
||||
|
||||
if (language === 'python' && !Container.get(NodesConfig).pythonEnabled) {
|
||||
const isJsLang = language === 'javaScript';
|
||||
const isPyLang = language === 'python' || language === 'pythonNative';
|
||||
const runnersConfig = Container.get(TaskRunnersConfig);
|
||||
const isJsRunner = runnersConfig.enabled;
|
||||
const isPyRunner = runnersConfig.isNativePythonRunnerEnabled;
|
||||
|
||||
if (isPyLang && !Container.get(NodesConfig).pythonEnabled) {
|
||||
throw new PythonDisabledError();
|
||||
}
|
||||
|
||||
const runnersConfig = Container.get(TaskRunnersConfig);
|
||||
const isRunnerEnabled = runnersConfig.enabled;
|
||||
|
||||
const nodeMode = this.getNodeParameter('mode', 0) as CodeExecutionMode;
|
||||
const workflowMode = this.getMode();
|
||||
const codeParameterName =
|
||||
language === 'python' || language === 'pythonNative' ? 'pythonCode' : 'jsCode';
|
||||
|
||||
if (language === 'javaScript' && isRunnerEnabled) {
|
||||
if (isJsLang && isJsRunner) {
|
||||
const code = this.getNodeParameter(codeParameterName, 0) as string;
|
||||
const sandbox = new JsTaskRunnerSandbox(code, nodeMode, workflowMode, this);
|
||||
const numInputItems = this.getInputData().length;
|
||||
@@ -145,9 +148,13 @@ export class Code implements INodeType {
|
||||
: [await sandbox.runCodeForEachItem(numInputItems)];
|
||||
}
|
||||
|
||||
if (language === 'pythonNative' && !isRunnerEnabled) throw new NativePythonWithoutRunnerError();
|
||||
if (language === 'pythonNative' && !isPyRunner) {
|
||||
throw new NativePythonWithoutRunnerError();
|
||||
}
|
||||
|
||||
if (language === 'pythonNative') {
|
||||
if (isPyLang && isPyRunner) {
|
||||
// When the native Python runner is enabled, both `python` and `pythonNative` are
|
||||
// sent to the runner, to ensure there is no path to run Pyodide in this scenario.
|
||||
const code = this.getNodeParameter(codeParameterName, 0) as string;
|
||||
const sandbox = new PythonTaskRunnerSandbox(code, nodeMode, workflowMode, this);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user