pytest-dsl 0.15.3__py3-none-any.whl → 0.15.5__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 +52 -3
- pytest_dsl/cli.py +8 -1
- pytest_dsl/core/context.py +82 -5
- pytest_dsl/core/custom_keyword_manager.py +14 -8
- pytest_dsl/core/dsl_executor.py +159 -35
- pytest_dsl/core/global_context.py +38 -8
- pytest_dsl/core/http_client.py +29 -5
- pytest_dsl/core/keyword_utils.py +7 -0
- pytest_dsl/core/remote_server_registry.py +333 -0
- pytest_dsl/core/serialization_utils.py +231 -0
- pytest_dsl/core/utils.py +34 -27
- pytest_dsl/core/variable_providers.py +202 -0
- pytest_dsl/core/variable_utils.py +45 -38
- pytest_dsl/core/yaml_loader.py +176 -36
- pytest_dsl/keywords/http_keywords.py +9 -5
- pytest_dsl/remote/__init__.py +63 -1
- pytest_dsl/remote/keyword_client.py +139 -55
- pytest_dsl/remote/keyword_server.py +32 -16
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/METADATA +1 -1
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/RECORD +24 -21
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/WHEEL +0 -0
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/entry_points.txt +0 -0
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/licenses/LICENSE +0 -0
- {pytest_dsl-0.15.3.dist-info → pytest_dsl-0.15.5.dist-info}/top_level.txt +0 -0
pytest_dsl/__init__.py
CHANGED
@@ -12,7 +12,7 @@ pytest-dsl - 基于pytest的DSL测试框架
|
|
12
12
|
- 自定义关键字支持
|
13
13
|
"""
|
14
14
|
|
15
|
-
__version__ = "0.
|
15
|
+
__version__ = "0.15.5"
|
16
16
|
|
17
17
|
# 核心执行器
|
18
18
|
from pytest_dsl.core.dsl_executor import DSLExecutor
|
@@ -47,6 +47,20 @@ from pytest_dsl.core.variable_utils import VariableReplacer
|
|
47
47
|
# 自定义关键字管理器
|
48
48
|
from pytest_dsl.core.custom_keyword_manager import custom_keyword_manager
|
49
49
|
|
50
|
+
# 远程服务器注册器
|
51
|
+
from pytest_dsl.core.remote_server_registry import (
|
52
|
+
remote_server_registry, RemoteServerRegistry,
|
53
|
+
register_remote_server_with_variables,
|
54
|
+
create_database_variable_provider,
|
55
|
+
create_config_file_variable_provider
|
56
|
+
)
|
57
|
+
|
58
|
+
# 远程服务器配置加载器
|
59
|
+
from pytest_dsl.core.yaml_loader import (
|
60
|
+
load_remote_servers_from_yaml,
|
61
|
+
register_remote_servers_from_config
|
62
|
+
)
|
63
|
+
|
50
64
|
# 关键字加载器
|
51
65
|
from pytest_dsl.core.keyword_loader import (
|
52
66
|
keyword_loader, KeywordLoader,
|
@@ -61,6 +75,22 @@ from pytest_dsl.core.keyword_utils import (
|
|
61
75
|
generate_html_report
|
62
76
|
)
|
63
77
|
|
78
|
+
# 远程关键字功能
|
79
|
+
try:
|
80
|
+
from pytest_dsl.remote import (
|
81
|
+
remote_keyword_manager, RemoteKeywordManager, RemoteKeywordClient,
|
82
|
+
register_remote_server, register_multiple_servers
|
83
|
+
)
|
84
|
+
_REMOTE_AVAILABLE = True
|
85
|
+
except ImportError:
|
86
|
+
# 如果远程功能依赖不可用,设置为None
|
87
|
+
remote_keyword_manager = None
|
88
|
+
RemoteKeywordManager = None
|
89
|
+
RemoteKeywordClient = None
|
90
|
+
register_remote_server = None
|
91
|
+
register_multiple_servers = None
|
92
|
+
_REMOTE_AVAILABLE = False
|
93
|
+
|
64
94
|
# 便捷导入的别名
|
65
95
|
Executor = DSLExecutor
|
66
96
|
Validator = DSLValidator
|
@@ -106,6 +136,17 @@ __all__ = [
|
|
106
136
|
'Node', 'get_parser', 'get_lexer',
|
107
137
|
'TestContext', 'global_context',
|
108
138
|
'VariableReplacer',
|
139
|
+
|
140
|
+
# 远程关键字功能(如果可用)
|
141
|
+
'remote_keyword_manager', 'RemoteKeywordManager', 'RemoteKeywordClient',
|
142
|
+
'register_remote_server', 'register_multiple_servers',
|
143
|
+
|
144
|
+
# 远程服务器注册器
|
145
|
+
'remote_server_registry', 'RemoteServerRegistry',
|
146
|
+
'register_remote_server_with_variables',
|
147
|
+
'create_database_variable_provider',
|
148
|
+
'create_config_file_variable_provider',
|
149
|
+
'load_remote_servers_from_yaml', 'register_remote_servers_from_config',
|
109
150
|
]
|
110
151
|
|
111
152
|
# 快捷函数
|
@@ -137,7 +178,8 @@ def parse_dsl(content: str) -> Node:
|
|
137
178
|
return parser.parse(content, lexer=lexer)
|
138
179
|
|
139
180
|
|
140
|
-
def execute_dsl(content: str, context: dict = None,
|
181
|
+
def execute_dsl(content: str, context: dict = None,
|
182
|
+
enable_hooks: bool = True) -> any:
|
141
183
|
"""执行DSL内容的便捷函数
|
142
184
|
|
143
185
|
Args:
|
@@ -158,7 +200,8 @@ def execute_dsl(content: str, context: dict = None, enable_hooks: bool = True) -
|
|
158
200
|
return executor.execute(ast)
|
159
201
|
|
160
202
|
|
161
|
-
def register_keyword(name: str, parameters: list = None,
|
203
|
+
def register_keyword(name: str, parameters: list = None,
|
204
|
+
source_type: str = "external",
|
162
205
|
source_name: str = "user_defined"):
|
163
206
|
"""注册关键字的装饰器
|
164
207
|
|
@@ -198,6 +241,12 @@ def check_version_compatibility():
|
|
198
241
|
pass
|
199
242
|
|
200
243
|
|
244
|
+
# 远程功能检查
|
245
|
+
def is_remote_available() -> bool:
|
246
|
+
"""检查远程功能是否可用"""
|
247
|
+
return _REMOTE_AVAILABLE
|
248
|
+
|
249
|
+
|
201
250
|
# 初始化时进行版本检查
|
202
251
|
check_version_compatibility()
|
203
252
|
|
pytest_dsl/cli.py
CHANGED
@@ -165,11 +165,18 @@ def load_yaml_variables(args):
|
|
165
165
|
environment = (os.environ.get('PYTEST_DSL_ENVIRONMENT') or
|
166
166
|
os.environ.get('ENVIRONMENT'))
|
167
167
|
|
168
|
+
# 智能判断是否应该加载默认配置
|
169
|
+
# 如果用户指定了YAML文件或目录,则不自动加载默认配置
|
170
|
+
user_specified_files = bool(args.yaml_vars)
|
171
|
+
user_specified_dir = bool(args.yaml_vars_dir)
|
172
|
+
auto_load_default = not (user_specified_files or user_specified_dir)
|
173
|
+
|
168
174
|
load_yaml_variables_from_args(
|
169
175
|
yaml_files=args.yaml_vars,
|
170
176
|
yaml_vars_dir=args.yaml_vars_dir,
|
171
177
|
project_root=os.getcwd(), # CLI模式下使用当前工作目录作为项目根目录
|
172
|
-
environment=environment
|
178
|
+
environment=environment,
|
179
|
+
auto_load_default=auto_load_default # 使用智能判断的结果
|
173
180
|
)
|
174
181
|
except Exception as e:
|
175
182
|
print(f"加载YAML变量失败: {str(e)}")
|
pytest_dsl/core/context.py
CHANGED
@@ -1,18 +1,42 @@
|
|
1
1
|
class TestContext:
|
2
2
|
def __init__(self):
|
3
3
|
self._data = {}
|
4
|
+
self._external_providers = [] # 外部变量提供者列表
|
4
5
|
|
5
6
|
def set(self, key: str, value: any) -> None:
|
6
7
|
"""设置上下文变量"""
|
7
8
|
self._data[key] = value
|
8
9
|
|
9
10
|
def get(self, key: str, default=None) -> any:
|
10
|
-
"""
|
11
|
-
|
11
|
+
"""获取上下文变量,遵循变量优先级:本地变量 > 外部提供者变量"""
|
12
|
+
# 1. 首先检查本地变量
|
13
|
+
if key in self._data:
|
14
|
+
return self._data[key]
|
15
|
+
|
16
|
+
# 2. 检查外部提供者(按注册顺序)
|
17
|
+
for provider in self._external_providers:
|
18
|
+
if hasattr(provider, 'get_variable'):
|
19
|
+
value = provider.get_variable(key)
|
20
|
+
if value is not None:
|
21
|
+
return value
|
22
|
+
|
23
|
+
# 3. 返回默认值
|
24
|
+
return default
|
12
25
|
|
13
26
|
def has(self, key: str) -> bool:
|
14
|
-
"""
|
15
|
-
|
27
|
+
"""检查上下文变量是否存在(包括外部提供者)"""
|
28
|
+
# 检查本地变量
|
29
|
+
if key in self._data:
|
30
|
+
return True
|
31
|
+
|
32
|
+
# 检查外部提供者
|
33
|
+
for provider in self._external_providers:
|
34
|
+
if hasattr(provider, 'get_variable'):
|
35
|
+
value = provider.get_variable(key)
|
36
|
+
if value is not None:
|
37
|
+
return True
|
38
|
+
|
39
|
+
return False
|
16
40
|
|
17
41
|
def clear(self) -> None:
|
18
42
|
"""清空上下文"""
|
@@ -20,4 +44,57 @@ class TestContext:
|
|
20
44
|
|
21
45
|
def get_local_variables(self) -> dict:
|
22
46
|
"""获取所有本地变量"""
|
23
|
-
return self._data
|
47
|
+
return self._data
|
48
|
+
|
49
|
+
def get_all_context_variables(self) -> dict:
|
50
|
+
"""获取所有上下文变量,包括本地变量和外部提供者变量
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
包含所有上下文变量的字典,本地变量优先级高于外部变量
|
54
|
+
"""
|
55
|
+
all_variables = {}
|
56
|
+
|
57
|
+
# 1. 先添加外部提供者的变量
|
58
|
+
for provider in self._external_providers:
|
59
|
+
if hasattr(provider, 'get_all_variables'):
|
60
|
+
try:
|
61
|
+
external_vars = provider.get_all_variables()
|
62
|
+
if isinstance(external_vars, dict):
|
63
|
+
all_variables.update(external_vars)
|
64
|
+
except Exception as e:
|
65
|
+
print(f"警告:获取外部变量提供者变量时发生错误: {e}")
|
66
|
+
|
67
|
+
# 2. 再添加本地变量(覆盖同名的外部变量)
|
68
|
+
all_variables.update(self._data)
|
69
|
+
|
70
|
+
return all_variables
|
71
|
+
|
72
|
+
def register_external_variable_provider(self, provider) -> None:
|
73
|
+
"""注册外部变量提供者
|
74
|
+
|
75
|
+
Args:
|
76
|
+
provider: 变量提供者,需要实现get_variable(key)方法
|
77
|
+
"""
|
78
|
+
if provider not in self._external_providers:
|
79
|
+
self._external_providers.append(provider)
|
80
|
+
|
81
|
+
def sync_variables_from_external_sources(self) -> None:
|
82
|
+
"""将外部变量提供者中的常用变量同步到本地缓存中,提高访问性能
|
83
|
+
|
84
|
+
这个方法会调用所有外部提供者的get_all_variables方法,
|
85
|
+
将常用变量缓存到本地_data字典中,以提高后续访问的性能。
|
86
|
+
注意:本地变量的优先级仍然高于外部变量。
|
87
|
+
"""
|
88
|
+
for provider in self._external_providers:
|
89
|
+
if hasattr(provider, 'get_all_variables'):
|
90
|
+
try:
|
91
|
+
# 获取提供者的所有变量
|
92
|
+
external_vars = provider.get_all_variables()
|
93
|
+
if isinstance(external_vars, dict):
|
94
|
+
# 只同步那些本地还没有的变量,保持本地变量的优先级
|
95
|
+
for key, value in external_vars.items():
|
96
|
+
if key not in self._data:
|
97
|
+
self._data[key] = value
|
98
|
+
except Exception as e:
|
99
|
+
# 如果某个提供者同步失败,记录警告但继续处理其他提供者
|
100
|
+
print(f"警告:同步外部变量提供者变量时发生错误: {e}")
|
@@ -212,7 +212,7 @@ class CustomKeywordManager:
|
|
212
212
|
print(f"资源文件 {file_path} 加载失败: {str(e)}")
|
213
213
|
raise
|
214
214
|
|
215
|
-
def _process_resource_file_content(self, content: str,
|
215
|
+
def _process_resource_file_content(self, content: str,
|
216
216
|
file_path: str) -> None:
|
217
217
|
"""处理资源文件内容
|
218
218
|
|
@@ -258,7 +258,7 @@ class CustomKeywordManager:
|
|
258
258
|
# 递归加载导入的资源文件
|
259
259
|
self.load_resource_file(imported_file)
|
260
260
|
|
261
|
-
def _register_keywords_from_ast(self, ast: Node,
|
261
|
+
def _register_keywords_from_ast(self, ast: Node,
|
262
262
|
source_name: str) -> None:
|
263
263
|
"""从AST中注册关键字(重构后的版本)
|
264
264
|
|
@@ -341,6 +341,12 @@ class CustomKeywordManager:
|
|
341
341
|
executor.test_context.set(
|
342
342
|
param_name, kwargs[param_mapping_name])
|
343
343
|
|
344
|
+
# 重要:创建变量替换器,使变量解析正常工作
|
345
|
+
from pytest_dsl.core.variable_utils import VariableReplacer
|
346
|
+
executor.variable_replacer = VariableReplacer(
|
347
|
+
executor.variables, executor.test_context
|
348
|
+
)
|
349
|
+
|
344
350
|
# 执行关键字体中的语句
|
345
351
|
result = None
|
346
352
|
try:
|
@@ -357,7 +363,7 @@ class CustomKeywordManager:
|
|
357
363
|
|
358
364
|
print(f"已注册自定义关键字: {keyword_name} 来自文件: {file_path}")
|
359
365
|
|
360
|
-
def register_keyword_from_dsl_content(self, dsl_content: str,
|
366
|
+
def register_keyword_from_dsl_content(self, dsl_content: str,
|
361
367
|
source_name: str = "DSL内容") -> list:
|
362
368
|
"""从DSL内容注册关键字(公共方法)
|
363
369
|
|
@@ -379,8 +385,8 @@ class CustomKeywordManager:
|
|
379
385
|
|
380
386
|
# 收集注册前的关键字列表
|
381
387
|
existing_keywords = (
|
382
|
-
set(keyword_manager._keywords.keys())
|
383
|
-
if hasattr(keyword_manager, '_keywords')
|
388
|
+
set(keyword_manager._keywords.keys())
|
389
|
+
if hasattr(keyword_manager, '_keywords')
|
384
390
|
else set()
|
385
391
|
)
|
386
392
|
|
@@ -389,8 +395,8 @@ class CustomKeywordManager:
|
|
389
395
|
|
390
396
|
# 计算新注册的关键字
|
391
397
|
new_keywords = (
|
392
|
-
set(keyword_manager._keywords.keys())
|
393
|
-
if hasattr(keyword_manager, '_keywords')
|
398
|
+
set(keyword_manager._keywords.keys())
|
399
|
+
if hasattr(keyword_manager, '_keywords')
|
394
400
|
else set()
|
395
401
|
)
|
396
402
|
registered_keywords = list(new_keywords - existing_keywords)
|
@@ -405,7 +411,7 @@ class CustomKeywordManager:
|
|
405
411
|
raise
|
406
412
|
|
407
413
|
def register_specific_keyword_from_dsl_content(
|
408
|
-
self, keyword_name: str, dsl_content: str,
|
414
|
+
self, keyword_name: str, dsl_content: str,
|
409
415
|
source_name: str = "DSL内容") -> bool:
|
410
416
|
"""从DSL内容注册指定的关键字(公共方法)
|
411
417
|
|