Skip to content

Commit 839c50c

Browse files
committed
Drop 3.9 support
1 parent 3bc8aa9 commit 839c50c

6 files changed

Lines changed: 34 additions & 247 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
matrix:
1515
# See https://github.com/actions/python-versions/releases for available versions
16-
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]
16+
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
1717

1818
steps:
1919
- name: Checkout

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# api-session Changelog
22

3+
## 1.6.0
4+
5+
* Drop support for Python 3.9
6+
37
## 1.5.3 (2025/12/22)
48

59
* We now use `uv` to manage the project instead of Poetry. This has no impact on the released library.

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ With Poetry:
2929

3030
poetry add api-session
3131

32-
Dependency: Python 3.9+.
32+
Dependency: Python 3.10+.
3333

34+
* Versions 1.6.x require Python 3.10+
3435
* Versions 1.5.x require Python 3.9+
3536
* Versions 1.4.x and before require Python 3.8+
3637

api_session/__init__.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ class APISession(requests.Session):
2828
"""HTTP Session with helpers to call a JSON-based API."""
2929
READ_METHODS = {"HEAD", "GET", "OPTIONS", "CONNECT", "TRACE"}
3030

31-
def __init__(self, base_url: str, user_agent: Optional[str] = None, read_only: bool = False, *,
31+
def __init__(self, base_url: str, user_agent: str | None = None, read_only: bool = False, *,
3232
offline: bool = False,
3333
none_on_404: bool = True,
3434
none_on_empty: bool = False,
35-
timeout: Optional[Union[int, tuple[int, int], Timeout]] = None,
36-
max_retries: Optional[Union[int, bool, Retry]] = None):
35+
timeout: int | tuple[int, int] | Timeout | None = None,
36+
max_retries: int | bool | Retry | None = None):
3737
""":param base_url: Base URL of the API.
3838
:param user_agent: Optional user-agent header to use.
3939
:param read_only: if True, any POST/PUT/DELETE call will fail with an AssertError.
@@ -90,7 +90,7 @@ def include_body_in_exception(self, response: requests.Response) -> bool:
9090
"""
9191
return response.status_code // 100 == 4
9292

93-
def request(self, method: Union[str, bytes], url: Union[str, bytes, str], *args: Any,
93+
def request(self, method: str | bytes, url: str | bytes | str, *args: Any,
9494
bypass_read_only: bool = False,
9595
**kwargs: Any) -> requests.Response:
9696
""":param method: method argument passed to the underlying ``.request()`` method
@@ -111,7 +111,7 @@ def request(self, method: Union[str, bytes], url: Union[str, bytes, str], *args:
111111

112112
return super().request(method, url, *args, **kwargs)
113113

114-
def request_api(self, method: str, path: str, *args: Any, throw: Optional[bool] = None,
114+
def request_api(self, method: str, path: str, *args: Any, throw: bool | None = None,
115115
**kwargs: Any) -> requests.Response:
116116
"""Wrapper around .request() that prefixes the path with the base API URL.
117117
@@ -131,7 +131,7 @@ def request_api(self, method: str, path: str, *args: Any, throw: Optional[bool]
131131
self.raise_for_response(r)
132132
return r
133133

134-
def get_api(self, path: str, params: Optional[dict[str, Any]] = None, *, throw: Optional[bool] = None,
134+
def get_api(self, path: str, params: dict[str, Any] | None = None, *, throw: bool | None = None,
135135
**kwargs: Any) -> requests.Response:
136136
"""Equivalent of .get() that prefixes the path with the base API URL.
137137
@@ -142,10 +142,10 @@ def get_api(self, path: str, params: Optional[dict[str, Any]] = None, *, throw:
142142
"""
143143
return self.request_api('get', path, params=params, throw=throw, **kwargs)
144144

145-
def get_json_api(self, path: str, params: Optional[dict[str, Any]] = None, *,
145+
def get_json_api(self, path: str, params: dict[str, Any] | None = None, *,
146146
throw: bool = True,
147-
none_on_404: Optional[bool] = None,
148-
none_on_empty: Optional[bool] = None,
147+
none_on_404: bool | None = None,
148+
none_on_empty: bool | None = None,
149149
**kwargs: Any) -> Any:
150150
"""Equivalent of ``.get_api()`` that parses a JSON response. Return ``None`` on 404s and throws on other errors.
151151
@@ -173,7 +173,7 @@ def get_json_api(self, path: str, params: Optional[dict[str, Any]] = None, *,
173173

174174
return r.json()
175175

176-
def head_api(self, path: str, params: Optional[dict[str, Any]] = None, *, throw: Optional[bool] = None,
176+
def head_api(self, path: str, params: dict[str, Any] | None = None, *, throw: bool | None = None,
177177
**kwargs: Any) -> requests.Response:
178178
"""Equivalent of .head() that prefixes the path with the base API URL.
179179
@@ -184,7 +184,7 @@ def head_api(self, path: str, params: Optional[dict[str, Any]] = None, *, throw:
184184
"""
185185
return self.request_api('head', path, params=params, throw=throw, **kwargs)
186186

187-
def post_api(self, path: str, *args: Any, throw: Optional[bool] = None, **kwargs: Any) -> requests.Response:
187+
def post_api(self, path: str, *args: Any, throw: bool | None = None, **kwargs: Any) -> requests.Response:
188188
"""Equivalent of .post() that prefixes the path with the base API URL.
189189
190190
:param path: URL path. This must start with a slash
@@ -204,7 +204,7 @@ def post_json_api(self, path: str, *args: Any, throw: bool = True, **kwargs: Any
204204
"""
205205
return self.post_api(path, *args, throw=throw, **kwargs).json()
206206

207-
def put_api(self, path: str, *args: Any, throw: Optional[bool] = None, **kwargs: Any) -> requests.Response:
207+
def put_api(self, path: str, *args: Any, throw: bool | None = None, **kwargs: Any) -> requests.Response:
208208
"""Equivalent of .put() that prefixes the path with the base API URL.
209209
210210
:param path: URL path. This must start with a slash
@@ -224,7 +224,7 @@ def put_json_api(self, path: str, *args: Any, throw: bool = True, **kwargs: Any)
224224
"""
225225
return self.put_api(path, *args, throw=throw, **kwargs).json()
226226

227-
def patch_api(self, path: str, *args: Any, throw: Optional[bool] = None, **kwargs: Any) -> requests.Response:
227+
def patch_api(self, path: str, *args: Any, throw: bool | None = None, **kwargs: Any) -> requests.Response:
228228
"""Equivalent of .patch() that prefixes the path with the base API URL.
229229
230230
:param path: URL path. This must start with a slash
@@ -244,7 +244,7 @@ def patch_json_api(self, path: str, *args: Any, throw: bool = True, **kwargs: An
244244
"""
245245
return self.patch_api(path, *args, throw=throw, **kwargs).json()
246246

247-
def delete_api(self, path: str, throw: Optional[bool] = None, **kwargs: Any) -> requests.Response:
247+
def delete_api(self, path: str, throw: bool | None = None, **kwargs: Any) -> requests.Response:
248248
"""Equivalent of .delete() that prefixes the path with the base API URL.
249249
250250
:param path: URL path. This must start with a slash

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "api-session"
33
version = "1.5.3"
44
description = "requests.Session to work with JSON APIs"
55
authors = [{ name = "Baptiste Fontaine", email = "baptiste@bixoto.com" }]
6-
requires-python = ">=3.9"
6+
requires-python = ">=3.10"
77
readme = "README.md"
88
license = "MIT"
99
classifiers = [
@@ -43,7 +43,7 @@ exclude_lines = [
4343

4444
[tool.ruff]
4545
line-length = 120
46-
target-version = "py39"
46+
target-version = "py310"
4747
[tool.ruff.lint]
4848
select = [
4949
"D", # docstrings

0 commit comments

Comments
 (0)