Skip to content

Commit f71a292

Browse files
committed
refactor: pyupgrade pass — adopt PEP 585/604 builtins
Now that Python 3.10 is the floor (previous commit), enable ruff's ``UP`` ruleset and apply the modernization fixes: - ``Dict[K, V]`` → ``dict[K, V]`` (PEP 585, 49 hits) - ``Optional[X]`` → ``X | None`` (PEP 604, 31 hits) - ``Union[A, B]`` → ``A | B`` (PEP 604, 6 hits) - ``open(p, "r")`` → ``open(p)`` (UP015, 5 hits) - drop unused ``typing.Dict/List/Optional/Union`` imports. 13 files touched, ~133 lines removed (no behaviour change). All modules keep ``from __future__ import annotations`` so PEP 604 unions in attribute defaults remain free at runtime. ruff/mypy/pytest all green; coverage 87.12 %. Activate ``UP`` permanently in ``[tool.ruff.lint].select`` so regressions surface in CI.
1 parent 5487a1e commit f71a292

13 files changed

Lines changed: 122 additions & 133 deletions

File tree

orca_cli/commands/audit.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Callable
56
from concurrent.futures import ThreadPoolExecutor, as_completed
6-
from typing import Any, Callable
7+
from typing import Any
78

89
import click
910

orca_cli/commands/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ def auth_check(ctx: click.Context, check_all: bool, clouds: bool) -> None:
238238
import yaml
239239
path = _find_clouds_yaml()
240240
if path:
241-
with open(path, "r") as fh:
241+
with open(path) as fh:
242242
data = yaml.safe_load(fh) or {}
243243
for cloud_name in sorted(data.get("clouds", {}).keys()):
244244
cfg = _load_clouds_yaml(cloud_name)

orca_cli/commands/find.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212

1313
from __future__ import annotations
1414

15+
from collections.abc import Callable
1516
from concurrent.futures import ThreadPoolExecutor, as_completed
16-
from typing import Any, Callable
17+
from typing import Any
1718

1819
import click
1920
from rich.table import Table

orca_cli/commands/overview.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Callable
56
from concurrent.futures import ThreadPoolExecutor, as_completed
6-
from typing import Any, Callable
7+
from typing import Any
78

89
import click
910
from rich.table import Table

orca_cli/commands/profile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ def profile_from_clouds(cloud_name: str, profile_name: str | None, clouds_file:
754754
p = Path(clouds_file)
755755
if not p.exists():
756756
raise OrcaCLIError(f"File not found: {clouds_file}")
757-
with open(p, "r") as fh:
757+
with open(p) as fh:
758758
data = yaml.safe_load(fh) or {}
759759
cloud = data.get("clouds", {}).get(cloud_name)
760760
else:
@@ -764,7 +764,7 @@ def profile_from_clouds(cloud_name: str, profile_name: str | None, clouds_file:
764764
"No clouds.yaml found. Searched: ./clouds.yaml, "
765765
"~/.config/openstack/clouds.yaml, /etc/openstack/clouds.yaml"
766766
)
767-
with open(found, "r") as fh:
767+
with open(found) as fh:
768768
data = yaml.safe_load(fh) or {}
769769
cloud = data.get("clouds", {}).get(cloud_name)
770770
if not cloud:

orca_cli/commands/server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import fnmatch
66
import os
77
import time
8-
from typing import Any, Mapping
8+
from collections.abc import Mapping
9+
from typing import Any
910

1011
import click
1112

orca_cli/core/client.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import time
3030
from datetime import datetime, timezone
3131
from pathlib import Path
32-
from typing import Any, Dict, Optional, Union
32+
from typing import Any
3333

3434
import httpx
3535
import yaml
@@ -75,7 +75,7 @@ def with_version(url: str, version: str) -> str:
7575
_REDACTED_HEADERS = frozenset({"x-auth-token", "x-subject-token", "authorization"})
7676

7777

78-
def _redact_headers(headers: Dict[str, str]) -> Dict[str, str]:
78+
def _redact_headers(headers: dict[str, str]) -> dict[str, str]:
7979
"""Return a copy of ``headers`` with sensitive values replaced by ``***``."""
8080
return {k: ("***" if k.lower() in _REDACTED_HEADERS else v)
8181
for k, v in headers.items()}
@@ -116,7 +116,7 @@ def _redact_headers(headers: Dict[str, str]) -> Dict[str, str]:
116116
)
117117

118118

119-
def _parse_retry_after(value: str) -> Optional[float]:
119+
def _parse_retry_after(value: str) -> float | None:
120120
"""Interpret a ``Retry-After`` header per RFC 7231 §7.1.3.
121121
122122
Accepts either delta-seconds (``"5"``) or an HTTP-date (``"Wed, 21 Oct 2015
@@ -528,7 +528,7 @@ def auth_url(self) -> str:
528528
return self._auth_url
529529

530530
@property
531-
def region_name(self) -> Optional[str]:
531+
def region_name(self) -> str | None:
532532
"""The region used to filter the catalogue, or ``None``."""
533533
return self._region_name
534534

@@ -540,7 +540,7 @@ def interface(self) -> str:
540540
return self._interface
541541

542542
@property
543-
def project_id(self) -> Optional[str]:
543+
def project_id(self) -> str | None:
544544
"""The project ID this client is scoped to, if any."""
545545
return self._project_id
546546

@@ -652,9 +652,9 @@ def rating_url(self) -> str:
652652

653653
# ── Generic HTTP helpers ──────────────────────────────────────────────────
654654

655-
def _headers(self, extra: Optional[Dict[str, str]] = None,
656-
url: Optional[str] = None) -> Dict[str, str]:
657-
h: Dict[str, str] = {
655+
def _headers(self, extra: dict[str, str] | None = None,
656+
url: str | None = None) -> dict[str, str]:
657+
h: dict[str, str] = {
658658
"X-Auth-Token": self._token or "",
659659
"Accept": "application/json",
660660
}
@@ -749,7 +749,7 @@ def _handle_response(self, response: httpx.Response) -> Any:
749749
return response.json()
750750

751751
def _send(self, method: str, url: str,
752-
extra_headers: Optional[Dict[str, str]] = None,
752+
extra_headers: dict[str, str] | None = None,
753753
**kwargs: Any) -> httpx.Response:
754754
"""Single HTTP send with inline 401→re-auth retry (once, cached token only)."""
755755
started = time.monotonic()
@@ -785,7 +785,7 @@ def _send(self, method: str, url: str,
785785
return resp
786786

787787
def _request(self, method: str, url: str,
788-
extra_headers: Optional[Dict[str, str]] = None,
788+
extra_headers: dict[str, str] | None = None,
789789
**kwargs: Any) -> Any:
790790
"""Execute an HTTP request with three independent recovery mechanisms:
791791
@@ -849,31 +849,31 @@ def _request(self, method: str, url: str,
849849

850850
# ── Public HTTP methods ───────────────────────────────────────────────────
851851

852-
def get(self, url: str, params: Optional[Dict[str, Any]] = None,
853-
headers: Optional[Dict[str, str]] = None) -> Any:
852+
def get(self, url: str, params: dict[str, Any] | None = None,
853+
headers: dict[str, str] | None = None) -> Any:
854854
return self._request("get", url, extra_headers=headers, params=params)
855855

856-
def post(self, url: str, json: Optional[Union[Dict[str, Any], list]] = None,
857-
headers: Optional[Dict[str, str]] = None) -> Any:
856+
def post(self, url: str, json: dict[str, Any] | list | None = None,
857+
headers: dict[str, str] | None = None) -> Any:
858858
return self._request("post", url, extra_headers=headers, json=json)
859859

860-
def put(self, url: str, json: Optional[Union[Dict[str, Any], list]] = None,
861-
headers: Optional[Dict[str, str]] = None) -> Any:
860+
def put(self, url: str, json: dict[str, Any] | list | None = None,
861+
headers: dict[str, str] | None = None) -> Any:
862862
return self._request("put", url, extra_headers=headers, json=json)
863863

864-
def patch(self, url: str, json: Optional[Union[Dict[str, Any], list]] = None,
865-
content: Optional[bytes] = None,
866-
content_type: Optional[str] = None) -> Any:
867-
extra: Dict[str, str] = {}
864+
def patch(self, url: str, json: dict[str, Any] | list | None = None,
865+
content: bytes | None = None,
866+
content_type: str | None = None) -> Any:
867+
extra: dict[str, str] = {}
868868
if content_type:
869869
extra["Content-Type"] = content_type
870870
if content is not None:
871871
return self._request("patch", url, extra_headers=extra or None, content=content)
872872
return self._request("patch", url, extra_headers=extra or None, json=json)
873873

874-
def delete(self, url: str, params: Optional[Dict[str, Any]] = None,
875-
headers: Optional[Dict[str, str]] = None,
876-
json: Optional[Union[Dict[str, Any], list]] = None) -> Any:
874+
def delete(self, url: str, params: dict[str, Any] | None = None,
875+
headers: dict[str, str] | None = None,
876+
json: dict[str, Any] | list | None = None) -> Any:
877877
# Some OpenStack APIs (e.g. Barbican container consumers) require a
878878
# JSON body on DELETE — uncommon for HTTP but valid per RFC 7231.
879879
# Only forward `json` when supplied so httpx's per-method shortcut
@@ -885,8 +885,8 @@ def delete(self, url: str, params: Optional[Dict[str, Any]] = None,
885885

886886
def paginate(self, url: str, key: str, *,
887887
page_size: int = 1000,
888-
params: Optional[Dict[str, Any]] = None,
889-
max_items: Optional[int] = None) -> list:
888+
params: dict[str, Any] | None = None,
889+
max_items: int | None = None) -> list:
890890
"""Walk an OpenStack list endpoint using marker-based pagination.
891891
892892
Many services (Nova, Cinder, Neutron with ``allow_pagination``) cap
@@ -908,8 +908,8 @@ def paginate(self, url: str, key: str, *,
908908
max_items: stop once this many items have been collected.
909909
"""
910910
collected: list = []
911-
marker: Optional[str] = None
912-
base_params: Dict[str, Any] = dict(params or {})
911+
marker: str | None = None
912+
base_params: dict[str, Any] = dict(params or {})
913913
while True:
914914
p = dict(base_params)
915915
p["limit"] = page_size
@@ -932,8 +932,8 @@ def paginate(self, url: str, key: str, *,
932932

933933
def put_stream(self, url: str, *, content: Any,
934934
content_type: str = "application/octet-stream",
935-
content_length: Optional[int] = None,
936-
extra_headers: Optional[Dict[str, str]] = None) -> httpx.Response:
935+
content_length: int | None = None,
936+
extra_headers: dict[str, str] | None = None) -> httpx.Response:
937937
"""PUT a streaming body (file-like or iterable). Returns the raw httpx response.
938938
939939
Streamed bodies cannot be replayed, so this path deliberately bypasses
@@ -952,8 +952,8 @@ def put_stream(self, url: str, *, content: Any,
952952

953953
def post_stream(self, url: str, *, content: Any,
954954
content_type: str = "application/octet-stream",
955-
content_length: Optional[int] = None,
956-
extra_headers: Optional[Dict[str, str]] = None) -> httpx.Response:
955+
content_length: int | None = None,
956+
extra_headers: dict[str, str] | None = None) -> httpx.Response:
957957
"""POST a streaming or raw body. Returns the raw httpx response.
958958
959959
Like :meth:`put_stream`, this bypasses ``_request``'s retry loop so the
@@ -970,7 +970,7 @@ def post_stream(self, url: str, *, content: Any,
970970
return self._http.post(url, headers=headers, content=content)
971971

972972
def post_no_body(self, url: str, *,
973-
extra_headers: Optional[Dict[str, str]] = None) -> httpx.Response:
973+
extra_headers: dict[str, str] | None = None) -> httpx.Response:
974974
"""POST without a JSON body, returning the raw response.
975975
976976
Used by Swift metadata updates (account/container/object), where the
@@ -983,7 +983,7 @@ def post_no_body(self, url: str, *,
983983
return self._http.post(url, headers=headers)
984984

985985
def head_request(self, url: str, *,
986-
extra_headers: Optional[Dict[str, str]] = None) -> httpx.Response:
986+
extra_headers: dict[str, str] | None = None) -> httpx.Response:
987987
"""HEAD request with auth headers — returns the raw response so callers
988988
can read metadata from response headers (Swift account/container/object).
989989
"""
@@ -993,7 +993,7 @@ def head_request(self, url: str, *,
993993
return self._http.head(url, headers=headers)
994994

995995
def get_stream(self, url: str, *,
996-
extra_headers: Optional[Dict[str, str]] = None):
996+
extra_headers: dict[str, str] | None = None):
997997
"""GET that returns a streaming response context manager."""
998998
headers = self._headers(url=url)
999999
if extra_headers:

0 commit comments

Comments
 (0)