expr-codegen 0.8.6__tar.gz → 0.8.7__tar.gz
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.
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/PKG-INFO +4 -4
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/README.md +3 -3
- expr_codegen-0.8.7/expr_codegen/_version.py +1 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/codes.py +115 -70
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen.egg-info/PKG-INFO +4 -4
- expr_codegen-0.8.6/expr_codegen/_version.py +0 -1
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/LICENSE +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/__init__.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/dag.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/expr.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/latex/__init__.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/latex/printer.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/model.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/pandas/__init__.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/pandas/code.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/pandas/printer.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/pandas/template.py.j2 +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/polars/__init__.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/polars/code.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/polars/printer.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/polars/template.py.j2 +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen/tool.py +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen.egg-info/SOURCES.txt +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen.egg-info/dependency_links.txt +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen.egg-info/requires.txt +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/expr_codegen.egg-info/top_level.txt +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/pyproject.toml +0 -0
- {expr_codegen-0.8.6 → expr_codegen-0.8.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: expr_codegen
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.7
|
|
4
4
|
Summary: symbol expression to polars expression tool
|
|
5
5
|
Author-email: wukan <wu-kan@163.com>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -198,11 +198,11 @@ df = codegen_exec(df, _code_block_1, _code_block_2) # 只执行,不保存代
|
|
|
198
198
|
|
|
199
199
|
## 特别语法
|
|
200
200
|
|
|
201
|
-
1.
|
|
202
|
-
2.
|
|
201
|
+
1. 支持`C?T:F`三元表达式(仅可字符串中使用),底层会先转成`C or True if( T )else F`,然后修正成`T if C else F`,最后转成`if_else(C,T,F)`。支持与`if else`混用
|
|
202
|
+
2. `(A<B)*-1`,底层将转换成`int_(A<B)*-1`
|
|
203
203
|
3. 为防止`A==B`被`sympy`替换成`False`,底层会换成`Eq(A,B)`
|
|
204
204
|
4. `A^B`的含义与`convert_xor`参数有关,`convert_xor=True`底层会转换成`Pow(A,B)`,反之为`Xor(A,B)`。默认为`False`,用`**`表示乘方
|
|
205
|
-
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB
|
|
205
|
+
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB是数值,可手工替换成`(A==B)==C`。如果ABC是数值需手工替换成`(A==B)&(B==C)`
|
|
206
206
|
6. 不支持`A<=B<=C`,需手工替换成`(A<=B)&(B<=C)`
|
|
207
207
|
7. 支持`A[0]+B[1]+C[2]`,底层会转成`A+ts_delay(B,1)+ts_delay(C,2)`
|
|
208
208
|
8. 支持`~A`,底层会转换成`Not(A)`
|
|
@@ -148,11 +148,11 @@ df = codegen_exec(df, _code_block_1, _code_block_2) # 只执行,不保存代
|
|
|
148
148
|
|
|
149
149
|
## 特别语法
|
|
150
150
|
|
|
151
|
-
1.
|
|
152
|
-
2.
|
|
151
|
+
1. 支持`C?T:F`三元表达式(仅可字符串中使用),底层会先转成`C or True if( T )else F`,然后修正成`T if C else F`,最后转成`if_else(C,T,F)`。支持与`if else`混用
|
|
152
|
+
2. `(A<B)*-1`,底层将转换成`int_(A<B)*-1`
|
|
153
153
|
3. 为防止`A==B`被`sympy`替换成`False`,底层会换成`Eq(A,B)`
|
|
154
154
|
4. `A^B`的含义与`convert_xor`参数有关,`convert_xor=True`底层会转换成`Pow(A,B)`,反之为`Xor(A,B)`。默认为`False`,用`**`表示乘方
|
|
155
|
-
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB
|
|
155
|
+
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB是数值,可手工替换成`(A==B)==C`。如果ABC是数值需手工替换成`(A==B)&(B==C)`
|
|
156
156
|
6. 不支持`A<=B<=C`,需手工替换成`(A<=B)&(B<=C)`
|
|
157
157
|
7. 支持`A[0]+B[1]+C[2]`,底层会转成`A+ts_delay(B,1)+ts_delay(C,2)`
|
|
158
158
|
8. 支持`~A`,底层会转换成`Not(A)`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.8.7"
|
|
@@ -7,8 +7,100 @@ from sympy import Add, Mul, Pow, Eq
|
|
|
7
7
|
from expr_codegen.expr import register_symbols, dict_to_exprs
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class
|
|
11
|
-
"""
|
|
10
|
+
class SyntaxTransformer(ast.NodeTransformer):
|
|
11
|
+
"""修改语法。注意:一定要修改语法后才能改名"""
|
|
12
|
+
|
|
13
|
+
# ^ 是异或还是乘方呢?
|
|
14
|
+
convert_xor: bool = True
|
|
15
|
+
|
|
16
|
+
def visit_Compare(self, node):
|
|
17
|
+
assert len(node.comparators) == 1, f"不支持连续等号,请手工添加括号, {ast.unparse(node)}"
|
|
18
|
+
|
|
19
|
+
self.generic_visit(node)
|
|
20
|
+
return node
|
|
21
|
+
|
|
22
|
+
def visit_IfExp(self, node):
|
|
23
|
+
# 三元表达式。需要在外部提前替换成or True if else
|
|
24
|
+
# 只要body区域,出现了or True,就认为是特殊处理过的
|
|
25
|
+
if isinstance(node.body, ast.BoolOp) and isinstance(node.body.op, ast.Or):
|
|
26
|
+
if isinstance(node.body.values[-1], ast.Constant):
|
|
27
|
+
if node.body.values[-1].value == True:
|
|
28
|
+
node.test, node.body = node.body.values[0], node.test
|
|
29
|
+
|
|
30
|
+
node = ast.Call(
|
|
31
|
+
func=ast.Name(id='if_else', ctx=ast.Load()),
|
|
32
|
+
args=[node.test, node.body, node.orelse],
|
|
33
|
+
keywords=[],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
self.generic_visit(node)
|
|
37
|
+
return node
|
|
38
|
+
|
|
39
|
+
def visit_BinOp(self, node):
|
|
40
|
+
# TypeError: unsupported operand type(s) for *: 'StrictLessThan' and 'int'
|
|
41
|
+
if isinstance(node.op, (ast.Mult, ast.Add, ast.Div, ast.Sub)):
|
|
42
|
+
# (OPEN < CLOSE) * -1
|
|
43
|
+
if isinstance(node.left, ast.Compare):
|
|
44
|
+
node.left = ast.Call(
|
|
45
|
+
func=ast.Name(id='int_', ctx=ast.Load()),
|
|
46
|
+
args=[node.left],
|
|
47
|
+
keywords=[],
|
|
48
|
+
)
|
|
49
|
+
# -1*(OPEN < CLOSE)
|
|
50
|
+
if isinstance(node.right, ast.Compare):
|
|
51
|
+
node.right = ast.Call(
|
|
52
|
+
func=ast.Name(id='int_', ctx=ast.Load()),
|
|
53
|
+
args=[node.right],
|
|
54
|
+
keywords=[],
|
|
55
|
+
)
|
|
56
|
+
# 这种情况,已经包含
|
|
57
|
+
# (OPEN < CLOSE)*(OPEN < CLOSE)
|
|
58
|
+
|
|
59
|
+
if isinstance(node.op, ast.BitXor):
|
|
60
|
+
# ^ 运算符,转换为pow还是xor
|
|
61
|
+
if self.convert_xor:
|
|
62
|
+
node = ast.Call(
|
|
63
|
+
func=ast.Name(id='Pow', ctx=ast.Load()),
|
|
64
|
+
args=[node.left, node.right],
|
|
65
|
+
keywords=[],
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
node = ast.Call(
|
|
69
|
+
func=ast.Name(id='Xor', ctx=ast.Load()),
|
|
70
|
+
args=[node.left, node.right],
|
|
71
|
+
keywords=[],
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
self.generic_visit(node)
|
|
75
|
+
return node
|
|
76
|
+
|
|
77
|
+
def visit_UnaryOp(self, node):
|
|
78
|
+
# ~ts_delay 报错,替换成Not(ts_delay)
|
|
79
|
+
if isinstance(node.op, ast.Invert):
|
|
80
|
+
node = ast.Call(
|
|
81
|
+
func=ast.Name(id='Not', ctx=ast.Load()),
|
|
82
|
+
args=[node.operand],
|
|
83
|
+
keywords=[],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.generic_visit(node)
|
|
87
|
+
return node
|
|
88
|
+
|
|
89
|
+
def visit_Subscript(self, node):
|
|
90
|
+
if node.slice.value == 0:
|
|
91
|
+
node = node.value
|
|
92
|
+
else:
|
|
93
|
+
node = ast.Call(
|
|
94
|
+
func=ast.Name(id='ts_delay', ctx=ast.Load()),
|
|
95
|
+
args=[node.value, node.slice],
|
|
96
|
+
keywords=[],
|
|
97
|
+
)
|
|
98
|
+
self.generic_visit(node)
|
|
99
|
+
return node
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class RenameTransformer(ast.NodeTransformer):
|
|
103
|
+
"""改名处理。改名前需要语法规范"""
|
|
12
104
|
|
|
13
105
|
# 旧记录
|
|
14
106
|
funcs_old = set()
|
|
@@ -25,8 +117,6 @@ class SympyTransformer(ast.NodeTransformer):
|
|
|
25
117
|
# !!!一定要在drop_symbols时排除
|
|
26
118
|
args_map = {'True': "_TRUE_", 'False': "_FALSE_", 'None': "_NONE_"}
|
|
27
119
|
targets_map = {} # 只对非下划线开头的生效
|
|
28
|
-
# ^ 是异或还是乘方呢?
|
|
29
|
-
convert_xor: bool = True
|
|
30
120
|
|
|
31
121
|
def config_map(self, funcs_map, args_map, targets_map):
|
|
32
122
|
self.funcs_map = funcs_map
|
|
@@ -115,6 +205,7 @@ class SympyTransformer(ast.NodeTransformer):
|
|
|
115
205
|
self.args_old.add(node.left.id)
|
|
116
206
|
node.left.id = self.args_map.get(node.left.id, node.left.id)
|
|
117
207
|
self.args_new.add(node.left.id)
|
|
208
|
+
|
|
118
209
|
for i, com in enumerate(node.comparators):
|
|
119
210
|
if isinstance(com, ast.Name):
|
|
120
211
|
self.args_old.add(com.id)
|
|
@@ -128,44 +219,23 @@ class SympyTransformer(ast.NodeTransformer):
|
|
|
128
219
|
node.comparators[i] = ast.Name(new_com_value, ctx=ast.Load())
|
|
129
220
|
self.args_new.add(new_com_value)
|
|
130
221
|
|
|
131
|
-
assert len(node.comparators) == 1, f"不支持连续等号,请手工添加括号, {ast.unparse(node)}"
|
|
132
|
-
|
|
133
222
|
self.generic_visit(node)
|
|
134
223
|
return node
|
|
135
224
|
|
|
136
225
|
def visit_IfExp(self, node):
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
226
|
+
if isinstance(node.body, ast.Name):
|
|
227
|
+
self.args_old.add(node.body.id)
|
|
228
|
+
node.body.id = self.args_map.get(node.body.id, node.body.id)
|
|
229
|
+
self.args_new.add(node.body.id)
|
|
230
|
+
if isinstance(node.orelse, ast.Name):
|
|
231
|
+
self.args_old.add(node.orelse.id)
|
|
232
|
+
node.orelse.id = self.args_map.get(node.orelse.id, node.orelse.id)
|
|
233
|
+
self.args_new.add(node.orelse.id)
|
|
145
234
|
|
|
146
235
|
self.generic_visit(node)
|
|
147
236
|
return node
|
|
148
237
|
|
|
149
238
|
def visit_BinOp(self, node):
|
|
150
|
-
# TypeError: unsupported operand type(s) for *: 'StrictLessThan' and 'int'
|
|
151
|
-
if isinstance(node.op, (ast.Mult, ast.Add, ast.Div, ast.Sub)):
|
|
152
|
-
# (OPEN < CLOSE) * -1
|
|
153
|
-
if isinstance(node.left, ast.Compare):
|
|
154
|
-
node.left = ast.Call(
|
|
155
|
-
func=ast.Name(id='int_', ctx=ast.Load()),
|
|
156
|
-
args=[node.left],
|
|
157
|
-
keywords=[],
|
|
158
|
-
)
|
|
159
|
-
# -1*(OPEN < CLOSE)
|
|
160
|
-
if isinstance(node.right, ast.Compare):
|
|
161
|
-
node.right = ast.Call(
|
|
162
|
-
func=ast.Name(id='int_', ctx=ast.Load()),
|
|
163
|
-
args=[node.right],
|
|
164
|
-
keywords=[],
|
|
165
|
-
)
|
|
166
|
-
# 这种情况,已经包含
|
|
167
|
-
# (OPEN < CLOSE)*(OPEN < CLOSE)
|
|
168
|
-
|
|
169
239
|
if isinstance(node.left, ast.Name):
|
|
170
240
|
self.args_old.add(node.left.id)
|
|
171
241
|
node.left.id = self.args_map.get(node.left.id, node.left.id)
|
|
@@ -189,21 +259,6 @@ class SympyTransformer(ast.NodeTransformer):
|
|
|
189
259
|
node.right = ast.Name(new_node_value, ctx=ast.Load())
|
|
190
260
|
self.args_new.add(new_node_value)
|
|
191
261
|
|
|
192
|
-
if isinstance(node.op, ast.BitXor):
|
|
193
|
-
# ^ 运算符,转换为pow还是xor
|
|
194
|
-
if self.convert_xor:
|
|
195
|
-
node = ast.Call(
|
|
196
|
-
func=ast.Name(id='Pow', ctx=ast.Load()),
|
|
197
|
-
args=[node.left, node.right],
|
|
198
|
-
keywords=[],
|
|
199
|
-
)
|
|
200
|
-
else:
|
|
201
|
-
node = ast.Call(
|
|
202
|
-
func=ast.Name(id='Xor', ctx=ast.Load()),
|
|
203
|
-
args=[node.left, node.right],
|
|
204
|
-
keywords=[],
|
|
205
|
-
)
|
|
206
|
-
|
|
207
262
|
self.generic_visit(node)
|
|
208
263
|
return node
|
|
209
264
|
|
|
@@ -221,26 +276,14 @@ class SympyTransformer(ast.NodeTransformer):
|
|
|
221
276
|
node.operand = ast.Name(new_operand_value, ctx=ast.Load())
|
|
222
277
|
self.args_new.add(new_operand_value)
|
|
223
278
|
|
|
224
|
-
# ~ts_delay 报错,替换成Not(ts_delay)
|
|
225
|
-
if isinstance(node.op, ast.Invert):
|
|
226
|
-
node = ast.Call(
|
|
227
|
-
func=ast.Name(id='Not', ctx=ast.Load()),
|
|
228
|
-
args=[node.operand],
|
|
229
|
-
keywords=[],
|
|
230
|
-
)
|
|
231
|
-
|
|
232
279
|
self.generic_visit(node)
|
|
233
280
|
return node
|
|
234
281
|
|
|
235
282
|
def visit_Subscript(self, node):
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
func=ast.Name(id='ts_delay', ctx=ast.Load()),
|
|
241
|
-
args=[node.value, node.slice],
|
|
242
|
-
keywords=[],
|
|
243
|
-
)
|
|
283
|
+
self.args_old.add(node.value.id)
|
|
284
|
+
node.value.id = self.args_map.get(node.value.id, node.value.id)
|
|
285
|
+
self.args_new.add(node.value.id)
|
|
286
|
+
|
|
244
287
|
self.generic_visit(node)
|
|
245
288
|
return node
|
|
246
289
|
|
|
@@ -260,13 +303,13 @@ def sources_to_asts(*sources, convert_xor: bool):
|
|
|
260
303
|
return '\n'.join(raw), assigns, funcs_new, args_new, targets_new
|
|
261
304
|
|
|
262
305
|
|
|
263
|
-
def source_replace(source):
|
|
306
|
+
def source_replace(source: str) -> str:
|
|
264
307
|
# 三元表达式转换成 错误版if( )else,一定得在Transformer中修正
|
|
265
308
|
num = 1
|
|
266
309
|
while num > 0:
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
source, num = re.subn(r'\?(.+?):(.+?)', r' if( \1 )else \2', source, flags=re.S)
|
|
310
|
+
# 利用or 的优先级最低,构造特殊的if else,只要出现,就认为位置要替换
|
|
311
|
+
# C?T:F --> C or True if( T )else F
|
|
312
|
+
source, num = re.subn(r'\?(.+?):(.+?)', r' or True if( \1 )else \2', source, flags=re.S)
|
|
270
313
|
# break
|
|
271
314
|
# 或、与
|
|
272
315
|
source = source.replace('||', '|').replace('&&', '&')
|
|
@@ -276,8 +319,10 @@ def source_replace(source):
|
|
|
276
319
|
def _source_to_asts(source, convert_xor: bool):
|
|
277
320
|
"""源代码"""
|
|
278
321
|
tree = ast.parse(source_replace(source))
|
|
279
|
-
|
|
280
|
-
|
|
322
|
+
t1 = SyntaxTransformer()
|
|
323
|
+
t1.convert_xor = convert_xor
|
|
324
|
+
t1.visit(tree)
|
|
325
|
+
t = RenameTransformer()
|
|
281
326
|
t.visit(tree)
|
|
282
327
|
|
|
283
328
|
raw = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: expr_codegen
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.7
|
|
4
4
|
Summary: symbol expression to polars expression tool
|
|
5
5
|
Author-email: wukan <wu-kan@163.com>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -198,11 +198,11 @@ df = codegen_exec(df, _code_block_1, _code_block_2) # 只执行,不保存代
|
|
|
198
198
|
|
|
199
199
|
## 特别语法
|
|
200
200
|
|
|
201
|
-
1.
|
|
202
|
-
2.
|
|
201
|
+
1. 支持`C?T:F`三元表达式(仅可字符串中使用),底层会先转成`C or True if( T )else F`,然后修正成`T if C else F`,最后转成`if_else(C,T,F)`。支持与`if else`混用
|
|
202
|
+
2. `(A<B)*-1`,底层将转换成`int_(A<B)*-1`
|
|
203
203
|
3. 为防止`A==B`被`sympy`替换成`False`,底层会换成`Eq(A,B)`
|
|
204
204
|
4. `A^B`的含义与`convert_xor`参数有关,`convert_xor=True`底层会转换成`Pow(A,B)`,反之为`Xor(A,B)`。默认为`False`,用`**`表示乘方
|
|
205
|
-
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB
|
|
205
|
+
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB是数值,可手工替换成`(A==B)==C`。如果ABC是数值需手工替换成`(A==B)&(B==C)`
|
|
206
206
|
6. 不支持`A<=B<=C`,需手工替换成`(A<=B)&(B<=C)`
|
|
207
207
|
7. 支持`A[0]+B[1]+C[2]`,底层会转成`A+ts_delay(B,1)+ts_delay(C,2)`
|
|
208
208
|
8. 支持`~A`,底层会转换成`Not(A)`
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.8.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|