Skip to content

Commit

Permalink
feat: deprecate litestar.contrib.sqlalchemy (#3755)
Browse files Browse the repository at this point in the history
* feat: deprecate `contrib.sqlalchemy`

* feat: linting

* feat: deprecate `contrib.sqlalchemy`

* feat: linting

* fix: correct variable reference

* fix: corrected deprecated version

* chore: linting

* feat: fix changes caused by linting

* fix: linting

* chore: bump deps

* fix: test case corrections

* fix: revert lock file changes

* feat: remove extra ignores

* feat: adds additional coverage

* feat: additional coverage

* chore: ignore catchall coverage
  • Loading branch information
cofin authored Sep 23, 2024
1 parent 8e875c1 commit b187749
Show file tree
Hide file tree
Showing 40 changed files with 1,286 additions and 174 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ __pypackages__/
# test certificates
certs/
pdm.toml
.zed
10 changes: 8 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@
(PY_CLASS, "litestar.response.RedirectResponse"),
(PY_CLASS, "litestar.response_containers.Redirect"),
(PY_CLASS, "litestar.response_containers.Template"),
(PY_CLASS, "litestar.contrib.sqlalchemy.plugins.SQLAlchemyPlugin"),
(PY_CLASS, "litestar.contrib.sqlalchemy.plugins.SQLAlchemySerializationPlugin"),
(PY_CLASS, "litestar.contrib.sqlalchemy.plugins.SQLAlchemyInitPlugin"),
(PY_CLASS, "litestar.contrib.sqlalchemy.dto.SQLAlchemyDTO"),
(PY_CLASS, "litestar.contrib.sqlalchemy.types.BigIntIdentity"),
(PY_CLASS, "litestar.contrib.sqlalchemy.types.JsonB"),
(PY_CLASS, "litestar.typing.ParsedType"),
Expand All @@ -165,6 +169,8 @@
(PY_CLASS, "advanced_alchemy.extensions.litestar.plugins._slots_base.SlotsBase"),
(PY_CLASS, "advanced_alchemy.config.EngineConfig"),
(PY_CLASS, "advanced_alchemy.config.common.GenericAlembicConfig"),
(PY_CLASS, "advanced_alchemy.extensions.litestar.SQLAlchemyDTO"),
(PY_CLASS, "advanced_alchemy.extensions.litestar.dto.SQLAlchemyDTO"),
(PY_CLASS, "advanced_alchemy.extensions.litestar.plugins.SQLAlchemyPlugin"),
(PY_CLASS, "advanced_alchemy.extensions.litestar.plugins.SQLAlchemySerializationPlugin"),
(PY_CLASS, "advanced_alchemy.extensions.litestar.plugins.SQLAlchemyInitPlugin"),
Expand Down Expand Up @@ -349,11 +355,11 @@ def delayed_setup(app: Sphinx) -> None:
return

app.setup_extension("pydata_sphinx_theme")
app.connect("html-page-context", update_html_context)
app.connect("html-page-context", update_html_context) # type: ignore


def setup(app: Sphinx) -> dict[str, bool]:
app.connect("builder-inited", delayed_setup, priority=0)
app.connect("builder-inited", delayed_setup, priority=0) # type: ignore

app.setup_extension("litestar_sphinx_theme")

Expand Down
26 changes: 15 additions & 11 deletions docs/examples/contrib/sqlalchemy/sqlalchemy_async_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@
from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload

from litestar import Litestar, get
from litestar.contrib.sqlalchemy.base import UUIDAuditBase, UUIDBase
from litestar.contrib.sqlalchemy.plugins import AsyncSessionConfig, SQLAlchemyAsyncConfig, SQLAlchemyInitPlugin
from litestar.contrib.sqlalchemy.repository import SQLAlchemyAsyncRepository
from litestar.controller import Controller
from litestar.di import Provide
from litestar.handlers.http_handlers.decorators import delete, patch, post
from litestar.pagination import OffsetPagination
from litestar.params import Parameter
from litestar.repository.filters import LimitOffset
from litestar.plugins.sqlalchemy import (
AsyncSessionConfig,
SQLAlchemyAsyncConfig,
SQLAlchemyInitPlugin,
base,
filters,
repository,
)

if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession
Expand All @@ -32,7 +36,7 @@ class BaseModel(_BaseModel):

# the SQLAlchemy base includes a declarative model for you to use in your models.
# The `Base` class includes a `UUID` based primary key (`id`)
class AuthorModel(UUIDBase):
class AuthorModel(base.UUIDBase):
# we can optionally provide the table name instead of auto-generating it
__tablename__ = "author" # type: ignore[assignment]
name: Mapped[str]
Expand All @@ -43,7 +47,7 @@ class AuthorModel(UUIDBase):
# The `AuditBase` class includes the same UUID` based primary key (`id`) and 2
# additional columns: `created` and `updated`. `created` is a timestamp of when the
# record created, and `updated` is the last time the record was modified.
class BookModel(UUIDAuditBase):
class BookModel(base.UUIDAuditBase):
__tablename__ = "book" # type: ignore[assignment]
title: Mapped[str]
author_id: Mapped[UUID] = mapped_column(ForeignKey("author.id"))
Expand All @@ -69,7 +73,7 @@ class AuthorUpdate(BaseModel):
dob: date | None = None


class AuthorRepository(SQLAlchemyAsyncRepository[AuthorModel]):
class AuthorRepository(repository.SQLAlchemyAsyncRepository[AuthorModel]):
"""Author repository."""

model_type = AuthorModel
Expand Down Expand Up @@ -98,7 +102,7 @@ def provide_limit_offset_pagination(
default=10,
required=False,
),
) -> LimitOffset:
) -> filters.LimitOffset:
"""Add offset/limit pagination.
Return type consumed by `Repository.apply_limit_offset_pagination()`.
Expand All @@ -110,7 +114,7 @@ def provide_limit_offset_pagination(
page_size : int
OFFSET to apply to select.
"""
return LimitOffset(page_size, page_size * (current_page - 1))
return filters.LimitOffset(page_size, page_size * (current_page - 1))


class AuthorController(Controller):
Expand All @@ -122,7 +126,7 @@ class AuthorController(Controller):
async def list_authors(
self,
authors_repo: AuthorRepository,
limit_offset: LimitOffset,
limit_offset: filters.LimitOffset,
) -> OffsetPagination[Author]:
"""List authors."""
results, total = await authors_repo.list_and_count(limit_offset)
Expand Down Expand Up @@ -205,7 +209,7 @@ async def delete_author(
async def on_startup() -> None:
"""Initializes the database."""
async with sqlalchemy_config.get_engine().begin() as conn:
await conn.run_sync(UUIDBase.metadata.create_all)
await conn.run_sync(base.UUIDBase.metadata.create_all)


app = Litestar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload

from litestar import Litestar, get
from litestar.contrib.sqlalchemy import SQLAlchemyInitPlugin, SQLAlchemySyncConfig
from litestar.contrib.sqlalchemy.base import UUIDAuditBase, UUIDBase
from litestar.contrib.sqlalchemy.plugins.init import SQLAlchemyInitPlugin, SQLAlchemySyncConfig
from litestar.contrib.sqlalchemy.repository import SQLAlchemySyncRepository
from litestar.controller import Controller
from litestar.di import Provide
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from sqlalchemy.orm import Mapped

from litestar import Litestar, get
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from typing_extensions import Annotated

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig, dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from typing_extensions import Annotated

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig, dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from sqlalchemy.orm import Mapped, mapped_column

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from sqlalchemy.orm import Mapped

from litestar import Litestar, get
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig
from litestar.pagination import ClassicPagination
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from typing_extensions import Annotated

from litestar import Litestar, put
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from typing_extensions import Annotated

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig, dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from typing_extensions import Annotated

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig, dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from sqlalchemy.orm import Mapped

from litestar import Litestar, Response, get
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import DTOConfig
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from sqlalchemy.orm import Mapped

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from sqlalchemy.orm import Mapped, mapped_column

from litestar import Litestar, post
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.dto import dto_field
from litestar.plugins.sqlalchemy import SQLAlchemyDTO

from .my_lib import Base

Expand Down
5 changes: 2 additions & 3 deletions docs/examples/websockets/with_dto.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from sqlalchemy.orm import Mapped

from litestar import Litestar, websocket_listener
from litestar.contrib.sqlalchemy.base import UUIDBase
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO
from litestar.plugins.sqlalchemy import SQLAlchemyDTO, base


class User(UUIDBase):
class User(base.UUIDBase):
name: Mapped[str]


Expand Down
2 changes: 1 addition & 1 deletion litestar/contrib/pydantic/pydantic_init_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _dec_pydantic_v1(model_type: type[pydantic_v1.BaseModel], value: Any) -> pyd
raise ExtendedMsgSpecValidationError(errors=cast("list[dict[str, Any]]", e.errors())) from e


def _dec_pydantic_v2(model_type: type[pydantic_v2.BaseModel], value: Any, strict: bool) -> pydantic_v2.BaseModel:
def _dec_pydantic_v2(model_type: type[pydantic_v2.BaseModel], value: Any, strict: bool) -> pydantic_v2.BaseModel: # pyright: ignore[reportInvalidTypeForm]
try:
return model_type.model_validate(value, strict=strict)
except pydantic_v2.ValidationError as e:
Expand Down
54 changes: 54 additions & 0 deletions litestar/contrib/sqlalchemy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# ruff: noqa: TCH004, F401
from __future__ import annotations

from typing import TYPE_CHECKING

from litestar.utils import warn_deprecation

__all__ = (
"SQLAlchemyAsyncRepository",
"SQLAlchemySyncRepository",
"ModelT",
"wrap_sqlalchemy_exception",
)


def __getattr__(attr_name: str) -> object:
if attr_name in __all__:
if attr_name in ("SQLAlchemyAsyncRepository", "SQLAlchemySyncRepository", "ModelT"):
module = "litestar.plugins.sqlalchemy.repository"
from advanced_alchemy.extensions.litestar import (
repository, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports]
)

value = globals()[attr_name] = getattr(repository, attr_name)
elif attr_name == "wrap_sqlalchemy_exception":
module = "litestar.plugins.sqlalchemy.exceptions"
from advanced_alchemy.extensions.litestar import (
exceptions, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports]
)

value = globals()[attr_name] = getattr(exceptions, attr_name)
warn_deprecation(
deprecated_name=f"litestar.contrib.sqlalchemy.{attr_name}",
version="2.12",
kind="import",
removal_in="3.0",
info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy' is deprecated, please "
f"import it from '{module}' instead",
)

return value

raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover


if TYPE_CHECKING:
from advanced_alchemy.exceptions import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports]
wrap_sqlalchemy_exception,
)
from advanced_alchemy.repository import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports]
ModelT,
SQLAlchemyAsyncRepository,
SQLAlchemySyncRepository,
)
Loading

0 comments on commit b187749

Please sign in to comment.