Skip to content

Commit 55f7a1d

Browse files
authored
refactor: remove __future__ annotations and update type hints (#17)
This commit removes `__future__` annotations from multiple files and updates type hints to be more precise and compatible with modern Python type checking. Key changes include: - Removed `from __future__ import annotations` from multiple files - Updated type hints to use `Optional` and `Union` more explicitly - Added type ignore comments for specific type checking issues - Simplified import statements - Updated type hints in function signatures - Improved type compatibility with pyright and other type checkers
1 parent 23398d7 commit 55f7a1d

File tree

30 files changed

+1427
-1191
lines changed

30 files changed

+1427
-1191
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ repos:
1717
- id: mixed-line-ending
1818
- id: trailing-whitespace
1919
- repo: https://github.com/charliermarsh/ruff-pre-commit
20-
rev: "v0.9.4"
20+
rev: "v0.9.10"
2121
hooks:
2222
- id: ruff
2323
args: ["--fix"]

base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from sqlspec.adapters.duckdb.config import DuckDBConfig
2+
from sqlspec.base import ConfigManager
3+
4+
dbs = ConfigManager()
5+
6+
config = DuckDBConfig(database="test.duckdb", extensions=[{"name": "vss"}])
7+
etl_db = dbs.add_config(config)
8+
9+
connection = dbs.get_connection(etl_db)

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ flask = ["flask"]
2222
litestar = ["litestar"]
2323
msgspec = ["msgspec"]
2424
oracledb = ["oracledb"]
25+
orjson = ["orjson"]
2526
performance = ["sqlglot[rs]"]
2627
psycopg = ["psycopg[binary,pool]"]
27-
pydantic = ["pydantic"]
28+
pydantic = ["pydantic", "pydantic-extra-types"]
2829
pymssql = ["pymssql"]
2930
pymysql = ["pymysql"]
3031
spanner = ["google-cloud-spanner"]
@@ -211,6 +212,7 @@ lint.select = [
211212
"UP", # pyupgrade
212213
"W", # pycodestyle - warning
213214
"YTT", # flake8-2020
215+
214216
]
215217

216218
line-length = 120
@@ -232,6 +234,8 @@ lint.ignore = [
232234
"PLW2901", # pylint - for loop variable overwritten by assignment target
233235
"RUF012", # Ruff-specific rule - annotated with classvar
234236
"ISC001", # Ruff formatter incompatible
237+
"A005", # flake8 - Module `x` shadows a Python standard-library module
238+
"PLC0415", # pylint - `import` should be at the top of the file
235239
]
236240
src = ["sqlspec", "tests", "docs/examples"]
237241
target-version = "py39"

sqlspec/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
from __future__ import annotations

sqlspec/__metadata__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"""Metadata for the Project."""
22

3-
from __future__ import annotations
4-
53
from importlib.metadata import PackageNotFoundError, metadata, version
64

75
__all__ = ("__project__", "__version__")

sqlspec/_serialization.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,69 @@
1+
import datetime
2+
import enum
13
from typing import Any
24

3-
__all__ = ("decode_json", "encode_json")
5+
from sqlspec._typing import PYDANTIC_INSTALLED, BaseModel
6+
7+
8+
def _type_to_string(value: Any) -> str: # pragma: no cover
9+
if isinstance(value, datetime.datetime):
10+
return convert_datetime_to_gmt_iso(value)
11+
if isinstance(value, datetime.date):
12+
return convert_date_to_iso(value)
13+
if isinstance(value, enum.Enum):
14+
return str(value.value)
15+
if PYDANTIC_INSTALLED and isinstance(value, BaseModel):
16+
return value.model_dump_json()
17+
try:
18+
val = str(value)
19+
except Exception as exc:
20+
raise TypeError from exc
21+
return val
22+
423

524
try:
6-
from msgspec.json import Decoder, Encoder # pyright: ignore[reportMissingImports]
25+
from msgspec.json import Decoder, Encoder
726

8-
encoder, decoder = Encoder(), Decoder()
27+
encoder, decoder = Encoder(enc_hook=_type_to_string), Decoder()
928
decode_json = decoder.decode
1029

11-
def encode_json(data: Any) -> str:
30+
def encode_json(data: Any) -> str: # pragma: no cover
1231
return encoder.encode(data).decode("utf-8")
1332

1433
except ImportError:
1534
try:
16-
from orjson import dumps as _encode_json # pyright: ignore[reportMissingImports,reportUnknownVariableType]
17-
from orjson import loads as decode_json # type: ignore[no-redef]
35+
from orjson import ( # pyright: ignore[reportMissingImports]
36+
OPT_NAIVE_UTC, # pyright: ignore[reportUnknownVariableType]
37+
OPT_SERIALIZE_NUMPY, # pyright: ignore[reportUnknownVariableType]
38+
OPT_SERIALIZE_UUID, # pyright: ignore[reportUnknownVariableType]
39+
)
40+
from orjson import dumps as _encode_json # pyright: ignore[reportUnknownVariableType,reportMissingImports]
41+
from orjson import loads as decode_json # type: ignore[no-redef,assignment,unused-ignore]
1842

19-
def encode_json(data: Any) -> str:
20-
return _encode_json(data).decode("utf-8") # type: ignore[no-any-return]
43+
def encode_json(data: Any) -> str: # pragma: no cover
44+
return _encode_json(
45+
data, default=_type_to_string, option=OPT_SERIALIZE_NUMPY | OPT_NAIVE_UTC | OPT_SERIALIZE_UUID
46+
).decode("utf-8")
2147

2248
except ImportError:
2349
from json import dumps as encode_json # type: ignore[assignment]
2450
from json import loads as decode_json # type: ignore[assignment]
51+
52+
__all__ = (
53+
"convert_date_to_iso",
54+
"convert_datetime_to_gmt_iso",
55+
"decode_json",
56+
"encode_json",
57+
)
58+
59+
60+
def convert_datetime_to_gmt_iso(dt: datetime.datetime) -> str: # pragma: no cover
61+
"""Handle datetime serialization for nested timestamps."""
62+
if not dt.tzinfo:
63+
dt = dt.replace(tzinfo=datetime.timezone.utc)
64+
return dt.isoformat().replace("+00:00", "Z")
65+
66+
67+
def convert_date_to_iso(dt: datetime.date) -> str: # pragma: no cover
68+
"""Handle datetime serialization for nested timestamps."""
69+
return dt.isoformat()

sqlspec/_typing.py

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
This is used to ensure compatibility when one or more of the libraries are installed.
44
"""
55

6-
from __future__ import annotations
7-
86
from enum import Enum
97
from typing import (
108
Any,
@@ -30,21 +28,58 @@ class DataclassProtocol(Protocol):
3028
T_co = TypeVar("T_co", covariant=True)
3129

3230
try:
33-
from pydantic import BaseModel, FailFast, TypeAdapter
31+
from pydantic import (
32+
BaseModel,
33+
FailFast, # pyright: ignore[reportGeneralTypeIssues,reportAssignmentType]
34+
TypeAdapter,
35+
)
3436

3537
PYDANTIC_INSTALLED = True
3638
except ImportError:
39+
from dataclasses import dataclass
3740

3841
@runtime_checkable
3942
class BaseModel(Protocol): # type: ignore[no-redef]
4043
"""Placeholder Implementation"""
4144

4245
model_fields: ClassVar[dict[str, Any]]
4346

44-
def model_dump(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
47+
def model_dump(
48+
self,
49+
/,
50+
*,
51+
include: "Optional[Any]" = None,
52+
exclude: "Optional[Any]" = None,
53+
context: "Optional[Any]" = None,
54+
by_alias: bool = False,
55+
exclude_unset: bool = False,
56+
exclude_defaults: bool = False,
57+
exclude_none: bool = False,
58+
round_trip: bool = False,
59+
warnings: "Union[bool, Literal['none', 'warn', 'error']]" = True,
60+
serialize_as_any: bool = False,
61+
) -> "dict[str, Any]":
4562
"""Placeholder"""
4663
return {}
4764

65+
def model_dump_json(
66+
self,
67+
/,
68+
*,
69+
include: "Optional[Any]" = None,
70+
exclude: "Optional[Any]" = None,
71+
context: "Optional[Any]" = None,
72+
by_alias: bool = False,
73+
exclude_unset: bool = False,
74+
exclude_defaults: bool = False,
75+
exclude_none: bool = False,
76+
round_trip: bool = False,
77+
warnings: "Union[bool, Literal['none', 'warn', 'error']]" = True,
78+
serialize_as_any: bool = False,
79+
) -> str:
80+
"""Placeholder"""
81+
return ""
82+
4883
@runtime_checkable
4984
class TypeAdapter(Protocol[T_co]): # type: ignore[no-redef]
5085
"""Placeholder Implementation"""
@@ -53,9 +88,9 @@ def __init__(
5388
self,
5489
type: Any, # noqa: A002
5590
*,
56-
config: Any | None = None,
91+
config: "Optional[Any]" = None,
5792
_parent_depth: int = 2,
58-
module: str | None = None,
93+
module: "Optional[str]" = None,
5994
) -> None:
6095
"""Init"""
6196

@@ -64,42 +99,56 @@ def validate_python(
6499
object: Any, # noqa: A002
65100
/,
66101
*,
67-
strict: bool | None = None,
68-
from_attributes: bool | None = None,
69-
context: dict[str, Any] | None = None,
70-
) -> T_co:
102+
strict: "Optional[bool]" = None,
103+
from_attributes: "Optional[bool]" = None,
104+
context: "Optional[dict[str, Any]]" = None,
105+
experimental_allow_partial: "Union[bool, Literal['off', 'on', 'trailing-strings']]" = False,
106+
) -> "T_co":
71107
"""Stub"""
72108
return cast("T_co", object)
73109

74-
@runtime_checkable
75-
class FailFast(Protocol): # type: ignore[no-redef]
110+
@dataclass
111+
class FailFast: # type: ignore[no-redef]
76112
"""Placeholder Implementation for FailFast"""
77113

78-
def __init__(self, *args: Any, **kwargs: Any) -> None:
79-
"""Init"""
114+
fail_fast: bool = True
80115

81116
PYDANTIC_INSTALLED = False # pyright: ignore[reportConstantRedefinition]
82117

83118
try:
84119
from msgspec import (
85120
UNSET,
86121
Struct,
87-
UnsetType, # pyright: ignore[reportAssignmentType]
122+
UnsetType, # pyright: ignore[reportAssignmentType,reportGeneralTypeIssues]
88123
convert,
89124
)
90125

91126
MSGSPEC_INSTALLED: bool = True
92127
except ImportError:
93128
import enum
129+
from collections.abc import Iterable
130+
from typing import TYPE_CHECKING, Callable, Optional, Union
131+
132+
if TYPE_CHECKING:
133+
from collections.abc import Iterable
94134

95135
@dataclass_transform()
96136
@runtime_checkable
97137
class Struct(Protocol): # type: ignore[no-redef]
98138
"""Placeholder Implementation"""
99139

100-
__struct_fields__: ClassVar[tuple[str, ...]]
101-
102-
def convert(*args: Any, **kwargs: Any) -> Any: # type: ignore[no-redef]
140+
__struct_fields__: "ClassVar[tuple[str, ...]]"
141+
142+
def convert( # type: ignore[no-redef]
143+
obj: Any,
144+
type: "Union[Any, type[T]]", # noqa: A002
145+
*,
146+
strict: bool = True,
147+
from_attributes: bool = False,
148+
dec_hook: "Optional[Callable[[type, Any], Any]]" = None,
149+
builtin_types: "Union[Iterable[type], None]" = None,
150+
str_keys: bool = False,
151+
) -> "Union[T, Any]":
103152
"""Placeholder implementation"""
104153
return {}
105154

@@ -124,11 +173,11 @@ class DTOData(Protocol[T]): # type: ignore[no-redef]
124173
def __init__(self, backend: Any, data_as_builtins: Any) -> None:
125174
"""Placeholder init"""
126175

127-
def create_instance(self, **kwargs: Any) -> T:
176+
def create_instance(self, **kwargs: Any) -> "T":
128177
"""Placeholder implementation"""
129178
return cast("T", kwargs)
130179

131-
def update_instance(self, instance: T, **kwargs: Any) -> T:
180+
def update_instance(self, instance: "T", **kwargs: Any) -> "T":
132181
"""Placeholder implementation"""
133182
return cast("T", kwargs)
134183

sqlspec/adapters/adbc/config.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from __future__ import annotations
2-
31
from contextlib import contextmanager
42
from dataclasses import dataclass
5-
from typing import TYPE_CHECKING
3+
from typing import TYPE_CHECKING, Any, Optional, Union
64

75
from sqlspec.base import NoPoolSyncConfig
86
from sqlspec.typing import Empty, EmptyType
@@ -27,15 +25,15 @@ class AdbcDatabaseConfig(NoPoolSyncConfig["Connection"]):
2725
__supports_connection_pooling = False
2826
__is_async = False
2927

30-
uri: str | EmptyType = Empty
28+
uri: "Union[str, EmptyType]" = Empty
3129
"""Database URI"""
32-
driver_name: str | EmptyType = Empty
30+
driver_name: "Union[str, EmptyType]" = Empty
3331
"""Name of the ADBC driver to use"""
34-
db_kwargs: dict[str, Any] | None = None
32+
db_kwargs: "Optional[dict[str, Any]]" = None
3533
"""Additional database-specific connection parameters"""
3634

3735
@property
38-
def connection_params(self) -> dict[str, Any]:
36+
def connection_params(self) -> "dict[str, Any]":
3937
"""Return the connection parameters as a dict."""
4038
return {
4139
k: v
@@ -44,7 +42,7 @@ def connection_params(self) -> dict[str, Any]:
4442
}
4543

4644
@contextmanager
47-
def provide_connection(self, *args: Any, **kwargs: Any) -> Generator[Connection, None, None]:
45+
def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[Connection, None, None]":
4846
"""Create and provide a database connection."""
4947
from adbc_driver_manager.dbapi import connect
5048

0 commit comments

Comments
 (0)