cnhkmcp 2.3.7__py3-none-any.whl → 2.3.8__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.
@@ -613,6 +613,16 @@ class ExpressionValidator:
613
613
  """验证参数类型是否符合预期"""
614
614
  errors = []
615
615
 
616
+ def _is_number_like(node: ASTNode) -> bool:
617
+ if node is None:
618
+ return False
619
+ if node.node_type == 'number':
620
+ return True
621
+ if node.node_type == 'unop' and isinstance(node.value, dict) and node.value.get('op') in {'-', '+'}:
622
+ if node.children and hasattr(node.children[0], 'node_type'):
623
+ return _is_number_like(node.children[0])
624
+ return False
625
+
616
626
  # Unit compatibility check
617
627
  # bucket()/group_cartesian_product() output a derived category (grouping key).
618
628
  # It can only be consumed where a category/grouping key is expected (typically by group_* operators).
@@ -634,7 +644,8 @@ class ExpressionValidator:
634
644
  # 表达式可以是任何有效的AST节点
635
645
  pass
636
646
  elif expected_type == 'number':
637
- if arg.node_type != 'number':
647
+ # 允许 -1 这类一元负号数字常量(解析为 unop(number))
648
+ if not _is_number_like(arg):
638
649
  errors.append(f"参数 {arg_index+1} 应该是一个数字,但得到 {arg.node_type}")
639
650
  elif expected_type == 'boolean':
640
651
  # 布尔值可以是 true/false 或数字(0/1)
@@ -900,6 +911,172 @@ class ExpressionValidator:
900
911
  Returns:
901
912
  Tuple[bool, str]: (是否成功, 转换后的表达式或错误信息)
902
913
  """
914
+ def _top_level_equals_positions(stmt: str) -> List[int]:
915
+ """返回所有“顶层赋值”等号位置。
916
+
917
+ 仅统计括号外(()[]{})、引号外、且不属于比较操作符(==,!=,<=,>=)的 '='。
918
+ 这样可以避免把关键字参数(如 rettype=0)误判为赋值语句。
919
+ """
920
+ positions: List[int] = []
921
+ paren_depth = 0
922
+ bracket_depth = 0
923
+ brace_depth = 0
924
+ in_single_quote = False
925
+ in_double_quote = False
926
+ escape = False
927
+
928
+ for i, ch in enumerate(stmt):
929
+ if escape:
930
+ escape = False
931
+ continue
932
+ if ch == '\\':
933
+ escape = True
934
+ continue
935
+
936
+ if in_single_quote:
937
+ if ch == "'":
938
+ in_single_quote = False
939
+ continue
940
+ if in_double_quote:
941
+ if ch == '"':
942
+ in_double_quote = False
943
+ continue
944
+
945
+ if ch == "'":
946
+ in_single_quote = True
947
+ continue
948
+ if ch == '"':
949
+ in_double_quote = True
950
+ continue
951
+
952
+ if ch == '(':
953
+ paren_depth += 1
954
+ continue
955
+ if ch == ')':
956
+ paren_depth = max(0, paren_depth - 1)
957
+ continue
958
+ if ch == '[':
959
+ bracket_depth += 1
960
+ continue
961
+ if ch == ']':
962
+ bracket_depth = max(0, bracket_depth - 1)
963
+ continue
964
+ if ch == '{':
965
+ brace_depth += 1
966
+ continue
967
+ if ch == '}':
968
+ brace_depth = max(0, brace_depth - 1)
969
+ continue
970
+
971
+ if paren_depth or bracket_depth or brace_depth:
972
+ continue
973
+
974
+ if ch != '=':
975
+ continue
976
+
977
+ prev_ch = stmt[i - 1] if i > 0 else ''
978
+ next_ch = stmt[i + 1] if i + 1 < len(stmt) else ''
979
+ if prev_ch in ['=', '!', '<', '>'] or next_ch == '=':
980
+ continue
981
+
982
+ positions.append(i)
983
+
984
+ return positions
985
+
986
+ def _keyword_arg_names(stmt: str):
987
+ """提取函数调用中的命名参数名(如 rettype=0 中的 rettype)。
988
+
989
+ 只收集括号/中括号/大括号内部出现的 name= 形式,避免把脚本级赋值误当作命名参数。
990
+ """
991
+ names = set()
992
+ paren_depth = 0
993
+ bracket_depth = 0
994
+ brace_depth = 0
995
+ in_single_quote = False
996
+ in_double_quote = False
997
+ escape = False
998
+
999
+ i = 0
1000
+ while i < len(stmt):
1001
+ ch = stmt[i]
1002
+
1003
+ if escape:
1004
+ escape = False
1005
+ i += 1
1006
+ continue
1007
+ if ch == '\\':
1008
+ escape = True
1009
+ i += 1
1010
+ continue
1011
+
1012
+ if in_single_quote:
1013
+ if ch == "'":
1014
+ in_single_quote = False
1015
+ i += 1
1016
+ continue
1017
+ if in_double_quote:
1018
+ if ch == '"':
1019
+ in_double_quote = False
1020
+ i += 1
1021
+ continue
1022
+
1023
+ if ch == "'":
1024
+ in_single_quote = True
1025
+ i += 1
1026
+ continue
1027
+ if ch == '"':
1028
+ in_double_quote = True
1029
+ i += 1
1030
+ continue
1031
+
1032
+ if ch == '(':
1033
+ paren_depth += 1
1034
+ i += 1
1035
+ continue
1036
+ if ch == ')':
1037
+ paren_depth = max(0, paren_depth - 1)
1038
+ i += 1
1039
+ continue
1040
+ if ch == '[':
1041
+ bracket_depth += 1
1042
+ i += 1
1043
+ continue
1044
+ if ch == ']':
1045
+ bracket_depth = max(0, bracket_depth - 1)
1046
+ i += 1
1047
+ continue
1048
+ if ch == '{':
1049
+ brace_depth += 1
1050
+ i += 1
1051
+ continue
1052
+ if ch == '}':
1053
+ brace_depth = max(0, brace_depth - 1)
1054
+ i += 1
1055
+ continue
1056
+
1057
+ inside_container = bool(paren_depth or bracket_depth or brace_depth)
1058
+
1059
+ if inside_container and (ch.isalpha() or ch == '_'):
1060
+ start = i
1061
+ i += 1
1062
+ while i < len(stmt) and (stmt[i].isalnum() or stmt[i] == '_'):
1063
+ i += 1
1064
+ name = stmt[start:i]
1065
+
1066
+ j = i
1067
+ while j < len(stmt) and stmt[j].isspace():
1068
+ j += 1
1069
+
1070
+ if j < len(stmt) and stmt[j] == '=':
1071
+ next_ch = stmt[j + 1] if j + 1 < len(stmt) else ''
1072
+ if next_ch != '=':
1073
+ names.add(name.lower())
1074
+ continue
1075
+
1076
+ i += 1
1077
+
1078
+ return names
1079
+
903
1080
  # 检查表达式是否以分号结尾
904
1081
  if expression.strip().endswith(';'):
905
1082
  return False, "表达式不能以分号结尾"
@@ -914,51 +1091,13 @@ class ExpressionValidator:
914
1091
 
915
1092
  # 处理每个赋值语句(除了最后一个)
916
1093
  for i, stmt in enumerate(statements[:-1]):
917
- # 检查是否包含赋值符号
918
- if '=' not in stmt:
919
- return False, f"第{i+1}个语句必须是赋值语句(使用=符号)"
920
-
921
- # 检查是否是比较操作符(==, !=, <=, >=)
922
- if any(op in stmt for op in ['==', '!=', '<=', '>=']):
923
- # 如果包含比较操作符,需要确认是否有赋值符号
924
- # 使用临时替换法:将比较操作符替换为临时标记,再检查是否还有=
925
- temp_stmt = stmt
926
- for op in ['==', '!=', '<=', '>=']:
927
- temp_stmt = temp_stmt.replace(op, '---')
928
-
929
- if '=' not in temp_stmt:
930
- return False, f"第{i+1}个语句必须是赋值语句,不能只是比较表达式"
931
-
932
- # 找到第一个=符号(不是比较操作符的一部分)
933
- # 先将比较操作符替换为临时标记,再找=
934
- temp_stmt = stmt
935
- for op in ['==', '!=', '<=', '>=']:
936
- temp_stmt = temp_stmt.replace(op, '---')
937
-
938
- if '=' not in temp_stmt:
1094
+ eq_positions = _top_level_equals_positions(stmt)
1095
+ if not eq_positions:
939
1096
  return False, f"第{i+1}个语句必须是赋值语句(使用=符号)"
940
-
941
- # 找到实际的=位置
942
- equals_pos = temp_stmt.index('=')
943
-
944
- # 在原始语句中找到对应位置
945
- real_equals_pos = 0
946
- temp_count = 0
947
- for char in stmt:
948
- if temp_count == equals_pos:
949
- break
950
- if char in '!<>':
951
- # 检查是否是比较操作符的一部分
952
- if real_equals_pos + 1 < len(stmt) and stmt[real_equals_pos + 1] == '=':
953
- # 是比较操作符,跳过两个字符
954
- real_equals_pos += 2
955
- temp_count += 3 # 因为替换成了三个字符的---
956
- else:
957
- real_equals_pos += 1
958
- temp_count += 1
959
- else:
960
- real_equals_pos += 1
961
- temp_count += 1
1097
+ if len(eq_positions) > 1:
1098
+ return False, f"第{i+1}个语句只能包含一个赋值符号(=)"
1099
+
1100
+ real_equals_pos = eq_positions[0]
962
1101
 
963
1102
  # 分割变量名和值
964
1103
  var_name = stmt[:real_equals_pos].strip()
@@ -975,9 +1114,12 @@ class ExpressionValidator:
975
1114
 
976
1115
  # 检查变量值中使用的变量是否已经定义
977
1116
  # 简单检查:提取所有可能的变量名
1117
+ kw_names = _keyword_arg_names(var_value)
978
1118
  used_vars = re.findall(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b', var_value)
979
1119
  for used_var in used_vars:
980
1120
  used_var_lower = used_var.lower()
1121
+ if used_var_lower in kw_names:
1122
+ continue
981
1123
  if used_var_lower not in variables:
982
1124
  # 检查是否是函数名
983
1125
  if used_var not in supported_functions:
@@ -1000,19 +1142,16 @@ class ExpressionValidator:
1000
1142
  final_stmt = statements[-1]
1001
1143
 
1002
1144
  # 检查最后一个语句是否是赋值语句
1003
- if '=' in final_stmt:
1004
- # 替换比较操作符为临时标记,然后检查是否还有单独的=
1005
- temp_stmt = final_stmt
1006
- for op in ['==', '!=', '<=', '>=']:
1007
- temp_stmt = temp_stmt.replace(op, '---')
1008
-
1009
- if '=' in temp_stmt:
1010
- return False, "最后一个语句不能是赋值语句"
1145
+ if _top_level_equals_positions(final_stmt):
1146
+ return False, "最后一个语句不能是赋值语句"
1011
1147
 
1012
1148
  # 检查最后一个语句中使用的变量是否已经定义
1149
+ kw_names = _keyword_arg_names(final_stmt)
1013
1150
  used_vars = re.findall(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b', final_stmt)
1014
1151
  for used_var in used_vars:
1015
1152
  used_var_lower = used_var.lower()
1153
+ if used_var_lower in kw_names:
1154
+ continue
1016
1155
  if used_var_lower not in variables:
1017
1156
  # 检查是否是函数名
1018
1157
  if used_var not in supported_functions:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 2.3.7
3
+ Version: 2.3.8
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -1,4 +1,4 @@
1
- cnhkmcp/__init__.py,sha256=13ULgeeyONpZWNtJMNnbw8quqeWiTEvC7Jx3rxgy4Gk,2759
1
+ cnhkmcp/__init__.py,sha256=aWRBIhD8S5oQMt2dB_le4tIteFbvHPhFteGiStHA2Go,2759
2
2
  cnhkmcp/untracked/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  cnhkmcp/untracked/arXiv_API_Tool_Manual.md,sha256=I3hvI5mpmIjBuWptufoVSWFnuhyUc67oCGHEuR0p_xs,13552
4
4
  cnhkmcp/untracked/arxiv_api.py,sha256=ka2TCUMNdPFSsqgsDxZyLoIXCKaiX9OKuAx6IMEjCdI,9300
@@ -131,7 +131,7 @@ cnhkmcp/untracked/APP/Tranformer/helpful_functions.py,sha256=Jc8gclRkvGx7el0XgTm
131
131
  cnhkmcp/untracked/APP/Tranformer/parsetab.py,sha256=L_XJWx4AmYWASQ-krdrcyu7cEFbRdKS5MWppZ0Qfjlo,7650
132
132
  cnhkmcp/untracked/APP/Tranformer/template_summary.txt,sha256=gWz5LFlPtOmw0JnLj68hgWsoSFNyA18uCJWIYWHLbe8,111054
133
133
  cnhkmcp/untracked/APP/Tranformer/transformer_config.json,sha256=ene-WntIVbcoN3_H1ztlwtZK6eadSXCfqs1SSgrGAIg,179
134
- cnhkmcp/untracked/APP/Tranformer/validator.py,sha256=lDFLTDWzSnW4h1QJnYjWq12jPjFYxUDGMYrjQL9dVyM,62077
134
+ cnhkmcp/untracked/APP/Tranformer/validator.py,sha256=-GqGCkE4pNjP6_-ZChNuNWKhEK988VywRJ8XMSoUz8g,66355
135
135
  cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json,sha256=vMw3zhzcwARGm92ykdGTeYTsrCje_RHt0sWv17R0qUs,368947
136
136
  cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_示例.json,sha256=K40tcWPiUKaPnrtMdfsN2BOBG5IzqSz04XT6gRz7FVE,23139
137
137
  cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json,sha256=T1PNoYwrqgwDVLtfmj7L5e0Sq02OEbqHPC8RFhICuUU,2
@@ -143,7 +143,7 @@ cnhkmcp/untracked/APP/blueprints/idea_house.py,sha256=P_Pq_kmw2N3YluBOH9e0SwsCsw
143
143
  cnhkmcp/untracked/APP/blueprints/inspiration_house.py,sha256=Zras66ksS3WRUnRcxKNaon2sHFeoZwdlY3K54sgcCyQ,18994
144
144
  cnhkmcp/untracked/APP/blueprints/paper_analysis.py,sha256=tYGh-A1pzvSw6ZzoMKyIJBysbX8xsdBZncWw8ZGKyVQ,22241
145
145
  cnhkmcp/untracked/APP/blueprints/parsetab.py,sha256=qJJR3QDtcqoBafLaIvvTiILY0REfP5VevvesWveEg1A,7650
146
- cnhkmcp/untracked/APP/blueprints/validator.py,sha256=lDFLTDWzSnW4h1QJnYjWq12jPjFYxUDGMYrjQL9dVyM,62077
146
+ cnhkmcp/untracked/APP/blueprints/validator.py,sha256=-GqGCkE4pNjP6_-ZChNuNWKhEK988VywRJ8XMSoUz8g,66355
147
147
  cnhkmcp/untracked/APP/custom_templates/templates.json,sha256=ARrpRsxGcUpC2iepS6j6A_0tdu_xUJTIyvLDb8uzL_E,48776
148
148
  cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md,sha256=vZZFH7_h1PXQIYRA5eFPqJDJflsfVFFFzDjm8bNjZPc,15401
149
149
  cnhkmcp/untracked/APP/give_me_idea/ace_lib.py,sha256=nSnmM5zfI6lxIln1vctz7TCwjAWcljVXITy7R4gS3Q0,53947
@@ -291,7 +291,7 @@ cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/script
291
291
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/implement_idea.py,sha256=8nAyiFE0X6pcGQwZ4m-S9ph7lPSAGzzX7VLKBucBfZ8,8181
292
292
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/merge_expression_list.py,sha256=4NzMqgwdLUx0baVm3CNRBlr17mtdnUzUdi3Depui8pc,3362
293
293
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/parsetab.py,sha256=29clH5xFEmKpqzRvrLN89QE8JFJNYFhH-gEFR4y7448,7650
294
- cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py,sha256=q6zpapSaZwRosCo5D0bumsqkr5dj0nKveNdjekLFJkY,62649
294
+ cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py,sha256=XPW94uD50rzX_MKNb0O405IZZcIrEh3T2vxXMljjMHY,66981
295
295
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/template_final_enhance/op总结.md,sha256=HDc8lhGdMst2QgFCqD5fJWvDZ3w1S2DEk0bMsHziflA,20562
296
296
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/template_final_enhance/sample_prompt.md,sha256=vf6Ps-hzIH-MRf-cv0Dyro7StdTJ-v6RAjHCXkpRwLE,6217
297
297
  cnhkmcp/untracked/APP/trailSomeAlphas/skills/template_final_enhance/单因子思考逻辑链.md,sha256=2IfV6lOKYwoZIlN1tjXjOezJn9pQxX4K3iPmnZh01gA,13232
@@ -308,7 +308,7 @@ cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这
308
308
  cnhkmcp/untracked/skills/Claude_Skill_Creation_Guide.md,sha256=Wx4w8deBkuw0UcSwzNNQdRIuCqDXGk3-fRQBWcPQivw,5025
309
309
  cnhkmcp/untracked/skills/alpha-expression-verifier/SKILL.md,sha256=7oGzMIXUJzDCtbxND6QWmh6azkLqoFJNURIh-F-aPUQ,2213
310
310
  cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/parsetab.py,sha256=L_XJWx4AmYWASQ-krdrcyu7cEFbRdKS5MWppZ0Qfjlo,7650
311
- cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/validator.py,sha256=lDFLTDWzSnW4h1QJnYjWq12jPjFYxUDGMYrjQL9dVyM,62077
311
+ cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/validator.py,sha256=-GqGCkE4pNjP6_-ZChNuNWKhEK988VywRJ8XMSoUz8g,66355
312
312
  cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/verify_expr.py,sha256=zDSlYf0XlkyML-fcL4wld445RMbztt4pDSP5b6W6JKQ,1659
313
313
  cnhkmcp/untracked/skills/brain-calculate-alpha-selfcorrQuick/SKILL.md,sha256=UKQhfHPOH8_YXnRotzXuG8BrgFeXhQoxAZIEeaQxGds,1183
314
314
  cnhkmcp/untracked/skills/brain-calculate-alpha-selfcorrQuick/reference.md,sha256=ws9oUgtEdK7aVjw6sNoVzFQ3gyoX5UIlyz3wItI0fxI,3115
@@ -380,7 +380,7 @@ cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/parse_i
380
380
  cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/parsetab.py,sha256=JvZ5WdYXoDafh4tSl2nw0rzhCCIdA4T_UXabMl9gkYg,7650
381
381
  cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/process_template.py,sha256=AbNB9IniG4JuZK8V9xJkOlvvafs8FNkGjMqVKLCL0RM,3627
382
382
  cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/resolve_settings.py,sha256=wdhmkHEvIX4OaLTwLbERXUU8RFmL7ezW4YTJXbEs4Fs,2928
383
- cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/validator.py,sha256=_OJTcDyO7XVgO0_icUEdUzMHTXkh9V7OWqJVWGYwtqs,62545
383
+ cnhkmcp/untracked/skills/brain-inspectRawTemplate-create-Setting/scripts/validator.py,sha256=b4NvSugrUPa2YZbXBbVy_LdCgCPf637fMumZlKdXS1A,66823
384
384
  cnhkmcp/untracked/skills/brain-nextMove-analysis/SKILL.md,sha256=MGmM3HHYTdzxLE6uOxs9mB4i3At4JGjJYzsbzQKTjgc,1685
385
385
  cnhkmcp/untracked/skills/brain-nextMove-analysis/reference.md,sha256=6aNmPqWRn09XdQMRxoVTka9IYVOUv5LcWparHu16EfQ,9460
386
386
  cnhkmcp/untracked/skills/planning-with-files/SKILL.md,sha256=WORMds3daIxA7qRTamVcTSiySAzXvkHlzONC1Kv6ato,6686
@@ -395,9 +395,9 @@ cnhkmcp/untracked/skills/pull_BRAINSkill/SKILL.md,sha256=QyXQ0wr9LeZyKqkvSTto72b
395
395
  cnhkmcp/untracked/skills/pull_BRAINSkill/scripts/pull_skills.py,sha256=6v3Z3cc9_qKvBj7C6y2jWY1pAd76SA3JmiVj_KkZkmw,6341
396
396
  cnhkmcp/vector_db/_manifest.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
397
397
  cnhkmcp/vector_db/_meta.json,sha256=xQwhRA0prLtwFAMAGR1ZgCR76jVEFIEfF-1SNPpTMgI,91
398
- cnhkmcp-2.3.7.dist-info/licenses/LICENSE,sha256=QLxO2eNMnJQEdI_R1UV2AOD-IvuA8zVrkHWA4D9gtoc,1081
399
- cnhkmcp-2.3.7.dist-info/METADATA,sha256=QJtvYs51Cvz14j2Bro0cgzmT6LerISsgNTDPeOQbrcw,5171
400
- cnhkmcp-2.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
401
- cnhkmcp-2.3.7.dist-info/entry_points.txt,sha256=lTQieVyIvjhSMK4fT-XwnccY-JBC1H4vVQ3V9dDM-Pc,70
402
- cnhkmcp-2.3.7.dist-info/top_level.txt,sha256=x--ibUcSgOS9Z_RWK2Qc-vfs7DaXQN-WMaaxEETJ1Bw,8
403
- cnhkmcp-2.3.7.dist-info/RECORD,,
398
+ cnhkmcp-2.3.8.dist-info/licenses/LICENSE,sha256=QLxO2eNMnJQEdI_R1UV2AOD-IvuA8zVrkHWA4D9gtoc,1081
399
+ cnhkmcp-2.3.8.dist-info/METADATA,sha256=RCn5ZGpYfNCYrTjuW4R7VhA-Wy3wU-cAlevJzQiqmDE,5171
400
+ cnhkmcp-2.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
401
+ cnhkmcp-2.3.8.dist-info/entry_points.txt,sha256=lTQieVyIvjhSMK4fT-XwnccY-JBC1H4vVQ3V9dDM-Pc,70
402
+ cnhkmcp-2.3.8.dist-info/top_level.txt,sha256=x--ibUcSgOS9Z_RWK2Qc-vfs7DaXQN-WMaaxEETJ1Bw,8
403
+ cnhkmcp-2.3.8.dist-info/RECORD,,