pytest-dsl 0.12.0__py3-none-any.whl → 0.13.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/cli.py CHANGED
@@ -78,7 +78,7 @@ def parse_args():
78
78
  list_parser.add_argument(
79
79
  '--category',
80
80
  choices=[
81
- 'builtin', 'plugin', 'custom',
81
+ 'builtin', 'plugin', 'custom',
82
82
  'project_custom', 'remote', 'all'
83
83
  ],
84
84
  default='all',
@@ -108,7 +108,7 @@ def parse_args():
108
108
  parser.add_argument(
109
109
  '--category',
110
110
  choices=[
111
- 'builtin', 'plugin', 'custom',
111
+ 'builtin', 'plugin', 'custom',
112
112
  'project_custom', 'remote', 'all'
113
113
  ],
114
114
  default='all'
@@ -157,6 +157,29 @@ def load_all_keywords(include_remote=False):
157
157
  # 扫描本地关键字
158
158
  scan_local_keywords()
159
159
 
160
+ # 自动导入项目中的resources目录
161
+ try:
162
+ from pytest_dsl.core.custom_keyword_manager import (
163
+ custom_keyword_manager)
164
+
165
+ # 尝试从多个可能的项目根目录位置导入resources
166
+ possible_roots = [
167
+ os.getcwd(), # 当前工作目录
168
+ os.path.dirname(os.getcwd()), # 上级目录
169
+ ]
170
+
171
+ # 尝试每个可能的根目录
172
+ for project_root in possible_roots:
173
+ if project_root and os.path.exists(project_root):
174
+ resources_dir = os.path.join(project_root, "resources")
175
+ if (os.path.exists(resources_dir) and
176
+ os.path.isdir(resources_dir)):
177
+ custom_keyword_manager.auto_import_resources_directory(
178
+ project_root)
179
+ break
180
+ except Exception as e:
181
+ print(f"自动导入resources目录时出现警告: {str(e)}")
182
+
160
183
  # 扫描项目中的自定义关键字(.resource文件中定义的)
161
184
  project_custom_keywords = scan_project_custom_keywords()
162
185
  if project_custom_keywords:
@@ -15,6 +15,7 @@ class CustomKeywordManager:
15
15
  """初始化自定义关键字管理器"""
16
16
  self.resource_cache = {} # 缓存已加载的资源文件
17
17
  self.resource_paths = [] # 资源文件搜索路径
18
+ self.auto_imported_resources = set() # 记录已自动导入的资源文件
18
19
 
19
20
  def add_resource_path(self, path: str) -> None:
20
21
  """添加资源文件搜索路径
@@ -25,6 +26,141 @@ class CustomKeywordManager:
25
26
  if path not in self.resource_paths:
26
27
  self.resource_paths.append(path)
27
28
 
29
+ def auto_import_resources_directory(
30
+ self, project_root: str = None) -> None:
31
+ """自动导入项目中的resources目录
32
+
33
+ Args:
34
+ project_root: 项目根目录,默认为当前工作目录
35
+ """
36
+ if project_root is None:
37
+ project_root = os.getcwd()
38
+
39
+ # 查找resources目录
40
+ resources_dir = os.path.join(project_root, "resources")
41
+
42
+ if (not os.path.exists(resources_dir) or
43
+ not os.path.isdir(resources_dir)):
44
+ # 如果没有resources目录,静默返回
45
+ return
46
+
47
+ print(f"发现resources目录: {resources_dir}")
48
+
49
+ # 递归查找所有.resource文件
50
+ resource_files = []
51
+ for root, dirs, files in os.walk(resources_dir):
52
+ for file in files:
53
+ if file.endswith('.resource'):
54
+ resource_files.append(os.path.join(root, file))
55
+
56
+ if not resource_files:
57
+ print("resources目录中没有找到.resource文件")
58
+ return
59
+
60
+ print(f"在resources目录中发现 {len(resource_files)} 个资源文件")
61
+
62
+ # 按照依赖关系排序并加载资源文件
63
+ sorted_files = self._sort_resources_by_dependencies(resource_files)
64
+
65
+ for resource_file in sorted_files:
66
+ try:
67
+ # 检查是否已经自动导入过
68
+ absolute_path = os.path.abspath(resource_file)
69
+ if absolute_path not in self.auto_imported_resources:
70
+ self.load_resource_file(resource_file)
71
+ self.auto_imported_resources.add(absolute_path)
72
+ print(f"自动导入资源文件: {resource_file}")
73
+ except Exception as e:
74
+ print(f"自动导入资源文件失败 {resource_file}: {e}")
75
+
76
+ def _sort_resources_by_dependencies(self, resource_files):
77
+ """根据依赖关系对资源文件进行排序
78
+
79
+ Args:
80
+ resource_files: 资源文件列表
81
+
82
+ Returns:
83
+ list: 按依赖关系排序后的资源文件列表
84
+ """
85
+ # 简单的拓扑排序实现
86
+ dependencies = {}
87
+ all_files = set()
88
+
89
+ # 分析每个文件的依赖关系
90
+ for file_path in resource_files:
91
+ all_files.add(file_path)
92
+ dependencies[file_path] = self._extract_dependencies(file_path)
93
+
94
+ # 拓扑排序
95
+ sorted_files = []
96
+ visited = set()
97
+ temp_visited = set()
98
+
99
+ def visit(file_path):
100
+ if file_path in temp_visited:
101
+ # 检测到循环依赖,跳过
102
+ return
103
+ if file_path in visited:
104
+ return
105
+
106
+ temp_visited.add(file_path)
107
+
108
+ # 访问依赖的文件
109
+ for dep in dependencies.get(file_path, []):
110
+ if dep in all_files: # 只处理在当前文件列表中的依赖
111
+ visit(dep)
112
+
113
+ temp_visited.remove(file_path)
114
+ visited.add(file_path)
115
+ sorted_files.append(file_path)
116
+
117
+ # 访问所有文件
118
+ for file_path in resource_files:
119
+ if file_path not in visited:
120
+ visit(file_path)
121
+
122
+ return sorted_files
123
+
124
+ def _extract_dependencies(self, file_path):
125
+ """提取资源文件的依赖关系
126
+
127
+ Args:
128
+ file_path: 资源文件路径
129
+
130
+ Returns:
131
+ list: 依赖的文件路径列表
132
+ """
133
+ dependencies = []
134
+
135
+ try:
136
+ with open(file_path, 'r', encoding='utf-8') as f:
137
+ content = f.read()
138
+
139
+ # 解析文件获取导入信息
140
+ lexer = get_lexer()
141
+ parser = get_parser()
142
+ ast = parser.parse(content, lexer=lexer)
143
+
144
+ if ast.type == 'Start' and ast.children:
145
+ metadata_node = ast.children[0]
146
+ if metadata_node.type == 'Metadata':
147
+ for item in metadata_node.children:
148
+ if item.type == '@import':
149
+ imported_file = item.value
150
+ # 处理相对路径
151
+ if not os.path.isabs(imported_file):
152
+ imported_file = os.path.join(
153
+ os.path.dirname(file_path), imported_file)
154
+ # 规范化路径
155
+ imported_file = os.path.normpath(imported_file)
156
+ dependencies.append(imported_file)
157
+
158
+ except Exception as e:
159
+ # 如果解析失败,返回空依赖列表
160
+ print(f"解析资源文件依赖失败 {file_path}: {e}")
161
+
162
+ return dependencies
163
+
28
164
  def load_resource_file(self, file_path: str) -> None:
29
165
  """加载资源文件
30
166
 
@@ -300,6 +300,9 @@ class DSLExecutor:
300
300
  metadata = {}
301
301
  teardown_node = None
302
302
 
303
+ # 自动导入项目中的resources目录
304
+ self._auto_import_resources()
305
+
303
306
  # 先处理元数据和找到teardown节点
304
307
  for child in node.children:
305
308
  if child.type == 'Metadata':
@@ -334,6 +337,40 @@ class DSLExecutor:
334
337
  # 测试用例执行完成后清空上下文
335
338
  self.test_context.clear()
336
339
 
340
+ def _auto_import_resources(self):
341
+ """自动导入项目中的resources目录"""
342
+ try:
343
+ from pytest_dsl.core.custom_keyword_manager import custom_keyword_manager
344
+
345
+ # 尝试从多个可能的项目根目录位置导入resources
346
+ possible_roots = [
347
+ os.getcwd(), # 当前工作目录
348
+ os.path.dirname(os.getcwd()), # 上级目录
349
+ ]
350
+
351
+ # 如果在pytest环境中,尝试获取pytest的根目录
352
+ try:
353
+ import pytest
354
+ if hasattr(pytest, 'config') and pytest.config:
355
+ pytest_root = pytest.config.rootdir
356
+ if pytest_root:
357
+ possible_roots.insert(0, str(pytest_root))
358
+ except:
359
+ pass
360
+
361
+ # 尝试每个可能的根目录
362
+ for project_root in possible_roots:
363
+ if project_root and os.path.exists(project_root):
364
+ resources_dir = os.path.join(project_root, "resources")
365
+ if os.path.exists(resources_dir) and os.path.isdir(resources_dir):
366
+ custom_keyword_manager.auto_import_resources_directory(
367
+ project_root)
368
+ break
369
+
370
+ except Exception as e:
371
+ # 自动导入失败不应该影响测试执行,只记录警告
372
+ print(f"自动导入resources目录时出现警告: {str(e)}")
373
+
337
374
  def _handle_import(self, file_path):
338
375
  """处理导入指令
339
376