Skip to content

Commit b9f24f4

Browse files
authored
feat!: removes 3.9 support and upgrades type hints to 3.10+ style (#95)
Remove support for Python 3.9 and transition type hints to the 3.10+ syntax across the codebase. This enhances type checking and maintains compatibility with newer Python versions.
1 parent f4a3539 commit b9f24f4

File tree

140 files changed

+1696
-2570
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+1696
-2570
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
uses: astral-sh/setup-uv@v3
1717

1818
- name: Set up Python
19-
run: uv python install 3.9
19+
run: uv python install 3.10
2020

2121
- name: Create virtual environment
2222
run: uv sync --all-extras --dev
@@ -43,7 +43,7 @@ jobs:
4343
uses: astral-sh/setup-uv@v3
4444

4545
- name: Set up Python
46-
run: uv python install 3.9
46+
run: uv python install 3.10
4747

4848
- name: Install dependencies
4949
run: uv sync --all-extras --dev
@@ -60,7 +60,7 @@ jobs:
6060
uses: astral-sh/setup-uv@v3
6161

6262
- name: Set up Python
63-
run: uv python install 3.9
63+
run: uv python install 3.10
6464

6565
- name: Install dependencies
6666
run: uv sync --all-extras --dev
@@ -77,7 +77,7 @@ jobs:
7777
uses: astral-sh/setup-uv@v3
7878

7979
- name: Set up Python
80-
run: uv python install 3.9
80+
run: uv python install 3.10
8181

8282
- name: Install dependencies
8383
run: uv sync --all-extras --dev
@@ -90,7 +90,7 @@ jobs:
9090
strategy:
9191
fail-fast: true
9292
matrix:
93-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
93+
python-version: ["3.10", "3.11", "3.12", "3.13"]
9494
timeout-minutes: 30
9595
steps:
9696
- name: Check out repository

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
runs-on: ubuntu-latest
6262
strategy:
6363
matrix:
64-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
64+
python-version: [ "3.10", "3.11", "3.12", "3.13"]
6565
steps:
6666
- name: Check out repository
6767
uses: actions/checkout@v4
@@ -89,7 +89,7 @@ jobs:
8989
MYPYC_MULTI_FILE: "1"
9090

9191
# Configure cibuildwheel
92-
CIBW_BUILD: "cp${{ matrix.python-version == '3.9' && '39' || matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' }}-*"
92+
CIBW_BUILD: "cp${{ matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' }}-*"
9393
CIBW_BUILD_VERBOSITY: 1
9494

9595
# Platform configuration - comprehensive coverage with QEMU emulation

.github/workflows/test-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
runs-on: ubuntu-latest
7373
strategy:
7474
matrix:
75-
python-version: ${{ github.event.inputs.test_matrix == 'full' && fromJSON('["3.9", "3.10", "3.11", "3.12", "3.13"]') || fromJSON('["3.12"]') }}
75+
python-version: ${{ github.event.inputs.test_matrix == 'full' && fromJSON('["3.10", "3.11", "3.12", "3.13"]') || fromJSON('["3.12"]') }}
7676
steps:
7777
- name: Check out repository
7878
uses: actions/checkout@v4
@@ -101,7 +101,7 @@ jobs:
101101
MYPYC_MULTI_FILE: "1"
102102

103103
# Configure cibuildwheel
104-
CIBW_BUILD: "cp${{ matrix.python-version == '3.9' && '39' || matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' }}-*"
104+
CIBW_BUILD: "cp${{ matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' }}-*"
105105
CIBW_BUILD_VERBOSITY: 1
106106

107107
# Platform configuration - conditional ARM64 support with QEMU

pyproject.toml

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
[project]
22
authors = [{ name = "Cody Fincher", email = "cody@litestar.dev" }]
3-
dependencies = [
4-
"typing-extensions",
5-
"eval_type_backport; python_version < \"3.10\"",
6-
"sqlglot>=19.9.0",
7-
"mypy-extensions",
8-
"rich-click",
9-
]
3+
dependencies = ["typing-extensions", "sqlglot>=19.9.0", "mypy-extensions", "rich-click"]
104
description = "SQL Experiments in Python"
115
license = "MIT"
126
maintainers = [{ name = "Litestar Developers", email = "hello@litestar.dev" }]
137
name = "sqlspec"
148
readme = "README.md"
15-
requires-python = ">=3.9, <4.0"
9+
requires-python = ">=3.10, <4.0"
1610
version = "0.26.0"
1711

1812
[project.urls]
@@ -68,8 +62,7 @@ dev = [
6862
doc = [
6963
"auto-pytabs[sphinx]>=0.5.0",
7064
"shibuya",
71-
"sphinx>=7.0.0; python_version <= \"3.9\"",
72-
"sphinx>=8.0.0; python_version >= \"3.10\"",
65+
"sphinx",
7366
"sphinx-autobuild>=2021.3.14",
7467
"sphinx-copybutton>=0.5.2",
7568
"sphinx-click>=6.0.0",
@@ -91,7 +84,7 @@ extras = [
9184
"adbc_driver_postgresql",
9285
"adbc_driver_flightsql",
9386
"adbc_driver_bigquery",
94-
"dishka ; python_version >= \"3.10\"",
87+
"dishka",
9588
]
9689
lint = [
9790
"mypy>=1.13.0",
@@ -309,7 +302,7 @@ testpaths = ["tests"]
309302
[tool.mypy]
310303
exclude = ["tmp/", ".tmp/", ".bugs/"]
311304
packages = ["sqlspec", "tests"]
312-
python_version = "3.9"
305+
python_version = "3.10"
313306

314307
disallow_any_generics = false
315308
disallow_untyped_decorators = true
@@ -366,7 +359,7 @@ module = "tests.*"
366359
disableBytesTypePromotions = true
367360
exclude = ["**/node_modules", "**/__pycache__", ".venv", "tools", "docs", "tmp", ".tmp", ".bugs"]
368361
include = ["sqlspec", "tests"]
369-
pythonVersion = "3.9"
362+
pythonVersion = "3.10"
370363
reportMissingTypeStubs = false
371364
reportPrivateImportUsage = true
372365
reportPrivateUsage = true
@@ -384,7 +377,7 @@ strict-imports = false
384377
exclude = [".venv", "node_modules", "tmp", ".tmp", ".bugs"]
385378
line-length = 120
386379
src = ["sqlspec", "tests", "docs/examples", "tools"]
387-
target-version = "py39"
380+
target-version = "py310"
388381

389382
[tool.ruff.format]
390383
docstring-code-format = true

sqlspec/_serialization.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import enum
1010
import json
1111
from abc import ABC, abstractmethod
12-
from typing import Any, Final, Literal, Optional, Protocol, Union, overload
12+
from typing import Any, Final, Literal, Protocol, overload
1313

1414
from sqlspec.typing import MSGSPEC_INSTALLED, ORJSON_INSTALLED, PYDANTIC_INSTALLED, BaseModel
1515

@@ -43,7 +43,7 @@ class JSONSerializer(Protocol):
4343
Users can implement this protocol to create custom serializers.
4444
"""
4545

46-
def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
46+
def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
4747
"""Encode data to JSON.
4848
4949
Args:
@@ -55,7 +55,7 @@ def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
5555
"""
5656
...
5757

58-
def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
58+
def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
5959
"""Decode from JSON.
6060
6161
Args:
@@ -74,12 +74,12 @@ class BaseJSONSerializer(ABC):
7474
__slots__ = ()
7575

7676
@abstractmethod
77-
def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
77+
def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
7878
"""Encode data to JSON."""
7979
...
8080

8181
@abstractmethod
82-
def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
82+
def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
8383
"""Decode from JSON."""
8484
...
8585

@@ -96,7 +96,7 @@ def __init__(self) -> None:
9696
self._encoder: Final[Encoder] = Encoder(enc_hook=_type_to_string)
9797
self._decoder: Final[Decoder] = Decoder()
9898

99-
def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
99+
def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
100100
"""Encode data using msgspec."""
101101
try:
102102
if as_bytes:
@@ -107,7 +107,7 @@ def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
107107
return OrjsonSerializer().encode(data, as_bytes=as_bytes)
108108
return StandardLibSerializer().encode(data, as_bytes=as_bytes)
109109

110-
def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
110+
def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
111111
"""Decode data using msgspec."""
112112
if isinstance(data, bytes):
113113
if decode_bytes:
@@ -132,7 +132,7 @@ class OrjsonSerializer(BaseJSONSerializer):
132132

133133
__slots__ = ()
134134

135-
def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
135+
def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
136136
"""Encode data using orjson."""
137137
from orjson import (
138138
OPT_NAIVE_UTC, # pyright: ignore[reportUnknownVariableType]
@@ -146,7 +146,7 @@ def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
146146
)
147147
return result if as_bytes else result.decode("utf-8")
148148

149-
def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
149+
def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
150150
"""Decode data using orjson."""
151151
from orjson import loads as _orjson_loads # pyright: ignore[reportMissingImports]
152152

@@ -162,12 +162,12 @@ class StandardLibSerializer(BaseJSONSerializer):
162162

163163
__slots__ = ()
164164

165-
def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
165+
def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
166166
"""Encode data using standard library json."""
167167
json_str = json.dumps(data, default=_type_to_string)
168168
return json_str.encode("utf-8") if as_bytes else json_str
169169

170-
def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
170+
def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
171171
"""Decode data using standard library json."""
172172
if isinstance(data, bytes):
173173
if decode_bytes:
@@ -176,7 +176,7 @@ def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
176176
return json.loads(data)
177177

178178

179-
_default_serializer: Optional[JSONSerializer] = None
179+
_default_serializer: JSONSerializer | None = None
180180

181181

182182
def get_default_serializer() -> JSONSerializer:
@@ -213,7 +213,7 @@ def encode_json(data: Any, *, as_bytes: Literal[False] = ...) -> str: ... # pra
213213
def encode_json(data: Any, *, as_bytes: Literal[True]) -> bytes: ... # pragma: no cover
214214

215215

216-
def encode_json(data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
216+
def encode_json(data: Any, *, as_bytes: bool = False) -> str | bytes:
217217
"""Encode to JSON, optionally returning bytes for optimal performance.
218218
219219
Args:
@@ -226,7 +226,7 @@ def encode_json(data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
226226
return get_default_serializer().encode(data, as_bytes=as_bytes)
227227

228228

229-
def decode_json(data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
229+
def decode_json(data: str | bytes, *, decode_bytes: bool = True) -> Any:
230230
"""Decode from JSON string or bytes efficiently.
231231
232232
Args:

0 commit comments

Comments
 (0)