| 
					
				 | 
			
			
				@@ -1,94 +1,13 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import json 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import re 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from base64 import b64encode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from typing import Optional 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from textwrap import dedent 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from core.helper.code_executor.entities import CodeDependency 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from core.helper.code_executor.python3.python3_transformer import PYTHON_STANDARD_PACKAGES 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from core.helper.code_executor.python3.python3_transformer import Python3TemplateTransformer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from core.helper.code_executor.template_transformer import TemplateTransformer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-PYTHON_RUNNER = """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import jinja2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from json import loads 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from base64 import b64decode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-template = jinja2.Template('''{{code}}''') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-def main(**inputs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return template.render(**inputs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# execute main function, and return the result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-inputs = b64decode('{{inputs}}').decode('utf-8') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-output = main(**loads(inputs)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-result = f'''<<RESULT>>{output}<<RESULT>>''' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-print(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-JINJA2_PRELOAD_TEMPLATE = """{% set fruits = ['Apple'] %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{{ 'a' }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% for fruit in fruits %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <li>{{ fruit }}</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% endfor %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% if fruits|length > 1 %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% endif %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% for i in range(5) %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    {% if i == 3 %}{{ i }}{% else %}{% endif %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% endfor %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    {% for i in range(3) %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        {{ i + 1 }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    {% endfor %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{% macro say_hello() %}a{{ 'b' }}{% endmacro %} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{{ s }}{{ say_hello() }}""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-JINJA2_PRELOAD = f""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import jinja2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from base64 import b64decode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-def _jinja2_preload_(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # prepare jinja2 environment, load template and render before to avoid sandbox issue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    template = jinja2.Template('''{JINJA2_PRELOAD_TEMPLATE}''') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    template.render(s='a') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-if __name__ == '__main__': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    _jinja2_preload_() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class Jinja2TemplateTransformer(TemplateTransformer): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @classmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def transform_caller(cls, code: str, inputs: dict,  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         dependencies: Optional[list[CodeDependency]] = None) -> tuple[str, str, list[CodeDependency]]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        Transform code to python runner 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :param code: code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :param inputs: inputs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :return: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        inputs_str = b64encode(json.dumps(inputs, ensure_ascii=False).encode()).decode('utf-8') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # transform jinja2 template to python code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        runner = PYTHON_RUNNER.replace('{{code}}', code) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        runner = runner.replace('{{inputs}}', inputs_str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if not dependencies: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            dependencies = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # add native packages and jinja2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for package in PYTHON_STANDARD_PACKAGES.union(['jinja2']): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            dependencies.append(CodeDependency(name=package, version='')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # deduplicate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        dependencies = list({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            dep.name: dep for dep in dependencies if dep.name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }.values()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return runner, JINJA2_PRELOAD, dependencies 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def get_standard_packages(cls) -> set[str]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return {'jinja2'} | Python3TemplateTransformer.get_standard_packages() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @classmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def transform_response(cls, response: str) -> dict: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -97,12 +16,49 @@ class Jinja2TemplateTransformer(TemplateTransformer): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         :param response: response 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         :return: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # extract result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        result = re.search(r'<<RESULT>>(.*)<<RESULT>>', response, re.DOTALL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if not result: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            raise ValueError('Failed to parse result') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        result = result.group(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'result': result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'result': cls.extract_result_str_from_response(response) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @classmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def get_runner_script(cls) -> str: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        runner_script = dedent(f""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # declare main function 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            def main(**inputs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                import jinja2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                template = jinja2.Template('''{cls._code_placeholder}''') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return template.render(**inputs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            import json 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            from base64 import b64decode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # decode and prepare input dict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            inputs_obj = json.loads(b64decode('{cls._inputs_placeholder}').decode('utf-8')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # execute main function 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            output = main(**inputs_obj) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # convert output and print 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = f'''<<RESULT>>{{output}}<<RESULT>>''' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            print(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            """) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return runner_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @classmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def get_preload_script(cls) -> str: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        preload_script = dedent(""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            import jinja2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            from base64 import b64decode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            def _jinja2_preload_(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # prepare jinja2 environment, load template and render before to avoid sandbox issue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                template = jinja2.Template('{{s}}') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                template.render(s='a') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if __name__ == '__main__': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _jinja2_preload_() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            """) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return preload_script 
			 |