py-adtools 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of py-adtools might be problematic. Click here for more details.
- adtools/__init__.py +1 -0
- adtools/evaluator.py +177 -0
- adtools/py_code.py +5 -5
- py_adtools-0.1.2.dist-info/METADATA +213 -0
- py_adtools-0.1.2.dist-info/RECORD +8 -0
- py_adtools-0.1.0.dist-info/METADATA +0 -89
- py_adtools-0.1.0.dist-info/RECORD +0 -7
- {py_adtools-0.1.0.dist-info → py_adtools-0.1.2.dist-info}/WHEEL +0 -0
- {py_adtools-0.1.0.dist-info → py_adtools-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {py_adtools-0.1.0.dist-info → py_adtools-0.1.2.dist-info}/top_level.txt +0 -0
adtools/__init__.py
CHANGED
adtools/evaluator.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import multiprocessing
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from queue import Empty
|
|
7
|
+
from typing import Any, Literal, Dict, Callable, List
|
|
8
|
+
import psutil
|
|
9
|
+
|
|
10
|
+
from .py_code import PyProgram
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PyEvaluator(ABC):
|
|
14
|
+
|
|
15
|
+
def __init__(self, debug_mode: bool = False, *, exec_code: bool = True):
|
|
16
|
+
"""Evaluator interface for evaluating the Python algorithm program.
|
|
17
|
+
Args:
|
|
18
|
+
debug_mode: Debug mode.
|
|
19
|
+
exec_code : Using 'exec()' to compile the code and provide the callable function.
|
|
20
|
+
"""
|
|
21
|
+
self._debug_mode = debug_mode
|
|
22
|
+
self._exec_code = exec_code
|
|
23
|
+
self._JOIN_TIMEOUT_SECONDS = 5
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def evaluate_program(
|
|
27
|
+
self,
|
|
28
|
+
program_str: str,
|
|
29
|
+
callable_functions_dict: Dict[str, Callable] | None,
|
|
30
|
+
callable_functions_list: List[Callable] | None,
|
|
31
|
+
callable_classes_dict: Dict[str, Callable] | None,
|
|
32
|
+
callable_classes_list: List[Callable] | None,
|
|
33
|
+
**kwargs
|
|
34
|
+
) -> Any | None:
|
|
35
|
+
"""Evaluate a given program.
|
|
36
|
+
Args:
|
|
37
|
+
program_str : The raw program text.
|
|
38
|
+
callable_functions_dict: A dict maps function name to callable function.
|
|
39
|
+
callable_functions_list: A list of callable functions.
|
|
40
|
+
callable_classes_dict : A dict maps class name to callable class.
|
|
41
|
+
callable_classes_list : A list of callable classes.
|
|
42
|
+
Return:
|
|
43
|
+
Returns the evaluation result.
|
|
44
|
+
"""
|
|
45
|
+
raise NotImplementedError('Must provide an evaluator for a python program. '
|
|
46
|
+
'Override this method in a subclass.')
|
|
47
|
+
|
|
48
|
+
def _kill_process_and_its_children(self, process: multiprocessing.Process):
|
|
49
|
+
# Find all children processes
|
|
50
|
+
try:
|
|
51
|
+
parent = psutil.Process(process.pid)
|
|
52
|
+
children_processes = parent.children(recursive=True)
|
|
53
|
+
except psutil.NoSuchProcess:
|
|
54
|
+
children_processes = []
|
|
55
|
+
# Terminate parent process
|
|
56
|
+
process.terminate()
|
|
57
|
+
process.join(timeout=self._JOIN_TIMEOUT_SECONDS)
|
|
58
|
+
if process.is_alive():
|
|
59
|
+
process.kill()
|
|
60
|
+
process.join()
|
|
61
|
+
# Kill all children processes
|
|
62
|
+
for child in children_processes:
|
|
63
|
+
if self._debug_mode:
|
|
64
|
+
print(f"Killing process {process.pid}'s children process {child.pid}")
|
|
65
|
+
child.terminate()
|
|
66
|
+
|
|
67
|
+
def evaluate(self, program_str: str, **kwargs):
|
|
68
|
+
try:
|
|
69
|
+
# Parse to program instance
|
|
70
|
+
program = PyProgram.from_text(program_str)
|
|
71
|
+
function_names = [f.name for f in program.functions]
|
|
72
|
+
class_names = [c.name for c in program.classes]
|
|
73
|
+
if self._exec_code:
|
|
74
|
+
# Compile the program, and maps the global func/var/class name to its address
|
|
75
|
+
all_globals_namespace = {}
|
|
76
|
+
# Execute the program, map func/var/class to global namespace
|
|
77
|
+
exec(program_str, all_globals_namespace)
|
|
78
|
+
# Get callable functions
|
|
79
|
+
callable_functions_list = [all_globals_namespace[f_name] for f_name in function_names]
|
|
80
|
+
callable_functions_dict = dict(zip(function_names, callable_functions_list))
|
|
81
|
+
# Get callable classes
|
|
82
|
+
callable_classes_list = [all_globals_namespace[c_name] for c_name in class_names]
|
|
83
|
+
callable_classes_dict = dict(zip(class_names, callable_classes_list))
|
|
84
|
+
else:
|
|
85
|
+
callable_functions_list = None
|
|
86
|
+
callable_functions_dict = None
|
|
87
|
+
callable_classes_list = None
|
|
88
|
+
callable_classes_dict = None
|
|
89
|
+
|
|
90
|
+
# Get evaluate result
|
|
91
|
+
res = self.evaluate_program(
|
|
92
|
+
program_str,
|
|
93
|
+
callable_functions_dict,
|
|
94
|
+
callable_functions_list,
|
|
95
|
+
callable_classes_dict,
|
|
96
|
+
callable_classes_list,
|
|
97
|
+
**kwargs
|
|
98
|
+
)
|
|
99
|
+
return res
|
|
100
|
+
except Exception as e:
|
|
101
|
+
if self._debug_mode:
|
|
102
|
+
print(e)
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
def _evaluate_in_safe_process(
|
|
106
|
+
self,
|
|
107
|
+
program_str: str,
|
|
108
|
+
result_queue: multiprocessing.Queue,
|
|
109
|
+
redirect_to_devnull: bool,
|
|
110
|
+
**kwargs
|
|
111
|
+
):
|
|
112
|
+
if redirect_to_devnull:
|
|
113
|
+
with open('/dev/null', 'w') as devnull:
|
|
114
|
+
os.dup2(devnull.fileno(), sys.stdout.fileno())
|
|
115
|
+
os.dup2(devnull.fileno(), sys.stderr.fileno())
|
|
116
|
+
res = self.evaluate(program_str, **kwargs)
|
|
117
|
+
result_queue.put(res)
|
|
118
|
+
|
|
119
|
+
def secure_evaluate(
|
|
120
|
+
self,
|
|
121
|
+
program: str | PyProgram,
|
|
122
|
+
timeout_seconds: int | float = None,
|
|
123
|
+
redirect_to_devnull: bool = True,
|
|
124
|
+
multiprocessing_start_method=Literal['auto', 'fork', 'spawn'],
|
|
125
|
+
**kwargs
|
|
126
|
+
):
|
|
127
|
+
"""
|
|
128
|
+
Args:
|
|
129
|
+
program: the program to be evaluated.
|
|
130
|
+
timeout_seconds: return 'None' if the execution time exceeds 'timeout_seconds'.
|
|
131
|
+
redirect_to_devnull: redirect any output to '/dev/null'.
|
|
132
|
+
multiprocessing_start_method: start a process using 'fork' or 'spawn'.
|
|
133
|
+
"""
|
|
134
|
+
if multiprocessing_start_method == 'auto':
|
|
135
|
+
# Force MacOS and Linux use 'fork' to generate new process
|
|
136
|
+
if sys.platform.startswith('darwin') or sys.platform.startswith('linux'):
|
|
137
|
+
multiprocessing.set_start_method('fork', force=True)
|
|
138
|
+
elif multiprocessing_start_method == 'fork':
|
|
139
|
+
multiprocessing.set_start_method('fork', force=True)
|
|
140
|
+
else:
|
|
141
|
+
multiprocessing.set_start_method('spawn', force=True)
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
# Start evaluation process
|
|
145
|
+
result_queue = multiprocessing.Queue()
|
|
146
|
+
process = multiprocessing.Process(
|
|
147
|
+
target=self._evaluate_in_safe_process,
|
|
148
|
+
args=(str(program), result_queue, redirect_to_devnull),
|
|
149
|
+
kwargs=kwargs,
|
|
150
|
+
)
|
|
151
|
+
process.start()
|
|
152
|
+
|
|
153
|
+
if timeout_seconds is not None:
|
|
154
|
+
try:
|
|
155
|
+
# Get the result in timeout seconds
|
|
156
|
+
result = result_queue.get(timeout=timeout_seconds)
|
|
157
|
+
# After getting the result, terminate/kill the process
|
|
158
|
+
self._kill_process_and_its_children(process)
|
|
159
|
+
except Empty:
|
|
160
|
+
# Timeout
|
|
161
|
+
if self._debug_mode:
|
|
162
|
+
print(f'DEBUG: the evaluation time exceeds {timeout_seconds}s.')
|
|
163
|
+
self._kill_process_and_its_children(process)
|
|
164
|
+
result = None
|
|
165
|
+
except Exception as e:
|
|
166
|
+
if self._debug_mode:
|
|
167
|
+
print(f'DEBUG: evaluation failed with exception:\n{e}')
|
|
168
|
+
self._kill_process_and_its_children(process)
|
|
169
|
+
result = None
|
|
170
|
+
else:
|
|
171
|
+
result = result_queue.get()
|
|
172
|
+
self._kill_process_and_its_children(process)
|
|
173
|
+
return result
|
|
174
|
+
except Exception as e:
|
|
175
|
+
if self._debug_mode:
|
|
176
|
+
print(e)
|
|
177
|
+
return None
|
adtools/py_code.py
CHANGED
|
@@ -44,7 +44,7 @@ class PyFunction:
|
|
|
44
44
|
# Here, we assume the indentation is always four spaces.
|
|
45
45
|
new_line = '\n' if self.body else ''
|
|
46
46
|
function += f' """{self.docstring}"""{new_line}'
|
|
47
|
-
# self.body is already indented.
|
|
47
|
+
# The self.body is already indented.
|
|
48
48
|
function += self.body + '\n\n'
|
|
49
49
|
return function
|
|
50
50
|
|
|
@@ -109,7 +109,7 @@ class PyClass:
|
|
|
109
109
|
# Ensure there aren't leading & trailing new lines in `body`
|
|
110
110
|
if name == 'body':
|
|
111
111
|
value = value.strip('\n')
|
|
112
|
-
#
|
|
112
|
+
# Ensure there aren't leading & trailing quotes in `docstring`
|
|
113
113
|
if name == 'docstring' and value is not None:
|
|
114
114
|
if '"""' in value:
|
|
115
115
|
value = value.strip()
|
|
@@ -189,7 +189,7 @@ class _ProgramVisitor(ast.NodeVisitor):
|
|
|
189
189
|
if has_decorators:
|
|
190
190
|
# Find the minimum line number and retain the code above
|
|
191
191
|
decorator_start_line = min(decorator.lineno for decorator in node.decorator_list)
|
|
192
|
-
decorator = '\n'.join(self._codelines[decorator_start_line - 1: node.lineno - 1])
|
|
192
|
+
decorator = '\n'.join(self._codelines[decorator_start_line - 1: node.lineno - 1]).strip()
|
|
193
193
|
# Update script end line
|
|
194
194
|
script_end_line = decorator_start_line - 1
|
|
195
195
|
else:
|
|
@@ -262,10 +262,10 @@ class _ProgramVisitor(ast.NodeVisitor):
|
|
|
262
262
|
if has_decorators:
|
|
263
263
|
# Find the minimum line number and retain the code above
|
|
264
264
|
decorator_start_line = min(decorator.lineno for decorator in item.decorator_list)
|
|
265
|
-
# Dedent decorator code
|
|
265
|
+
# Dedent decorator code
|
|
266
266
|
decorator = []
|
|
267
267
|
for line in range(decorator_start_line - 1, item.lineno - 1):
|
|
268
|
-
dedented_decorator = self._codelines[line]
|
|
268
|
+
dedented_decorator = self._codelines[line].strip()
|
|
269
269
|
decorator.append(dedented_decorator)
|
|
270
270
|
decorator = '\n'.join(decorator)
|
|
271
271
|
else:
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: py-adtools
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Useful tools for parsing and evaluating Python programs for algorithm design.
|
|
5
|
+
Home-page: https://github.com/RayZhhh/py-adtools
|
|
6
|
+
Author: Rui Zhang
|
|
7
|
+
Author-email: rzhang.cs@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: psutil
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# Useful tools for parsing and evaluating Python programs for algorithm design
|
|
28
|
+
|
|
29
|
+
------
|
|
30
|
+
|
|
31
|
+
> This repo aims to help develop more powerful [Large Language Models for Algorithm Design (LLM4AD)](https://github.com/Optima-CityU/llm4ad) applications.
|
|
32
|
+
>
|
|
33
|
+
> More tools will be provided soon.
|
|
34
|
+
|
|
35
|
+
------
|
|
36
|
+
|
|
37
|
+
The figure demonstrates how a Python program is parsed into `PyScript`, `PyFunction`, `PyClass,` and `PyProgram` via `adtools`.
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
------
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
> [!TIP]
|
|
46
|
+
>
|
|
47
|
+
> It is recommended to use Python >= 3.10.
|
|
48
|
+
|
|
49
|
+
Run the following instructions to install adtools.
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
pip install git+https://github.com/RayZhhh/py-adtools.git
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or install via pip:
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
pip install py-adtools
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
### Parser for a Python program
|
|
64
|
+
|
|
65
|
+
Parse your code (in string) into Python code instances, so that you can check each component and modify it.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from adtools import PyProgram
|
|
69
|
+
|
|
70
|
+
code = r'''
|
|
71
|
+
import ast, numba # This part will be parsed into PyScript
|
|
72
|
+
import numpy as np
|
|
73
|
+
|
|
74
|
+
@numba.jit() # This part will be parsed into PyFunction
|
|
75
|
+
def function(arg1, arg2=True):
|
|
76
|
+
if arg2:
|
|
77
|
+
return arg1 * 2
|
|
78
|
+
else:
|
|
79
|
+
return arg1 * 4
|
|
80
|
+
|
|
81
|
+
@some.decorators() # This part will be parsed into PyClass
|
|
82
|
+
class PythonClass(BaseClass):
|
|
83
|
+
class_var1 = 1 # This part will be parsed into PyScript
|
|
84
|
+
class_varb = 2 # and placed in PyClass.class_vars_and_code
|
|
85
|
+
|
|
86
|
+
def __init__(self, x): # This part will be parsed into PyFunction
|
|
87
|
+
self.x = x # and placed in PyClass.functions
|
|
88
|
+
|
|
89
|
+
def method1(self):
|
|
90
|
+
return self.x * 10
|
|
91
|
+
|
|
92
|
+
@some.decorators()
|
|
93
|
+
def method2(self, x, y):
|
|
94
|
+
return x + y + self.method1(x)
|
|
95
|
+
|
|
96
|
+
class InnerClass: # This part will be parsed into PyScript
|
|
97
|
+
def __init__(self): # and placed in PyClass.class_vars_and_code
|
|
98
|
+
...
|
|
99
|
+
|
|
100
|
+
if __name__ == '__main__': # This part will be parsed into PyScript
|
|
101
|
+
res = function(1)
|
|
102
|
+
print(res)
|
|
103
|
+
res = PythonClass().method2(1, 2)
|
|
104
|
+
'''
|
|
105
|
+
|
|
106
|
+
p = PyProgram.from_text(code)
|
|
107
|
+
print(p)
|
|
108
|
+
print(f'-------------------------------------')
|
|
109
|
+
print(p.classes[0].functions[2].decorator)
|
|
110
|
+
print(f'-------------------------------------')
|
|
111
|
+
print(p.functions[0].name)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Evaluate Python programs
|
|
115
|
+
|
|
116
|
+
Evaluate Python programs in a secure process to avoid the abortation of the main process. Two steps:
|
|
117
|
+
|
|
118
|
+
- Extend the `PyEvaluator` class and override the `evaluate_program` method.
|
|
119
|
+
- Evaluate the program (in str) by calling the `evaluate` (directly evaluate without executing in a sandbox process) or the `secure_evaluate` (evaluate in a sandbox process) methods.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import time
|
|
123
|
+
from typing import Dict, Callable, List, Any
|
|
124
|
+
|
|
125
|
+
from adtools import PyEvaluator
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class SortAlgorithmEvaluator(PyEvaluator):
|
|
129
|
+
def evaluate_program(
|
|
130
|
+
self,
|
|
131
|
+
program_str: str,
|
|
132
|
+
callable_functions_dict: Dict[str, Callable] | None,
|
|
133
|
+
callable_functions_list: List[Callable] | None,
|
|
134
|
+
callable_classes_dict: Dict[str, Callable] | None,
|
|
135
|
+
callable_classes_list: List[Callable] | None,
|
|
136
|
+
**kwargs
|
|
137
|
+
) -> Any | None:
|
|
138
|
+
"""Evaluate a given sort algorithm program.
|
|
139
|
+
Args:
|
|
140
|
+
program_str : The raw program text.
|
|
141
|
+
callable_functions_dict: A dict maps function name to callable function.
|
|
142
|
+
callable_functions_list: A list of callable functions.
|
|
143
|
+
callable_classes_dict : A dict maps class name to callable class.
|
|
144
|
+
callable_classes_list : A list of callable classes.
|
|
145
|
+
Return:
|
|
146
|
+
Returns the evaluation result.
|
|
147
|
+
"""
|
|
148
|
+
# Get the sort algorithm
|
|
149
|
+
sort_algo: Callable = callable_functions_dict['merge_sort']
|
|
150
|
+
# Test data
|
|
151
|
+
input = [10, 2, 4, 76, 19, 29, 3, 5, 1]
|
|
152
|
+
# Compute execution time
|
|
153
|
+
start = time.time()
|
|
154
|
+
res = sort_algo(input)
|
|
155
|
+
duration = time.time() - start
|
|
156
|
+
if res == sorted(input): # If the result is correct
|
|
157
|
+
return duration # Return the execution time as the score of the algorithm
|
|
158
|
+
else:
|
|
159
|
+
return None # Return None as the algorithm is incorrect
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
code_generated_by_llm = '''
|
|
163
|
+
def merge_sort(arr):
|
|
164
|
+
if len(arr) <= 1:
|
|
165
|
+
return arr
|
|
166
|
+
|
|
167
|
+
mid = len(arr) // 2
|
|
168
|
+
left = merge_sort(arr[:mid])
|
|
169
|
+
right = merge_sort(arr[mid:])
|
|
170
|
+
|
|
171
|
+
return merge(left, right)
|
|
172
|
+
|
|
173
|
+
def merge(left, right):
|
|
174
|
+
result = []
|
|
175
|
+
i = j = 0
|
|
176
|
+
|
|
177
|
+
while i < len(left) and j < len(right):
|
|
178
|
+
if left[i] < right[j]:
|
|
179
|
+
result.append(left[i])
|
|
180
|
+
i += 1
|
|
181
|
+
else:
|
|
182
|
+
result.append(right[j])
|
|
183
|
+
j += 1
|
|
184
|
+
|
|
185
|
+
result.extend(left[i:])
|
|
186
|
+
result.extend(right[j:])
|
|
187
|
+
|
|
188
|
+
return result
|
|
189
|
+
'''
|
|
190
|
+
|
|
191
|
+
harmful_code_generated_by_llm = '''
|
|
192
|
+
def merge_sort(arr):
|
|
193
|
+
while True:
|
|
194
|
+
pass
|
|
195
|
+
'''
|
|
196
|
+
|
|
197
|
+
if __name__ == '__main__':
|
|
198
|
+
evaluator = SortAlgorithmEvaluator()
|
|
199
|
+
|
|
200
|
+
# Evaluate
|
|
201
|
+
score = evaluator.evaluate(code_generated_by_llm)
|
|
202
|
+
print(f'Score: {score}')
|
|
203
|
+
|
|
204
|
+
# Secure evaluate (the evaluation is executed in a sandbox process)
|
|
205
|
+
score = evaluator.secure_evaluate(code_generated_by_llm, timeout_seconds=10)
|
|
206
|
+
print(f'Score: {score}')
|
|
207
|
+
|
|
208
|
+
# Evaluate a harmful code, the evaluation will be terminated within 10 seconds
|
|
209
|
+
# We will obtain a score of `None` due to the violation of time restriction
|
|
210
|
+
score = evaluator.secure_evaluate(harmful_code_generated_by_llm, timeout_seconds=10)
|
|
211
|
+
print(f'Score: {score}')
|
|
212
|
+
```
|
|
213
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
adtools/__init__.py,sha256=99EPY13OhXs2Zt7IOsa53uQ0Uv-g9dSkHby8mEjDdQM,96
|
|
2
|
+
adtools/evaluator.py,sha256=-VIt9fmR6qjVLQPyKhNf072tJUVndkVJ1PgcHu6Yneo,7200
|
|
3
|
+
adtools/py_code.py,sha256=1XNc5ckX_ivePSGYEEcKHXat-v4zjbxKUcYiTIEjqCw,13649
|
|
4
|
+
py_adtools-0.1.2.dist-info/licenses/LICENSE,sha256=E5GGyecx3y5h2gcEGQloF-rDY9wbaef5IHjRsvtFbt8,1065
|
|
5
|
+
py_adtools-0.1.2.dist-info/METADATA,sha256=B_HjhfOtTiHLNgXOCyRfCAnpp7S73pm064faw13bOjk,6232
|
|
6
|
+
py_adtools-0.1.2.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
7
|
+
py_adtools-0.1.2.dist-info/top_level.txt,sha256=X2kKzmJFDAKR2FWCij5pfMG9pVVjVUomyl4e-1VLXIk,8
|
|
8
|
+
py_adtools-0.1.2.dist-info/RECORD,,
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: py-adtools
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Useful tools for parsing Python programs for algorithm design.
|
|
5
|
-
Home-page: https://github.com/RayZhhh/py-adtools
|
|
6
|
-
Author: Rui Zhang
|
|
7
|
-
Author-email: rzhang.cs@gmail.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Topic :: Scientific/Engineering
|
|
12
|
-
Requires-Python: >=3.10
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Dynamic: author
|
|
16
|
-
Dynamic: author-email
|
|
17
|
-
Dynamic: classifier
|
|
18
|
-
Dynamic: description
|
|
19
|
-
Dynamic: description-content-type
|
|
20
|
-
Dynamic: home-page
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
Dynamic: requires-python
|
|
23
|
-
Dynamic: summary
|
|
24
|
-
|
|
25
|
-
# Useful tools for parsing Python programs for algorithm design
|
|
26
|
-
|
|
27
|
-
------
|
|
28
|
-
|
|
29
|
-
> This repo aims to help develop more powerful [Large Language Models for Algorithm Design (LLM4AD)](https://github.com/Optima-CityU/llm4ad) applications.
|
|
30
|
-
>
|
|
31
|
-
> More tools will be provided soon.
|
|
32
|
-
|
|
33
|
-
------
|
|
34
|
-
|
|
35
|
-
The figure demonstrates how a Python program is parsed into `PyScript`, `PyFunction`, `PyClass,` and `PyProgram` via `adtools`.
|
|
36
|
-
|
|
37
|
-

|
|
38
|
-
|
|
39
|
-
------
|
|
40
|
-
|
|
41
|
-
## Installation
|
|
42
|
-
|
|
43
|
-
> [!TIP]
|
|
44
|
-
>
|
|
45
|
-
> It is recommended to use Python >= 3.10.
|
|
46
|
-
|
|
47
|
-
Run the following instructions to install adtools.
|
|
48
|
-
|
|
49
|
-
```shell
|
|
50
|
-
pip install git+https://github.com/RayZhhh/adtool.git
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
Parse your code (in string) into Python code instances.
|
|
56
|
-
|
|
57
|
-
```python
|
|
58
|
-
from adtools import PyProgram
|
|
59
|
-
|
|
60
|
-
code = r'''
|
|
61
|
-
import ast
|
|
62
|
-
import numpy as np
|
|
63
|
-
|
|
64
|
-
def func():
|
|
65
|
-
a = 5
|
|
66
|
-
return a + a
|
|
67
|
-
|
|
68
|
-
class A(B):
|
|
69
|
-
a=1
|
|
70
|
-
|
|
71
|
-
@yes()
|
|
72
|
-
@deco()
|
|
73
|
-
def __init__(self):
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
def method(self):
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
b=2
|
|
80
|
-
'''
|
|
81
|
-
|
|
82
|
-
p = PyProgram.from_text(code)
|
|
83
|
-
print(p)
|
|
84
|
-
print(f'-------------------------------------')
|
|
85
|
-
print(p.classes[0].functions[0].decorator)
|
|
86
|
-
print(f'-------------------------------------')
|
|
87
|
-
print(p.functions[0].name)
|
|
88
|
-
```
|
|
89
|
-
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
adtools/__init__.py,sha256=l1JmS0mViywF9Nv3Dt4wtrOewfbTwchq_5vfiTwtMSw,62
|
|
2
|
-
adtools/py_code.py,sha256=4_KGvhHZaruVFtZ3LTERkJ-swXgPWyTtEwIMTm39dwQ,13646
|
|
3
|
-
py_adtools-0.1.0.dist-info/licenses/LICENSE,sha256=E5GGyecx3y5h2gcEGQloF-rDY9wbaef5IHjRsvtFbt8,1065
|
|
4
|
-
py_adtools-0.1.0.dist-info/METADATA,sha256=1YEeHkE81yVH6vMGfXcjp9phR8j_uEyFdyf-IsKUlrQ,1870
|
|
5
|
-
py_adtools-0.1.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
6
|
-
py_adtools-0.1.0.dist-info/top_level.txt,sha256=X2kKzmJFDAKR2FWCij5pfMG9pVVjVUomyl4e-1VLXIk,8
|
|
7
|
-
py_adtools-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|