From 8a2d189374f73b97be977735183eb39d9f890a0c Mon Sep 17 00:00:00 2001 From: "everywhere.z" Date: Thu, 28 Mar 2024 14:52:12 +0800 Subject: [PATCH] =?UTF-8?q?enhancement=20#I95XTD=20python=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=97=A0=E6=B3=95=E5=86=99return=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liteflow-script-python/pom.xml | 1 - .../script/python/PythonScriptExecutor.java | 125 +++++++++++++++--- .../common/ScriptPythonCommonELTest.java | 3 +- 3 files changed, 105 insertions(+), 24 deletions(-) diff --git a/liteflow-script-plugin/liteflow-script-python/pom.xml b/liteflow-script-plugin/liteflow-script-python/pom.xml index 311ba8d96..5ab16e68b 100644 --- a/liteflow-script-plugin/liteflow-script-python/pom.xml +++ b/liteflow-script-plugin/liteflow-script-python/pom.xml @@ -24,5 +24,4 @@ jython-standalone - \ No newline at end of file diff --git a/liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java b/liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java index b6fc46a91..9ceb333df 100644 --- a/liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java +++ b/liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java @@ -3,39 +3,120 @@ package com.yomahub.liteflow.script.python; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.enums.ScriptTypeEnum; -import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor; -import java.util.Arrays; -import java.util.List; +import com.yomahub.liteflow.script.ScriptExecuteWrap; +import com.yomahub.liteflow.script.ScriptExecutor; +import com.yomahub.liteflow.script.exception.ScriptLoadException; +import org.python.core.PyCode; +import org.python.core.PyObject; +import org.python.core.PySystemState; +import org.python.util.PythonInterpreter; +import java.util.*; import java.util.stream.Collectors; /** * Python脚本语言的执行器实现 * * @author Bryan.Zhang - * @since 2.9.5 + * @since 2.12.0 */ -public class PythonScriptExecutor extends JSR223ScriptExecutor { +public class PythonScriptExecutor extends ScriptExecutor { - @Override - public ScriptTypeEnum scriptType() { - return ScriptTypeEnum.PYTHON; - } + private PythonInterpreter pythonInterpreter; - @Override - protected String convertScript(String script) { - String[] lineArray = script.split("\\n"); - List noBlankLineList = Arrays.stream(lineArray) - .filter(s -> !StrUtil.isBlank(s)) - .collect(Collectors.toList()); + private final String RESULT_KEY = "result"; - // 用第一行的缩进的空格数作为整个代码的缩进量 - String blankStr = ReUtil.getGroup0("^[ ]*", noBlankLineList.get(0)); + private final Map compiledScriptMap = new HashMap<>(); - // 重新构建脚本 - StringBuilder scriptSB = new StringBuilder(); - noBlankLineList.forEach(s -> scriptSB.append(StrUtil.format("{}\n", s.replaceFirst(blankStr, StrUtil.EMPTY)))); - return scriptSB.toString(); - } + @Override + public ScriptExecutor init(){ + PySystemState systemState = new PySystemState(); + systemState.setdefaultencoding("UTF-8"); + this.pythonInterpreter = new PythonInterpreter(null, systemState); + return this; + } + @Override + public void load(String nodeId, String script) { + try { + PyCode pyCode = (PyCode) compile(script); + compiledScriptMap.put(nodeId, pyCode); + } + catch (Exception e) { + String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage()); + throw new ScriptLoadException(errorMsg); + } + } + + @Override + public void unLoad(String nodeId) { + compiledScriptMap.remove(nodeId); + } + + @Override + public List getNodeIds() { + return new ArrayList<>(compiledScriptMap.keySet()); + } + + @Override + public Object executeScript(ScriptExecuteWrap wrap) throws Exception { + if (!compiledScriptMap.containsKey(wrap.getNodeId())) { + String errorMsg = StrUtil.format("script for node[{}] is not loaded", wrap.getNodeId()); + throw new ScriptLoadException(errorMsg); + } + + PyCode compiledScript = compiledScriptMap.get(wrap.getNodeId()); + + bindParam(wrap, pythonInterpreter::set, pythonInterpreter::set); + + pythonInterpreter.exec(compiledScript); + + PyObject result = pythonInterpreter.get(RESULT_KEY); + + if (result == null){ + return null; + } + + pythonInterpreter.cleanup(); + + switch (wrap.getCmp().getType()){ + case BOOLEAN_SCRIPT: + return result.__tojava__(Boolean.class); + case FOR_SCRIPT: + return result.__tojava__(Integer.class); + default: + return result.__tojava__(Object.class); + } + } + + @Override + public void cleanCache() { + compiledScriptMap.clear(); + } + + @Override + public ScriptTypeEnum scriptType() { + return ScriptTypeEnum.PYTHON; + } + + @Override + public Object compile(String script) throws Exception { + return pythonInterpreter.compile(convertScript(script)); + } + + private String convertScript(String script) { + String[] lineArray = script.split("\\n"); + List noBlankLineList = Arrays.stream(lineArray) + .filter(s -> !StrUtil.isBlank(s)) + .collect(Collectors.toList()); + + // 用第一行的缩进的空格数作为整个代码的缩进量 + String blankStr = ReUtil.getGroup0("^[ ]*", noBlankLineList.get(0)); + + // 重新构建脚本 + StringBuilder scriptSB = new StringBuilder(); + noBlankLineList.forEach(s -> scriptSB.append(StrUtil.format("{}\n", s.replaceFirst(blankStr, StrUtil.EMPTY)))); + + return scriptSB.toString().replace("return", RESULT_KEY + "="); + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/java/com/yomahub/liteflow/test/script/python/common/ScriptPythonCommonELTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/java/com/yomahub/liteflow/test/script/python/common/ScriptPythonCommonELTest.java index a29b63fbe..a21420d23 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/java/com/yomahub/liteflow/test/script/python/common/ScriptPythonCommonELTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/java/com/yomahub/liteflow/test/script/python/common/ScriptPythonCommonELTest.java @@ -39,8 +39,9 @@ public class ScriptPythonCommonELTest extends BaseTest { DefaultContext context = response.getFirstContextBean(); Assertions.assertTrue(response.isSuccess()); Assertions.assertEquals(Integer.valueOf(30), context.getData("s1")); - Assertions.assertEquals("杰克", context.getData("name")); + Assertions.assertEquals("jack", context.getData("name")); Assertions.assertEquals("hi,jack", context.getData("td")); + Assertions.assertEquals("中文",context.getData("s2")); } @Test