cnhkmcp 2.3.4__py3-none-any.whl → 2.3.6__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.
- cnhkmcp/__init__.py +1 -1
- cnhkmcp/untracked/AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221/BRAIN_AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221Mac_Linux/321/207/320/231/320/230/321/206/320/254/320/274.zip +0 -0
- cnhkmcp/untracked/AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221//321/205/320/237/320/234/321/205/320/227/342/225/227/321/205/320/276/320/231/321/210/320/263/320/225AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221_Windows/321/207/320/231/320/230/321/206/320/254/320/274.exe +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +6 -3
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +5 -3
- cnhkmcp/untracked/APP/Tranformer/validator.py +149 -32
- cnhkmcp/untracked/APP/ace_lib.py +5 -3
- cnhkmcp/untracked/APP/blueprints/parsetab.py +60 -0
- cnhkmcp/untracked/APP/blueprints/validator.py +1080 -0
- cnhkmcp/untracked/APP/requirements.txt +0 -0
- cnhkmcp/untracked/APP/static/decoder.js +164 -38
- cnhkmcp/untracked/APP/static/simulator.js +15 -15
- cnhkmcp/untracked/APP/templates/feature_engineering.html +78 -78
- cnhkmcp/untracked/APP/templates/idea_house.html +49 -49
- cnhkmcp/untracked/APP/templates/index.html +58 -58
- cnhkmcp/untracked/APP/templates/inspiration_house.html +64 -64
- cnhkmcp/untracked/APP/templates/paper_analysis.html +21 -21
- cnhkmcp/untracked/APP/templates/simulator.html +38 -38
- cnhkmcp/untracked/APP/templates/transformer_web.html +24 -24
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-data-feature-engineering/SKILL.md +15 -15
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927658009727000.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927658519220600.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659002708800.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659510920900.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769927659982673800.json +10 -0
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py +153 -32
- cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +51 -3
- cnhkmcp/untracked/arxiv_api.py +5 -3
- cnhkmcp/untracked/back_up/forum_functions.py +5 -3
- cnhkmcp/untracked/forum_functions.py +5 -3
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +5 -3
- cnhkmcp/untracked/platform_functions.py +5 -3
- cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/validator.py +149 -32
- cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/SKILL.md +8 -2
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/ace.log +0 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/idea_context.json +15 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/__init__.py +0 -0
- cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/parse_idea_file.py +33 -1
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/parsetab.py +60 -0
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/validator.py +1086 -0
- cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +5 -3
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/METADATA +1 -1
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/RECORD +60 -48
- /cnhkmcp/untracked/{skills/brain-inspectTemplate-create-Setting → APP/hkSimulator}/ace.log +0 -0
- /cnhkmcp/untracked/{skills/brain-inspectTemplate-create-Setting/scripts/__init__.py → APP/hkSimulator/autosim_20260201_172428.log} +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/.gitignore +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/ace_lib.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/config.json +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/fundamental28_GLB_1_idea_1769874845978315000.json +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/helpful_functions.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/build_alpha_list.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/fetch_sim_options.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/load_credentials.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/process_template.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/scripts/resolve_settings.py +0 -0
- /cnhkmcp/untracked/skills/{brain-inspectTemplate-create-Setting → brain-inspectRawTemplate-create-Setting}/sim_options_snapshot.json +0 -0
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/licenses/LICENSE +0 -0
- {cnhkmcp-2.3.4.dist-info → cnhkmcp-2.3.6.dist-info}/top_level.txt +0 -0
cnhkmcp/__init__.py
CHANGED
|
@@ -14,9 +14,12 @@ import sys
|
|
|
14
14
|
|
|
15
15
|
# try set gbk problem
|
|
16
16
|
try:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
import io
|
|
18
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
19
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
20
|
+
elif hasattr(sys.stdout, 'buffer'):
|
|
21
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
22
|
+
except Exception:
|
|
20
23
|
pass
|
|
21
24
|
|
|
22
25
|
# --- Auto-Install Dependencies ---
|
|
@@ -18,9 +18,11 @@ import io
|
|
|
18
18
|
|
|
19
19
|
# try set gbk problem
|
|
20
20
|
try:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
22
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
23
|
+
elif hasattr(sys.stdout, 'buffer'):
|
|
24
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
25
|
+
except Exception:
|
|
24
26
|
pass
|
|
25
27
|
|
|
26
28
|
# 获取脚本所在目录(项目根目录)
|
|
@@ -65,51 +65,65 @@ supported_functions = {
|
|
|
65
65
|
'ts_delay': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
66
66
|
'ts_corr': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
67
67
|
'ts_zscore': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
68
|
-
'ts_returns': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'mode']},
|
|
68
|
+
'ts_returns': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'mode'], 'keyword_only': True},
|
|
69
69
|
'ts_product': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
70
|
-
|
|
70
|
+
# Platform: ts_backfill(x, d)
|
|
71
|
+
'ts_backfill': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'd']},
|
|
71
72
|
'days_from_last_change': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
|
|
72
73
|
'last_diff_value': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
73
|
-
|
|
74
|
-
'
|
|
74
|
+
# Platform: ts_scale(x, d, constant=0)
|
|
75
|
+
'ts_scale': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'constant'], 'keyword_only': True},
|
|
76
|
+
# Platform: ts_entropy(x, d)
|
|
77
|
+
'ts_entropy': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'd']},
|
|
75
78
|
'ts_step': {'min_args': 1, 'max_args': 1, 'arg_types': ['number']},
|
|
76
79
|
'ts_sum': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
77
80
|
'ts_co_kurtosis': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
78
81
|
'inst_tvr': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
79
|
-
'ts_decay_exp_window': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'factor']},
|
|
82
|
+
'ts_decay_exp_window': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'factor'], 'keyword_only': True},
|
|
80
83
|
'ts_av_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
81
84
|
'ts_kurtosis': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
82
|
-
|
|
85
|
+
# Platform: ts_min_max_diff(x, d, f=0.5)
|
|
86
|
+
'ts_min_max_diff': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'f'], 'keyword_only': True},
|
|
83
87
|
'ts_arg_max': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
84
88
|
'ts_max': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
85
|
-
|
|
86
|
-
'
|
|
89
|
+
# Platform: ts_min_max_cps(x, d, f=2)
|
|
90
|
+
'ts_min_max_cps': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'f'], 'keyword_only': True},
|
|
91
|
+
# Platform: ts_rank(x, d, constant=0)
|
|
92
|
+
'ts_rank': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'constant'], 'keyword_only': True},
|
|
87
93
|
'ts_ir': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
88
94
|
'ts_theilsen': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
89
|
-
|
|
90
|
-
'
|
|
91
|
-
|
|
95
|
+
# Platform: hump_decay(x, p=0)
|
|
96
|
+
'hump_decay': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'p'], 'keyword_only': True},
|
|
97
|
+
# Platform: ts_weighted_decay(x, k=0.5)
|
|
98
|
+
'ts_weighted_decay': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'k'], 'keyword_only': True},
|
|
99
|
+
# Platform: ts_quantile(x, d, driver="gaussian")
|
|
100
|
+
'ts_quantile': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'string'], 'param_names': ['x', 'd', 'driver'], 'keyword_only': True},
|
|
92
101
|
'ts_min': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
93
102
|
'ts_count_nans': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
94
103
|
'ts_covariance': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
95
104
|
'ts_co_skewness': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number']},
|
|
96
105
|
'ts_min_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
97
|
-
|
|
98
|
-
'
|
|
99
|
-
|
|
106
|
+
# Platform: ts_decay_linear(x, d, dense=false)
|
|
107
|
+
'ts_decay_linear': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'boolean'], 'param_names': ['x', 'd', 'dense'], 'keyword_only': True},
|
|
108
|
+
# Platform: jump_decay(x, d, sensitivity=0.5, force=0.1)
|
|
109
|
+
'jump_decay': {'min_args': 2, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'd', 'sensitivity', 'force'], 'keyword_only': True},
|
|
110
|
+
# Platform: ts_moment(x, d, k=0)
|
|
111
|
+
'ts_moment': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'number', 'number'], 'param_names': ['x', 'd', 'k'], 'keyword_only': True},
|
|
100
112
|
'ts_arg_min': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
101
|
-
'ts_regression': {'min_args': 3, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'lag', 'rettype']},
|
|
113
|
+
'ts_regression': {'min_args': 3, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'lag', 'rettype'], 'keyword_only': True},
|
|
102
114
|
'ts_skewness': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
103
115
|
'ts_max_diff': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
104
116
|
'kth_element': {'min_args': 3, 'max_args': 3, 'arg_types': ['expression', 'number', 'number']},
|
|
105
117
|
'hump': {'min_args': 1, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'hump']},
|
|
106
118
|
'ts_median': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
107
119
|
'ts_delta': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number']},
|
|
108
|
-
|
|
109
|
-
'
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
120
|
+
# Platform: ts_poly_regression(y, x, d, k=1) and k must be keyword if provided
|
|
121
|
+
'ts_poly_regression': {'min_args': 3, 'max_args': 4, 'arg_types': ['expression', 'expression', 'number', 'number'], 'param_names': ['y', 'x', 'd', 'k'], 'keyword_only': True, 'keyword_only_from': 3},
|
|
122
|
+
'ts_target_tvr_decay': {'min_args': 1, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
123
|
+
'ts_target_tvr_delta_limit': {'min_args': 2, 'max_args': 5, 'arg_types': ['expression', 'expression', 'number', 'number', 'number'], 'param_names': ['x', 'y', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
124
|
+
'ts_target_tvr_hump': {'min_args': 1, 'max_args': 4, 'arg_types': ['expression', 'number', 'number', 'number'], 'param_names': ['x', 'lambda_min', 'lambda_max', 'target_tvr'], 'keyword_only': True},
|
|
125
|
+
# Platform: ts_delta_limit(x, y, limit_volume=0.1)
|
|
126
|
+
'ts_delta_limit': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'number'], 'param_names': ['x', 'y', 'limit_volume'], 'keyword_only': True},
|
|
113
127
|
|
|
114
128
|
# Special 类别函数
|
|
115
129
|
'inst_pnl': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
|
|
@@ -276,6 +290,10 @@ class ExpressionValidator:
|
|
|
276
290
|
self.parser = yacc.yacc(module=self, debug=False)
|
|
277
291
|
# 错误信息存储
|
|
278
292
|
self.errors = []
|
|
293
|
+
# Cache for unit inference (unit/scalar/category)
|
|
294
|
+
self._unit_cache: Dict[int, str] = {}
|
|
295
|
+
# Cache for derived category detection (bucket/group_cartesian_product outputs)
|
|
296
|
+
self._derived_category_cache: Dict[int, bool] = {}
|
|
279
297
|
|
|
280
298
|
# 词法分析器规则
|
|
281
299
|
tokens = ('FUNCTION', 'FIELD', 'NUMBER', 'LPAREN', 'RPAREN',
|
|
@@ -509,6 +527,12 @@ class ExpressionValidator:
|
|
|
509
527
|
return self._validate_add(args, is_in_group_arg)
|
|
510
528
|
|
|
511
529
|
errors = []
|
|
530
|
+
|
|
531
|
+
# Keyword-only enforcement for optional parameters.
|
|
532
|
+
# If enabled, only the required leading arguments can be positional.
|
|
533
|
+
keyword_only_from = function_info.get('keyword_only_from')
|
|
534
|
+
if keyword_only_from is None and function_info.get('keyword_only'):
|
|
535
|
+
keyword_only_from = function_info.get('min_args', 0)
|
|
512
536
|
|
|
513
537
|
# 检查参数数量
|
|
514
538
|
if len(args) < function_info['min_args']:
|
|
@@ -545,12 +569,14 @@ class ExpressionValidator:
|
|
|
545
569
|
errors.append(f"函数 {function_name} 不存在参数 '{arg['name']}'")
|
|
546
570
|
elif arg['type'] == 'positional':
|
|
547
571
|
# 位置参数(字典形式)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
572
|
+
if keyword_only_from is not None and positional_index >= keyword_only_from:
|
|
573
|
+
param_name = None
|
|
574
|
+
if 'param_names' in function_info and positional_index < len(function_info['param_names']):
|
|
575
|
+
param_name = function_info['param_names'][positional_index]
|
|
576
|
+
if param_name:
|
|
577
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数 '{param_name}='")
|
|
578
|
+
else:
|
|
579
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数")
|
|
554
580
|
else:
|
|
555
581
|
# 验证位置参数的类型
|
|
556
582
|
if positional_index < len(function_info['arg_types']):
|
|
@@ -564,12 +590,14 @@ class ExpressionValidator:
|
|
|
564
590
|
positional_index += 1
|
|
565
591
|
else:
|
|
566
592
|
# 位置参数(直接ASTNode形式)
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
593
|
+
if keyword_only_from is not None and positional_index >= keyword_only_from:
|
|
594
|
+
param_name = None
|
|
595
|
+
if 'param_names' in function_info and positional_index < len(function_info['param_names']):
|
|
596
|
+
param_name = function_info['param_names'][positional_index]
|
|
597
|
+
if param_name:
|
|
598
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数 '{param_name}='")
|
|
599
|
+
else:
|
|
600
|
+
errors.append(f"函数 {function_name} 的第{positional_index+1}个参数必须使用命名参数")
|
|
573
601
|
else:
|
|
574
602
|
# 验证位置参数的类型
|
|
575
603
|
if positional_index < len(function_info['arg_types']):
|
|
@@ -583,6 +611,15 @@ class ExpressionValidator:
|
|
|
583
611
|
def _validate_arg_type(self, arg: ASTNode, expected_type: str, arg_index: int, function_name: str, is_in_group_arg: bool = False) -> List[str]:
|
|
584
612
|
"""验证参数类型是否符合预期"""
|
|
585
613
|
errors = []
|
|
614
|
+
|
|
615
|
+
# Unit compatibility check
|
|
616
|
+
# bucket()/group_cartesian_product() output a derived category (grouping key).
|
|
617
|
+
# It can only be consumed where a category/grouping key is expected.
|
|
618
|
+
if self._is_derived_category(arg) and expected_type != 'category':
|
|
619
|
+
errors.append(
|
|
620
|
+
f"Incompatible unit for input of \"{function_name}\" at index {arg_index}, expected \"Unit[]\", found \"Unit[Group:1]\""
|
|
621
|
+
)
|
|
622
|
+
return errors
|
|
586
623
|
|
|
587
624
|
# 首先检查是否是group类型字段,如果是则只能用于Group类型函数
|
|
588
625
|
# 但是如果当前函数是group_xxx或在group函数的参数链中,则允许使用
|
|
@@ -618,6 +655,83 @@ class ExpressionValidator:
|
|
|
618
655
|
|
|
619
656
|
return errors
|
|
620
657
|
|
|
658
|
+
def _infer_unit(self, node: ASTNode) -> str:
|
|
659
|
+
"""Infer the Unit kind of an AST node.
|
|
660
|
+
|
|
661
|
+
Returns:
|
|
662
|
+
'unit' - regular numeric time-series Unit[]
|
|
663
|
+
'scalar' - literals (numbers/booleans/strings)
|
|
664
|
+
'category' - category/grouping keys (industry/sector or derived via bucket/cartesian)
|
|
665
|
+
"""
|
|
666
|
+
if node is None:
|
|
667
|
+
return 'unit'
|
|
668
|
+
|
|
669
|
+
cache_key = id(node)
|
|
670
|
+
cached = self._unit_cache.get(cache_key)
|
|
671
|
+
if cached is not None:
|
|
672
|
+
return cached
|
|
673
|
+
|
|
674
|
+
unit = 'unit'
|
|
675
|
+
|
|
676
|
+
if node.node_type in {'number', 'boolean', 'string'}:
|
|
677
|
+
unit = 'scalar'
|
|
678
|
+
elif node.node_type in {'field', 'identifier'}:
|
|
679
|
+
unit = 'unit'
|
|
680
|
+
elif node.node_type == 'category':
|
|
681
|
+
unit = 'category'
|
|
682
|
+
elif node.node_type in {'unop', 'binop'}:
|
|
683
|
+
child_units = [self._infer_unit(child) for child in node.children if hasattr(child, 'node_type')]
|
|
684
|
+
unit = 'category' if 'category' in child_units else 'unit'
|
|
685
|
+
elif node.node_type == 'function':
|
|
686
|
+
fname = node.value
|
|
687
|
+
if fname in {'bucket', 'group_cartesian_product'}:
|
|
688
|
+
unit = 'category'
|
|
689
|
+
else:
|
|
690
|
+
first_arg = None
|
|
691
|
+
for child in node.children:
|
|
692
|
+
if isinstance(child, dict):
|
|
693
|
+
if child.get('type') == 'positional':
|
|
694
|
+
first_arg = child.get('value')
|
|
695
|
+
break
|
|
696
|
+
else:
|
|
697
|
+
first_arg = child
|
|
698
|
+
break
|
|
699
|
+
if hasattr(first_arg, 'node_type'):
|
|
700
|
+
unit = self._infer_unit(first_arg)
|
|
701
|
+
else:
|
|
702
|
+
unit = 'unit'
|
|
703
|
+
|
|
704
|
+
self._unit_cache[cache_key] = unit
|
|
705
|
+
return unit
|
|
706
|
+
|
|
707
|
+
def _is_derived_category(self, node: ASTNode) -> bool:
|
|
708
|
+
"""Return True if node is a derived category/grouping key (e.g., bucket/cartesian output)."""
|
|
709
|
+
if node is None:
|
|
710
|
+
return False
|
|
711
|
+
|
|
712
|
+
cache_key = id(node)
|
|
713
|
+
cached = self._derived_category_cache.get(cache_key)
|
|
714
|
+
if cached is not None:
|
|
715
|
+
return cached
|
|
716
|
+
|
|
717
|
+
derived = False
|
|
718
|
+
if node.node_type == 'function' and node.value in {'bucket', 'group_cartesian_product'}:
|
|
719
|
+
derived = True
|
|
720
|
+
elif node.node_type in {'unop', 'binop'}:
|
|
721
|
+
derived = any(
|
|
722
|
+
self._is_derived_category(child)
|
|
723
|
+
for child in node.children
|
|
724
|
+
if hasattr(child, 'node_type')
|
|
725
|
+
)
|
|
726
|
+
elif node.node_type == 'function':
|
|
727
|
+
derived = any(
|
|
728
|
+
self._is_derived_category(child.get('value')) if isinstance(child, dict) else self._is_derived_category(child)
|
|
729
|
+
for child in node.children
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
self._derived_category_cache[cache_key] = derived
|
|
733
|
+
return derived
|
|
734
|
+
|
|
621
735
|
def _validate_add(self, args: List[Any], is_in_group_arg: bool = False) -> List[str]:
|
|
622
736
|
"""Validate add(x, y, ..., filter=false).
|
|
623
737
|
|
|
@@ -883,6 +997,9 @@ class ExpressionValidator:
|
|
|
883
997
|
"""
|
|
884
998
|
# 重置错误列表
|
|
885
999
|
self.errors = []
|
|
1000
|
+
# Reset unit inference cache for this expression
|
|
1001
|
+
self._unit_cache = {}
|
|
1002
|
+
self._derived_category_cache = {}
|
|
886
1003
|
|
|
887
1004
|
try:
|
|
888
1005
|
expression = expression.strip()
|
cnhkmcp/untracked/APP/ace_lib.py
CHANGED
|
@@ -17,9 +17,11 @@ import sys
|
|
|
17
17
|
import io
|
|
18
18
|
# try set gbk problem
|
|
19
19
|
try:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
21
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
22
|
+
elif hasattr(sys.stdout, 'buffer'):
|
|
23
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
24
|
+
except Exception:
|
|
23
25
|
pass
|
|
24
26
|
from helpful_functions import (
|
|
25
27
|
expand_dict_columns,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
|
|
2
|
+
# parsetab.py
|
|
3
|
+
# This file is automatically generated. Do not edit.
|
|
4
|
+
# pylint: disable=W,C,R
|
|
5
|
+
_tabversion = '3.10'
|
|
6
|
+
|
|
7
|
+
_lr_method = 'LALR'
|
|
8
|
+
|
|
9
|
+
_lr_signature = 'ASSIGN BOOLEAN CATEGORY COMMA DIVIDE EQUAL FIELD FUNCTION GREATER GREATEREQUAL IDENTIFIER LESS LESSEQUAL LPAREN MINUS NOTEQUAL NUMBER PLUS RPAREN STRING TIMESexpression : comparison\n| expression EQUAL comparison\n| expression NOTEQUAL comparison\n| expression GREATER comparison\n| expression LESS comparison\n| expression GREATEREQUAL comparison\n| expression LESSEQUAL comparisoncomparison : term\n| comparison PLUS term\n| comparison MINUS termterm : factor\n| term TIMES factor\n| term DIVIDE factorfactor : NUMBER\n| STRING\n| FIELD\n| CATEGORY\n| IDENTIFIER\n| BOOLEAN\n| MINUS factor\n| LPAREN expression RPAREN\n| function_callfunction_call : FUNCTION LPAREN args RPARENargs : arg_list\n| emptyarg_list : arg\n| arg_list COMMA argarg : expression\n| IDENTIFIER ASSIGN expressionempty :'
|
|
10
|
+
|
|
11
|
+
_lr_action_items = {'NUMBER':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,]),'STRING':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,]),'FIELD':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,]),'CATEGORY':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,]),'IDENTIFIER':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[10,10,10,10,10,10,10,10,10,10,10,10,10,44,44,10,]),'BOOLEAN':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,]),'MINUS':([0,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,35,36,37,38,44,45,46,47,],[4,22,-8,4,-11,-14,-15,-16,-17,-18,-19,4,-22,4,4,4,4,4,4,4,4,4,4,-20,4,22,22,22,22,22,22,-9,-10,-12,-13,-21,-18,-23,4,4,]),'LPAREN':([0,4,12,14,15,16,17,18,19,20,21,22,23,24,27,46,47,],[12,12,12,27,12,12,12,12,12,12,12,12,12,12,12,12,12,]),'FUNCTION':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,]),'$end':([1,2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,45,],[0,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,-23,]),'EQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[15,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,15,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,15,-18,-23,15,]),'NOTEQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[16,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,16,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,16,-18,-23,16,]),'GREATER':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[17,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,17,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,17,-18,-23,17,]),'LESS':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[18,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,18,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,18,-18,-23,18,]),'GREATEREQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[19,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,19,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,19,-18,-23,19,]),'LESSEQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[20,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,20,-18,-23,20,]),'RPAREN':([2,3,5,6,7,8,9,10,11,13,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,48,49,],[-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,38,-30,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,45,-24,-25,-26,-28,-18,-23,-27,-29,]),'COMMA':([2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,40,42,43,44,45,48,49,],[-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,46,-26,-28,-18,-23,-27,-29,]),'PLUS':([2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,44,45,],[21,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,21,21,21,21,21,21,-9,-10,-12,-13,-21,-18,-23,]),'TIMES':([3,5,6,7,8,9,10,11,13,25,34,35,36,37,38,44,45,],[23,-11,-14,-15,-16,-17,-18,-19,-22,-20,23,23,-12,-13,-21,-18,-23,]),'DIVIDE':([3,5,6,7,8,9,10,11,13,25,34,35,36,37,38,44,45,],[24,-11,-14,-15,-16,-17,-18,-19,-22,-20,24,24,-12,-13,-21,-18,-23,]),'ASSIGN':([44,],[47,]),}
|
|
12
|
+
|
|
13
|
+
_lr_action = {}
|
|
14
|
+
for _k, _v in _lr_action_items.items():
|
|
15
|
+
for _x,_y in zip(_v[0],_v[1]):
|
|
16
|
+
if not _x in _lr_action: _lr_action[_x] = {}
|
|
17
|
+
_lr_action[_x][_k] = _y
|
|
18
|
+
del _lr_action_items
|
|
19
|
+
|
|
20
|
+
_lr_goto_items = {'expression':([0,12,27,46,47,],[1,26,43,43,49,]),'comparison':([0,12,15,16,17,18,19,20,27,46,47,],[2,2,28,29,30,31,32,33,2,2,2,]),'term':([0,12,15,16,17,18,19,20,21,22,27,46,47,],[3,3,3,3,3,3,3,3,34,35,3,3,3,]),'factor':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[5,25,5,5,5,5,5,5,5,5,5,36,37,5,5,5,]),'function_call':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,]),'args':([27,],[39,]),'arg_list':([27,],[40,]),'empty':([27,],[41,]),'arg':([27,46,],[42,48,]),}
|
|
21
|
+
|
|
22
|
+
_lr_goto = {}
|
|
23
|
+
for _k, _v in _lr_goto_items.items():
|
|
24
|
+
for _x, _y in zip(_v[0], _v[1]):
|
|
25
|
+
if not _x in _lr_goto: _lr_goto[_x] = {}
|
|
26
|
+
_lr_goto[_x][_k] = _y
|
|
27
|
+
del _lr_goto_items
|
|
28
|
+
_lr_productions = [
|
|
29
|
+
("S' -> expression","S'",1,None,None,None),
|
|
30
|
+
('expression -> comparison','expression',1,'p_expression','validator.py',390),
|
|
31
|
+
('expression -> expression EQUAL comparison','expression',3,'p_expression','validator.py',391),
|
|
32
|
+
('expression -> expression NOTEQUAL comparison','expression',3,'p_expression','validator.py',392),
|
|
33
|
+
('expression -> expression GREATER comparison','expression',3,'p_expression','validator.py',393),
|
|
34
|
+
('expression -> expression LESS comparison','expression',3,'p_expression','validator.py',394),
|
|
35
|
+
('expression -> expression GREATEREQUAL comparison','expression',3,'p_expression','validator.py',395),
|
|
36
|
+
('expression -> expression LESSEQUAL comparison','expression',3,'p_expression','validator.py',396),
|
|
37
|
+
('comparison -> term','comparison',1,'p_comparison','validator.py',403),
|
|
38
|
+
('comparison -> comparison PLUS term','comparison',3,'p_comparison','validator.py',404),
|
|
39
|
+
('comparison -> comparison MINUS term','comparison',3,'p_comparison','validator.py',405),
|
|
40
|
+
('term -> factor','term',1,'p_term','validator.py',412),
|
|
41
|
+
('term -> term TIMES factor','term',3,'p_term','validator.py',413),
|
|
42
|
+
('term -> term DIVIDE factor','term',3,'p_term','validator.py',414),
|
|
43
|
+
('factor -> NUMBER','factor',1,'p_factor','validator.py',421),
|
|
44
|
+
('factor -> STRING','factor',1,'p_factor','validator.py',422),
|
|
45
|
+
('factor -> FIELD','factor',1,'p_factor','validator.py',423),
|
|
46
|
+
('factor -> CATEGORY','factor',1,'p_factor','validator.py',424),
|
|
47
|
+
('factor -> IDENTIFIER','factor',1,'p_factor','validator.py',425),
|
|
48
|
+
('factor -> BOOLEAN','factor',1,'p_factor','validator.py',426),
|
|
49
|
+
('factor -> MINUS factor','factor',2,'p_factor','validator.py',427),
|
|
50
|
+
('factor -> LPAREN expression RPAREN','factor',3,'p_factor','validator.py',428),
|
|
51
|
+
('factor -> function_call','factor',1,'p_factor','validator.py',429),
|
|
52
|
+
('function_call -> FUNCTION LPAREN args RPAREN','function_call',4,'p_function_call','validator.py',457),
|
|
53
|
+
('args -> arg_list','args',1,'p_args','validator.py',461),
|
|
54
|
+
('args -> empty','args',1,'p_args','validator.py',462),
|
|
55
|
+
('arg_list -> arg','arg_list',1,'p_arg_list','validator.py',469),
|
|
56
|
+
('arg_list -> arg_list COMMA arg','arg_list',3,'p_arg_list','validator.py',470),
|
|
57
|
+
('arg -> expression','arg',1,'p_arg','validator.py',477),
|
|
58
|
+
('arg -> IDENTIFIER ASSIGN expression','arg',3,'p_arg','validator.py',478),
|
|
59
|
+
('empty -> <empty>','empty',0,'p_empty','validator.py',485),
|
|
60
|
+
]
|