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 CHANGED
@@ -12,7 +12,7 @@ pytest-dsl - 基于pytest的DSL测试框架
12
12
  - 自定义关键字支持
13
13
  """
14
14
 
15
- __version__ = "0.1.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, enable_hooks: bool = True) -> any:
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, source_type: str = "external",
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)}")
@@ -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
- return self._data.get(key, default)
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
- return key in self._data
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