Skip to content

Commit fc76936

Browse files
authored
fix: correction for 3.8 and 3.9 type hints (#330)
* fix: fix `3.9` type hints * fix: 3.9 syntax * fix: re-enable 3.8 support * fix: 3.8 lint warnings * fix: additional ignores * fix: remove SO reference * fix: re-renable 3.8 tests for Starlette and FastAPI * fix: re-enable `3.8` support * fix: linting...
1 parent c397838 commit fc76936

File tree

15 files changed

+354
-225
lines changed

15 files changed

+354
-225
lines changed

advanced_alchemy/extensions/litestar/plugins/init/plugin.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ def on_app_init(self, app_config: AppConfig) -> AppConfig:
9999
with contextlib.suppress(ImportError):
100100
import uuid_utils # pyright: ignore[reportMissingImports]
101101

102-
signature_namespace_values.update({"uuid_utils.UUID": uuid_utils.UUID})
103-
app_config.type_encoders = {uuid_utils.UUID: str, **(app_config.type_encoders or {})}
102+
signature_namespace_values.update({"uuid_utils.UUID": uuid_utils.UUID}) # pyright: ignore[reportUnknownMemberType]
103+
app_config.type_encoders = {uuid_utils.UUID: str, **(app_config.type_encoders or {})} # pyright: ignore[reportUnknownMemberType]
104104
app_config.type_decoders = [
105-
(lambda x: x is uuid_utils.UUID, lambda t, v: t(str(v))),
105+
(lambda x: x is uuid_utils.UUID, lambda t, v: t(str(v))), # pyright: ignore[reportUnknownMemberType]
106106
*(app_config.type_decoders or []),
107107
]
108108
configure_exception_handler = False

advanced_alchemy/mixins/nanoid.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
from advanced_alchemy.types import NANOID_INSTALLED
99

1010
if NANOID_INSTALLED and not TYPE_CHECKING:
11-
from fastnanoid import generate as nanoid # pyright: ignore[reportMissingImports]
11+
from fastnanoid import ( # type: ignore[import-not-found,unused-ignore] # pyright: ignore[reportMissingImports]
12+
generate as nanoid,
13+
)
1214
else:
13-
from uuid import uuid4 as nanoid # type: ignore[assignment]
15+
from uuid import uuid4 as nanoid # type: ignore[assignment,unused-ignore]
1416

1517

1618
@declarative_mixin

advanced_alchemy/mixins/uuid.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99
from advanced_alchemy.types import UUID_UTILS_INSTALLED
1010

1111
if UUID_UTILS_INSTALLED and not TYPE_CHECKING:
12-
from uuid_utils.compat import uuid4, uuid6, uuid7 # pyright: ignore[reportMissingImports]
12+
from uuid_utils.compat import ( # type: ignore[no-redef,unused-ignore] # pyright: ignore[reportMissingImports]
13+
uuid4,
14+
uuid6,
15+
uuid7,
16+
)
1317
else:
14-
from uuid import uuid4
18+
from uuid import uuid4 # type: ignore[no-redef,unused-ignore]
1519

16-
uuid6 = uuid4 # type: ignore[assignment]
17-
uuid7 = uuid4 # type: ignore[assignment]
20+
uuid6 = uuid4 # type: ignore[assignment, unused-ignore]
21+
uuid7 = uuid4 # type: ignore[assignment, unused-ignore]
1822

1923

2024
@declarative_mixin

docs/conf.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,6 @@
252252
"url": "https://github.com/litestar-org/advanced-alchemy/discussions",
253253
"icon": "coc",
254254
},
255-
{
256-
"title": "Stack Overflow",
257-
"summary": "We monitor the <code><b>litestar</b></code> tag on Stack Overflow",
258-
"url": "https://stackoverflow.com/questions/tagged/litestar",
259-
"icon": "coc",
260-
},
261255
],
262256
},
263257
],

examples/fastapi.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
from contextlib import asynccontextmanager
44
from datetime import date # noqa: TC003
5-
from typing import AsyncGenerator
5+
from typing import AsyncGenerator, List
66
from uuid import UUID # noqa: TC003
77

88
from fastapi import APIRouter, Depends, FastAPI, Request
99
from pydantic import BaseModel as _BaseModel
10-
from sqlalchemy import ForeignKey, select
10+
from sqlalchemy import ForeignKey
1111
from sqlalchemy.ext.asyncio import AsyncSession # noqa: TC002
12-
from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload
12+
from sqlalchemy.orm import Mapped, mapped_column, relationship
1313
from typing_extensions import Annotated
1414

1515
from advanced_alchemy.base import UUIDAuditBase, UUIDBase, metadata_registry
@@ -37,7 +37,7 @@ class AuthorModel(UUIDBase):
3737
__tablename__ = "author"
3838
name: Mapped[str]
3939
dob: Mapped[date | None]
40-
books: Mapped[list[BookModel]] = relationship(back_populates="author", lazy="noload")
40+
books: Mapped[List[BookModel]] = relationship(back_populates="author", lazy="noload") # noqa: UP006
4141

4242

4343
# The `AuditBase` class includes the same UUID` based primary key (`id`) and 2
@@ -95,9 +95,7 @@ async def provide_authors_service(
9595
db_session: Annotated[AsyncSession, Depends(provide_db_session)],
9696
) -> AsyncGenerator[AuthorService, None]:
9797
"""This provides the default Authors repository."""
98-
async with AuthorService.new(
99-
session=db_session,
100-
) as service:
98+
async with AuthorService.new(session=db_session) as service:
10199
yield service
102100

103101

@@ -107,10 +105,7 @@ async def provide_author_details_service(
107105
db_session: Annotated[AsyncSession, Depends(provide_db_session)],
108106
) -> AsyncGenerator[AuthorService, None]:
109107
"""This provides a simple example demonstrating how to override the join options for the repository."""
110-
async with AuthorService.new(
111-
statement=select(AuthorModel).options(selectinload(AuthorModel.books)),
112-
session=db_session,
113-
) as service:
108+
async with AuthorService.new(load=[AuthorModel.books], session=db_session) as service:
114109
yield service
115110

116111

examples/litestar/litestar_repo_only.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from datetime import date # noqa: TC003
4-
from typing import TYPE_CHECKING, List
4+
from typing import TYPE_CHECKING, List, Optional
55
from uuid import UUID # noqa: TC003
66

77
from litestar import Litestar
@@ -12,8 +12,8 @@
1212
from litestar.params import Parameter
1313
from pydantic import BaseModel as _BaseModel
1414
from pydantic import TypeAdapter
15-
from sqlalchemy import ForeignKey, select
16-
from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload
15+
from sqlalchemy import ForeignKey
16+
from sqlalchemy.orm import Mapped, mapped_column, relationship
1717

1818
from advanced_alchemy.base import UUIDAuditBase, UUIDBase
1919
from advanced_alchemy.config import AsyncSessionConfig
@@ -37,8 +37,8 @@ class AuthorModel(UUIDBase):
3737
# we can optionally provide the table name instead of auto-generating it
3838
__tablename__ = "author"
3939
name: Mapped[str]
40-
dob: Mapped[date | None]
41-
books: Mapped[list[BookModel]] = relationship(back_populates="author", lazy="noload")
40+
dob: Mapped[Optional[date]] # noqa: UP007
41+
books: Mapped[List[BookModel]] = relationship(back_populates="author", lazy="noload") # noqa: UP006
4242

4343

4444
# The `AuditBase` class includes the same UUID` based primary key (`id`) and 2
@@ -85,10 +85,7 @@ async def provide_authors_repo(db_session: AsyncSession) -> AuthorRepository:
8585
# specific SQL options such as join details
8686
async def provide_author_details_repo(db_session: AsyncSession) -> AuthorRepository:
8787
"""This provides a simple example demonstrating how to override the join options for the repository."""
88-
return AuthorRepository(
89-
statement=select(AuthorModel).options(selectinload(AuthorModel.books)),
90-
session=db_session,
91-
)
88+
return AuthorRepository(load=[AuthorModel.books], session=db_session)
9289

9390

9491
def provide_limit_offset_pagination(

examples/litestar/litestar_service.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, AsyncGenerator
3+
from datetime import date # noqa: TC003
4+
from typing import TYPE_CHECKING, AsyncGenerator, List, Optional
5+
from uuid import UUID # noqa: TC003
46

57
from litestar import Litestar
68
from litestar.controller import Controller
@@ -22,9 +24,6 @@
2224
from advanced_alchemy.service import OffsetPagination, SQLAlchemyAsyncRepositoryService
2325

2426
if TYPE_CHECKING:
25-
from datetime import date
26-
from uuid import UUID
27-
2827
from sqlalchemy.ext.asyncio import AsyncSession
2928

3029

@@ -40,8 +39,8 @@ class AuthorModel(UUIDBase):
4039
# we can optionally provide the table name instead of auto-generating it
4140
__tablename__ = "author"
4241
name: Mapped[str]
43-
dob: Mapped[date | None]
44-
books: Mapped[list[BookModel]] = relationship(back_populates="author", lazy="noload")
42+
dob: Mapped[Optional[date]] # noqa: UP007
43+
books: Mapped[List[BookModel]] = relationship(back_populates="author", lazy="noload") # noqa: UP006
4544

4645

4746
# The `AuditBase` class includes the same UUID` based primary key (`id`) and 2

examples/sanic.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from __future__ import annotations
22

33
from datetime import date # noqa: TC003
4-
from typing import Any
4+
from typing import Any, List
55
from uuid import UUID # noqa: TC003
66

77
from sanic import Request, Sanic
88
from sanic_ext import Extend
9-
from sqlalchemy import ForeignKey, select
9+
from sqlalchemy import ForeignKey
1010
from sqlalchemy.ext.asyncio import AsyncSession
11-
from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload
11+
from sqlalchemy.orm import Mapped, mapped_column, relationship
1212

1313
from advanced_alchemy.base import UUIDAuditBase, UUIDBase
1414
from advanced_alchemy.config import AsyncSessionConfig, SQLAlchemyAsyncConfig
@@ -24,7 +24,7 @@ class AuthorModel(UUIDBase):
2424
__tablename__ = "author"
2525
name: Mapped[str]
2626
dob: Mapped[date | None]
27-
books: Mapped[list[BookModel]] = relationship(back_populates="author", lazy="noload")
27+
books: Mapped[List[BookModel]] = relationship(back_populates="author", lazy="noload") # noqa: UP006
2828

2929

3030
# The `AuditBase` class includes the same UUID` based primary key (`id`) and 2
@@ -64,10 +64,7 @@ async def provide_author_details_repo(
6464
db_session: AsyncSession,
6565
) -> AuthorRepository:
6666
"""This provides a simple example demonstrating how to override the join options for the repository."""
67-
return AuthorRepository(
68-
statement=select(AuthorModel).options(selectinload(AuthorModel.books)),
69-
session=db_session,
70-
)
67+
return AuthorRepository(load=[AuthorModel.books], session=db_session)
7168

7269

7370
def provide_limit_offset_pagination(

pyproject.toml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ classifiers = [
2525
"Topic :: Database",
2626
"Topic :: Database :: Database Engines/Servers",
2727
]
28-
dependencies = ["sqlalchemy>=2.0.20", "alembic>=1.12.0", "typing-extensions>=4.0.0", "greenlet"]
28+
dependencies = [
29+
"sqlalchemy>=2.0.20",
30+
"alembic>=1.12.0",
31+
"typing-extensions>=4.0.0",
32+
"greenlet",
33+
"eval-type-backport ; python_full_version < '3.10'",
34+
]
2935
description = "Ready-to-go SQLAlchemy concoctions."
3036
keywords = ["sqlalchemy", "alembic", "litestar", "sanic", "fastapi", "flask"]
3137
license = { text = "MIT" }
@@ -104,7 +110,7 @@ doc = [
104110
"sphinx-autodoc-typehints",
105111
]
106112
duckdb = ["duckdb>=1.1.2", "duckdb-engine>=0.13.4", "pytz>=2024.2"]
107-
fastapi = ["fastapi[all]>=0.115.3"]
113+
fastapi = ["fastapi[all]>=0.115.3", "starlette<0.45.0; python_version < '3.9'", "starlette; python_version >= '3.9'"]
108114
flask = ["flask-sqlalchemy>=3.1.1"]
109115
lint = [
110116
"mypy>=1.13.0",
@@ -130,10 +136,17 @@ mssql = ["aioodbc>=0.5.0", "pyodbc>=5.2.0"]
130136
mysql = ["asyncmy>=0.2.9"]
131137
oracle = ["oracledb>=2.4.1"]
132138
postgres = ["asyncpg>=0.29.0", "psycopg2-binary>=2.9.10", "psycopg[binary,pool]>=3.2.3"]
133-
sanic = ["sanic-testing>=24.6.0", "sanic[ext]>=24.6.0"]
139+
sanic = [
140+
"sanic<24.12; python_version < '3.9'",
141+
"sanic; python_version >= '3.9'",
142+
"sanic-testing>=24.6.0",
143+
"sanic[ext]>=24.6.0",
144+
]
134145
spanner = ["sqlalchemy-spanner>=1.7.0"]
135146
sqlite = ["aiosqlite>=0.20.0"]
136147
test = [
148+
"pydantic-extra-types < 2.9.0; python_version < \"3.9\"",
149+
"pydantic-extra-types; python_version >= \"3.9\"",
137150
"coverage>=7.6.1",
138151
"pytest>=7.4.4",
139152
"pytest-asyncio>=0.23.8",

tests/integration/test_loader_and_execution_options.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ class CountryRepository(SQLAlchemySyncRepository[UUIDCountryTest]):
289289
assert len(usa_country_1.states) == 2
290290
usa_country_2 = si1_country_repo.get_one(
291291
name="United States of America",
292-
load=UUIDCountryTest.states,
292+
load="*",
293293
execution_options={"populate_existing": True},
294294
)
295295
assert len(usa_country_2.states) == 2

0 commit comments

Comments
 (0)