pytest-dsl 0.13.0__py3-none-any.whl → 0.15.0__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.
- pytest_dsl/__init__.py +190 -3
- pytest_dsl/cli.py +37 -260
- pytest_dsl/core/custom_keyword_manager.py +114 -14
- pytest_dsl/core/dsl_executor.py +549 -166
- pytest_dsl/core/dsl_executor_utils.py +21 -22
- pytest_dsl/core/execution_tracker.py +291 -0
- pytest_dsl/core/hook_manager.py +87 -0
- pytest_dsl/core/hookable_executor.py +134 -0
- pytest_dsl/core/hookable_keyword_manager.py +106 -0
- pytest_dsl/core/hookspecs.py +175 -0
- pytest_dsl/core/keyword_loader.py +402 -0
- pytest_dsl/core/keyword_manager.py +29 -23
- pytest_dsl/core/parser.py +94 -18
- pytest_dsl/core/validator.py +417 -0
- pytest_dsl/core/yaml_loader.py +142 -42
- pytest_dsl/core/yaml_vars.py +90 -7
- pytest_dsl/plugin.py +10 -1
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/METADATA +1 -1
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/RECORD +23 -16
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/WHEEL +0 -0
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/entry_points.txt +0 -0
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/licenses/LICENSE +0 -0
- {pytest_dsl-0.13.0.dist-info → pytest_dsl-0.15.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
"""
|
2
|
+
pytest-dsl hook规范定义
|
3
|
+
|
4
|
+
使用pluggy定义hook接口,允许外部框架扩展DSL功能
|
5
|
+
"""
|
6
|
+
import pluggy
|
7
|
+
from typing import Dict, List, Optional, Any
|
8
|
+
|
9
|
+
# 创建pytest-dsl的hook标记器
|
10
|
+
hookspec = pluggy.HookspecMarker("pytest_dsl")
|
11
|
+
hookimpl = pluggy.HookimplMarker("pytest_dsl")
|
12
|
+
|
13
|
+
|
14
|
+
class DSLHookSpecs:
|
15
|
+
"""DSL Hook规范"""
|
16
|
+
|
17
|
+
@hookspec
|
18
|
+
def dsl_load_content(self, dsl_id: str) -> Optional[str]:
|
19
|
+
"""加载DSL内容
|
20
|
+
|
21
|
+
Args:
|
22
|
+
dsl_id: DSL标识符(可以是文件路径、数据库ID等)
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
DSL内容字符串,如果无法加载返回None
|
26
|
+
"""
|
27
|
+
|
28
|
+
@hookspec
|
29
|
+
def dsl_list_cases(self, project_id: Optional[int] = None,
|
30
|
+
filters: Optional[Dict[str, Any]] = None
|
31
|
+
) -> List[Dict[str, Any]]:
|
32
|
+
"""列出DSL用例
|
33
|
+
|
34
|
+
Args:
|
35
|
+
project_id: 项目ID,用于过滤(可选)
|
36
|
+
filters: 其他过滤条件(可选)
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
用例列表,每个用例包含id、name、description等字段
|
40
|
+
"""
|
41
|
+
|
42
|
+
@hookspec
|
43
|
+
def dsl_register_custom_keywords(self,
|
44
|
+
project_id: Optional[int] = None) -> None:
|
45
|
+
"""注册自定义关键字
|
46
|
+
|
47
|
+
Args:
|
48
|
+
project_id: 项目ID,用于过滤(可选)
|
49
|
+
"""
|
50
|
+
|
51
|
+
@hookspec
|
52
|
+
def dsl_get_execution_context(self, dsl_id: str,
|
53
|
+
base_context: Dict[str, Any]
|
54
|
+
) -> Dict[str, Any]:
|
55
|
+
"""获取执行上下文
|
56
|
+
|
57
|
+
Args:
|
58
|
+
dsl_id: DSL标识符
|
59
|
+
base_context: 基础上下文
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
扩展后的执行上下文
|
63
|
+
"""
|
64
|
+
|
65
|
+
@hookspec(firstresult=True) # 只使用第一个返回结果
|
66
|
+
def dsl_create_executor(self) -> Optional[Any]:
|
67
|
+
"""创建自定义DSL执行器
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
自定义执行器实例,如果返回None则使用默认执行器
|
71
|
+
"""
|
72
|
+
|
73
|
+
@hookspec
|
74
|
+
def dsl_before_execution(self, dsl_id: str,
|
75
|
+
context: Dict[str, Any]) -> None:
|
76
|
+
"""DSL执行前的hook
|
77
|
+
|
78
|
+
Args:
|
79
|
+
dsl_id: DSL标识符
|
80
|
+
context: 执行上下文
|
81
|
+
"""
|
82
|
+
|
83
|
+
@hookspec
|
84
|
+
def dsl_after_execution(self, dsl_id: str, context: Dict[str, Any],
|
85
|
+
result: Any,
|
86
|
+
exception: Optional[Exception] = None) -> None:
|
87
|
+
"""DSL执行后的hook
|
88
|
+
|
89
|
+
Args:
|
90
|
+
dsl_id: DSL标识符
|
91
|
+
context: 执行上下文
|
92
|
+
result: 执行结果
|
93
|
+
exception: 如果执行失败,包含异常信息
|
94
|
+
"""
|
95
|
+
|
96
|
+
@hookspec
|
97
|
+
def dsl_transform_content(self, dsl_id: str, content: str) -> str:
|
98
|
+
"""转换DSL内容
|
99
|
+
|
100
|
+
Args:
|
101
|
+
dsl_id: DSL标识符
|
102
|
+
content: 原始DSL内容
|
103
|
+
|
104
|
+
Returns:
|
105
|
+
转换后的DSL内容
|
106
|
+
"""
|
107
|
+
|
108
|
+
@hookspec
|
109
|
+
def dsl_validate_content(self, dsl_id: str, content: str) -> List[str]:
|
110
|
+
"""验证DSL内容
|
111
|
+
|
112
|
+
Args:
|
113
|
+
dsl_id: DSL标识符
|
114
|
+
content: DSL内容
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
验证错误列表,空列表表示验证通过
|
118
|
+
"""
|
119
|
+
|
120
|
+
@hookspec
|
121
|
+
def dsl_load_variables(self, project_id: Optional[int] = None,
|
122
|
+
environment: Optional[str] = None,
|
123
|
+
filters: Optional[Dict[str, Any]] = None
|
124
|
+
) -> Dict[str, Any]:
|
125
|
+
"""加载变量配置
|
126
|
+
|
127
|
+
Args:
|
128
|
+
project_id: 项目ID,用于过滤(可选)
|
129
|
+
environment: 环境名称,如dev、test、prod等(可选)
|
130
|
+
filters: 其他过滤条件(可选)
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
变量字典,键为变量名,值为变量值
|
134
|
+
"""
|
135
|
+
|
136
|
+
@hookspec
|
137
|
+
def dsl_get_variable(self, var_name: str, project_id: Optional[int] = None,
|
138
|
+
environment: Optional[str] = None
|
139
|
+
) -> Optional[Any]:
|
140
|
+
"""获取单个变量值
|
141
|
+
|
142
|
+
Args:
|
143
|
+
var_name: 变量名
|
144
|
+
project_id: 项目ID,用于过滤(可选)
|
145
|
+
environment: 环境名称(可选)
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
变量值,如果变量不存在返回None
|
149
|
+
"""
|
150
|
+
|
151
|
+
@hookspec
|
152
|
+
def dsl_list_variable_sources(self, project_id: Optional[int] = None
|
153
|
+
) -> List[Dict[str, Any]]:
|
154
|
+
"""列出可用的变量源
|
155
|
+
|
156
|
+
Args:
|
157
|
+
project_id: 项目ID,用于过滤(可选)
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
变量源列表,每个源包含name、type、description等字段
|
161
|
+
"""
|
162
|
+
|
163
|
+
@hookspec
|
164
|
+
def dsl_validate_variables(self, variables: Dict[str, Any],
|
165
|
+
project_id: Optional[int] = None
|
166
|
+
) -> List[str]:
|
167
|
+
"""验证变量配置
|
168
|
+
|
169
|
+
Args:
|
170
|
+
variables: 变量字典
|
171
|
+
project_id: 项目ID,用于过滤(可选)
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
验证错误列表,空列表表示验证通过
|
175
|
+
"""
|
@@ -0,0 +1,402 @@
|
|
1
|
+
"""
|
2
|
+
pytest-dsl关键字加载器
|
3
|
+
|
4
|
+
提供统一的关键字加载和管理功能,包括:
|
5
|
+
- 内置关键字加载
|
6
|
+
- 插件关键字发现和加载
|
7
|
+
- 本地关键字扫描
|
8
|
+
- 项目自定义关键字扫描
|
9
|
+
- 远程关键字支持
|
10
|
+
- 关键字分类和信息获取
|
11
|
+
"""
|
12
|
+
|
13
|
+
import os
|
14
|
+
import sys
|
15
|
+
from pathlib import Path
|
16
|
+
from typing import Dict, Any, Optional, List
|
17
|
+
|
18
|
+
from pytest_dsl.core.plugin_discovery import load_all_plugins, scan_local_keywords
|
19
|
+
from pytest_dsl.core.keyword_manager import keyword_manager
|
20
|
+
from pytest_dsl.core.lexer import get_lexer
|
21
|
+
from pytest_dsl.core.parser import get_parser
|
22
|
+
|
23
|
+
|
24
|
+
class KeywordLoader:
|
25
|
+
"""关键字加载器类"""
|
26
|
+
|
27
|
+
def __init__(self):
|
28
|
+
self._project_custom_keywords = None
|
29
|
+
|
30
|
+
def load_all_keywords(self, include_remote: bool = False) -> Dict[str, Any]:
|
31
|
+
"""加载所有可用的关键字
|
32
|
+
|
33
|
+
Args:
|
34
|
+
include_remote: 是否包含远程关键字,默认为False
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
项目自定义关键字信息字典
|
38
|
+
"""
|
39
|
+
# 首先导入内置关键字模块,确保内置关键字被注册
|
40
|
+
try:
|
41
|
+
import pytest_dsl.keywords # noqa: F401
|
42
|
+
print("内置关键字模块加载完成")
|
43
|
+
except ImportError as e:
|
44
|
+
print(f"加载内置关键字模块失败: {e}")
|
45
|
+
|
46
|
+
# 加载已安装的关键字插件
|
47
|
+
load_all_plugins()
|
48
|
+
|
49
|
+
# 扫描本地关键字
|
50
|
+
scan_local_keywords()
|
51
|
+
|
52
|
+
# 自动导入项目中的resources目录
|
53
|
+
self._load_resources_directory()
|
54
|
+
|
55
|
+
# 扫描项目中的自定义关键字(.resource文件中定义的)
|
56
|
+
project_custom_keywords = self.scan_project_custom_keywords()
|
57
|
+
if project_custom_keywords:
|
58
|
+
print(f"发现 {len(project_custom_keywords)} 个项目自定义关键字")
|
59
|
+
self._load_resource_files(project_custom_keywords)
|
60
|
+
|
61
|
+
# 根据参数决定是否加载远程关键字
|
62
|
+
if include_remote:
|
63
|
+
print("正在扫描远程关键字...")
|
64
|
+
# 这里可以添加远程关键字的扫描逻辑
|
65
|
+
# 目前远程关键字是通过DSL文件中的@remote导入指令动态加载的
|
66
|
+
else:
|
67
|
+
print("跳过远程关键字扫描")
|
68
|
+
|
69
|
+
self._project_custom_keywords = project_custom_keywords
|
70
|
+
return project_custom_keywords
|
71
|
+
|
72
|
+
def _load_resources_directory(self):
|
73
|
+
"""自动导入项目中的resources目录"""
|
74
|
+
try:
|
75
|
+
from pytest_dsl.core.custom_keyword_manager import custom_keyword_manager
|
76
|
+
|
77
|
+
# 尝试从多个可能的项目根目录位置导入resources
|
78
|
+
possible_roots = [
|
79
|
+
os.getcwd(), # 当前工作目录
|
80
|
+
os.path.dirname(os.getcwd()), # 上级目录
|
81
|
+
]
|
82
|
+
|
83
|
+
# 尝试每个可能的根目录
|
84
|
+
for project_root in possible_roots:
|
85
|
+
if project_root and os.path.exists(project_root):
|
86
|
+
resources_dir = os.path.join(project_root, "resources")
|
87
|
+
if (os.path.exists(resources_dir) and
|
88
|
+
os.path.isdir(resources_dir)):
|
89
|
+
custom_keyword_manager.auto_import_resources_directory(
|
90
|
+
project_root)
|
91
|
+
break
|
92
|
+
except Exception as e:
|
93
|
+
print(f"自动导入resources目录时出现警告: {str(e)}")
|
94
|
+
|
95
|
+
def _load_resource_files(self, project_custom_keywords: Dict[str, Any]):
|
96
|
+
"""加载.resource文件中的关键字到关键字管理器"""
|
97
|
+
from pytest_dsl.core.custom_keyword_manager import custom_keyword_manager
|
98
|
+
|
99
|
+
project_root = Path(os.getcwd())
|
100
|
+
resource_files = list(project_root.glob('**/*.resource'))
|
101
|
+
|
102
|
+
for resource_file in resource_files:
|
103
|
+
try:
|
104
|
+
custom_keyword_manager.load_resource_file(str(resource_file))
|
105
|
+
print(f"已加载资源文件: {resource_file}")
|
106
|
+
except Exception as e:
|
107
|
+
print(f"加载资源文件失败 {resource_file}: {e}")
|
108
|
+
|
109
|
+
def scan_project_custom_keywords(self, project_root: Optional[str] = None) -> Dict[str, Any]:
|
110
|
+
"""扫描项目中.resource文件中的自定义关键字
|
111
|
+
|
112
|
+
Args:
|
113
|
+
project_root: 项目根目录,默认为当前工作目录
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
自定义关键字信息,格式为
|
117
|
+
{keyword_name: {'file': file_path, 'node': ast_node, 'parameters': [...]}}
|
118
|
+
"""
|
119
|
+
if project_root is None:
|
120
|
+
project_root = os.getcwd()
|
121
|
+
|
122
|
+
project_root = Path(project_root)
|
123
|
+
custom_keywords = {}
|
124
|
+
|
125
|
+
# 查找所有.resource文件
|
126
|
+
resource_files = list(project_root.glob('**/*.resource'))
|
127
|
+
|
128
|
+
if not resource_files:
|
129
|
+
return custom_keywords
|
130
|
+
|
131
|
+
lexer = get_lexer()
|
132
|
+
parser = get_parser()
|
133
|
+
|
134
|
+
for file_path in resource_files:
|
135
|
+
try:
|
136
|
+
# 读取并解析文件
|
137
|
+
content = self._read_file(str(file_path))
|
138
|
+
ast = parser.parse(content, lexer=lexer)
|
139
|
+
|
140
|
+
# 查找自定义关键字定义
|
141
|
+
keywords_in_file = self._extract_custom_keywords_from_ast(
|
142
|
+
ast, str(file_path)
|
143
|
+
)
|
144
|
+
custom_keywords.update(keywords_in_file)
|
145
|
+
|
146
|
+
except Exception as e:
|
147
|
+
print(f"解析资源文件 {file_path} 时出错: {e}")
|
148
|
+
|
149
|
+
return custom_keywords
|
150
|
+
|
151
|
+
def _read_file(self, filename: str) -> str:
|
152
|
+
"""读取文件内容"""
|
153
|
+
with open(filename, 'r', encoding='utf-8') as f:
|
154
|
+
return f.read()
|
155
|
+
|
156
|
+
def _extract_custom_keywords_from_ast(self, ast, file_path: str) -> Dict[str, Any]:
|
157
|
+
"""从AST中提取自定义关键字定义
|
158
|
+
|
159
|
+
Args:
|
160
|
+
ast: 抽象语法树
|
161
|
+
file_path: 文件路径
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
自定义关键字信息字典
|
165
|
+
"""
|
166
|
+
custom_keywords = {}
|
167
|
+
|
168
|
+
if ast.type != 'Start' or len(ast.children) < 2:
|
169
|
+
return custom_keywords
|
170
|
+
|
171
|
+
# 遍历语句节点
|
172
|
+
statements_node = ast.children[1]
|
173
|
+
if statements_node.type != 'Statements':
|
174
|
+
return custom_keywords
|
175
|
+
|
176
|
+
for node in statements_node.children:
|
177
|
+
# 支持两种格式:CustomKeyword(旧格式)和Function(新格式)
|
178
|
+
if node.type in ['CustomKeyword', 'Function']:
|
179
|
+
keyword_name = node.value
|
180
|
+
|
181
|
+
# 提取参数信息
|
182
|
+
params_node = node.children[0] if node.children else None
|
183
|
+
parameters = []
|
184
|
+
|
185
|
+
if params_node:
|
186
|
+
for param in params_node:
|
187
|
+
param_name = param.value
|
188
|
+
param_default = None
|
189
|
+
|
190
|
+
# 检查是否有默认值
|
191
|
+
if param.children and param.children[0]:
|
192
|
+
param_default = param.children[0].value
|
193
|
+
|
194
|
+
param_info = {
|
195
|
+
'name': param_name,
|
196
|
+
'mapping': param_name,
|
197
|
+
'description': f'自定义关键字参数 {param_name}'
|
198
|
+
}
|
199
|
+
|
200
|
+
if param_default is not None:
|
201
|
+
param_info['default'] = param_default
|
202
|
+
|
203
|
+
parameters.append(param_info)
|
204
|
+
|
205
|
+
custom_keywords[keyword_name] = {
|
206
|
+
'file': file_path,
|
207
|
+
'node': node,
|
208
|
+
'type': 'project_custom',
|
209
|
+
'parameters': parameters
|
210
|
+
}
|
211
|
+
|
212
|
+
return custom_keywords
|
213
|
+
|
214
|
+
def categorize_keyword(self, keyword_name: str, keyword_info: Dict[str, Any],
|
215
|
+
project_custom_keywords: Optional[Dict[str, Any]] = None) -> str:
|
216
|
+
"""判断关键字的类别
|
217
|
+
|
218
|
+
Args:
|
219
|
+
keyword_name: 关键字名称
|
220
|
+
keyword_info: 关键字信息
|
221
|
+
project_custom_keywords: 项目自定义关键字信息
|
222
|
+
|
223
|
+
Returns:
|
224
|
+
关键字类别:'builtin', 'plugin', 'custom', 'project_custom', 'remote'
|
225
|
+
"""
|
226
|
+
# 优先使用存储的来源信息
|
227
|
+
source_type = keyword_info.get('source_type')
|
228
|
+
if source_type:
|
229
|
+
if source_type == 'builtin':
|
230
|
+
return 'builtin'
|
231
|
+
elif source_type == 'plugin':
|
232
|
+
return 'plugin'
|
233
|
+
elif source_type in ['external', 'local']:
|
234
|
+
return 'custom'
|
235
|
+
elif source_type == 'project_custom':
|
236
|
+
return 'project_custom'
|
237
|
+
|
238
|
+
# 向后兼容:使用原有的判断逻辑
|
239
|
+
if keyword_info.get('remote', False):
|
240
|
+
return 'remote'
|
241
|
+
|
242
|
+
# 检查是否是项目自定义关键字(DSL文件中定义的)
|
243
|
+
if project_custom_keywords and keyword_name in project_custom_keywords:
|
244
|
+
return 'project_custom'
|
245
|
+
|
246
|
+
# 检查是否是内置关键字(通过检查函数所在模块)
|
247
|
+
func = keyword_info.get('func')
|
248
|
+
if func and hasattr(func, '__module__'):
|
249
|
+
module_name = func.__module__
|
250
|
+
if module_name and module_name.startswith('pytest_dsl.keywords'):
|
251
|
+
return 'builtin'
|
252
|
+
|
253
|
+
return 'custom'
|
254
|
+
|
255
|
+
def get_keyword_source_info(self, keyword_info: Dict[str, Any]) -> Dict[str, Any]:
|
256
|
+
"""获取关键字的详细来源信息
|
257
|
+
|
258
|
+
Args:
|
259
|
+
keyword_info: 关键字信息
|
260
|
+
|
261
|
+
Returns:
|
262
|
+
来源信息字典
|
263
|
+
"""
|
264
|
+
source_type = keyword_info.get('source_type', 'unknown')
|
265
|
+
source_name = keyword_info.get('source_name', '未知')
|
266
|
+
|
267
|
+
return {
|
268
|
+
'type': source_type,
|
269
|
+
'name': source_name,
|
270
|
+
'display_name': source_name,
|
271
|
+
'module': keyword_info.get('module_name', ''),
|
272
|
+
'plugin_module': keyword_info.get('plugin_module', '')
|
273
|
+
}
|
274
|
+
|
275
|
+
def group_keywords_by_source(self, keywords_dict: Dict[str, Any],
|
276
|
+
project_custom_keywords: Optional[Dict[str, Any]] = None) -> Dict[str, Dict[str, List]]:
|
277
|
+
"""按来源分组关键字
|
278
|
+
|
279
|
+
Args:
|
280
|
+
keywords_dict: 关键字字典
|
281
|
+
project_custom_keywords: 项目自定义关键字信息
|
282
|
+
|
283
|
+
Returns:
|
284
|
+
分组后的关键字字典,格式为 {source_group: {source_name: [keywords]}}
|
285
|
+
"""
|
286
|
+
groups = {
|
287
|
+
'builtin': {},
|
288
|
+
'plugin': {},
|
289
|
+
'custom': {},
|
290
|
+
'project_custom': {},
|
291
|
+
'remote': {}
|
292
|
+
}
|
293
|
+
|
294
|
+
for keyword_name, keyword_info in keywords_dict.items():
|
295
|
+
category = self.categorize_keyword(
|
296
|
+
keyword_name, keyword_info, project_custom_keywords
|
297
|
+
)
|
298
|
+
source_info = self.get_keyword_source_info(keyword_info)
|
299
|
+
|
300
|
+
# 特殊处理项目自定义关键字
|
301
|
+
if category == 'project_custom' and project_custom_keywords:
|
302
|
+
custom_info = project_custom_keywords[keyword_name]
|
303
|
+
source_name = custom_info['file']
|
304
|
+
else:
|
305
|
+
source_name = source_info['name']
|
306
|
+
|
307
|
+
if source_name not in groups[category]:
|
308
|
+
groups[category][source_name] = []
|
309
|
+
|
310
|
+
groups[category][source_name].append({
|
311
|
+
'name': keyword_name,
|
312
|
+
'info': keyword_info,
|
313
|
+
'source_info': source_info
|
314
|
+
})
|
315
|
+
|
316
|
+
return groups
|
317
|
+
|
318
|
+
def get_all_keywords(self) -> Dict[str, Any]:
|
319
|
+
"""获取所有已注册的关键字
|
320
|
+
|
321
|
+
Returns:
|
322
|
+
所有关键字的字典
|
323
|
+
"""
|
324
|
+
return keyword_manager._keywords
|
325
|
+
|
326
|
+
def get_project_custom_keywords(self) -> Optional[Dict[str, Any]]:
|
327
|
+
"""获取项目自定义关键字信息
|
328
|
+
|
329
|
+
Returns:
|
330
|
+
项目自定义关键字信息,如果尚未加载则返回None
|
331
|
+
"""
|
332
|
+
return self._project_custom_keywords
|
333
|
+
|
334
|
+
|
335
|
+
# 创建全局实例
|
336
|
+
keyword_loader = KeywordLoader()
|
337
|
+
|
338
|
+
|
339
|
+
# 便捷函数
|
340
|
+
def load_all_keywords(include_remote: bool = False) -> Dict[str, Any]:
|
341
|
+
"""加载所有可用的关键字
|
342
|
+
|
343
|
+
Args:
|
344
|
+
include_remote: 是否包含远程关键字,默认为False
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
项目自定义关键字信息字典
|
348
|
+
"""
|
349
|
+
return keyword_loader.load_all_keywords(include_remote=include_remote)
|
350
|
+
|
351
|
+
|
352
|
+
def categorize_keyword(keyword_name: str, keyword_info: Dict[str, Any],
|
353
|
+
project_custom_keywords: Optional[Dict[str, Any]] = None) -> str:
|
354
|
+
"""判断关键字的类别
|
355
|
+
|
356
|
+
Args:
|
357
|
+
keyword_name: 关键字名称
|
358
|
+
keyword_info: 关键字信息
|
359
|
+
project_custom_keywords: 项目自定义关键字信息
|
360
|
+
|
361
|
+
Returns:
|
362
|
+
关键字类别
|
363
|
+
"""
|
364
|
+
return keyword_loader.categorize_keyword(keyword_name, keyword_info, project_custom_keywords)
|
365
|
+
|
366
|
+
|
367
|
+
def get_keyword_source_info(keyword_info: Dict[str, Any]) -> Dict[str, Any]:
|
368
|
+
"""获取关键字的详细来源信息
|
369
|
+
|
370
|
+
Args:
|
371
|
+
keyword_info: 关键字信息
|
372
|
+
|
373
|
+
Returns:
|
374
|
+
来源信息字典
|
375
|
+
"""
|
376
|
+
return keyword_loader.get_keyword_source_info(keyword_info)
|
377
|
+
|
378
|
+
|
379
|
+
def group_keywords_by_source(keywords_dict: Dict[str, Any],
|
380
|
+
project_custom_keywords: Optional[Dict[str, Any]] = None) -> Dict[str, Dict[str, List]]:
|
381
|
+
"""按来源分组关键字
|
382
|
+
|
383
|
+
Args:
|
384
|
+
keywords_dict: 关键字字典
|
385
|
+
project_custom_keywords: 项目自定义关键字信息
|
386
|
+
|
387
|
+
Returns:
|
388
|
+
分组后的关键字字典
|
389
|
+
"""
|
390
|
+
return keyword_loader.group_keywords_by_source(keywords_dict, project_custom_keywords)
|
391
|
+
|
392
|
+
|
393
|
+
def scan_project_custom_keywords(project_root: Optional[str] = None) -> Dict[str, Any]:
|
394
|
+
"""扫描项目中.resource文件中的自定义关键字
|
395
|
+
|
396
|
+
Args:
|
397
|
+
project_root: 项目根目录,默认为当前工作目录
|
398
|
+
|
399
|
+
Returns:
|
400
|
+
自定义关键字信息字典
|
401
|
+
"""
|
402
|
+
return keyword_loader.scan_project_custom_keywords(project_root)
|