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 +25 -2
- pytest_dsl/core/custom_keyword_manager.py +136 -0
- pytest_dsl/core/dsl_executor.py +37 -0
- pytest_dsl/core/http_request.py +135 -61
- pytest_dsl/core/parser.py +7 -2
- pytest_dsl/core/parsetab.py +90 -89
- pytest_dsl/examples/http/http_example.auto +1 -1
- pytest_dsl/examples/http/http_retry_assertions.auto +4 -4
- pytest_dsl/examples/http/http_retry_assertions_enhanced.auto +2 -2
- pytest_dsl/examples/http/new_retry_test.auto +1 -1
- pytest_dsl/examples/http/retry_assertions_only.auto +3 -3
- pytest_dsl/examples/http/retry_config_only.auto +3 -3
- pytest_dsl/examples/http/retry_debug.auto +19 -8
- pytest_dsl/examples/http/retry_with_fix.auto +1 -1
- pytest_dsl/keywords/http_keywords.py +42 -14
- pytest_dsl/plugin.py +22 -4
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/METADATA +1 -1
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/RECORD +22 -22
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/WHEEL +0 -0
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/entry_points.txt +0 -0
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/licenses/LICENSE +0 -0
- {pytest_dsl-0.12.0.dist-info → pytest_dsl-0.13.0.dist-info}/top_level.txt +0 -0
@@ -130,7 +130,8 @@ def _load_file_content(file_path: str, is_template: bool = False,
|
|
130
130
|
|
131
131
|
|
132
132
|
def _process_request_config(config: Dict[str, Any],
|
133
|
-
test_context: TestContext = None) ->
|
133
|
+
test_context: TestContext = None) -> \
|
134
|
+
Dict[str, Any]:
|
134
135
|
"""处理请求配置,检查并处理文件引用
|
135
136
|
|
136
137
|
Args:
|
@@ -219,7 +220,15 @@ def _normalize_retry_config(config, assert_retry_count=None,
|
|
219
220
|
if 'indices' in retry_assertions:
|
220
221
|
standard_retry_config['indices'] = retry_assertions['indices']
|
221
222
|
if 'specific' in retry_assertions:
|
222
|
-
|
223
|
+
# 确保specific配置中的整数键被转换为字符串键,保持兼容性
|
224
|
+
specific_config = {}
|
225
|
+
for key, value in retry_assertions['specific'].items():
|
226
|
+
# 同时支持整数键和字符串键
|
227
|
+
specific_config[str(key)] = value
|
228
|
+
# 保留原始键类型以便查找
|
229
|
+
if isinstance(key, int):
|
230
|
+
specific_config[key] = value
|
231
|
+
standard_retry_config['specific'] = specific_config
|
223
232
|
|
224
233
|
# 处理传统retry配置(如果专用配置不存在)
|
225
234
|
elif 'retry' in config and config['retry']:
|
@@ -360,7 +369,17 @@ def http_request(context, **kwargs):
|
|
360
369
|
# 执行请求
|
361
370
|
response = http_req.execute(disable_auth=disable_auth)
|
362
371
|
|
363
|
-
#
|
372
|
+
# 统一处理断言逻辑
|
373
|
+
with allure.step("执行断言验证"):
|
374
|
+
if retry_config['enabled']:
|
375
|
+
# 使用统一的重试处理函数
|
376
|
+
_process_assertions_with_unified_retry(http_req, retry_config,
|
377
|
+
disable_auth)
|
378
|
+
else:
|
379
|
+
# 不需要重试,直接断言
|
380
|
+
http_req.process_asserts()
|
381
|
+
|
382
|
+
# 在断言完成后获取最终的捕获值(可能在重试期间被更新)
|
364
383
|
captured_values = http_req.captured_values
|
365
384
|
|
366
385
|
# 将捕获的变量注册到上下文
|
@@ -371,15 +390,6 @@ def http_request(context, **kwargs):
|
|
371
390
|
if save_response:
|
372
391
|
context.set(save_response, response)
|
373
392
|
|
374
|
-
# 统一处理断言逻辑
|
375
|
-
with allure.step("执行断言验证"):
|
376
|
-
if retry_config['enabled']:
|
377
|
-
# 使用统一的重试处理函数
|
378
|
-
_process_assertions_with_unified_retry(http_req, retry_config)
|
379
|
-
else:
|
380
|
-
# 不需要重试,直接断言
|
381
|
-
http_req.process_asserts()
|
382
|
-
|
383
393
|
# 获取会话状态(如果使用了会话)
|
384
394
|
session_state = None
|
385
395
|
if session_name:
|
@@ -447,7 +457,8 @@ def _deep_merge(dict1, dict2):
|
|
447
457
|
return dict1
|
448
458
|
|
449
459
|
|
450
|
-
def _process_assertions_with_unified_retry(http_req, retry_config
|
460
|
+
def _process_assertions_with_unified_retry(http_req, retry_config,
|
461
|
+
disable_auth=False):
|
451
462
|
"""使用统一的重试配置处理断言
|
452
463
|
|
453
464
|
Args:
|
@@ -482,6 +493,11 @@ def _process_assertions_with_unified_retry(http_req, retry_config):
|
|
482
493
|
# 临时替换配置
|
483
494
|
http_req.config = temp_config
|
484
495
|
|
496
|
+
# 确保在收集失败断言之前,response和captures是可用的
|
497
|
+
if not http_req.response:
|
498
|
+
# 如果response为空,重新执行一次请求
|
499
|
+
http_req.execute(disable_auth=disable_auth)
|
500
|
+
|
485
501
|
# 重新运行断言,这次只收集失败的断言而不抛出异常
|
486
502
|
_, failed_retryable_assertions = http_req.process_asserts()
|
487
503
|
except Exception as collect_err:
|
@@ -582,7 +598,17 @@ def _process_assertions_with_unified_retry(http_req, retry_config):
|
|
582
598
|
time.sleep(retry_interval)
|
583
599
|
|
584
600
|
# 重新发送请求
|
585
|
-
|
601
|
+
try:
|
602
|
+
http_req.execute(disable_auth=disable_auth)
|
603
|
+
except Exception as exec_error:
|
604
|
+
# 如果重新执行请求失败,记录错误并继续重试
|
605
|
+
allure.attach(
|
606
|
+
f"重试执行请求失败: {type(exec_error).__name__}: "
|
607
|
+
f"{str(exec_error)}",
|
608
|
+
name=f"重试请求执行失败 #{attempt}",
|
609
|
+
attachment_type=allure.attachment_type.TEXT
|
610
|
+
)
|
611
|
+
continue
|
586
612
|
|
587
613
|
# 过滤出仍在重试范围内的断言
|
588
614
|
still_retryable_assertions = []
|
@@ -657,6 +683,8 @@ def _process_assertions_with_unified_retry(http_req, retry_config):
|
|
657
683
|
)
|
658
684
|
|
659
685
|
try:
|
686
|
+
# 确保在最终断言之前重新执行一次请求
|
687
|
+
http_req.execute(disable_auth=disable_auth)
|
660
688
|
results, _ = http_req.process_asserts()
|
661
689
|
return results
|
662
690
|
except AssertionError as final_err:
|
pytest_dsl/plugin.py
CHANGED
@@ -5,11 +5,12 @@
|
|
5
5
|
"""
|
6
6
|
import pytest
|
7
7
|
import os
|
8
|
-
from pathlib import Path
|
9
8
|
|
10
9
|
# 导入模块化组件
|
11
10
|
from pytest_dsl.core.yaml_loader import add_yaml_options, load_yaml_variables
|
12
|
-
from pytest_dsl.core.plugin_discovery import
|
11
|
+
from pytest_dsl.core.plugin_discovery import (
|
12
|
+
load_all_plugins, scan_local_keywords
|
13
|
+
)
|
13
14
|
from pytest_dsl.core.global_context import global_context
|
14
15
|
|
15
16
|
|
@@ -39,6 +40,23 @@ def pytest_configure(config):
|
|
39
40
|
|
40
41
|
# 加载所有已安装的关键字插件
|
41
42
|
load_all_plugins()
|
42
|
-
|
43
|
+
|
43
44
|
# 加载本地关键字(向后兼容)
|
44
|
-
scan_local_keywords()
|
45
|
+
scan_local_keywords()
|
46
|
+
|
47
|
+
# 自动导入项目中的resources目录
|
48
|
+
try:
|
49
|
+
from pytest_dsl.core.custom_keyword_manager import custom_keyword_manager
|
50
|
+
|
51
|
+
# 获取pytest的根目录
|
52
|
+
project_root = str(config.rootdir) if config.rootdir else os.getcwd()
|
53
|
+
|
54
|
+
# 检查是否存在resources目录
|
55
|
+
resources_dir = os.path.join(project_root, "resources")
|
56
|
+
if os.path.exists(resources_dir) and os.path.isdir(resources_dir):
|
57
|
+
custom_keyword_manager.auto_import_resources_directory(
|
58
|
+
project_root)
|
59
|
+
print(f"pytest环境:已自动导入resources目录 {resources_dir}")
|
60
|
+
|
61
|
+
except Exception as e:
|
62
|
+
print(f"pytest环境:自动导入resources目录时出现警告: {str(e)}")
|
@@ -1,23 +1,23 @@
|
|
1
1
|
pytest_dsl/__init__.py,sha256=FzwXGvmuvMhRBKxvCdh1h-yJ2wUOnDxcTbU4Nt5fHn8,301
|
2
|
-
pytest_dsl/cli.py,sha256=
|
2
|
+
pytest_dsl/cli.py,sha256=kFGOoGQ3dzi5C895QPawnAkif6UmQ4f9zFZmmag0Zgo,34336
|
3
3
|
pytest_dsl/conftest_adapter.py,sha256=cevEb0oEZKTZfUrGe1-CmkFByxKhUtjuurBJP7kpLc0,149
|
4
4
|
pytest_dsl/main_adapter.py,sha256=pUIPN_EzY3JCDlYK7yF_OeLDVqni8vtG15G7gVzPJXg,181
|
5
|
-
pytest_dsl/plugin.py,sha256=
|
5
|
+
pytest_dsl/plugin.py,sha256=Ymepaknms6N5mMoFgtiVi4YYiycE8a_6BPCBONmN-W8,1901
|
6
6
|
pytest_dsl/core/__init__.py,sha256=ersUoxIWSrisxs9GX_STlH4XAbjNxAWUQB0NboaC5zI,322
|
7
7
|
pytest_dsl/core/auth_provider.py,sha256=IZfXXrr4Uuc8QHwRPvhHSzNa2fwrqhjYts1xh78D39Q,14861
|
8
8
|
pytest_dsl/core/auto_decorator.py,sha256=9Mga-GB4AzV5nkB6zpfaq8IuHa0KOH8LlFvnWyH_tnU,6623
|
9
9
|
pytest_dsl/core/auto_directory.py,sha256=egyTnVxtGs4P75EIivRauLRPJfN9aZpoGVvp_Ma72AM,2714
|
10
10
|
pytest_dsl/core/context.py,sha256=fXpVQon666Lz_PCexjkWMBBr-Xcd1SkDMp2vHar6eIs,664
|
11
|
-
pytest_dsl/core/custom_keyword_manager.py,sha256=
|
12
|
-
pytest_dsl/core/dsl_executor.py,sha256=
|
11
|
+
pytest_dsl/core/custom_keyword_manager.py,sha256=vFXRfKXOu7CxoLsLCd6B2TI_JgOrfnE8JN9iShdv_hw,12308
|
12
|
+
pytest_dsl/core/dsl_executor.py,sha256=T-8_U3s3KD3HIZ0fWcydftOh9qAwWZDbSNxiT2SBDeA,32039
|
13
13
|
pytest_dsl/core/dsl_executor_utils.py,sha256=cFoR2p3qQ2pb-UhkoefleK-zbuFqf0aBLh2Rlp8Ebs4,2180
|
14
14
|
pytest_dsl/core/global_context.py,sha256=NcEcS2V61MT70tgAsGsFWQq0P3mKjtHQr1rgT3yTcyY,3535
|
15
15
|
pytest_dsl/core/http_client.py,sha256=hdx8gI4JCmq1-96pbiKeyKzSQUzPAi08cRNmljiPQmY,15536
|
16
|
-
pytest_dsl/core/http_request.py,sha256=
|
16
|
+
pytest_dsl/core/http_request.py,sha256=6e-gTztH3wu2eSW27Nc0uPmyWjB6oBwndx8Vqnu5uyg,60030
|
17
17
|
pytest_dsl/core/keyword_manager.py,sha256=hoNXHQcumnufPRUobnY0mnku4CHxSg2amwPFby4gQEs,7643
|
18
18
|
pytest_dsl/core/lexer.py,sha256=WaLzt9IhtHiA90Fg2WGgfVztveCUhtgxzANBaEiy-F8,4347
|
19
|
-
pytest_dsl/core/parser.py,sha256=
|
20
|
-
pytest_dsl/core/parsetab.py,sha256=
|
19
|
+
pytest_dsl/core/parser.py,sha256=pZjbfvab-VLjGJ28AV-69Nrdom_F1L0hwO76TyTyC2s,11947
|
20
|
+
pytest_dsl/core/parsetab.py,sha256=o4XbFKwpsi3fYmfI_F6u5NSM61Qp6gTx-Sfh1jDINxI,31767
|
21
21
|
pytest_dsl/core/plugin_discovery.py,sha256=3pt3EXJ7EPF0rkUlyDZMVHkIiTy2vicdIIQJkrHXZjY,8305
|
22
22
|
pytest_dsl/core/utils.py,sha256=q0AMdw5HO33JvlA3UJeQ7IXh1Z_8K1QlwiM1_yiITrU,5350
|
23
23
|
pytest_dsl/core/variable_utils.py,sha256=sx5DFZAO_syi0E_0ACisiZUQL9yxGeOfNmMtV6w9V3E,13947
|
@@ -39,16 +39,16 @@ pytest_dsl/examples/http/__init__.py,sha256=TCV9NzLmBbPDwNpLQs4_s_LlX9T47ApQ5UAr
|
|
39
39
|
pytest_dsl/examples/http/builtin_auth_test.auto,sha256=qZYpmxTBW018E5YQ4c8bbnoByEA3Y7BzpPfLJtDwMKQ,2374
|
40
40
|
pytest_dsl/examples/http/file_reference_test.auto,sha256=lHDxuR9NWp-DdASRUt5xNlcOn7FtmLu6oAGDvSsMpeo,3870
|
41
41
|
pytest_dsl/examples/http/http_advanced.auto,sha256=rVEtEY93rYcSrQJ7ntwW-GbHm8wltDobgd-KydIdVLU,2595
|
42
|
-
pytest_dsl/examples/http/http_example.auto,sha256=
|
42
|
+
pytest_dsl/examples/http/http_example.auto,sha256=g66-jQODonQeoVSRdggUIho6FGm5ON6Vqa0nuLDKG1o,4982
|
43
43
|
pytest_dsl/examples/http/http_length_test.auto,sha256=GYlFtSj0Nfk_9aqQrCXvRlwvTJHOk9CIf8X1CV_VKJg,1972
|
44
|
-
pytest_dsl/examples/http/http_retry_assertions.auto,sha256=
|
45
|
-
pytest_dsl/examples/http/http_retry_assertions_enhanced.auto,sha256=
|
44
|
+
pytest_dsl/examples/http/http_retry_assertions.auto,sha256=Dke5gkEZ9PTnKAhH86Umoo5DSh8P3RGjZN-gQSmrcBU,3385
|
45
|
+
pytest_dsl/examples/http/http_retry_assertions_enhanced.auto,sha256=Y9Lt6KO9z799na-jtZGv6nrskOlM3CXVGPVo82SEmHM,3195
|
46
46
|
pytest_dsl/examples/http/http_with_yaml.auto,sha256=u6Bw4EqQuQAMV-g2xS_iPmZwL4WRTpTqsJhL3xMRyfo,1942
|
47
|
-
pytest_dsl/examples/http/new_retry_test.auto,sha256=
|
48
|
-
pytest_dsl/examples/http/retry_assertions_only.auto,sha256=
|
49
|
-
pytest_dsl/examples/http/retry_config_only.auto,sha256=
|
50
|
-
pytest_dsl/examples/http/retry_debug.auto,sha256=
|
51
|
-
pytest_dsl/examples/http/retry_with_fix.auto,sha256=
|
47
|
+
pytest_dsl/examples/http/new_retry_test.auto,sha256=8ALnUYsZDI9TryQ2zDUg1JJYy7KGWKNQaECqure_0ck,669
|
48
|
+
pytest_dsl/examples/http/retry_assertions_only.auto,sha256=KhLnpGYIGz49VQZuXqcbKucEV4uW0mUWiQKg_MM80Vw,1887
|
49
|
+
pytest_dsl/examples/http/retry_config_only.auto,sha256=jGlpOcJS9IkN9OSe3Hs4uIq5EwxCzIg_72q5HFJK8NI,1482
|
50
|
+
pytest_dsl/examples/http/retry_debug.auto,sha256=5f32aYYpnNg98sl8-2arooHA4LI4870rkEGu8Z4UlE8,1136
|
51
|
+
pytest_dsl/examples/http/retry_with_fix.auto,sha256=GUn4T9oPsOQTsxScBRJD-M_sQkS3k2HDFYShtJNH-9s,693
|
52
52
|
pytest_dsl/examples/http/simple_retry.auto,sha256=Y7S8sR8VRjdk-iVJxcOD0Fb2tt_RO00BmA9eat3L0ks,569
|
53
53
|
pytest_dsl/examples/http/vars.yaml,sha256=GO0x6kpaUYk90TSOxtXh_3RYcacw8-ogBv5nG72Lr9Y,1186
|
54
54
|
pytest_dsl/examples/quickstart/api_basics.auto,sha256=SrDRBASqy5ZMXnmfczuKNCXoTijF54DChpeTrfsDtGQ,1544
|
@@ -57,7 +57,7 @@ pytest_dsl/examples/quickstart/loops.auto,sha256=ZNZ6qP636v8QMY8QRyTUBB43gWCsqHb
|
|
57
57
|
pytest_dsl/keywords/__init__.py,sha256=5aiyPU_t1UiB2MEZ6M9ffOKnV1mFT_2YHxnZvyWaBNI,372
|
58
58
|
pytest_dsl/keywords/assertion_keywords.py,sha256=obW06H_3AizsvEM_9VE2JVuwvgrNVqP1kUTDd3U1SMk,23240
|
59
59
|
pytest_dsl/keywords/global_keywords.py,sha256=4yw5yeXoGf_4W26F39EA2Pp-mH9GiKGy2jKgFO9a_wM,2509
|
60
|
-
pytest_dsl/keywords/http_keywords.py,sha256=
|
60
|
+
pytest_dsl/keywords/http_keywords.py,sha256=baT_p04lOqZpfmOvBdPdzW2_KTikMEJmKPvpEx5sddU,28839
|
61
61
|
pytest_dsl/keywords/system_keywords.py,sha256=hjsACYER87rseSj4thBFnjDqe6At5hBT4Gjifj4ulDE,24470
|
62
62
|
pytest_dsl/remote/__init__.py,sha256=syRSxTlTUfdAPleJnVS4MykRyEN8_SKiqlsn6SlIK8k,120
|
63
63
|
pytest_dsl/remote/hook_manager.py,sha256=0hwRKP8yhcnfAnrrnZGVT-S0TBgo6c0A4qO5XRpvV1U,4899
|
@@ -65,9 +65,9 @@ pytest_dsl/remote/keyword_client.py,sha256=BL80MOaLroUi0v-9sLtkJ55g1R0Iw9SE1k11I
|
|
65
65
|
pytest_dsl/remote/keyword_server.py,sha256=vGIE3Bhh461xX_u1U-Cf5nrWL2GQFYdtQdcMWfFIYgE,22320
|
66
66
|
pytest_dsl/remote/variable_bridge.py,sha256=dv-d3Gq9ttvvrXM1fdlLtoSOPB6vRp0_GBOwX4wvcy8,7121
|
67
67
|
pytest_dsl/templates/keywords_report.html,sha256=7x84iq6hi08nf1iQ95jZ3izcAUPx6JFm0_8xS85CYws,31241
|
68
|
-
pytest_dsl-0.
|
69
|
-
pytest_dsl-0.
|
70
|
-
pytest_dsl-0.
|
71
|
-
pytest_dsl-0.
|
72
|
-
pytest_dsl-0.
|
73
|
-
pytest_dsl-0.
|
68
|
+
pytest_dsl-0.13.0.dist-info/licenses/LICENSE,sha256=Rguy8cb9sYhK6cmrBdXvwh94rKVDh2tVZEWptsHIsVM,1071
|
69
|
+
pytest_dsl-0.13.0.dist-info/METADATA,sha256=Z3ywUBY2yKn3V6BouBNFEcZ1l1D6I-_S2-NLCGBcGeE,29655
|
70
|
+
pytest_dsl-0.13.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
71
|
+
pytest_dsl-0.13.0.dist-info/entry_points.txt,sha256=PLOBbH02OGY1XR1JDKIZB1Em87loUvbgMRWaag-5FhY,204
|
72
|
+
pytest_dsl-0.13.0.dist-info/top_level.txt,sha256=4CrSx4uNqxj7NvK6k1y2JZrSrJSzi-UvPZdqpUhumWM,11
|
73
|
+
pytest_dsl-0.13.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|