Skip to content

Commit 7991852

Browse files
committed
Rename all exceptions from *Exception to *Error (N818)
Rename all custom exception classes to use the Error suffix per PEP 8 naming conventions (ruff N818). Also fix typo NotSuchTokenException to NoSuchTokenError. Enable pep8-naming (N) ruff rules.
1 parent d3fa87a commit 7991852

File tree

13 files changed

+217
-216
lines changed

13 files changed

+217
-216
lines changed

docs/action-queue.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Action queue
22

3-
The action queue automatically groups rapid, consecutive calls to `execute_action_group()` into a single ActionGroup execution. This minimizes the number of API calls and helps prevent rate limiting issues, such as `TooManyRequestsException`, `TooManyConcurrentRequestsException`, `TooManyExecutionsException`, or `ExecutionQueueFullException` which can occur if actions are sent individually in quick succession.
3+
The action queue automatically groups rapid, consecutive calls to `execute_action_group()` into a single ActionGroup execution. This minimizes the number of API calls and helps prevent rate limiting issues, such as `TooManyRequestsError`, `TooManyConcurrentRequestsError`, `TooManyExecutionsError`, or `ExecutionQueueFullError` which can occur if actions are sent individually in quick succession.
44

55
Important limitation:
66
- Gateways only allow a single action per device in each action group. The queue

docs/device-control.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ await client.execute_action_group(
198198

199199
## Limitations and rate limits
200200

201-
Gateways impose limits on how many executions can run or be queued simultaneously. If the execution queue is full, the API will raise an `ExecutionQueueFullException`. Most gateways allow up to 10 concurrent executions.
201+
Gateways impose limits on how many executions can run or be queued simultaneously. If the execution queue is full, the API will raise an `ExecutionQueueFullError`. Most gateways allow up to 10 concurrent executions.
202202

203203
### Action queue (batching across calls)
204204

docs/error-handling.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Error handling
22

3-
## Common exceptions
3+
## Common errors
44

5-
- `NotAuthenticatedException`
6-
- `TooManyRequestsException`
7-
- `TooManyConcurrentRequestsException`
8-
- `TooManyExecutionsException`
9-
- `MaintenanceException`
10-
- `AccessDeniedToGatewayException`
11-
- `BadCredentialsException`
5+
- `NotAuthenticatedError`
6+
- `TooManyRequestsError`
7+
- `TooManyConcurrentRequestsError`
8+
- `TooManyExecutionsError`
9+
- `MaintenanceError`
10+
- `AccessDeniedToGatewayError`
11+
- `BadCredentialsError`
1212

1313
## Retry and backoff guidance
1414

@@ -21,9 +21,9 @@ from pyoverkiz.auth.credentials import UsernamePasswordCredentials
2121
from pyoverkiz.client import OverkizClient
2222
from pyoverkiz.enums import Server
2323
from pyoverkiz.exceptions import (
24-
NotAuthenticatedException,
25-
TooManyConcurrentRequestsException,
26-
TooManyRequestsException,
24+
NotAuthenticatedError,
25+
TooManyConcurrentRequestsError,
26+
TooManyRequestsError,
2727
)
2828

2929

@@ -38,9 +38,9 @@ async def fetch_devices_with_retry() -> None:
3838
devices = await client.get_devices()
3939
print(devices)
4040
return
41-
except (TooManyRequestsException, TooManyConcurrentRequestsException):
41+
except (TooManyRequestsError, TooManyConcurrentRequestsError):
4242
await asyncio.sleep(0.5 * (attempt + 1))
43-
except NotAuthenticatedException:
43+
except NotAuthenticatedError:
4444
await client.login()
4545

4646

docs/event-handling.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ from pyoverkiz.auth.credentials import UsernamePasswordCredentials
3232
from pyoverkiz.client import OverkizClient
3333
from pyoverkiz.enums import Server
3434
from pyoverkiz.exceptions import (
35-
InvalidEventListenerIdException,
36-
NoRegisteredEventListenerException,
35+
InvalidEventListenerIdError,
36+
NoRegisteredEventListenerError,
3737
)
3838

3939

@@ -48,7 +48,7 @@ async def main() -> None:
4848
while True:
4949
try:
5050
events = await client.fetch_events()
51-
except (InvalidEventListenerIdException, NoRegisteredEventListenerException):
51+
except (InvalidEventListenerIdError, NoRegisteredEventListenerError):
5252
await asyncio.sleep(1)
5353
await client.register_event_listener()
5454
continue
@@ -96,6 +96,6 @@ asyncio.run(main())
9696

9797
## Reconnect tips
9898

99-
- Re-register the listener when you see `InvalidEventListenerIdException`.
99+
- Re-register the listener when you see `InvalidEventListenerIdError`.
100100
- Poll occasionally if your network has unstable connectivity.
101101
- Keep the fetch loop alive to avoid listener timeout.

docs/troubleshooting.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ If the gateway uses a self-signed certificate, pass `verify_ssl=False` when crea
1717
## Rate limits and concurrency
1818

1919
- Reduce polling frequency.
20-
- Back off on `TooManyRequestsException` or `TooManyConcurrentRequestsException`.
20+
- Back off on `TooManyRequestsError` or `TooManyConcurrentRequestsError`.
2121

2222
## Listener drops
2323

24-
- Re-register the event listener when you see `InvalidEventListenerIdException`.
24+
- Re-register the event listener when you see `InvalidEventListenerIdError`.
2525
- Ensure your fetch loop is running every few seconds.
2626

2727
## Device not found

pyoverkiz/auth/strategies.py

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@
4242
)
4343
from pyoverkiz.enums import APIType
4444
from pyoverkiz.exceptions import (
45-
BadCredentialsException,
46-
CozyTouchBadCredentialsException,
47-
CozyTouchServiceException,
48-
InvalidTokenException,
49-
NexityBadCredentialsException,
50-
NexityServiceException,
51-
SomfyBadCredentialsException,
52-
SomfyServiceException,
45+
BadCredentialsError,
46+
CozyTouchBadCredentialsError,
47+
CozyTouchServiceError,
48+
InvalidTokenError,
49+
NexityBadCredentialsError,
50+
NexityServiceError,
51+
SomfyBadCredentialsError,
52+
SomfyServiceError,
5353
)
5454
from pyoverkiz.models import ServerConfig
5555

@@ -118,7 +118,7 @@ async def _post_login(self, data: Mapping[str, Any]) -> None:
118118
ssl=self._ssl,
119119
) as response:
120120
if response.status not in (200, 204):
121-
raise BadCredentialsException(
121+
raise BadCredentialsError(
122122
f"Login failed for {self.server.name}: {response.status}"
123123
)
124124

@@ -128,7 +128,7 @@ async def _post_login(self, data: Mapping[str, Any]) -> None:
128128

129129
result = await response.json()
130130
if not result.get("success"):
131-
raise BadCredentialsException("Login failed: bad credentials")
131+
raise BadCredentialsError("Login failed: bad credentials")
132132

133133

134134
class SomfyAuthStrategy(BaseAuthStrategy):
@@ -195,11 +195,11 @@ async def _request_access_token(
195195
token = await response.json()
196196

197197
if token.get("message") == "error.invalid.grant":
198-
raise SomfyBadCredentialsException(token["message"])
198+
raise SomfyBadCredentialsError(token["message"])
199199

200200
access_token = token.get("access_token")
201201
if not access_token:
202-
raise SomfyServiceException("No Somfy access token provided.")
202+
raise SomfyServiceError("No Somfy access token provided.")
203203

204204
self.context.access_token = cast(str, access_token)
205205
self.context.refresh_token = token.get("refresh_token")
@@ -233,10 +233,10 @@ async def login(self) -> None:
233233
token = await response.json()
234234

235235
if token.get("error") == "invalid_grant":
236-
raise CozyTouchBadCredentialsException(token["error_description"])
236+
raise CozyTouchBadCredentialsError(token["error_description"])
237237

238238
if "token_type" not in token:
239-
raise CozyTouchServiceException("No CozyTouch token provided.")
239+
raise CozyTouchServiceError("No CozyTouch token provided.")
240240

241241
async with self.session.get(
242242
f"{COZYTOUCH_ATLANTIC_API}/magellan/accounts/jwt",
@@ -245,7 +245,7 @@ async def login(self) -> None:
245245
jwt = await response.text()
246246

247247
if not jwt:
248-
raise CozyTouchServiceException("No JWT token provided.")
248+
raise CozyTouchServiceError("No JWT token provided.")
249249

250250
jwt = jwt.strip('"')
251251

@@ -278,7 +278,7 @@ def _client() -> BaseClient:
278278
except ClientError as error:
279279
code = error.response.get("Error", {}).get("Code")
280280
if code in {"NotAuthorizedException", "UserNotFoundException"}:
281-
raise NexityBadCredentialsException() from error
281+
raise NexityBadCredentialsError() from error
282282
raise
283283

284284
id_token = tokens["AuthenticationResult"]["IdToken"]
@@ -290,7 +290,7 @@ def _client() -> BaseClient:
290290
token = await response.json()
291291

292292
if "token" not in token:
293-
raise NexityServiceException("No Nexity SSO token provided.")
293+
raise NexityServiceError("No Nexity SSO token provided.")
294294

295295
user_id = self.credentials.username.replace("@", "_-_")
296296
await self._post_login({"ssoToken": token["token"], "userId": user_id})
@@ -314,7 +314,7 @@ def __init__(
314314
async def login(self) -> None:
315315
"""Validate that a token is provided for local API access."""
316316
if not self.credentials.token:
317-
raise InvalidTokenException("Local API requires a token.")
317+
raise InvalidTokenError("Local API requires a token.")
318318

319319
def auth_headers(self, path: str | None = None) -> Mapping[str, str]:
320320
"""Return authentication headers for a request path."""
@@ -385,16 +385,14 @@ async def _exchange_token(self, payload: Mapping[str, str]) -> None:
385385
if error:
386386
description = token.get("error_description") or token.get("message")
387387
if description:
388-
raise InvalidTokenException(
388+
raise InvalidTokenError(
389389
f"Error retrieving Rexel access token: {description}"
390390
)
391-
raise InvalidTokenException(
392-
f"Error retrieving Rexel access token: {error}"
393-
)
391+
raise InvalidTokenError(f"Error retrieving Rexel access token: {error}")
394392

395393
access_token = token.get("access_token")
396394
if not access_token:
397-
raise InvalidTokenException("No Rexel access token provided.")
395+
raise InvalidTokenError("No Rexel access token provided.")
398396

399397
self._ensure_consent(access_token)
400398
self.context.access_token = cast(str, access_token)
@@ -411,9 +409,7 @@ def _ensure_consent(access_token: str) -> None:
411409
payload = _decode_jwt_payload(access_token)
412410
consent = payload.get("consent")
413411
if consent != REXEL_REQUIRED_CONSENT:
414-
raise InvalidTokenException(
415-
"Consent is missing or revoked for Rexel token."
416-
)
412+
raise InvalidTokenError("Consent is missing or revoked for Rexel token.")
417413

418414

419415
class BearerTokenAuthStrategy(BaseAuthStrategy):
@@ -442,12 +438,12 @@ def _decode_jwt_payload(token: str) -> dict[str, Any]:
442438
"""Decode the payload of a JWT token."""
443439
parts = token.split(".")
444440
if len(parts) < 2:
445-
raise InvalidTokenException("Malformed JWT received.")
441+
raise InvalidTokenError("Malformed JWT received.")
446442

447443
payload_segment = parts[1]
448444
padding = "=" * (-len(payload_segment) % 4)
449445
try:
450446
decoded = base64.urlsafe_b64decode(payload_segment + padding)
451447
return cast(dict[str, Any], json.loads(decoded))
452448
except (binascii.Error, json.JSONDecodeError) as error:
453-
raise InvalidTokenException("Malformed JWT received.") from error
449+
raise InvalidTokenError("Malformed JWT received.") from error

pyoverkiz/client.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
from pyoverkiz.const import SUPPORTED_SERVERS
2424
from pyoverkiz.enums import APIType, CommandMode, Server
2525
from pyoverkiz.exceptions import (
26-
ExecutionQueueFullException,
27-
InvalidEventListenerIdException,
28-
NoRegisteredEventListenerException,
29-
NotAuthenticatedException,
30-
OverkizException,
31-
TooManyConcurrentRequestsException,
32-
TooManyExecutionsException,
26+
ExecutionQueueFullError,
27+
InvalidEventListenerIdError,
28+
NoRegisteredEventListenerError,
29+
NotAuthenticatedError,
30+
OverkizError,
31+
TooManyConcurrentRequestsError,
32+
TooManyExecutionsError,
3333
)
3434
from pyoverkiz.models import (
3535
Action,
@@ -74,7 +74,7 @@ async def refresh_listener(invocation: Details) -> None:
7474
# Reusable backoff decorators to reduce code duplication
7575
retry_on_auth_error = backoff.on_exception(
7676
backoff.expo,
77-
(NotAuthenticatedException, ServerDisconnectedError),
77+
(NotAuthenticatedError, ServerDisconnectedError),
7878
max_tries=2,
7979
on_backoff=relogin,
8080
logger=_LOGGER,
@@ -89,29 +89,29 @@ async def refresh_listener(invocation: Details) -> None:
8989

9090
retry_on_concurrent_requests = backoff.on_exception(
9191
backoff.expo,
92-
TooManyConcurrentRequestsException,
92+
TooManyConcurrentRequestsError,
9393
max_tries=5,
9494
logger=_LOGGER,
9595
)
9696

9797
retry_on_too_many_executions = backoff.on_exception(
9898
backoff.expo,
99-
TooManyExecutionsException,
99+
TooManyExecutionsError,
100100
max_tries=10,
101101
logger=_LOGGER,
102102
)
103103

104104
retry_on_listener_error = backoff.on_exception(
105105
backoff.expo,
106-
(InvalidEventListenerIdException, NoRegisteredEventListenerException),
106+
(InvalidEventListenerIdError, NoRegisteredEventListenerError),
107107
max_tries=2,
108108
on_backoff=refresh_listener,
109109
logger=_LOGGER,
110110
)
111111

112112
retry_on_execution_queue_full = backoff.on_exception(
113113
backoff.expo,
114-
ExecutionQueueFullException,
114+
ExecutionQueueFullError,
115115
max_tries=5,
116116
logger=_LOGGER,
117117
)
@@ -241,7 +241,7 @@ def _normalize_server(server: ServerConfig | Server | str) -> ServerConfig:
241241
try:
242242
return SUPPORTED_SERVERS[server_key]
243243
except KeyError as error:
244-
raise OverkizException(
244+
raise OverkizError(
245245
f"Unknown server '{server_key}'. Provide a supported server key or ServerConfig instance."
246246
) from error
247247

@@ -629,7 +629,7 @@ async def get_setup_option_parameter(
629629
630630
For example `developerMode-{gateway_id}` and `gatewayId` to understand if developer mode is on.
631631
632-
If the option is not available, an OverkizException will be thrown.
632+
If the option is not available, an OverkizError will be thrown.
633633
If the parameter is not available you will receive None.
634634
"""
635635
response = await self._get(f"setup/options/{option}/{parameter}")

0 commit comments

Comments
 (0)