From 1c69d8d44ee4414e6bf922988018cc7cf0a11818 Mon Sep 17 00:00:00 2001 From: Zach Fuller Date: Tue, 23 Apr 2024 18:41:26 -0700 Subject: [PATCH] Added Logging (#28) * added logging with loguru * run ci workflow on all branches for push --- .github/workflows/ci.yml | 2 +- poetry.lock | 85 +++++++++++++++++++++--------- pyproject.toml | 5 +- requirements.txt | 9 ++++ src/loamy/session.py | 111 ++++++++++++++++++++++++++++++++++----- tests/test_requests.py | 3 +- 6 files changed, 171 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e967f84..1332958 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ name: CI on: push: - branches: [ "main", "dev"] + branches: [ "*" ] pull_request: branches: [ "main", "dev" ] diff --git a/poetry.lock b/poetry.lock index 024aba4..bc3a0a5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -840,6 +840,24 @@ files = [ docs = ["Sphinx (>=5.0.2)", "doc8 (>=0.11.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-reredirects (>=0.1.2)", "sphinx-rtd-dark-mode (>=1.3.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-apidoc (>=0.4.0)"] testing = ["black", "isort", "pytest (>=6,!=7.0.0)", "pytest-xdist (>=2)", "twine"] +[[package]] +name = "loguru" +version = "0.7.2" +description = "Python logging made (stupidly) simple" +optional = false +python-versions = ">=3.5" +files = [ + {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, + {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1335,18 +1353,19 @@ testing = ["aboutcode-toolkit (>=6.0.0)", "black", "pytest (>=6,!=7.0.0)", "pyte [[package]] name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, + {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" @@ -1666,28 +1685,28 @@ files = [ [[package]] name = "ruff" -version = "0.3.7" +version = "0.4.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, - {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, - {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, - {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, - {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, - {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, - {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, - {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, + {file = "ruff-0.4.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2d9ef6231e3fbdc0b8c72404a1a0c46fd0dcea84efca83beb4681c318ea6a953"}, + {file = "ruff-0.4.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9485f54a7189e6f7433e0058cf8581bee45c31a25cd69009d2a040d1bd4bfaef"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2921ac03ce1383e360e8a95442ffb0d757a6a7ddd9a5be68561a671e0e5807e"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eec8d185fe193ad053eda3a6be23069e0c8ba8c5d20bc5ace6e3b9e37d246d3f"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa27d9d72a94574d250f42b7640b3bd2edc4c58ac8ac2778a8c82374bb27984"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f1ee41580bff1a651339eb3337c20c12f4037f6110a36ae4a2d864c52e5ef954"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0926cefb57fc5fced629603fbd1a23d458b25418681d96823992ba975f050c2b"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c6e37f2e3cd74496a74af9a4fa67b547ab3ca137688c484749189bf3a686ceb"}, + {file = "ruff-0.4.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd703a5975ac1998c2cc5e9494e13b28f31e66c616b0a76e206de2562e0843c"}, + {file = "ruff-0.4.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b92f03b4aa9fa23e1799b40f15f8b95cdc418782a567d6c43def65e1bbb7f1cf"}, + {file = "ruff-0.4.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c859f294f8633889e7d77de228b203eb0e9a03071b72b5989d89a0cf98ee262"}, + {file = "ruff-0.4.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b34510141e393519a47f2d7b8216fec747ea1f2c81e85f076e9f2910588d4b64"}, + {file = "ruff-0.4.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6e68d248ed688b9d69fd4d18737edcbb79c98b251bba5a2b031ce2470224bdf9"}, + {file = "ruff-0.4.1-py3-none-win32.whl", hash = "sha256:b90506f3d6d1f41f43f9b7b5ff845aeefabed6d2494307bc7b178360a8805252"}, + {file = "ruff-0.4.1-py3-none-win_amd64.whl", hash = "sha256:c7d391e5936af5c9e252743d767c564670dc3889aff460d35c518ee76e4b26d7"}, + {file = "ruff-0.4.1-py3-none-win_arm64.whl", hash = "sha256:a1eaf03d87e6a7cd5e661d36d8c6e874693cb9bc3049d110bc9a97b350680c43"}, + {file = "ruff-0.4.1.tar.gz", hash = "sha256:d592116cdbb65f8b1b7e2a2b48297eb865f6bdc20641879aa9d7b9c11d86db79"}, ] [[package]] @@ -1854,13 +1873,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "virtualenv" -version = "20.25.3" +version = "20.26.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.3-py3-none-any.whl", hash = "sha256:8aac4332f2ea6ef519c648d0bc48a5b1d324994753519919bddbb1aff25a104e"}, - {file = "virtualenv-20.25.3.tar.gz", hash = "sha256:7bb554bbdfeaacc3349fa614ea5bff6ac300fc7c335e9facf3a3bcfc703f45be"}, + {file = "virtualenv-20.26.0-py3-none-any.whl", hash = "sha256:0846377ea76e818daaa3e00a4365c018bc3ac9760cbb3544de542885aad61fb3"}, + {file = "virtualenv-20.26.0.tar.gz", hash = "sha256:ec25a9671a5102c8d2657f62792a27b48f016664c6873f6beed3800008577210"}, ] [package.dependencies] @@ -1883,6 +1902,20 @@ files = [ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +optional = false +python-versions = ">=3.5" +files = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] + +[package.extras] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] + [[package]] name = "yarl" version = "1.9.4" @@ -1992,4 +2025,4 @@ uvloop = ["uvloop"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "0d08c19e02523c43bd3e87c452111772edb9cafca341fa44639ca69e9c4759e1" +content-hash = "47cb3db92cb1dfda6aebe74fe6cdeb026c417dcb1e904477cf86f9fc3532f561" diff --git a/pyproject.toml b/pyproject.toml index e8d8b8d..07608e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,9 +14,10 @@ aiohttp = ">=3.9.5" aiodns = "~3.1.1" msgspec = "~0.18.6" uvloop = { version = "0.19.0", optional = true } +loguru = "^0.7.2" [tool.poetry.group.dev.dependencies] -ruff = "~0.3.7" +ruff = "^0.4.0" pre-commit = "3.5.0" pytest = "^7.4.4" pytest-asyncio = "^0.21.1" @@ -38,7 +39,7 @@ target-version = "py310" [tool.ruff.lint] select = ["E", "F", "W", "C90", "I", "N", "UP", "ASYNC", "S", "B", "ERA", "PLE", "PLW", "PERF", "RUF"] -ignore = [] +ignore = ["E501"] # Allow fix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] diff --git a/requirements.txt b/requirements.txt index 2ad3424..9d185f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -140,6 +140,9 @@ cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 +colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" \ + --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ + --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7 \ --hash=sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98 \ @@ -221,6 +224,9 @@ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +loguru==0.7.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb \ + --hash=sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac msgspec==0.18.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06acbd6edf175bee0e36295d6b0302c6de3aaf61246b46f9549ca0041a9d7177 \ --hash=sha256:0e24539b25c85c8f0597274f11061c102ad6b0c56af053373ba4629772b407be \ @@ -404,6 +410,9 @@ pycares==4.4.0 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc +win32-setctime==1.1.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" \ + --hash=sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2 \ + --hash=sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51 \ --hash=sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce \ diff --git a/src/loamy/session.py b/src/loamy/session.py index bbfbc9f..2d5b0bc 100644 --- a/src/loamy/session.py +++ b/src/loamy/session.py @@ -1,15 +1,27 @@ import asyncio +import sys +from json import JSONDecodeError from typing import Literal import aiohttp import msgspec +from loguru import logger + +logger.add( + sys.stdout, + format="{time} {level} {message}", + filter="loamy", + level="DEBUG", +) try: import uvloop async_run = uvloop.run + logger.debug("Using uvloop for async operations") except ModuleNotFoundError: async_run = asyncio.run # type: ignore + logger.debug("Using asyncio for async operations") class RequestMap(msgspec.Struct): @@ -30,8 +42,12 @@ class RequestResponse(msgspec.Struct): class Clump: def __init__(self, requests: list[RequestMap]) -> None: self._requestMaps: list[RequestMap] = requests + logger.debug(f"Clump created with {len(self._requestMaps)} requests") def send_requests(self, return_exceptions: bool = False) -> list[RequestResponse]: + logger.info( + f"Sending {len(self._requestMaps)!s} requests with {return_exceptions=!s}" + ) return async_run(self._send_requests(rtn_exc=return_exceptions)) async def _send_requests(self, rtn_exc: bool) -> list[RequestResponse]: @@ -40,12 +56,15 @@ async def _send_requests(self, rtn_exc: bool) -> list[RequestResponse]: asyncio.ensure_future(self._route_request(req, session)) for req in self._requestMaps ] + logger.debug("Beginnging execution of request coroutines") results: list[RequestResponse | BaseException] = await asyncio.gather( *http_tasks, return_exceptions=rtn_exc ) + logger.debug("Finished execution of request coroutines") responses: list[RequestResponse] = [] for i, resp in enumerate(results): if isinstance(resp, BaseException): + logger.error(f"Manually creating RequestResponse object and nesting error - index {i}") # fmt: skip responses.append( RequestResponse( request_map=self._requestMaps[i], @@ -55,6 +74,7 @@ async def _send_requests(self, rtn_exc: bool) -> list[RequestResponse]: ) else: responses.append(resp) + logger.info(f"Returning {len(responses)!s} responses") return responses async def _route_request( @@ -62,6 +82,7 @@ async def _route_request( ) -> RequestResponse: response: RequestResponse = RequestResponse(request_map=req_map, status_code=0) try: + logger.debug(f"Sending {req_map.http_op} request to {req_map.url}") match req_map.http_op: case "GET": response = await self._send_get_request(req_map, session) @@ -76,8 +97,12 @@ async def _route_request( case "DELETE": response = await self._send_delete_request(req_map, session) case _: - pass + logger.error("No matching HTTP operation found") + raise NotImplementedError except Exception as e: + logger.exception( + f"Error sending {req_map.http_op} request to {req_map.url}" + ) response.error = e return response @@ -88,10 +113,20 @@ async def _send_get_request( async with session.get( req_map.url, headers=req_map.headers, params=req_map.query_params ) as resp: + error: aiohttp.ContentTypeError | JSONDecodeError | None = None status_code: int = resp.status - body = await resp.json() + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response @@ -104,10 +139,20 @@ async def _send_post_request( headers=req_map.headers, params=req_map.query_params, ) as resp: + error: aiohttp.ContentTypeError | JSONDecodeError | None = None status_code: int = resp.status - body = await resp.json() + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response @@ -121,9 +166,19 @@ async def _send_put_request( params=req_map.query_params, ) as resp: status_code: int = resp.status - body = await resp.json() + error: aiohttp.ContentTypeError | JSONDecodeError | None = None + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response @@ -137,9 +192,19 @@ async def _send_patch_request( params=req_map.query_params, ) as resp: status_code: int = resp.status - body = await resp.json() + error: aiohttp.ContentTypeError | JSONDecodeError | None = None + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response @@ -153,9 +218,19 @@ async def _send_options_request( params=req_map.query_params, ) as resp: status_code: int = resp.status - body = await resp.json() + error: aiohttp.ContentTypeError | JSONDecodeError | None = None + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response @@ -169,8 +244,18 @@ async def _send_delete_request( params=req_map.query_params, ) as resp: status_code: int = resp.status - body = await resp.json() + error: aiohttp.ContentTypeError | JSONDecodeError | None = None + logger.debug(f"{resp.url} returned {status_code}") + try: + body = await resp.json() + except (aiohttp.ContentTypeError, JSONDecodeError) as e: + logger.exception(f"Failed to decode JSON response from {resp.url}") + error = e + logger.trace("Attempting to read response as text") + text: str = await resp.text() + logger.trace("Successfully read response as text") + body = {"text": text} response = RequestResponse( - request_map=req_map, status_code=status_code, body=body + request_map=req_map, status_code=status_code, body=body, error=error ) return response diff --git a/tests/test_requests.py b/tests/test_requests.py index 53b9a0d..e7fdbf2 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -9,7 +9,6 @@ def request_map_collection() -> List[RequestMap]: requests: List[RequestMap] = [] for i in range(0, 100): - print(i) if i % 2 == 0: requests.append( RequestMap( @@ -57,7 +56,7 @@ def test_send_requests_with_exceptions( assert len(responses) == 101 for response in responses: if response.request_map.url == "http://localhost:44777/exception": - assert response.status_code == 0 + assert response.status_code == 500 assert response.error is not None else: assert response.status_code == 200