expr-codegen 0.12.0__tar.gz → 0.12.1__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.12.0 → expr_codegen-0.12.1}/PKG-INFO +1 -1
- expr_codegen-0.12.1/expr_codegen/_version.py +1 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/code.py +5 -6
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_group/code.py +5 -7
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_over/code.py +5 -7
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/tool.py +49 -21
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen.egg-info/PKG-INFO +1 -1
- expr_codegen-0.12.0/expr_codegen/_version.py +0 -1
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/LICENSE +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/README.md +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/__init__.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/codes.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/dag.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/expr.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/latex/__init__.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/latex/printer.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/model.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/__init__.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/helper.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/printer.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/ta.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/pandas/template.py.j2 +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_group/__init__.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_group/printer.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_group/template.py.j2 +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_over/__init__.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_over/printer.py +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen/polars_over/template.py.j2 +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen.egg-info/SOURCES.txt +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen.egg-info/dependency_links.txt +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen.egg-info/requires.txt +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/expr_codegen.egg-info/top_level.txt +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/pyproject.toml +0 -0
- {expr_codegen-0.12.0 → expr_codegen-0.12.1}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.12.1"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import Sequence
|
|
2
|
+
from typing import Sequence
|
|
3
3
|
|
|
4
4
|
import jinja2
|
|
5
5
|
from jinja2 import FileSystemLoader, TemplateNotFound
|
|
@@ -27,9 +27,9 @@ def get_groupby_from_tuple(tup, func_name, drop_cols):
|
|
|
27
27
|
return f'df = {func_name}(df).drop(columns={drop_cols})'
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def symbols_to_code(syms
|
|
30
|
+
def symbols_to_code(syms):
|
|
31
31
|
a = [f"{s}" for s in syms]
|
|
32
|
-
b = [f"'{
|
|
32
|
+
b = [f"'{s}'" for s in syms]
|
|
33
33
|
return f"""_ = [{','.join(b)}]
|
|
34
34
|
[{','.join(a)}] = _"""
|
|
35
35
|
|
|
@@ -37,7 +37,6 @@ def symbols_to_code(syms, alias):
|
|
|
37
37
|
def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
38
38
|
filename,
|
|
39
39
|
date='date', asset='asset',
|
|
40
|
-
alias: Dict[str, str] = {},
|
|
41
40
|
extra_codes: Sequence[str] = (),
|
|
42
41
|
**kwargs):
|
|
43
42
|
"""基于模板的代码生成"""
|
|
@@ -92,8 +91,8 @@ def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
|
92
91
|
# 分组应用代码
|
|
93
92
|
groupbys[func_name] = get_groupby_from_tuple(k, func_name, ds)
|
|
94
93
|
|
|
95
|
-
syms1 = symbols_to_code(syms_dst
|
|
96
|
-
syms2 = symbols_to_code(syms_out
|
|
94
|
+
syms1 = symbols_to_code(syms_dst)
|
|
95
|
+
syms2 = symbols_to_code(syms_out)
|
|
97
96
|
|
|
98
97
|
try:
|
|
99
98
|
env = jinja2.Environment(loader=FileSystemLoader(os.path.dirname(__file__)))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import Sequence
|
|
2
|
+
from typing import Sequence
|
|
3
3
|
|
|
4
4
|
import jinja2
|
|
5
5
|
from jinja2 import FileSystemLoader, TemplateNotFound
|
|
@@ -27,10 +27,9 @@ def get_groupby_from_tuple(tup, func_name, drop_cols):
|
|
|
27
27
|
return f'df = {func_name}(df).drop(*{drop_cols})'
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def symbols_to_code(syms
|
|
30
|
+
def symbols_to_code(syms):
|
|
31
31
|
a = [f"{s}" for s in syms]
|
|
32
|
-
b = [f"
|
|
33
|
-
b = [f"'{alias.get(s, s)}'" for s in syms]
|
|
32
|
+
b = [f"'{s}'" for s in syms]
|
|
34
33
|
return f"""_ = [{','.join(b)}]
|
|
35
34
|
[{','.join(a)}] = [pl.col(i) for i in _]"""
|
|
36
35
|
|
|
@@ -38,7 +37,6 @@ def symbols_to_code(syms, alias):
|
|
|
38
37
|
def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
39
38
|
filename,
|
|
40
39
|
date='date', asset='asset',
|
|
41
|
-
alias: Dict[str, str] = {},
|
|
42
40
|
extra_codes: Sequence[str] = (),
|
|
43
41
|
**kwargs):
|
|
44
42
|
"""基于模板的代码生成"""
|
|
@@ -100,8 +98,8 @@ def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
|
100
98
|
# 分组应用代码
|
|
101
99
|
groupbys[func_name] = get_groupby_from_tuple(k, func_name, ds)
|
|
102
100
|
|
|
103
|
-
syms1 = symbols_to_code(syms_dst
|
|
104
|
-
syms2 = symbols_to_code(syms_out
|
|
101
|
+
syms1 = symbols_to_code(syms_dst)
|
|
102
|
+
syms2 = symbols_to_code(syms_out)
|
|
105
103
|
|
|
106
104
|
try:
|
|
107
105
|
env = jinja2.Environment(loader=FileSystemLoader(os.path.dirname(__file__)))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import os
|
|
3
|
-
from typing import Sequence,
|
|
3
|
+
from typing import Sequence, Literal
|
|
4
4
|
|
|
5
5
|
import jinja2
|
|
6
6
|
from jinja2 import FileSystemLoader, TemplateNotFound
|
|
@@ -28,10 +28,9 @@ def get_groupby_from_tuple(tup, func_name, drop_cols):
|
|
|
28
28
|
return f'df = {func_name}(df).drop(*{drop_cols})'
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def symbols_to_code(syms
|
|
31
|
+
def symbols_to_code(syms):
|
|
32
32
|
a = [f"{s}" for s in syms]
|
|
33
|
-
b = [f"
|
|
34
|
-
b = [f"'{alias.get(s, s)}'" for s in syms]
|
|
33
|
+
b = [f"'{s}'" for s in syms]
|
|
35
34
|
return f"""_ = [{','.join(b)}]
|
|
36
35
|
[{','.join(a)}] = [pl.col(i) for i in _]"""
|
|
37
36
|
|
|
@@ -39,7 +38,6 @@ def symbols_to_code(syms, alias):
|
|
|
39
38
|
def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
40
39
|
filename,
|
|
41
40
|
date='date', asset='asset',
|
|
42
|
-
alias: Dict[str, str] = {},
|
|
43
41
|
extra_codes: Sequence[str] = (),
|
|
44
42
|
over_null: Literal['order_by', 'partition_by', None] = 'partition_by',
|
|
45
43
|
**kwargs):
|
|
@@ -118,8 +116,8 @@ def codegen(exprs_ldl: ListDictList, exprs_src, syms_dst,
|
|
|
118
116
|
# 分组应用代码
|
|
119
117
|
groupbys[func_name] = get_groupby_from_tuple(k, func_name, ds)
|
|
120
118
|
|
|
121
|
-
syms1 = symbols_to_code(syms_dst
|
|
122
|
-
syms2 = symbols_to_code(syms_out
|
|
119
|
+
syms1 = symbols_to_code(syms_dst)
|
|
120
|
+
syms2 = symbols_to_code(syms_out)
|
|
123
121
|
|
|
124
122
|
try:
|
|
125
123
|
env = jinja2.Environment(loader=FileSystemLoader(os.path.dirname(__file__)))
|
|
@@ -2,8 +2,9 @@ import inspect
|
|
|
2
2
|
import pathlib
|
|
3
3
|
from functools import lru_cache
|
|
4
4
|
from io import TextIOBase
|
|
5
|
-
from typing import Sequence,
|
|
5
|
+
from typing import Sequence, Union, TypeVar, Optional, Literal
|
|
6
6
|
|
|
7
|
+
import polars as pl
|
|
7
8
|
from black import Mode, format_str
|
|
8
9
|
from loguru import logger
|
|
9
10
|
from sympy import simplify, cse, symbols, numbered_symbols
|
|
@@ -200,8 +201,8 @@ class ExprTool:
|
|
|
200
201
|
template_file: Optional[str] = None,
|
|
201
202
|
replace: bool = True, regroup: bool = False, format: bool = True,
|
|
202
203
|
date='date', asset='asset',
|
|
203
|
-
alias: Dict[str, str] = {},
|
|
204
204
|
extra_codes: Sequence[object] = (),
|
|
205
|
+
table_name: str = 'self',
|
|
205
206
|
**kwargs):
|
|
206
207
|
"""功能集成版,将几个功能写到一起方便使用
|
|
207
208
|
|
|
@@ -223,8 +224,6 @@ class ExprTool:
|
|
|
223
224
|
日期字段名
|
|
224
225
|
asset:str
|
|
225
226
|
资产字段名
|
|
226
|
-
alias: Dict[str,str]
|
|
227
|
-
符号别名。可以变通的传入正则符号名
|
|
228
227
|
extra_codes: Sequence[object]
|
|
229
228
|
需要复制到模板中的额外代码
|
|
230
229
|
|
|
@@ -266,11 +265,11 @@ class ExprTool:
|
|
|
266
265
|
|
|
267
266
|
codes = codegen(exprs_ldl, exprs_src, syms_dst,
|
|
268
267
|
filename=template_file, date=date, asset=asset,
|
|
269
|
-
alias=alias,
|
|
270
268
|
extra_codes=extra_codes,
|
|
269
|
+
table_name=table_name,
|
|
271
270
|
**kwargs)
|
|
272
271
|
|
|
273
|
-
logger.info(f'code is generated')
|
|
272
|
+
logger.info(f'{style} code is generated')
|
|
274
273
|
|
|
275
274
|
if format:
|
|
276
275
|
# 格式化。在遗传算法中没有必要
|
|
@@ -287,6 +286,7 @@ class ExprTool:
|
|
|
287
286
|
style: Literal['pandas', 'polars_group', 'polars_over', 'sql'] = 'polars_over',
|
|
288
287
|
template_file: Optional[str] = None,
|
|
289
288
|
date: str = 'date', asset: str = 'asset',
|
|
289
|
+
table_name: str = 'self',
|
|
290
290
|
**kwargs) -> str:
|
|
291
291
|
"""通过字符串生成代码, 加了缓存,多次调用不重复生成"""
|
|
292
292
|
raw, exprs_list = sources_to_exprs(self.globals_, source, *more_sources, convert_xor=convert_xor)
|
|
@@ -300,6 +300,7 @@ class ExprTool:
|
|
|
300
300
|
# 传入多个列的方法
|
|
301
301
|
extra_codes,
|
|
302
302
|
),
|
|
303
|
+
table_name=table_name,
|
|
303
304
|
**kwargs)
|
|
304
305
|
|
|
305
306
|
# 移回到cache,防止多次调用多次保存
|
|
@@ -316,8 +317,8 @@ class ExprTool:
|
|
|
316
317
|
|
|
317
318
|
|
|
318
319
|
@lru_cache(maxsize=64, typed=True)
|
|
319
|
-
def
|
|
320
|
-
logger.info(f'get func from code')
|
|
320
|
+
def _get_func_from_code_py(code: str):
|
|
321
|
+
logger.info(f'get func from code py')
|
|
321
322
|
globals_ = {}
|
|
322
323
|
exec(code, globals_)
|
|
323
324
|
return globals_['main']
|
|
@@ -332,7 +333,7 @@ def _get_func_from_module(module: str):
|
|
|
332
333
|
|
|
333
334
|
|
|
334
335
|
@lru_cache(maxsize=64, typed=True)
|
|
335
|
-
def
|
|
336
|
+
def _get_func_from_file_py(file: str):
|
|
336
337
|
file = pathlib.Path(file)
|
|
337
338
|
logger.info(f'get func from file "{file.absolute()}"')
|
|
338
339
|
with open(file, 'r', encoding='utf-8') as f:
|
|
@@ -341,6 +342,14 @@ def _get_func_from_file(file: str):
|
|
|
341
342
|
return globals_['main']
|
|
342
343
|
|
|
343
344
|
|
|
345
|
+
@lru_cache(maxsize=64, typed=True)
|
|
346
|
+
def _get_code_from_file(file: str):
|
|
347
|
+
file = pathlib.Path(file)
|
|
348
|
+
logger.info(f'get code from file "{file.absolute()}"')
|
|
349
|
+
with open(file, 'r', encoding='utf-8') as f:
|
|
350
|
+
return f.read()
|
|
351
|
+
|
|
352
|
+
|
|
344
353
|
_TOOL_ = ExprTool()
|
|
345
354
|
|
|
346
355
|
|
|
@@ -354,14 +363,15 @@ def codegen_exec(df: Optional[DataFrame],
|
|
|
354
363
|
style: Literal['pandas', 'polars_group', 'polars_over', 'sql'] = 'polars_over',
|
|
355
364
|
template_file: Optional[str] = None,
|
|
356
365
|
date: str = 'date', asset: str = 'asset',
|
|
357
|
-
|
|
358
|
-
**kwargs) ->
|
|
366
|
+
table_name: str = 'self',
|
|
367
|
+
**kwargs) -> Union[DataFrame, str, None]:
|
|
359
368
|
"""快速转换源代码并执行
|
|
360
369
|
|
|
361
370
|
Parameters
|
|
362
371
|
----------
|
|
363
|
-
df: pl.DataFrame, pd.DataFrame, pl.LazyFrame
|
|
364
|
-
输入DataFrame
|
|
372
|
+
df: pl.DataFrame, pd.DataFrame, pl.LazyFrame,None
|
|
373
|
+
输入DataFrame,输出DataFrame
|
|
374
|
+
输入None,输出代码
|
|
365
375
|
codes:
|
|
366
376
|
函数体。此部分中的表达式会被翻译成目标代码
|
|
367
377
|
extra_codes: str
|
|
@@ -392,10 +402,15 @@ def codegen_exec(df: Optional[DataFrame],
|
|
|
392
402
|
- partition_by: 空值划分到不同分区
|
|
393
403
|
- order_by: 空值排同一分区的前排
|
|
394
404
|
- None: 不做处理
|
|
405
|
+
table_name:str
|
|
406
|
+
表名。style=sql时有效
|
|
395
407
|
|
|
396
408
|
Returns
|
|
397
409
|
-------
|
|
398
410
|
DataFrame
|
|
411
|
+
输出DataFrame
|
|
412
|
+
str
|
|
413
|
+
输出代码
|
|
399
414
|
|
|
400
415
|
Notes
|
|
401
416
|
-----
|
|
@@ -406,16 +421,24 @@ def codegen_exec(df: Optional[DataFrame],
|
|
|
406
421
|
|
|
407
422
|
"""
|
|
408
423
|
if df is not None:
|
|
424
|
+
input_file = None
|
|
409
425
|
# 以下代码都带缓存功能
|
|
410
426
|
if run_file is True:
|
|
411
427
|
assert output_file is not None, 'output_file is required'
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
428
|
+
input_file = str(output_file)
|
|
429
|
+
elif run_file is not False:
|
|
430
|
+
input_file = str(run_file)
|
|
431
|
+
|
|
432
|
+
if input_file is not None:
|
|
433
|
+
if input_file.endswith('.py'):
|
|
434
|
+
return _get_func_from_file_py(input_file)(df)
|
|
435
|
+
elif input_file.endswith('.sql'):
|
|
436
|
+
ctx = pl.SQLContext(frames={table_name: df})
|
|
437
|
+
return ctx.execute(_get_code_from_file(input_file), eager=isinstance(df, _pl_DataFrame))
|
|
417
438
|
else:
|
|
418
|
-
return _get_func_from_module(
|
|
439
|
+
return _get_func_from_module(input_file)(df) # 可断点调试
|
|
440
|
+
else:
|
|
441
|
+
pass
|
|
419
442
|
|
|
420
443
|
# 此代码来自于sympy.var
|
|
421
444
|
frame = inspect.currentframe().f_back
|
|
@@ -432,11 +455,16 @@ def codegen_exec(df: Optional[DataFrame],
|
|
|
432
455
|
style=style, template_file=template_file,
|
|
433
456
|
date=date, asset=asset,
|
|
434
457
|
over_null=over_null,
|
|
458
|
+
table_name=table_name,
|
|
435
459
|
**kwargs
|
|
436
460
|
)
|
|
437
461
|
|
|
438
462
|
if df is None:
|
|
439
|
-
|
|
463
|
+
# 如果df为空,直接返回代码
|
|
464
|
+
return code
|
|
465
|
+
elif style == 'sql':
|
|
466
|
+
ctx = pl.SQLContext(frames={table_name: df})
|
|
467
|
+
return ctx.execute(code, eager=isinstance(df, _pl_DataFrame))
|
|
440
468
|
else:
|
|
441
469
|
# 代码一样时就从缓存中取出函数
|
|
442
|
-
return
|
|
470
|
+
return _get_func_from_code_py(code)(df)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.12.0"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|