From 03434dcc8b658fde8cbbff252ca8232457a088fa Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:22:26 +0000 Subject: [PATCH 1/5] fix --- gli4py/error_handling.py | 50 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/gli4py/error_handling.py b/gli4py/error_handling.py index aa19ef6..6d00676 100644 --- a/gli4py/error_handling.py +++ b/gli4py/error_handling.py @@ -23,42 +23,38 @@ class AuthenticationError(NonZeroResponse): class TokenError(AuthenticationError): """Should be raised when the token is invalid or expired""" +from aiohttp import ClientResponse -def raise_for_status(response: Response) -> dict: +async def raise_for_status(response: ClientResponse) -> dict: """Checks whether or not the response was successful.""" - # 1. Read the body to guarantee aiohttp releases the connection back to the pool + + # 1. Safely read the body as JSON, falling back to text if it's HTML try: - text = ( - response.text() - if callable(getattr(response, "text", None)) - else response.text - ) - except Exception: # pylint: disable=broad-except # noqa: BLE001 - text = "" + # content_type=None forces aiohttp to parse it even if the router sends the wrong headers + res = await response.json(content_type=None) + except Exception: + text = await response.text() + raise UnsuccessfulRequest(f"Request failed or returned invalid JSON (Status {response.status}): {text}") + # 2. Process the GL-iNet logic if 200 <= response.status < 300: - res: dict = loads(text) if "result" in res: return res["result"] - - # Gl-inet's api uses its own error codes that are returned in - # status 200 messages - this is out of spec so we must handle it + if "error" not in res: raise ConnectionError(f"Unexpected response from GLinet router {res}") + if "message" not in res["error"]: res["error"]["message"] = "null" - if res["error"]["code"] == -1: - raise TokenError( - f"Request returned error code -1 ({res['error']['message']}), is the token expired or the password wrong?" - ) - if res["error"]["code"] == -32000: - raise AuthenticationError( - f"Request returned error code -32000 ({res['error']['message']}), is password wrong or the hashing process incorrect?" - ) - if res["error"]["code"] < 0: - raise NonZeroResponse( - f"Request returned error code {res['error']['code']} with message: {res['error']['message']}. Full response: {res}" - ) + + code = res["error"].get("code", 0) + if code == -1: + raise TokenError(f"Request returned error code -1 ({res['error']['message']})") + if code == -32000: + raise AuthenticationError(f"Request returned error code -32000 ({res['error']['message']})") + if code < 0: + raise NonZeroResponse(f"Request returned error code {code} with message: {res['error']['message']}") + return res - - raise UnsuccessfulRequest(f"Request failed with status {response.status}: {text}") + + raise UnsuccessfulRequest(f"Request failed with status {response.status}: {res}") From 49659a0b621f536040674902d267aaacad39e013 Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:15:53 +0000 Subject: [PATCH 2/5] re order import --- gli4py/error_handling.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gli4py/error_handling.py b/gli4py/error_handling.py index 6d00676..99167ce 100644 --- a/gli4py/error_handling.py +++ b/gli4py/error_handling.py @@ -1,7 +1,7 @@ """This module contains custom exceptions and a function to handle API response status codes.""" from json import loads -from requests import Response +from aiohttp import ClientResponse class APIClientError(Exception): @@ -23,8 +23,6 @@ class AuthenticationError(NonZeroResponse): class TokenError(AuthenticationError): """Should be raised when the token is invalid or expired""" -from aiohttp import ClientResponse - async def raise_for_status(response: ClientResponse) -> dict: """Checks whether or not the response was successful.""" From 37d2be95d8c05d32499df2d87ec7f640ea7b0f12 Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:24:38 +0000 Subject: [PATCH 3/5] whitespace --- gli4py/error_handling.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gli4py/error_handling.py b/gli4py/error_handling.py index 99167ce..7eabd72 100644 --- a/gli4py/error_handling.py +++ b/gli4py/error_handling.py @@ -25,11 +25,11 @@ class TokenError(AuthenticationError): async def raise_for_status(response: ClientResponse) -> dict: """Checks whether or not the response was successful.""" - + # 1. Safely read the body as JSON, falling back to text if it's HTML try: # content_type=None forces aiohttp to parse it even if the router sends the wrong headers - res = await response.json(content_type=None) + res = await response.json(content_type=None) except Exception: text = await response.text() raise UnsuccessfulRequest(f"Request failed or returned invalid JSON (Status {response.status}): {text}") @@ -38,13 +38,13 @@ async def raise_for_status(response: ClientResponse) -> dict: if 200 <= response.status < 300: if "result" in res: return res["result"] - + if "error" not in res: raise ConnectionError(f"Unexpected response from GLinet router {res}") - + if "message" not in res["error"]: res["error"]["message"] = "null" - + code = res["error"].get("code", 0) if code == -1: raise TokenError(f"Request returned error code -1 ({res['error']['message']})") @@ -52,7 +52,7 @@ async def raise_for_status(response: ClientResponse) -> dict: raise AuthenticationError(f"Request returned error code -32000 ({res['error']['message']})") if code < 0: raise NonZeroResponse(f"Request returned error code {code} with message: {res['error']['message']}") - + return res - + raise UnsuccessfulRequest(f"Request failed with status {response.status}: {res}") From 36527ae4ef1daba50eac065adb8812479cf107a6 Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:28:18 +0000 Subject: [PATCH 4/5] unused import --- gli4py/error_handling.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gli4py/error_handling.py b/gli4py/error_handling.py index 7eabd72..035d050 100644 --- a/gli4py/error_handling.py +++ b/gli4py/error_handling.py @@ -1,6 +1,5 @@ """This module contains custom exceptions and a function to handle API response status codes.""" -from json import loads from aiohttp import ClientResponse @@ -30,9 +29,9 @@ async def raise_for_status(response: ClientResponse) -> dict: try: # content_type=None forces aiohttp to parse it even if the router sends the wrong headers res = await response.json(content_type=None) - except Exception: + except Exception as exc: text = await response.text() - raise UnsuccessfulRequest(f"Request failed or returned invalid JSON (Status {response.status}): {text}") + raise UnsuccessfulRequest(f"Request failed or returned invalid JSON (Status {response.status}): {text}") from exc # 2. Process the GL-iNet logic if 200 <= response.status < 300: From d0ca500d85d45636f32a661f693bc3d24b48f392 Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:32:54 +0000 Subject: [PATCH 5/5] bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ea5f237..114c1b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gli4py" -version = "0.0.17-beta.2" +version = "0.0.17-beta.3" description = "A python 3 API wrapper for GL-inet routers for consumption by Home Assistant" authors = ["HarvsG "] license = "GNU GENERAL PUBLIC LICENSE"