Skip to content

Commit 156d9a5

Browse files
author
Peter Sprygada
committed
refactor: Modernize type annotations across all modules
- Add `from __future__ import annotations` to all modules for deferred evaluation - Replace Optional[T] with T | None for more idiomatic union syntax (PEP 604) - Replace Dict[K, V] with dict[K, V] using built-in dict type (PEP 585) - Replace List[T] with list[T] using built-in list type (PEP 585) - Remove unnecessary typing imports (Dict, List, Optional) where no longer needed - Maintain compatibility with Python 3.10+ while using modern annotation syntax - Update all modules: connection, logging, heuristics, platform, gateway, http, exceptions
1 parent c7b8fb3 commit 156d9a5

8 files changed

Lines changed: 116 additions & 96 deletions

File tree

pyproject.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,33 +266,46 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
266266

267267
# Public API functions can use boolean parameters
268268
"src/ipsdk/connection.py" = [
269+
"E402", # Module level import not at top of file (after module docstring)
269270
"FBT001", # Boolean-typed positional argument (part of public API)
270271
"FBT002", # Boolean default positional argument (part of public API)
271272
"TRY301", # Abstract raise to inner function (acceptable for error handling)
272273
]
273274

274275
"src/ipsdk/platform.py" = [
276+
"E402", # Module level import not at top of file (after module docstring)
275277
"FBT001", # Boolean-typed positional argument (part of public API)
276278
"FBT002", # Boolean default positional argument (part of public API)
277279
"TRY301", # Abstract raise to inner function (acceptable for error handling)
278280
]
279281

280282
"src/ipsdk/gateway.py" = [
283+
"E402", # Module level import not at top of file (after module docstring)
281284
"FBT001", # Boolean-typed positional argument (part of public API)
282285
"FBT002", # Boolean default positional argument (part of public API)
283286
]
284287

285288
"src/ipsdk/exceptions.py" = [
289+
"E402", # Module level import not at top of file (after module docstring)
286290
"S110", # try-except-pass (intentional for error handling)
287291
]
288292

289293
"src/ipsdk/logging.py" = [
294+
"E402", # Module level import not at top of file (after module docstring)
290295
"FBT001", # Boolean-typed positional argument (part of public API)
291296
"FBT002", # Boolean default positional argument (part of public API)
292297
"G004", # Logging statement uses f-string (acceptable for informational logging)
293298
"E501", # Line too long (docstrings can be longer)
294299
]
295300

301+
"src/ipsdk/heuristics.py" = [
302+
"E402", # Module level import not at top of file (after module docstring)
303+
]
304+
305+
"src/ipsdk/http.py" = [
306+
"E402", # Module level import not at top of file (after module docstring)
307+
]
308+
296309
[tool.ruff.lint.isort]
297310
known-first-party = ["ipsdk"]
298311
force-single-line = true

src/ipsdk/connection.py

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) 2025 Itential, Inc
22
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
33

4+
from __future__ import annotations
5+
46
"""HTTP connection implementations for the Itential Python SDK.
57
68
This module provides both synchronous and asynchronous HTTP client implementations
@@ -130,9 +132,6 @@ async def fetch_devices():
130132
import urllib.parse
131133

132134
from typing import Any
133-
from typing import Dict
134-
from typing import Optional
135-
from typing import Union
136135

137136
import httpx
138137

@@ -144,7 +143,7 @@ async def fetch_devices():
144143

145144

146145
class ConnectionBase:
147-
client: Union[httpx.Client, httpx.AsyncClient]
146+
client: httpx.Client | httpx.AsyncClient
148147

149148
def __init__(
150149
self,
@@ -196,7 +195,7 @@ def __init__(
196195
self.token = None
197196

198197
self.authenticated = False
199-
self._auth_lock: Optional[Any] = None
198+
self._auth_lock: Any | None = None
200199

201200
self.client = self.__init_client__(
202201
base_url=self._make_base_url(host, port, base_path, use_tls),
@@ -247,8 +246,8 @@ def _build_request(
247246
self,
248247
method: HTTPMethod,
249248
path: str,
250-
json: Union[str, bytes, dict, list] | None = None,
251-
params: dict[str, Any] | None = None,
249+
json: str | bytes | dict | list | None = None,
250+
params: dict[str, Any | None] | None = None,
252251
) -> httpx.Request:
253252
"""Build an HTTP request object.
254253
@@ -307,8 +306,8 @@ def _validate_request_args(
307306
self,
308307
method: HTTPMethod,
309308
path: str,
310-
params: Optional[Dict[str, Any]] = None,
311-
json: Optional[Union[str, bytes, dict, list]] = None,
309+
params: dict[str, Any | None] | None = None,
310+
json: str | bytes | dict | (list | None) = None,
312311
) -> None:
313312
"""
314313
Validate request arguments to ensure they have correct types.
@@ -321,8 +320,8 @@ def _validate_request_args(
321320
Args:
322321
method (HTTPMethod): The HTTP method enum value to validate
323322
path (str): The request path to validate
324-
params (Optional[Dict[str, Any]]): Query parameters dict to validate
325-
json (Optional[Union[str, bytes, dict, list]]): JSON body to validate
323+
params (dict[str, Any | None]): Query parameters dict to validate
324+
json (Union[str, bytes, dict, list | None]): JSON body to validate
326325
327326
Returns:
328327
None
@@ -353,7 +352,7 @@ def _validate_request_args(
353352
@abc.abstractmethod
354353
def __init_client__(
355354
self, base_url: str | None = None, verify: bool = True, timeout: int = 30
356-
) -> Union[httpx.Client, httpx.AsyncClient]:
355+
) -> httpx.Client | httpx.AsyncClient:
357356
"""Initialize the HTTP client.
358357
359358
Abstract method to be implemented by subclasses to create either a
@@ -365,7 +364,7 @@ def __init_client__(
365364
timeout: Connection timeout in seconds. Defaults to 30.
366365
367366
Returns:
368-
Union[httpx.Client, httpx.AsyncClient]: The initialized HTTP client.
367+
httpx.Client | httpx.AsyncClient: The initialized HTTP client.
369368
370369
Raises:
371370
None
@@ -416,8 +415,8 @@ def _send_request(
416415
self,
417416
method: HTTPMethod,
418417
path: str,
419-
params: dict[str, Any] | None = None,
420-
json: Union[str, bytes, dict, list] | None = None,
418+
params: dict[str, Any | None] | None = None,
419+
json: str | bytes | dict | list | None = None,
421420
) -> Response:
422421
"""Send an HTTP request to the API endpoint.
423422
@@ -473,7 +472,7 @@ def _send_request(
473472

474473
return Response(res)
475474

476-
def get(self, path: str, params: dict[str, Any] | None = None) -> Response:
475+
def get(self, path: str, params: dict[str, Any | None] | None = None) -> Response:
477476
"""Send an HTTP GET request to the server.
478477
479478
Args:
@@ -490,7 +489,9 @@ def get(self, path: str, params: dict[str, Any] | None = None) -> Response:
490489
logging.trace(self.get, modname=__name__, clsname=self.__class__)
491490
return self._send_request(HTTPMethod.GET, path=path, params=params)
492491

493-
def delete(self, path: str, params: dict[str, Any] | None = None) -> Response:
492+
def delete(
493+
self, path: str, params: dict[str, Any | None] | None = None
494+
) -> Response:
494495
"""Send an HTTP DELETE request to the server.
495496
496497
Args:
@@ -510,8 +511,8 @@ def delete(self, path: str, params: dict[str, Any] | None = None) -> Response:
510511
def post(
511512
self,
512513
path: str,
513-
params: dict[str, Any] | None = None,
514-
json: Union[str, bytes, list, dict] | None = None,
514+
params: dict[str, Any | None] | None = None,
515+
json: str | bytes | list | dict | None = None,
515516
) -> Response:
516517
"""Send an HTTP POST request to the server.
517518
@@ -534,8 +535,8 @@ def post(
534535
def put(
535536
self,
536537
path: str,
537-
params: dict[str, Any] | None = None,
538-
json: Union[str, bytes, list, dict] | None = None,
538+
params: dict[str, Any | None] | None = None,
539+
json: str | bytes | list | dict | None = None,
539540
) -> Response:
540541
"""Send an HTTP PUT request to the server.
541542
@@ -558,8 +559,8 @@ def put(
558559
def patch(
559560
self,
560561
path: str,
561-
params: dict[str, Any] | None = None,
562-
json: Union[str, bytes, list, dict] | None = None,
562+
params: dict[str, Any | None] | None = None,
563+
json: str | bytes | list | dict | None = None,
563564
) -> Response:
564565
"""Send an HTTP PATCH request to the server.
565566
@@ -588,7 +589,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
588589
self._auth_lock = asyncio.Lock()
589590

590591
def __init_client__(
591-
self, base_url: Optional[str] = None, verify: bool = True, timeout: int = 30
592+
self, base_url: str | None = None, verify: bool = True, timeout: int = 30
592593
) -> httpx.AsyncClient:
593594
"""
594595
Initialize the httpx.AsyncClient instance
@@ -625,8 +626,8 @@ async def _send_request(
625626
self,
626627
method: HTTPMethod,
627628
path: str,
628-
params: dict[str, Any] | None = None,
629-
json: Union[str, bytes, dict, list] | None = None,
629+
params: dict[str, Any | None] | None = None,
630+
json: str | bytes | dict | list | None = None,
630631
) -> Response:
631632
"""Send an asynchronous HTTP request to the API endpoint.
632633
@@ -682,7 +683,9 @@ async def _send_request(
682683

683684
return Response(res)
684685

685-
async def get(self, path: str, params: dict[str, Any] | None = None) -> Response:
686+
async def get(
687+
self, path: str, params: dict[str, Any | None] | None = None
688+
) -> Response:
686689
"""
687690
Send a HTTP GET request to the server and return the response.
688691
@@ -705,7 +708,7 @@ async def get(self, path: str, params: dict[str, Any] | None = None) -> Response
705708
return await self._send_request(HTTPMethod.GET, path=path, params=params)
706709

707710
async def delete(
708-
self, path: str, params: dict[str, Any] | None = None
711+
self, path: str, params: dict[str, Any | None] | None = None
709712
) -> Response:
710713
"""
711714
Send a HTTP DELETE request to the server and return the response.
@@ -731,8 +734,8 @@ async def delete(
731734
async def post(
732735
self,
733736
path: str,
734-
params: dict[str, Any] | None = None,
735-
json: Union[str, bytes, dict, list] | None = None,
737+
params: dict[str, Any | None] | None = None,
738+
json: str | bytes | dict | list | None = None,
736739
) -> Response:
737740
"""
738741
Send a HTTP POST request to the server and return the response.
@@ -766,8 +769,8 @@ async def post(
766769
async def put(
767770
self,
768771
path: str,
769-
params: dict[str, Any] | None = None,
770-
json: Union[str, bytes, dict, list] | None = None,
772+
params: dict[str, Any | None] | None = None,
773+
json: str | bytes | dict | list | None = None,
771774
) -> Response:
772775
"""
773776
Send a HTTP PUT request to the server and return the response.
@@ -801,8 +804,8 @@ async def put(
801804
async def patch(
802805
self,
803806
path: str,
804-
params: dict[str, Any] | None = None,
805-
json: Union[str, bytes, dict, list] | None = None,
807+
params: dict[str, Any | None] | None = None,
808+
json: str | bytes | dict | list | None = None,
806809
) -> Response:
807810
"""
808811
Send a HTTP PATCH request to the server and return the response.

src/ipsdk/exceptions.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) 2025 Itential, Inc
22
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
33

4+
from __future__ import annotations
5+
46
"""
57
Exception hierarchy for the Itential Python SDK.
68
@@ -73,13 +75,14 @@
7375
print(f"Response body: {e.response.text}")
7476
"""
7577

78+
from typing import TYPE_CHECKING
7679
from typing import Any
77-
from typing import Optional
78-
79-
import httpx
8080

8181
from . import logging
8282

83+
if TYPE_CHECKING:
84+
import httpx
85+
8386

8487
class IpsdkError(Exception):
8588
"""
@@ -93,7 +96,7 @@ class IpsdkError(Exception):
9396
details (dict): Additional error details and context
9497
"""
9598

96-
def __init__(self, message: str, exc: Optional[httpx.HTTPError] = None) -> None:
99+
def __init__(self, message: str, exc: httpx.HTTPError | None = None) -> None:
97100
"""
98101
Initialize the base SDK exception.
99102

src/ipsdk/gateway.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) 2025 Itential, Inc
22
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
33

4+
from __future__ import annotations
5+
46
"""Itential Automation Gateway client implementation for the SDK.
57
68
This module provides client implementations for connecting to and interacting
@@ -149,7 +151,6 @@ async def get_devices():
149151
"""
150152

151153
from typing import Any
152-
from typing import Optional
153154

154155
import httpx
155156

@@ -206,8 +207,8 @@ class AuthMixin:
206207
"""
207208

208209
# Attributes that should be provided by ConnectionBase
209-
user: Optional[str]
210-
password: Optional[str]
210+
user: str | None
211+
password: str | None
211212
client: httpx.Client
212213

213214
def authenticate(self) -> None:
@@ -242,8 +243,8 @@ class AsyncAuthMixin:
242243
"""
243244

244245
# Attributes that should be provided by ConnectionBase
245-
user: Optional[str]
246-
password: Optional[str]
246+
user: str | None
247+
password: str | None
247248
client: httpx.AsyncClient
248249

249250
async def authenticate(self) -> None:

0 commit comments

Comments
 (0)