From a0ce13a4cc3af1fb0b64f60622f90d38a81d99f7 Mon Sep 17 00:00:00 2001 From: Ric Evans <19216225+ric-evans@users.noreply.github.com> Date: Wed, 22 May 2024 11:56:13 -1000 Subject: [PATCH] Use openapi's `RequestsOpenAPIResponse` and Log on Error (#147) * Use `openapi_core_requests.RequestsOpenAPIResponse` and Log on Error * update dependencies*.log files(s) * take 2 * better logging * stable logging * remove breakpoint --------- Co-authored-by: github-actions --- dependencies-dev.log | 12 ++++++------ dependencies-mypy.log | 24 +++++++++++------------ dependencies-openapi.log | 8 ++++---- dependencies-telemetry.log | 8 ++++---- dependencies-tests.log | 16 +++++++-------- dependencies.log | 4 ++-- rest_tools/client/utils.py | 40 +++++++++++++------------------------- 7 files changed, 49 insertions(+), 63 deletions(-) diff --git a/dependencies-dev.log b/dependencies-dev.log index f70672c3..633efb5a 100644 --- a/dependencies-dev.log +++ b/dependencies-dev.log @@ -12,7 +12,7 @@ cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 # via requests -cryptography==42.0.5 +cryptography==42.0.7 # via # pyjwt # wipac-rest-tools (setup.py) @@ -44,18 +44,18 @@ pyjwt[crypto]==2.8.0 # via wipac-rest-tools (setup.py) pypng==0.20220715.0 # via qrcode -pytest==8.2.0 +pytest==8.2.1 # via # pytest-asyncio # pytest-mock # wipac-rest-tools (setup.py) -pytest-asyncio==0.23.6 +pytest-asyncio==0.23.7 # via wipac-rest-tools (setup.py) pytest-mock==3.14.0 # via wipac-rest-tools (setup.py) qrcode==7.4.2 # via wipac-rest-tools (setup.py) -requests==2.31.0 +requests==2.32.2 # via # requests-futures # requests-mock @@ -65,11 +65,11 @@ requests-futures==1.0.1 # via wipac-rest-tools (setup.py) requests-mock==1.12.1 # via wipac-rest-tools (setup.py) -ruff==0.4.2 +ruff==0.4.4 # via wipac-rest-tools (setup.py) tornado==6.4 # via wipac-rest-tools (setup.py) -types-requests==2.31.0.20240406 +types-requests==2.32.0.20240521 # via wipac-rest-tools (setup.py) typing-extensions==4.11.0 # via diff --git a/dependencies-mypy.log b/dependencies-mypy.log index e37c336c..2ffc8bed 100644 --- a/dependencies-mypy.log +++ b/dependencies-mypy.log @@ -26,13 +26,13 @@ colorama==0.4.6 # via crayons coloredlogs==15.0.1 # via wipac-telemetry -coverage[toml]==7.5.0 +coverage[toml]==7.5.1 # via # pytest-cov # wipac-rest-tools (setup.py) crayons==0.4.0 # via pycycle -cryptography==42.0.5 +cryptography==42.0.7 # via # pyjwt # wipac-rest-tools (setup.py) @@ -46,7 +46,7 @@ googleapis-common-protos==1.59.1 # via # opentelemetry-exporter-jaeger-proto-grpc # opentelemetry-exporter-otlp-proto-http -grpcio==1.63.0 +grpcio==1.64.0 # via opentelemetry-exporter-jaeger-proto-grpc httpretty==1.1.4 # via wipac-rest-tools (setup.py) @@ -60,7 +60,7 @@ iniconfig==2.0.0 # via pytest isodate==0.6.1 # via openapi-core -jinja2==3.1.3 +jinja2==3.1.4 # via click-completion jsonschema==4.22.0 # via @@ -151,14 +151,14 @@ pyjwt[crypto]==2.8.0 # via wipac-rest-tools (setup.py) pypng==0.20220715.0 # via qrcode -pytest==8.2.0 +pytest==8.2.1 # via # pycycle # pytest-asyncio # pytest-cov # pytest-mock # wipac-rest-tools (setup.py) -pytest-asyncio==0.23.6 +pytest-asyncio==0.23.7 # via wipac-rest-tools (setup.py) pytest-cov==5.0.0 # via wipac-rest-tools (setup.py) @@ -173,7 +173,7 @@ referencing==0.31.1 # jsonschema # jsonschema-path # jsonschema-specifications -requests==2.31.0 +requests==2.32.2 # via # jsonschema-path # opentelemetry-exporter-otlp-proto-http @@ -187,11 +187,11 @@ requests-mock==1.12.1 # via wipac-rest-tools (setup.py) rfc3339-validator==0.1.4 # via openapi-schema-validator -rpds-py==0.18.0 +rpds-py==0.18.1 # via # jsonschema # referencing -ruff==0.4.2 +ruff==0.4.4 # via wipac-rest-tools (setup.py) shellingham==1.5.4 # via click-completion @@ -205,7 +205,7 @@ thrift==0.20.0 # via opentelemetry-exporter-jaeger-thrift tornado==6.4 # via wipac-rest-tools (setup.py) -types-requests==2.31.0.20240406 +types-requests==2.32.0.20240521 # via wipac-rest-tools (setup.py) typing-extensions==4.11.0 # via @@ -219,7 +219,7 @@ urllib3==2.2.1 # requests # types-requests # wipac-rest-tools (setup.py) -werkzeug==3.0.2 +werkzeug==3.0.3 # via openapi-core wheel==0.43.0 # via wipac-rest-tools (setup.py) @@ -231,5 +231,5 @@ wipac-telemetry==0.3.0 # via wipac-rest-tools (setup.py) wrapt==1.16.0 # via deprecated -zipp==3.18.1 +zipp==3.18.2 # via importlib-metadata diff --git a/dependencies-openapi.log b/dependencies-openapi.log index af78c18f..c31cb609 100644 --- a/dependencies-openapi.log +++ b/dependencies-openapi.log @@ -16,7 +16,7 @@ cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 # via requests -cryptography==42.0.5 +cryptography==42.0.7 # via pyjwt idna==3.7 # via requests @@ -68,7 +68,7 @@ referencing==0.31.1 # jsonschema # jsonschema-path # jsonschema-specifications -requests==2.31.0 +requests==2.32.2 # via # jsonschema-path # requests-futures @@ -78,7 +78,7 @@ requests-futures==1.0.1 # via wipac-rest-tools (setup.py) rfc3339-validator==0.1.4 # via openapi-schema-validator -rpds-py==0.18.0 +rpds-py==0.18.1 # via # jsonschema # referencing @@ -96,7 +96,7 @@ urllib3==2.2.1 # via # requests # wipac-rest-tools (setup.py) -werkzeug==3.0.2 +werkzeug==3.0.3 # via openapi-core wipac-dev-tools==1.9.1 # via wipac-rest-tools (setup.py) diff --git a/dependencies-telemetry.log b/dependencies-telemetry.log index 0d3eb059..df4ab2c2 100644 --- a/dependencies-telemetry.log +++ b/dependencies-telemetry.log @@ -14,7 +14,7 @@ charset-normalizer==3.3.2 # via requests coloredlogs==15.0.1 # via wipac-telemetry -cryptography==42.0.5 +cryptography==42.0.7 # via pyjwt deprecated==1.2.14 # via @@ -24,7 +24,7 @@ googleapis-common-protos==1.59.1 # via # opentelemetry-exporter-jaeger-proto-grpc # opentelemetry-exporter-otlp-proto-http -grpcio==1.63.0 +grpcio==1.64.0 # via opentelemetry-exporter-jaeger-proto-grpc humanfriendly==10.0 # via coloredlogs @@ -74,7 +74,7 @@ pypng==0.20220715.0 # via qrcode qrcode==7.4.2 # via wipac-rest-tools (setup.py) -requests==2.31.0 +requests==2.32.2 # via # opentelemetry-exporter-otlp-proto-http # requests-futures @@ -106,5 +106,5 @@ wipac-telemetry==0.3.0 # via wipac-rest-tools (setup.py) wrapt==1.16.0 # via deprecated -zipp==3.18.1 +zipp==3.18.2 # via importlib-metadata diff --git a/dependencies-tests.log b/dependencies-tests.log index 85677744..cdd901a8 100644 --- a/dependencies-tests.log +++ b/dependencies-tests.log @@ -20,13 +20,13 @@ click-completion==0.5.2 # via pycycle colorama==0.4.6 # via crayons -coverage[toml]==7.5.0 +coverage[toml]==7.5.1 # via # pytest-cov # wipac-rest-tools (setup.py) crayons==0.4.0 # via pycycle -cryptography==42.0.5 +cryptography==42.0.7 # via pyjwt flake8==7.0.0 # via wipac-rest-tools (setup.py) @@ -36,7 +36,7 @@ idna==3.7 # via requests iniconfig==2.0.0 # via pytest -jinja2==3.1.3 +jinja2==3.1.4 # via click-completion markupsafe==2.1.5 # via jinja2 @@ -58,14 +58,14 @@ pyjwt[crypto]==2.8.0 # via wipac-rest-tools (setup.py) pypng==0.20220715.0 # via qrcode -pytest==8.2.0 +pytest==8.2.1 # via # pycycle # pytest-asyncio # pytest-cov # pytest-mock # wipac-rest-tools (setup.py) -pytest-asyncio==0.23.6 +pytest-asyncio==0.23.7 # via wipac-rest-tools (setup.py) pytest-cov==5.0.0 # via wipac-rest-tools (setup.py) @@ -73,7 +73,7 @@ pytest-mock==3.14.0 # via wipac-rest-tools (setup.py) qrcode==7.4.2 # via wipac-rest-tools (setup.py) -requests==2.31.0 +requests==2.32.2 # via # requests-futures # requests-mock @@ -83,7 +83,7 @@ requests-futures==1.0.1 # via wipac-rest-tools (setup.py) requests-mock==1.12.1 # via wipac-rest-tools (setup.py) -ruff==0.4.2 +ruff==0.4.4 # via wipac-rest-tools (setup.py) shellingham==1.5.4 # via click-completion @@ -91,7 +91,7 @@ six==1.16.0 # via click-completion tornado==6.4 # via wipac-rest-tools (setup.py) -types-requests==2.31.0.20240406 +types-requests==2.32.0.20240521 # via wipac-rest-tools (setup.py) typing-extensions==4.11.0 # via diff --git a/dependencies.log b/dependencies.log index 46c5c8a1..a59f03ed 100644 --- a/dependencies.log +++ b/dependencies.log @@ -12,7 +12,7 @@ cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 # via requests -cryptography==42.0.5 +cryptography==42.0.7 # via pyjwt idna==3.7 # via requests @@ -24,7 +24,7 @@ pypng==0.20220715.0 # via qrcode qrcode==7.4.2 # via wipac-rest-tools (setup.py) -requests==2.31.0 +requests==2.32.2 # via # requests-futures # wipac-dev-tools diff --git a/rest_tools/client/utils.py b/rest_tools/client/utils.py index e0915458..74b8cdff 100644 --- a/rest_tools/client/utils.py +++ b/rest_tools/client/utils.py @@ -15,6 +15,7 @@ try: import openapi_core from openapi_core.contrib import requests as openapi_core_requests + from openapi_core.exceptions import OpenAPIError except ImportError: pass # if client code wants to use these features, then let the built-in errors raise @@ -37,33 +38,18 @@ async def request_and_validate( # run request as async in case of other dependent, concurrent actions (ex: test suite runs server in same process) response = await asyncio.wrap_future(rc.session.request(method, url, **kwargs)) # type: ignore[var-annotated,arg-type] - # duck typing magic - class _DuckResponse(openapi_core.protocols.Response): - """AKA 'openapi_core_requests.RequestsOpenAPIResponse' but correct.""" - - @property - def data(self) -> Optional[bytes]: - return response.content - - @property - def status_code(self) -> int: - return int(response.status_code) - - @property - def content_type(self) -> str: - # application/json; charset=UTF-8 -> application/json - # ex: openapi_core.validation.response.exceptions.DataValidationError: DataValidationError: Content for the following mimetype not found: application/json; charset=UTF-8. Valid mimetypes: ['application/json'] - return str(response.headers.get("Content-Type", "")).split(";")[0] - # alternatively, look at how 'openapi_core_requests.RequestsOpenAPIRequest.mimetype' handles similarly - - @property - def headers(self) -> dict: - return dict(response.headers) - - openapi_spec.validate_response( - openapi_core_requests.RequestsOpenAPIRequest(response.request), - _DuckResponse(), - ) + try: + openapi_spec.validate_response( + openapi_core_requests.RequestsOpenAPIRequest(response.request), + openapi_core_requests.RequestsOpenAPIResponse(response), + ) + except OpenAPIError as e: + LOGGER.error( + f"OpenAPI response validator encountered an error: '{e}'; more info below." + ) + LOGGER.info(f"request: {vars(response.request)}") + LOGGER.info(f"response: {vars(response)}") + raise out = rc._decode(response.content) response.raise_for_status()