pytest-dsl 0.10.0__py3-none-any.whl → 0.11.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.
@@ -1,11 +1,8 @@
1
- from typing import Dict, Any, List, Optional
2
1
  import os
3
- import pathlib
4
2
  from pytest_dsl.core.lexer import get_lexer
5
3
  from pytest_dsl.core.parser import get_parser, Node
6
4
  from pytest_dsl.core.dsl_executor import DSLExecutor
7
5
  from pytest_dsl.core.keyword_manager import keyword_manager
8
- from pytest_dsl.core.context import TestContext
9
6
 
10
7
 
11
8
  class CustomKeywordManager:
@@ -127,7 +124,7 @@ class CustomKeywordManager:
127
124
  return
128
125
 
129
126
  for node in statements_node.children:
130
- if node.type == 'CustomKeyword':
127
+ if node.type in ['CustomKeyword', 'Function']:
131
128
  self._register_custom_keyword(node, file_path)
132
129
 
133
130
  def _register_custom_keyword(self, node: Node, file_path: str) -> None:
@@ -16,8 +16,14 @@ class KeywordManager:
16
16
  self._keywords: Dict[str, Dict] = {}
17
17
  self.current_context = None
18
18
 
19
- def register(self, name: str, parameters: List[Dict]):
20
- """关键字注册装饰器"""
19
+ def register(self, name: str, parameters: List[Dict], source_info: Optional[Dict] = None):
20
+ """关键字注册装饰器
21
+
22
+ Args:
23
+ name: 关键字名称
24
+ parameters: 参数列表
25
+ source_info: 来源信息,包含 source_type, source_name, module_name 等
26
+ """
21
27
  def decorator(func: Callable) -> Callable:
22
28
  @functools.wraps(func)
23
29
  def wrapper(**kwargs):
@@ -40,15 +46,71 @@ class KeywordManager:
40
46
  # 自动添加 step_name 到 mapping 中
41
47
  mapping["步骤名称"] = "step_name"
42
48
 
43
- self._keywords[name] = {
49
+ # 构建关键字信息,包含来源信息
50
+ keyword_info = {
44
51
  'func': wrapper,
45
52
  'mapping': mapping,
46
53
  'parameters': param_list,
47
54
  'defaults': defaults # 存储默认值
48
55
  }
56
+
57
+ # 添加来源信息
58
+ if source_info:
59
+ keyword_info.update(source_info)
60
+ else:
61
+ # 尝试从函数模块推断来源信息
62
+ keyword_info.update(self._infer_source_info(func))
63
+
64
+ self._keywords[name] = keyword_info
49
65
  return wrapper
50
66
  return decorator
51
67
 
68
+ def _infer_source_info(self, func: Callable) -> Dict:
69
+ """从函数推断来源信息"""
70
+ source_info = {}
71
+
72
+ if hasattr(func, '__module__'):
73
+ module_name = func.__module__
74
+ source_info['module_name'] = module_name
75
+
76
+ if module_name.startswith('pytest_dsl.keywords'):
77
+ # 内置关键字
78
+ source_info['source_type'] = 'builtin'
79
+ source_info['source_name'] = 'pytest-dsl内置'
80
+ elif 'pytest_dsl' in module_name:
81
+ # pytest-dsl相关但不是内置的
82
+ source_info['source_type'] = 'internal'
83
+ source_info['source_name'] = 'pytest-dsl'
84
+ else:
85
+ # 第三方插件或用户自定义
86
+ source_info['source_type'] = 'external'
87
+ # 提取可能的包名
88
+ parts = module_name.split('.')
89
+ if len(parts) > 1:
90
+ source_info['source_name'] = parts[0]
91
+ else:
92
+ source_info['source_name'] = module_name
93
+
94
+ return source_info
95
+
96
+ def register_with_source(self, name: str, parameters: List[Dict],
97
+ source_type: str, source_name: str, **kwargs):
98
+ """带来源信息的关键字注册装饰器
99
+
100
+ Args:
101
+ name: 关键字名称
102
+ parameters: 参数列表
103
+ source_type: 来源类型 (builtin, plugin, local, remote, project_custom)
104
+ source_name: 来源名称 (插件名、文件路径等)
105
+ **kwargs: 其他来源相关信息
106
+ """
107
+ source_info = {
108
+ 'source_type': source_type,
109
+ 'source_name': source_name,
110
+ **kwargs
111
+ }
112
+ return self.register(name, parameters, source_info)
113
+
52
114
  def execute(self, keyword_name: str, **params: Any) -> Any:
53
115
  """执行关键字"""
54
116
  keyword_info = self._keywords.get(keyword_name)
@@ -84,6 +146,18 @@ class KeywordManager:
84
146
 
85
147
  return keyword_info
86
148
 
149
+ def get_keywords_by_source(self) -> Dict[str, List[str]]:
150
+ """按来源分组获取关键字"""
151
+ by_source = {}
152
+
153
+ for name, info in self._keywords.items():
154
+ source_name = info.get('source_name', '未知来源')
155
+ if source_name not in by_source:
156
+ by_source[source_name] = []
157
+ by_source[source_name].append(name)
158
+
159
+ return by_source
160
+
87
161
  def _log_execution(self, keyword_name: str, params: Dict, result: Any) -> None:
88
162
  """记录关键字执行结果"""
89
163
  allure.attach(
@@ -62,7 +62,28 @@ def load_plugin_keywords(plugin_name: str) -> None:
62
62
 
63
63
  # 如果插件有register_keywords函数,调用它
64
64
  if hasattr(plugin, 'register_keywords') and callable(plugin.register_keywords):
65
- plugin.register_keywords(keyword_manager)
65
+ # 创建一个包装的关键字管理器,自动添加来源信息
66
+ class PluginKeywordManager:
67
+ def __init__(self, original_manager, plugin_name):
68
+ self.original_manager = original_manager
69
+ self.plugin_name = plugin_name
70
+
71
+ def register(self, name: str, parameters):
72
+ """带插件来源信息的注册方法"""
73
+ return self.original_manager.register_with_source(
74
+ name, parameters,
75
+ source_type='plugin',
76
+ source_name=plugin_name,
77
+ module_name=plugin_name
78
+ )
79
+
80
+ def __getattr__(self, name):
81
+ # 代理其他方法到原始管理器
82
+ return getattr(self.original_manager, name)
83
+
84
+ plugin_manager = PluginKeywordManager(keyword_manager, plugin_name)
85
+ plugin.register_keywords(plugin_manager)
86
+ print(f"通过register_keywords加载插件: {plugin_name}")
66
87
  return
67
88
 
68
89
  # 否则,遍历包中的所有模块
@@ -71,13 +92,29 @@ def load_plugin_keywords(plugin_name: str) -> None:
71
92
  if not is_pkg:
72
93
  try:
73
94
  module = importlib.import_module(name)
95
+ print(f"加载插件模块: {name}")
74
96
  # 模块已导入,关键字装饰器会自动注册
97
+ # 但我们需要在导入后更新来源信息
98
+ _update_keywords_source_info(plugin_name, name)
75
99
  except ImportError as e:
76
100
  print(f"无法导入模块 {name}: {e}")
77
101
  except ImportError as e:
78
102
  print(f"无法导入插件 {plugin_name}: {e}")
79
103
 
80
104
 
105
+ def _update_keywords_source_info(plugin_name: str, module_name: str):
106
+ """更新模块中关键字的来源信息"""
107
+ # 找到可能是新注册的关键字
108
+ for keyword_name, keyword_info in keyword_manager._keywords.items():
109
+ if keyword_info.get('module_name') == module_name:
110
+ # 更新来源信息
111
+ keyword_info.update({
112
+ 'source_type': 'plugin',
113
+ 'source_name': plugin_name,
114
+ 'plugin_module': module_name
115
+ })
116
+
117
+
81
118
  def load_all_plugins() -> None:
82
119
  """
83
120
  发现并加载所有已安装的关键字插件