Upload 10 files
Browse files- CodeTestingAtomicFlow.py +49 -0
- CodeTestingAtomicFlow.yaml +10 -0
- README.md +101 -3
- TestCodeFileEditAtomicFlow.py +43 -0
- TestCodeFileEditAtomicFlow.yaml +11 -0
- TestCodeFlow.py +66 -0
- TestCodeFlow.yaml +38 -0
- __init__.py +12 -0
- pip_requirements.txt +15 -0
- run.py +50 -0
CodeTestingAtomicFlow.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
import subprocess
|
4 |
+
from typing import Dict, Any
|
5 |
+
from flow_modules.aiflows.InterpreterFlowModule import InterpreterAtomicFlow
|
6 |
+
|
7 |
+
|
8 |
+
class CodeTestingAtomicFlow(InterpreterAtomicFlow):
|
9 |
+
"""This class inherits from InterpreterAtomicFlow and is used to test code.
|
10 |
+
|
11 |
+
*Input Interface*:
|
12 |
+
- `temp_code_file_location`: Location of the file containing the code to be tested.
|
13 |
+
|
14 |
+
*Output Interface*:
|
15 |
+
- `feedback`: Feedback from the test (i.e. test results).
|
16 |
+
"""
|
17 |
+
def _open_file_and_wait_for_file_update(self, file_location, check_interval=1):
|
18 |
+
process = subprocess.Popen(["code", "--wait", file_location])
|
19 |
+
while True:
|
20 |
+
if process.poll() is not None:
|
21 |
+
break
|
22 |
+
time.sleep(check_interval)
|
23 |
+
def _prepare_code_and_lang(self, input_data: Dict[str, Any]):
|
24 |
+
file_location = input_data["temp_code_file_location"]
|
25 |
+
input_data["language"] = "python"
|
26 |
+
with open(file_location, "r") as file:
|
27 |
+
code_str = file.read()
|
28 |
+
input_data["code"] = code_str
|
29 |
+
|
30 |
+
def _check_input(self, input_data: Dict[str, Any]):
|
31 |
+
assert "temp_code_file_location" in input_data, "temp_code_file_location not passed to CodeTestingAtomicFlow"
|
32 |
+
|
33 |
+
def _delete_file(self, file_location):
|
34 |
+
if os.path.exists(file_location):
|
35 |
+
os.remove(file_location)
|
36 |
+
|
37 |
+
def run(
|
38 |
+
self,
|
39 |
+
input_data: Dict[str, Any]):
|
40 |
+
self._check_input(input_data)
|
41 |
+
file_loc = input_data["temp_code_file_location"]
|
42 |
+
self._open_file_and_wait_for_file_update(file_loc)
|
43 |
+
self._prepare_code_and_lang(input_data)
|
44 |
+
self._process_input_data(input_data)
|
45 |
+
response = self._call()
|
46 |
+
self._delete_file(file_loc)
|
47 |
+
if response.strip() == '':
|
48 |
+
response = "test passed"
|
49 |
+
return {"feedback": response}
|
CodeTestingAtomicFlow.yaml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
_target_: flow_modules.aiflows.TestCodeFlowModule.CodeTestingAtomicFlow.instantiate_from_default_config
|
2 |
+
name: "CodeTestingAtomicFlow"
|
3 |
+
description: "A flow that runs test code"
|
4 |
+
|
5 |
+
|
6 |
+
input_interface:
|
7 |
+
- "temp_code_file_location"
|
8 |
+
|
9 |
+
output_interface:
|
10 |
+
- "feedback"
|
README.md
CHANGED
@@ -1,3 +1,101 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
### Structure of TestCodeFlow
|
2 |
+
|
3 |
+
```
|
4 |
+
code
|
5 |
+
|
|
6 |
+
v
|
7 |
+
+-------------------+
|
8 |
+
| TestCodeFileEdit | Edit a temp code file with the code to be tested and necessary imports (manually added): https://huggingface.co/Tachi67/TestCodeFlowModule/blob/main/TestCodeFileEditAtomicFlow.py
|
9 |
+
+-------------------+
|
10 |
+
|
|
11 |
+
| (temp_code_file_location)
|
12 |
+
|
|
13 |
+
v
|
14 |
+
+------------------+
|
15 |
+
| CodeTesting | Opens up the temp file until user closes the file, run the test code.
|
16 |
+
+------------------+
|
17 |
+
|
|
18 |
+
| (feedback)
|
19 |
+
|
|
20 |
+
v
|
21 |
+
feedback
|
22 |
+
|
23 |
+
|
24 |
+
```
|
25 |
+
Memory_files:
|
26 |
+
- library.py
|
27 |
+
|
28 |
+
# Table of Contents
|
29 |
+
|
30 |
+
* [TestCodeFlow](#TestCodeFlow)
|
31 |
+
* [TestCodeFlow](#TestCodeFlow.TestCodeFlow)
|
32 |
+
* [TestCodeFileEditAtomicFlow](#TestCodeFileEditAtomicFlow)
|
33 |
+
* [TestCodeFileEditAtomicFlow](#TestCodeFileEditAtomicFlow.TestCodeFileEditAtomicFlow)
|
34 |
+
* [\_\_init\_\_](#__init__)
|
35 |
+
* [CodeTestingAtomicFlow](#CodeTestingAtomicFlow)
|
36 |
+
* [CodeTestingAtomicFlow](#CodeTestingAtomicFlow.CodeTestingAtomicFlow)
|
37 |
+
|
38 |
+
<a id="TestCodeFlow"></a>
|
39 |
+
|
40 |
+
# TestCodeFlow
|
41 |
+
|
42 |
+
<a id="TestCodeFlow.TestCodeFlow"></a>
|
43 |
+
|
44 |
+
## TestCodeFlow Objects
|
45 |
+
|
46 |
+
```python
|
47 |
+
class TestCodeFlow(SequentialFlow)
|
48 |
+
```
|
49 |
+
|
50 |
+
This class is used to test code. It is a sequential flow that runs the following steps:
|
51 |
+
1. Prepares the code to be tested, it is composed of the code to be tested and necessary import statements manually added.
|
52 |
+
2. Opens the code in VSCode and waits for the user to clode the vscode session. The user is able to add tests.
|
53 |
+
3. The following will be tested:
|
54 |
+
a. (Default & Compulsory) Code syntax;
|
55 |
+
b. (Added by user) Any other tests.
|
56 |
+
4. Runs the test and returns the output.
|
57 |
+
|
58 |
+
*Input Interface*:
|
59 |
+
- `code` (str): The code to be tested.
|
60 |
+
|
61 |
+
*Output Interface*:
|
62 |
+
- `feedback` (str): The test results.
|
63 |
+
|
64 |
+
<a id="TestCodeFileEditAtomicFlow"></a>
|
65 |
+
|
66 |
+
# TestCodeFileEditAtomicFlow
|
67 |
+
|
68 |
+
<a id="TestCodeFileEditAtomicFlow.TestCodeFileEditAtomicFlow"></a>
|
69 |
+
|
70 |
+
## TestCodeFileEditAtomicFlow Objects
|
71 |
+
|
72 |
+
```python
|
73 |
+
class TestCodeFileEditAtomicFlow(CodeFileEditAtomicFlow)
|
74 |
+
```
|
75 |
+
|
76 |
+
Refer to: https://huggingface.co/Tachi67/CodeFileEditFlowModule/tree/main
|
77 |
+
|
78 |
+
<a id="__init__"></a>
|
79 |
+
|
80 |
+
# \_\_init\_\_
|
81 |
+
|
82 |
+
<a id="CodeTestingAtomicFlow"></a>
|
83 |
+
|
84 |
+
# CodeTestingAtomicFlow
|
85 |
+
|
86 |
+
<a id="CodeTestingAtomicFlow.CodeTestingAtomicFlow"></a>
|
87 |
+
|
88 |
+
## CodeTestingAtomicFlow Objects
|
89 |
+
|
90 |
+
```python
|
91 |
+
class CodeTestingAtomicFlow(InterpreterAtomicFlow)
|
92 |
+
```
|
93 |
+
|
94 |
+
This class inherits from InterpreterAtomicFlow and is used to test code.
|
95 |
+
|
96 |
+
*Input Interface*:
|
97 |
+
- `temp_code_file_location`: Location of the file containing the code to be tested.
|
98 |
+
|
99 |
+
*Output Interface*:
|
100 |
+
- `feedback`: Feedback from the test (i.e. test results).
|
101 |
+
|
TestCodeFileEditAtomicFlow.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from typing import Dict, Any
|
3 |
+
from flow_modules.aiflows.CodeFileEditFlowModule import CodeFileEditAtomicFlow
|
4 |
+
|
5 |
+
class TestCodeFileEditAtomicFlow(CodeFileEditAtomicFlow):
|
6 |
+
"""Refer to: https://huggingface.co/Tachi67/CodeFileEditFlowModule/tree/main"""
|
7 |
+
def _generate_import_statement(self, code_lib_location):
|
8 |
+
module_dir = os.path.dirname(code_lib_location)
|
9 |
+
module_name = os.path.splitext(os.path.basename(code_lib_location))[0]
|
10 |
+
|
11 |
+
import_code = (
|
12 |
+
f"import sys\n"
|
13 |
+
f"sys.path.insert(0, '{module_dir}')\n"
|
14 |
+
f"from {module_name} import *\n"
|
15 |
+
)
|
16 |
+
return import_code
|
17 |
+
|
18 |
+
def _generate_content(self, code_lib_location, code_str) -> str:
|
19 |
+
import_code_lib_str = self._generate_import_statement(code_lib_location)
|
20 |
+
content = (
|
21 |
+
"# Don't touch this import statement \n"
|
22 |
+
+ import_code_lib_str + "\n"
|
23 |
+
"# Here is the code just generated \n" +
|
24 |
+
code_str + "\n"
|
25 |
+
"# Below, please provide code to test it.\n"
|
26 |
+
"# The simplest form could be just calling it with appropriate parameters. \n"
|
27 |
+
"# You could also assert the output, anyway, the test results will be informed to JARVIS. \n"
|
28 |
+
"# If you do not write anything, JARVIS just checks if the syntax is alright. \n"
|
29 |
+
"###########\n"
|
30 |
+
"# Test Code:\n" +
|
31 |
+
"\n############\n"
|
32 |
+
)
|
33 |
+
return content
|
34 |
+
|
35 |
+
def _generate_temp_file_location(self, code_lib_location):
|
36 |
+
directory = os.path.dirname(code_lib_location)
|
37 |
+
ret = os.path.join(directory, 'temp_tests.py')
|
38 |
+
return ret
|
39 |
+
|
40 |
+
def _check_input(self, input_data: Dict[str, Any]):
|
41 |
+
assert "code" in input_data, "code is not passed to TestCodeFileEditAtomicFlow"
|
42 |
+
assert "memory_files" in input_data, "memory_files is not passed to TestCodeFileEditAtomicFlow"
|
43 |
+
|
TestCodeFileEditAtomicFlow.yaml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
_target_: flow_modules.aiflows.TestCodeFlowModule.TestCodeFileEditAtomicFlow.instantiate_from_default_config
|
2 |
+
name: "TestCodeFileEditorAtomicFlow"
|
3 |
+
description: "A flow that writes tests code to a temp file"
|
4 |
+
|
5 |
+
input_interface:
|
6 |
+
- "code"
|
7 |
+
- "memory_files"
|
8 |
+
|
9 |
+
output_interface:
|
10 |
+
- "code_editor_output"
|
11 |
+
- "temp_code_file_location"
|
TestCodeFlow.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from copy import deepcopy
|
2 |
+
from typing import Any, Dict
|
3 |
+
|
4 |
+
from aiflows.base_flows import SequentialFlow
|
5 |
+
from aiflows.utils import logging
|
6 |
+
|
7 |
+
logging.set_verbosity_debug()
|
8 |
+
log = logging.get_logger(__name__)
|
9 |
+
|
10 |
+
class TestCodeFlow(SequentialFlow):
|
11 |
+
"""This class is used to test code. It is a sequential flow that runs the following steps:
|
12 |
+
1. Prepares the code to be tested, it is composed of the code to be tested and necessary import statements manually added.
|
13 |
+
2. Opens the code in VSCode and waits for the user to clode the vscode session. The user is able to add tests.
|
14 |
+
3. The following will be tested:
|
15 |
+
a. (Default & Compulsory) Code syntax;
|
16 |
+
b. (Added by user) Any other tests.
|
17 |
+
4. Runs the test and returns the output.
|
18 |
+
|
19 |
+
*Input Interface*:
|
20 |
+
- `code` (str): The code to be tested.
|
21 |
+
|
22 |
+
*Output Interface*:
|
23 |
+
- `feedback` (str): The test results.
|
24 |
+
"""
|
25 |
+
REQUIRED_KEYS_CONFIG = ["max_rounds", "early_exit_key", "topology", "memory_files"]
|
26 |
+
|
27 |
+
def __init__(
|
28 |
+
self,
|
29 |
+
memory_files: Dict[str, Any],
|
30 |
+
**kwargs
|
31 |
+
):
|
32 |
+
super().__init__(**kwargs)
|
33 |
+
self.memory_files = memory_files
|
34 |
+
|
35 |
+
@classmethod
|
36 |
+
def instantiate_from_config(cls, config):
|
37 |
+
flow_config = deepcopy(config)
|
38 |
+
|
39 |
+
kwargs = {"flow_config": flow_config}
|
40 |
+
|
41 |
+
# ~~~ Set up memory file ~~~
|
42 |
+
memory_files = flow_config["memory_files"]
|
43 |
+
kwargs.update({"memory_files": memory_files})
|
44 |
+
|
45 |
+
# ~~~ Set up subflows ~~~
|
46 |
+
kwargs.update({"subflows": cls._set_up_subflows(flow_config)})
|
47 |
+
|
48 |
+
# ~~~ Instantiate flow ~~~
|
49 |
+
return cls(**kwargs)
|
50 |
+
|
51 |
+
def run(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
|
52 |
+
# ~~~ sets the input_data in the flow_state dict ~~~
|
53 |
+
self._state_update_dict(update_data=input_data)
|
54 |
+
|
55 |
+
# ~~~ set the memory file to the flow state ~~~
|
56 |
+
self._state_update_dict(update_data={"memory_files": self.memory_files})
|
57 |
+
|
58 |
+
max_rounds = self.flow_config.get("max_rounds", 1)
|
59 |
+
if max_rounds is None:
|
60 |
+
log.info(f"Running {self.flow_config['name']} without `max_rounds` until the early exit condition is met.")
|
61 |
+
|
62 |
+
self._sequential_run(max_rounds=max_rounds)
|
63 |
+
|
64 |
+
output = self._get_output_from_state()
|
65 |
+
|
66 |
+
return output
|
TestCodeFlow.yaml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: "TestCodeFlow"
|
2 |
+
description: "Test the code generated by InteractiveCodeGenFlow"
|
3 |
+
|
4 |
+
_target_: flow_modules.aiflows.TestCodeFlowModule.TestCodeFlow.instantiate_from_default_config
|
5 |
+
|
6 |
+
memory_files: ???
|
7 |
+
|
8 |
+
input_interface:
|
9 |
+
- "code"
|
10 |
+
|
11 |
+
output_interface:
|
12 |
+
- "feedback"
|
13 |
+
|
14 |
+
subflows_config:
|
15 |
+
TestCodeFileEdit:
|
16 |
+
_target_: flow_modules.aiflows.TestCodeFlowModule.TestCodeFileEditAtomicFlow.instantiate_from_default_config
|
17 |
+
|
18 |
+
CodeTesting:
|
19 |
+
_target_: flow_modules.aiflows.TestCodeFlowModule.CodeTestingAtomicFlow.instantiate_from_default_config
|
20 |
+
|
21 |
+
early_exit_key: "EARLY_EXIT"
|
22 |
+
|
23 |
+
topology:
|
24 |
+
- goal: "Write the code & instructions for testing to a temp file"
|
25 |
+
input_interface:
|
26 |
+
_target_: aiflows.interfaces.KeyInterface
|
27 |
+
additional_transformations:
|
28 |
+
- _target_: aiflows.data_transformations.KeyMatchInput
|
29 |
+
flow: TestCodeFileEdit
|
30 |
+
reset: false
|
31 |
+
|
32 |
+
- goal: "Test the code"
|
33 |
+
input_interface:
|
34 |
+
_target_: aiflows.interfaces.KeyInterface
|
35 |
+
additional_transformations:
|
36 |
+
- _target_: aiflows.data_transformations.KeyMatchInput
|
37 |
+
flow: CodeTesting
|
38 |
+
reset: false
|
__init__.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
dependencies = [
|
2 |
+
{"url": "aiflows/CodeFileEditFlowModule", "revision": "main"},
|
3 |
+
{"url": "aiflows/InterpreterFlowModule", "revision": "main"},
|
4 |
+
]
|
5 |
+
|
6 |
+
from aiflows import flow_verse
|
7 |
+
|
8 |
+
flow_verse.sync_dependencies(dependencies)
|
9 |
+
|
10 |
+
from .CodeTestingAtomicFlow import CodeTestingAtomicFlow
|
11 |
+
from .TestCodeFileEditAtomicFlow import TestCodeFileEditAtomicFlow
|
12 |
+
from .TestCodeFlow import TestCodeFlow
|
pip_requirements.txt
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
colorama==0.4.6
|
2 |
+
pytest==7.3.1
|
3 |
+
pytest-cov==4.1.0
|
4 |
+
hydra-core==1.3.2
|
5 |
+
hydra-colorlog==1.1.0
|
6 |
+
wrapt-timeout-decorator==1.3.12.2
|
7 |
+
diskcache==5.6.1
|
8 |
+
openai==1.0.0
|
9 |
+
huggingface_hub==0.19.4
|
10 |
+
jsonlines==3.1.0
|
11 |
+
jinja2==3.1.2
|
12 |
+
mock==5.0.2
|
13 |
+
rich==12.6.0
|
14 |
+
litellm==1.0.0
|
15 |
+
aiflows
|
run.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import hydra
|
4 |
+
|
5 |
+
from aiflows.backends.api_info import ApiInfo
|
6 |
+
from aiflows.messages import InputMessage
|
7 |
+
from aiflows.utils.general_helpers import read_yaml_file, quick_load
|
8 |
+
|
9 |
+
from aiflows import logging
|
10 |
+
from aiflows.flow_cache import CACHING_PARAMETERS, clear_cache
|
11 |
+
|
12 |
+
CACHING_PARAMETERS.do_caching = False # Set to True in order to disable caching
|
13 |
+
|
14 |
+
logging.set_verbosity_debug()
|
15 |
+
logging.auto_set_dir()
|
16 |
+
|
17 |
+
dependencies = [
|
18 |
+
{"url": "aiflows/TestCodeFlowModule", "revision": "main"},
|
19 |
+
]
|
20 |
+
|
21 |
+
from aiflows import flow_verse
|
22 |
+
|
23 |
+
flow_verse.sync_dependencies(dependencies)
|
24 |
+
|
25 |
+
if __name__ == "__main__":
|
26 |
+
current_dir = os.getcwd()
|
27 |
+
cfg_path = os.path.join(current_dir, "TestCodeFlow.yaml")
|
28 |
+
cfg = read_yaml_file(cfg_path)
|
29 |
+
with open(os.path.join(current_dir, "example_library.py"), 'w') as f:
|
30 |
+
pass
|
31 |
+
memory_files = {"code_library": os.path.join(current_dir, "example_library.py")}
|
32 |
+
cfg["memory_files"] = memory_files
|
33 |
+
|
34 |
+
|
35 |
+
TestCodeFlow = hydra.utils.instantiate(cfg, _recursive_=False, _convert_="partial")
|
36 |
+
|
37 |
+
|
38 |
+
input_data = {
|
39 |
+
"code": "def test():\n print('hello world')\n'",
|
40 |
+
}
|
41 |
+
input_message = InputMessage.build(
|
42 |
+
data_dict=input_data,
|
43 |
+
src_flow="Launcher",
|
44 |
+
dst_flow=TestCodeFlow.name
|
45 |
+
)
|
46 |
+
|
47 |
+
# ~~~ calling the flow ~~~
|
48 |
+
output_message = TestCodeFlow(input_message)
|
49 |
+
|
50 |
+
print(output_message.data)
|