如何从tenacity中获取底层AssertionError的完整错误信息?
问题:如何获取Tenacity重试中断言的完整错误提示?
环境与代码
使用Tenacity 9.0.0 + Python 3.9,实现重试逻辑的代码如下:
@retry(stop=stop_after_attempt(6), wait=wait_fixed(5)) def assert_response(): logging.info("Retrying get flow logs") es.indices.refresh(index='monitoring') response = requests.get(url, headers=headers, json=data, params=params) assert response.status_code == 200, f"Response status is {response.status_code} and body: {response.text}" response_json = response.json() logging.info("Response: " + str(response_json)) assert response_json['meta']['run_id'] == 1742403068092, "run_id does not match" try: assert_response() except RetryError as e: underlying_error = e.last_attempt.exception() error_message = str(underlying_error) logging.error(f"Failed to get flow logs after retries: {underlying_error}") raise AssertionError(f"Failed to get flow logs after multiple retries: {error_message}") from underlying_error
当前问题
日志仅显示片段错误信息,无法获取断言中定义的完整提示(如"run_id does not match"):
integration-tests-1 | FAILED test_apps/monitoring_service/test_es_monitoring_dao.py::test - AssertionError: Failed to get flow logs after multiple retries: 'run_id' integration-tests-1 | ====================== 1 failed, 130 deselected in 11.42s ====================== integration-tests-1 | Result of the pytest script: 1
原因分析
日志里的'run_id'是KeyError的错误内容,说明在触发run_id匹配断言之前,代码先因为response_json['meta']['run_id']中的meta或run_id键不存在抛出了KeyError,导致断言的错误信息根本没机会触发。
解决方案
方案1:先检查键是否存在,再执行断言
在原断言前增加键存在性检查,确保只有当键存在时才执行匹配断言,同时给出明确的缺失提示:
@retry(stop=stop_after_attempt(6), wait=wait_fixed(5)) def assert_response(): logging.info("Retrying get flow logs") es.indices.refresh(index='monitoring') response = requests.get(url, headers=headers, json=data, params=params) assert response.status_code == 200, f"Response status is {response.status_code} and body: {response.text}" response_json = response.json() logging.info("Response: " + str(response_json)) # 先检查meta和run_id是否存在 assert 'meta' in response_json, "meta field not found in response" assert 'run_id' in response_json['meta'], "run_id field not found in meta" # 再执行run_id匹配断言 assert response_json['meta']['run_id'] == 1742403068092, "run_id does not match"
方案2:使用.get()安全取值,统一断言提示
用字典的.get()方法避免KeyError,同时在断言中包含实际获取到的值,方便排查:
@retry(stop=stop_after_attempt(6), wait=wait_fixed(5)) def assert_response(): logging.info("Retrying get flow logs") es.indices.refresh(index='monitoring') response = requests.get(url, headers=headers, json=data, params=params) assert response.status_code == 200, f"Response status is {response.status_code} and body: {response.text}" response_json = response.json() logging.info("Response: " + str(response_json)) # 安全获取run_id,不存在则返回None run_id = response_json.get('meta', {}).get('run_id') # 统一断言,覆盖键缺失和值不匹配两种情况 assert run_id == 1742403068092, f"run_id does not match or is missing. Expected: 1742403068092, Got: {run_id}"
方案3:捕获KeyError并转换为明确的断言错误
如果需要保留原有的直接取值方式,可以在函数内部捕获KeyError,将其转换为包含完整信息的AssertionError:
@retry(stop=stop_after_attempt(6), wait=wait_fixed(5)) def assert_response(): logging.info("Retrying get flow logs") es.indices.refresh(index='monitoring') response = requests.get(url, headers=headers, json=data, params=params) assert response.status_code == 200, f"Response status is {response.status_code} and body: {response.text}" response_json = response.json() logging.info("Response: " + str(response_json)) try: assert response_json['meta']['run_id'] == 1742403068092, "run_id does not match" except KeyError as e: raise AssertionError(f"Missing key in response: {str(e)}") from e
验证修改效果
修改后,无论是键缺失还是值不匹配,都会抛出包含完整信息的AssertionError,最终日志会显示你定义的完整错误提示,比如:
AssertionError: Failed to get flow logs after multiple retries: run_id does not match
或者
AssertionError: Failed to get flow logs after multiple retries: Missing key in response: 'meta'
内容的提问来源于stack exchange,提问作者tuk
相关产品推荐
相关产品推荐

