From b18774922fedc86089d143d9a5484f393826557d Mon Sep 17 00:00:00 2001 From: Cody Fincher <204685+cofin@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:02:29 -0500 Subject: [PATCH] feat: deprecate `litestar.contrib.sqlalchemy` (#3755) * 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 --- .gitignore | 1 + docs/conf.py | 10 +- .../sqlalchemy/sqlalchemy_async_repository.py | 26 +- .../sqlalchemy/sqlalchemy_sync_repository.py | 2 +- .../factory/enveloping_return_data.py | 2 +- .../factory/excluding_fields.py | 2 +- .../factory/included_fields.py | 2 +- .../factory/marking_fields.py | 2 +- .../factory/paginated_return_data.py | 2 +- .../factory/related_items.py | 2 +- .../factory/renaming_all_fields.py | 2 +- .../factory/renaming_fields.py | 2 +- .../factory/response_return_data.py | 2 +- .../factory/simple_dto_factory_example.py | 2 +- .../factory/type_checking.py | 2 +- docs/examples/websockets/with_dto.py | 5 +- .../contrib/pydantic/pydantic_init_plugin.py | 2 +- litestar/contrib/sqlalchemy/__init__.py | 54 +++ litestar/contrib/sqlalchemy/base.py | 96 +++-- litestar/contrib/sqlalchemy/dto.py | 36 +- .../contrib/sqlalchemy/plugins/__init__.py | 69 +++- .../sqlalchemy/plugins/init/__init__.py | 65 +++- .../plugins/init/config/__init__.py | 58 ++- .../sqlalchemy/plugins/init/config/asyncio.py | 72 +++- .../sqlalchemy/plugins/init/config/common.py | 48 ++- .../sqlalchemy/plugins/init/config/compat.py | 2 +- .../sqlalchemy/plugins/init/config/engine.py | 29 +- .../sqlalchemy/plugins/init/config/sync.py | 71 +++- .../contrib/sqlalchemy/plugins/init/plugin.py | 28 +- .../sqlalchemy/plugins/serialization.py | 27 +- .../contrib/sqlalchemy/repository/__init__.py | 52 ++- .../contrib/sqlalchemy/repository/_async.py | 31 +- .../contrib/sqlalchemy/repository/_sync.py | 31 +- .../contrib/sqlalchemy/repository/_util.py | 37 +- .../contrib/sqlalchemy/repository/types.py | 48 ++- litestar/contrib/sqlalchemy/types.py | 40 ++- litestar/plugins/sqlalchemy.py | 153 ++++++-- pyproject.toml | 8 + tests/unit/test_contrib/test_sqlalchemy.py | 335 +++++++++++++++++- .../test_dto/test_factory/test_integration.py | 2 +- 40 files changed, 1286 insertions(+), 174 deletions(-) diff --git a/.gitignore b/.gitignore index 72e2ed9cfb..8e4c4ae0bc 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ __pypackages__/ # test certificates certs/ pdm.toml +.zed diff --git a/docs/conf.py b/docs/conf.py index 95092864e2..75e59710e1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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"), @@ -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"), @@ -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") diff --git a/docs/examples/contrib/sqlalchemy/sqlalchemy_async_repository.py b/docs/examples/contrib/sqlalchemy/sqlalchemy_async_repository.py index 69cc19242d..f8255a17bf 100644 --- a/docs/examples/contrib/sqlalchemy/sqlalchemy_async_repository.py +++ b/docs/examples/contrib/sqlalchemy/sqlalchemy_async_repository.py @@ -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 @@ -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] @@ -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")) @@ -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 @@ -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()`. @@ -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): @@ -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) @@ -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( diff --git a/docs/examples/contrib/sqlalchemy/sqlalchemy_sync_repository.py b/docs/examples/contrib/sqlalchemy/sqlalchemy_sync_repository.py index 1e8cb107c9..67e2840761 100644 --- a/docs/examples/contrib/sqlalchemy/sqlalchemy_sync_repository.py +++ b/docs/examples/contrib/sqlalchemy/sqlalchemy_sync_repository.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/enveloping_return_data.py b/docs/examples/data_transfer_objects/factory/enveloping_return_data.py index f25908028f..d0b8393672 100644 --- a/docs/examples/data_transfer_objects/factory/enveloping_return_data.py +++ b/docs/examples/data_transfer_objects/factory/enveloping_return_data.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/excluding_fields.py b/docs/examples/data_transfer_objects/factory/excluding_fields.py index 3199dc160b..3e77533bc3 100644 --- a/docs/examples/data_transfer_objects/factory/excluding_fields.py +++ b/docs/examples/data_transfer_objects/factory/excluding_fields.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/included_fields.py b/docs/examples/data_transfer_objects/factory/included_fields.py index e9be67832b..6e583e5228 100644 --- a/docs/examples/data_transfer_objects/factory/included_fields.py +++ b/docs/examples/data_transfer_objects/factory/included_fields.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/marking_fields.py b/docs/examples/data_transfer_objects/factory/marking_fields.py index 14366cee6f..7649f2f8b5 100644 --- a/docs/examples/data_transfer_objects/factory/marking_fields.py +++ b/docs/examples/data_transfer_objects/factory/marking_fields.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/paginated_return_data.py b/docs/examples/data_transfer_objects/factory/paginated_return_data.py index a9624e69d5..01596430e9 100644 --- a/docs/examples/data_transfer_objects/factory/paginated_return_data.py +++ b/docs/examples/data_transfer_objects/factory/paginated_return_data.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/related_items.py b/docs/examples/data_transfer_objects/factory/related_items.py index 0831c196b2..9cccdaa5ab 100644 --- a/docs/examples/data_transfer_objects/factory/related_items.py +++ b/docs/examples/data_transfer_objects/factory/related_items.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/renaming_all_fields.py b/docs/examples/data_transfer_objects/factory/renaming_all_fields.py index eb2bca28e1..d001db36a8 100644 --- a/docs/examples/data_transfer_objects/factory/renaming_all_fields.py +++ b/docs/examples/data_transfer_objects/factory/renaming_all_fields.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/renaming_fields.py b/docs/examples/data_transfer_objects/factory/renaming_fields.py index 632617fa1c..693e6e8576 100644 --- a/docs/examples/data_transfer_objects/factory/renaming_fields.py +++ b/docs/examples/data_transfer_objects/factory/renaming_fields.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/response_return_data.py b/docs/examples/data_transfer_objects/factory/response_return_data.py index d83069ec75..15f2ce224d 100644 --- a/docs/examples/data_transfer_objects/factory/response_return_data.py +++ b/docs/examples/data_transfer_objects/factory/response_return_data.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/simple_dto_factory_example.py b/docs/examples/data_transfer_objects/factory/simple_dto_factory_example.py index b293690f73..0bcf7fd184 100644 --- a/docs/examples/data_transfer_objects/factory/simple_dto_factory_example.py +++ b/docs/examples/data_transfer_objects/factory/simple_dto_factory_example.py @@ -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 diff --git a/docs/examples/data_transfer_objects/factory/type_checking.py b/docs/examples/data_transfer_objects/factory/type_checking.py index 670b91703f..4a7ec357ad 100644 --- a/docs/examples/data_transfer_objects/factory/type_checking.py +++ b/docs/examples/data_transfer_objects/factory/type_checking.py @@ -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 diff --git a/docs/examples/websockets/with_dto.py b/docs/examples/websockets/with_dto.py index d3f66dba17..6cb6eccf72 100644 --- a/docs/examples/websockets/with_dto.py +++ b/docs/examples/websockets/with_dto.py @@ -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] diff --git a/litestar/contrib/pydantic/pydantic_init_plugin.py b/litestar/contrib/pydantic/pydantic_init_plugin.py index ff7cbfff3a..0ca368453e 100644 --- a/litestar/contrib/pydantic/pydantic_init_plugin.py +++ b/litestar/contrib/pydantic/pydantic_init_plugin.py @@ -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: diff --git a/litestar/contrib/sqlalchemy/__init__.py b/litestar/contrib/sqlalchemy/__init__.py index e69de29bb2..5ecc157758 100644 --- a/litestar/contrib/sqlalchemy/__init__.py +++ b/litestar/contrib/sqlalchemy/__init__.py @@ -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, + ) diff --git a/litestar/contrib/sqlalchemy/base.py b/litestar/contrib/sqlalchemy/base.py index 9ce9608f7e..9b8a42bf88 100644 --- a/litestar/contrib/sqlalchemy/base.py +++ b/litestar/contrib/sqlalchemy/base.py @@ -1,26 +1,12 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false """Application ORM configuration.""" from __future__ import annotations -try: - # v0.6.0+ - from advanced_alchemy._listeners import touch_updated_timestamp # pyright: ignore -except ImportError: - from advanced_alchemy.base import touch_updated_timestamp # type: ignore[no-redef,attr-defined] - -from advanced_alchemy.base import ( - AuditColumns, - BigIntAuditBase, - BigIntBase, - BigIntPrimaryKey, - CommonTableAttributes, - ModelProtocol, - UUIDAuditBase, - UUIDBase, - UUIDPrimaryKey, - create_registry, - orm_registry, -) +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "AuditColumns", @@ -28,11 +14,79 @@ "BigIntBase", "BigIntPrimaryKey", "CommonTableAttributes", - "create_registry", "ModelProtocol", - "touch_updated_timestamp", "UUIDAuditBase", "UUIDBase", "UUIDPrimaryKey", + "create_registry", "orm_registry", + "touch_updated_timestamp", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name == "touch_updated_timestamp": + try: + # v0.6.0+ + from advanced_alchemy._listeners import touch_updated_timestamp # pyright: ignore + except ImportError: + from advanced_alchemy.base import touch_updated_timestamp # type: ignore[no-redef,attr-defined] + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.base.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.base' is deprecated, please" + f"see the 'Advanced Alchemy' documentation for more details on how to use '{attr_name}' instead", + ) + value = globals()[attr_name] = locals()[attr_name] # pyright: ignore[reportUnknownVariableType] + return value # pyright: ignore[reportUnknownVariableType] + from advanced_alchemy.base import ( # pyright: ignore[reportMissingImports] + AuditColumns, + BigIntAuditBase, + BigIntBase, + BigIntPrimaryKey, + CommonTableAttributes, + ModelProtocol, + UUIDAuditBase, + UUIDBase, + UUIDPrimaryKey, + create_registry, + orm_registry, + ) + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.base.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.base' is deprecated, please" + f"import it from 'litestar.plugins.sqlalchemy.base.{attr_name}' instead", + ) + value = globals()[attr_name] = locals()[attr_name] # pyright: ignore[reportUnknownVariableType] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + try: + # v0.6.0+ + from advanced_alchemy._listeners import touch_updated_timestamp # pyright: ignore + except ImportError: + from advanced_alchemy.base import touch_updated_timestamp # type: ignore[no-redef,attr-defined] + + from advanced_alchemy.base import ( # pyright: ignore[reportMissingImports] + AuditColumns, + BigIntAuditBase, + BigIntBase, + BigIntPrimaryKey, + CommonTableAttributes, + ModelProtocol, + UUIDAuditBase, + UUIDBase, + UUIDPrimaryKey, + create_registry, + orm_registry, + ) diff --git a/litestar/contrib/sqlalchemy/dto.py b/litestar/contrib/sqlalchemy/dto.py index beea75d262..bc6eeb80c0 100644 --- a/litestar/contrib/sqlalchemy/dto.py +++ b/litestar/contrib/sqlalchemy/dto.py @@ -1,5 +1,39 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false +"""SQLAlchemy DTO configuration.""" + from __future__ import annotations -from advanced_alchemy.extensions.litestar.dto import SQLAlchemyDTO, SQLAlchemyDTOConfig +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("SQLAlchemyDTO", "SQLAlchemyDTOConfig") + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.extensions.litestar.dto import ( + SQLAlchemyDTO, # pyright: ignore[reportMissingImports] + SQLAlchemyDTOConfig, # pyright: ignore[reportMissingImports] + ) + + 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.dto' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy.dto' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.extensions.litestar.dto import ( + SQLAlchemyDTO, # pyright: ignore[reportMissingImports] + SQLAlchemyDTOConfig, # pyright: ignore[reportMissingImports] + ) diff --git a/litestar/contrib/sqlalchemy/plugins/__init__.py b/litestar/contrib/sqlalchemy/plugins/__init__.py index 5bc913c9ab..7a2e447144 100644 --- a/litestar/contrib/sqlalchemy/plugins/__init__.py +++ b/litestar/contrib/sqlalchemy/plugins/__init__.py @@ -1,18 +1,10 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from advanced_alchemy.extensions.litestar.plugins import SQLAlchemyPlugin - -from .init import ( - AsyncSessionConfig, - EngineConfig, - GenericSessionConfig, - GenericSQLAlchemyConfig, - SQLAlchemyAsyncConfig, - SQLAlchemyInitPlugin, - SQLAlchemySyncConfig, - SyncSessionConfig, -) -from .serialization import SQLAlchemySerializationPlugin +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "AsyncSessionConfig", @@ -26,3 +18,54 @@ "SQLAlchemySyncConfig", "SyncSessionConfig", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name in ("GenericSQLAlchemyConfig", "GenericSessionConfig"): + module = "litestar.plugins.sqlalchemy.config" + from advanced_alchemy.config import ( # pyright: ignore[reportMissingImports] + GenericSessionConfig, + GenericSQLAlchemyConfig, + ) + + value = globals()[attr_name] = locals()[attr_name] + else: + module = "litestar.plugins.sqlalchemy" + from advanced_alchemy.extensions.litestar import ( # pyright: ignore[reportMissingImports] + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyInitPlugin, + SQLAlchemyPlugin, + SQLAlchemySerializationPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) + + value = globals()[attr_name] = locals()[attr_name] + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins' 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.config import GenericSessionConfig, GenericSQLAlchemyConfig + from advanced_alchemy.extensions.litestar import ( + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyInitPlugin, + SQLAlchemyPlugin, + SQLAlchemySerializationPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/__init__.py b/litestar/contrib/sqlalchemy/plugins/init/__init__.py index 2e507c1066..c7cb3e1356 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/__init__.py +++ b/litestar/contrib/sqlalchemy/plugins/init/__init__.py @@ -1,15 +1,10 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from .config import ( - AsyncSessionConfig, - EngineConfig, - GenericSessionConfig, - GenericSQLAlchemyConfig, - SQLAlchemyAsyncConfig, - SQLAlchemySyncConfig, - SyncSessionConfig, -) -from .plugin import SQLAlchemyInitPlugin +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "AsyncSessionConfig", @@ -21,3 +16,53 @@ "SQLAlchemySyncConfig", "SyncSessionConfig", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name in ("GenericSQLAlchemyConfig", "GenericSessionConfig"): + module = "advanced_alchemy.config" + from advanced_alchemy.config import ( # pyright: ignore[reportMissingImports] + GenericSessionConfig, + GenericSQLAlchemyConfig, + ) + + value = globals()[attr_name] = locals()[attr_name] + else: + module = "litestar.plugins.sqlalchemy" + from advanced_alchemy.extensions.litestar import ( + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyInitPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) + + value = globals()[attr_name] = locals()[attr_name] + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init' 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.config import ( # pyright: ignore[reportMissingImports] + GenericSessionConfig, + GenericSQLAlchemyConfig, + ) + from advanced_alchemy.extensions.litestar import ( # pyright: ignore[reportMissingImports] + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyInitPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/__init__.py b/litestar/contrib/sqlalchemy/plugins/init/config/__init__.py index f2e39da99e..2cd96d2941 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/__init__.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/__init__.py @@ -1,9 +1,9 @@ +# ruff: noqa: TCH004,F401 from __future__ import annotations -from .asyncio import AsyncSessionConfig, SQLAlchemyAsyncConfig -from .common import GenericSessionConfig, GenericSQLAlchemyConfig -from .engine import EngineConfig -from .sync import SQLAlchemySyncConfig, SyncSessionConfig +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "AsyncSessionConfig", @@ -14,3 +14,53 @@ "SQLAlchemySyncConfig", "SyncSessionConfig", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name in ("GenericSQLAlchemyConfig", "GenericSessionConfig"): + module = "litestar.plugins.sqlalchemy.config" + from advanced_alchemy.config import ( # pyright: ignore[reportMissingImports] + GenericSessionConfig, # pyright: ignore[reportUnusedImport] + GenericSQLAlchemyConfig, # pyright: ignore[reportUnusedImport] + ) + + value = globals()[attr_name] = locals()[attr_name] + else: + module = "litestar.plugins.sqlalchemy" + from advanced_alchemy.extensions.litestar import ( # pyright: ignore[reportMissingImports] + AsyncSessionConfig, # pyright: ignore[reportUnusedImport] + EngineConfig, # pyright: ignore[reportUnusedImport] + SQLAlchemyAsyncConfig, # pyright: ignore[reportUnusedImport] + SQLAlchemySyncConfig, # pyright: ignore[reportUnusedImport] + SyncSessionConfig, # pyright: ignore[reportUnusedImport] + ) + + value = globals()[attr_name] = locals()[attr_name] + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.config.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init.config' is deprecated, please " + f"import it from '{module}' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.config import ( # pyright: ignore[reportMissingImports] + GenericSessionConfig, + GenericSQLAlchemyConfig, + ) + from advanced_alchemy.extensions.litestar import ( # pyright: ignore[reportMissingImports] + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/asyncio.py b/litestar/contrib/sqlalchemy/plugins/init/config/asyncio.py index 434c7611ae..e849313722 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/asyncio.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/asyncio.py @@ -1,16 +1,10 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from advanced_alchemy.config.asyncio import AlembicAsyncConfig, AsyncSessionConfig -from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import ( - SQLAlchemyAsyncConfig as _SQLAlchemyAsyncConfig, -) -from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import ( - autocommit_before_send_handler, - default_before_send_handler, -) -from sqlalchemy.ext.asyncio import AsyncEngine +from typing import TYPE_CHECKING -from litestar.contrib.sqlalchemy.plugins.init.config.compat import _CreateEngineMixin +from litestar.utils import warn_deprecation __all__ = ( "SQLAlchemyAsyncConfig", @@ -21,4 +15,60 @@ ) -class SQLAlchemyAsyncConfig(_SQLAlchemyAsyncConfig, _CreateEngineMixin[AsyncEngine]): ... +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name == "SQLAlchemyAsyncConfig": + from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import ( + SQLAlchemyAsyncConfig as _SQLAlchemyAsyncConfig, + ) + from sqlalchemy.ext.asyncio import AsyncEngine + + from litestar.contrib.sqlalchemy.plugins.init.config.compat import ( + _CreateEngineMixin, # pyright: ignore[reportPrivateUsage] + ) + + class SQLAlchemyAsyncConfig(_SQLAlchemyAsyncConfig, _CreateEngineMixin[AsyncEngine]): ... + + module = "litestar.plugins.sqlalchemy" + value = globals()[attr_name] = SQLAlchemyAsyncConfig + elif attr_name in {"default_before_send_handler", "autocommit_before_send_handler"}: + module = "litestar.plugins.sqlalchemy.plugins.init.config.asyncio" + from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import ( + autocommit_before_send_handler, + default_before_send_handler, + ) + + value = globals()[attr_name] = locals()[attr_name] + else: + module = "litestar.plugins.sqlalchemy" + from advanced_alchemy.extensions.litestar import ( + AlembicAsyncConfig, + AsyncSessionConfig, + ) + + value = globals()[attr_name] = locals()[attr_name] + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.config.asyncio.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated, please " + f"import it from '{module}' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.extensions.litestar import ( + AlembicAsyncConfig, + AsyncSessionConfig, + SQLAlchemyAsyncConfig, + ) + from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import ( + autocommit_before_send_handler, + default_before_send_handler, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/common.py b/litestar/contrib/sqlalchemy/plugins/init/config/common.py index 9afc48c428..99f4e15afa 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/common.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/common.py @@ -1,10 +1,9 @@ +# ruff: noqa: TCH004, F401 from __future__ import annotations -from advanced_alchemy.config.common import GenericAlembicConfig, GenericSessionConfig, GenericSQLAlchemyConfig -from advanced_alchemy.extensions.litestar.plugins.init.config.common import ( - SESSION_SCOPE_KEY, - SESSION_TERMINUS_ASGI_EVENTS, -) +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "SESSION_SCOPE_KEY", @@ -13,3 +12,42 @@ "GenericSessionConfig", "GenericAlembicConfig", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name in ("GenericSQLAlchemyConfig", "GenericSessionConfig", "GenericAlembicConfig"): + module = "litestar.plugins.sqlalchemy.config" + from advanced_alchemy.config.common import ( # pyright: ignore[reportMissingImports] + GenericAlembicConfig, # pyright: ignore[reportUnusedImport] + GenericSessionConfig, # pyright: ignore[reportUnusedImport] + GenericSQLAlchemyConfig, # pyright: ignore[reportUnusedImport] + ) + else: + from advanced_alchemy.extensions.litestar.plugins.init.config.common import ( # pyright: ignore[reportMissingImports] + SESSION_SCOPE_KEY, # pyright: ignore[reportUnusedImport] + SESSION_TERMINUS_ASGI_EVENTS, # pyright: ignore[reportUnusedImport] + ) + + module = "litestar.plugins.sqlalchemy.plugins.init.config.common" + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.config.common.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init.config.common' is deprecated, please " + f"import it from '{module}' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.config.common import GenericAlembicConfig, GenericSessionConfig, GenericSQLAlchemyConfig + from advanced_alchemy.extensions.litestar.plugins.init.config.common import ( + SESSION_SCOPE_KEY, + SESSION_TERMINUS_ASGI_EVENTS, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/compat.py b/litestar/contrib/sqlalchemy/plugins/init/config/compat.py index d76dea700d..73969f8944 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/compat.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/compat.py @@ -16,7 +16,7 @@ class HasGetEngine(Protocol[EngineT_co]): def get_engine(self) -> EngineT_co: ... -class _CreateEngineMixin(Generic[EngineT_co]): +class _CreateEngineMixin(Generic[EngineT_co]): # pyright: ignore[reportUnusedClass] @deprecated(version="2.1.1", removal_in="3.0.0", alternative="get_engine()") def create_engine(self: HasGetEngine[EngineT_co]) -> EngineT_co: return self.get_engine() diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/engine.py b/litestar/contrib/sqlalchemy/plugins/init/config/engine.py index 31c3f5e2a3..f733057863 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/engine.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/engine.py @@ -1,5 +1,32 @@ +# ruff: noqa: TCH004, F401 from __future__ import annotations -from advanced_alchemy.config.engine import EngineConfig +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("EngineConfig",) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.extensions.litestar import EngineConfig + + module = "litestar.plugins.sqlalchemy" + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.config.engine.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init.config.engine' is deprecated, please " + f"import it from '{module}' instead", + ) + value = globals()[attr_name] = EngineConfig + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.extensions.litestar import EngineConfig diff --git a/litestar/contrib/sqlalchemy/plugins/init/config/sync.py b/litestar/contrib/sqlalchemy/plugins/init/config/sync.py index 48a029b3db..0454bf8259 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/config/sync.py +++ b/litestar/contrib/sqlalchemy/plugins/init/config/sync.py @@ -1,16 +1,10 @@ +# ruff: noqa: TCH004, F401 + from __future__ import annotations -from advanced_alchemy.config.sync import AlembicSyncConfig, SyncSessionConfig -from advanced_alchemy.extensions.litestar.plugins.init.config.sync import ( - SQLAlchemySyncConfig as _SQLAlchemySyncConfig, -) -from advanced_alchemy.extensions.litestar.plugins.init.config.sync import ( - autocommit_before_send_handler, - default_before_send_handler, -) -from sqlalchemy import Engine +from typing import TYPE_CHECKING -from litestar.contrib.sqlalchemy.plugins.init.config.compat import _CreateEngineMixin +from litestar.utils import warn_deprecation __all__ = ( "SQLAlchemySyncConfig", @@ -21,4 +15,59 @@ ) -class SQLAlchemySyncConfig(_SQLAlchemySyncConfig, _CreateEngineMixin[Engine]): ... +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + if attr_name == "SQLAlchemySyncConfig": + from advanced_alchemy.extensions.litestar.plugins.init.config.sync import ( + SQLAlchemySyncConfig as _SQLAlchemySyncConfig, + ) + from sqlalchemy import Engine + + from litestar.contrib.sqlalchemy.plugins.init.config.compat import ( + _CreateEngineMixin, # pyright: ignore[reportPrivateUsage] + ) + + class SQLAlchemySyncConfig(_SQLAlchemySyncConfig, _CreateEngineMixin[Engine]): ... + + module = "litestar.plugins.sqlalchemy" + value = globals()[attr_name] = SQLAlchemySyncConfig + elif attr_name in {"default_before_send_handler", "autocommit_before_send_handler"}: + module = "litestar.plugins.sqlalchemy.plugins.init.config.sync" + from advanced_alchemy.extensions.litestar.plugins.init.config.sync import ( + autocommit_before_send_handler, # pyright: ignore[reportUnusedImport] + default_before_send_handler, # pyright: ignore[reportUnusedImport] + ) + + value = globals()[attr_name] = locals()[attr_name] + else: + module = "litestar.plugins.sqlalchemy" + from advanced_alchemy.extensions.litestar import ( + AlembicSyncConfig, # pyright: ignore[reportUnusedImport] + SyncSessionConfig, # pyright: ignore[reportUnusedImport] + ) + + value = globals()[attr_name] = locals()[attr_name] + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.config.sync.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' 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.extensions.litestar import ( + AlembicSyncConfig, + SQLAlchemySyncConfig, + SyncSessionConfig, + ) + from advanced_alchemy.extensions.litestar.plugins.init.config.sync import ( + autocommit_before_send_handler, + default_before_send_handler, + ) diff --git a/litestar/contrib/sqlalchemy/plugins/init/plugin.py b/litestar/contrib/sqlalchemy/plugins/init/plugin.py index dbf814bfef..d2b7b4cfa2 100644 --- a/litestar/contrib/sqlalchemy/plugins/init/plugin.py +++ b/litestar/contrib/sqlalchemy/plugins/init/plugin.py @@ -1,5 +1,31 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from advanced_alchemy.extensions.litestar.plugins import SQLAlchemyInitPlugin +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("SQLAlchemyInitPlugin",) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.init.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy' instead", + ) + from advanced_alchemy.extensions.litestar import SQLAlchemyInitPlugin + + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.extensions.litestar import SQLAlchemyInitPlugin diff --git a/litestar/contrib/sqlalchemy/plugins/serialization.py b/litestar/contrib/sqlalchemy/plugins/serialization.py index 539b194cc4..57fb368670 100644 --- a/litestar/contrib/sqlalchemy/plugins/serialization.py +++ b/litestar/contrib/sqlalchemy/plugins/serialization.py @@ -1,5 +1,30 @@ +# ruff: noqa: TCH004 from __future__ import annotations -from advanced_alchemy.extensions.litestar.plugins import SQLAlchemySerializationPlugin +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("SQLAlchemySerializationPlugin",) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.plugins.serialization.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.plugins.serialization' is deprecated, please " + f"import it from 'litstar.plugins.sqlalchemy' instead", + ) + from advanced_alchemy.extensions.litestar import SQLAlchemySerializationPlugin + + value = globals()[attr_name] = SQLAlchemySerializationPlugin + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.extensions.litestar import SQLAlchemySerializationPlugin diff --git a/litestar/contrib/sqlalchemy/repository/__init__.py b/litestar/contrib/sqlalchemy/repository/__init__.py index 64a8359169..ccf4716e73 100644 --- a/litestar/contrib/sqlalchemy/repository/__init__.py +++ b/litestar/contrib/sqlalchemy/repository/__init__.py @@ -1,7 +1,10 @@ -from ._async import SQLAlchemyAsyncRepository -from ._sync import SQLAlchemySyncRepository -from ._util import wrap_sqlalchemy_exception -from .types import ModelT +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false +from __future__ import annotations + +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "SQLAlchemyAsyncRepository", @@ -9,3 +12,44 @@ "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.repository import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImport] + ModelT, + SQLAlchemyAsyncRepository, + SQLAlchemySyncRepository, + ) + + elif attr_name == "wrap_sqlalchemy_exception": + module = "litestar.plugins.sqlalchemy.exceptions" + from advanced_alchemy.exceptions import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImport] + wrap_sqlalchemy_exception, # type: ignore[import-not-found] # pyright: ignore[reportMissingImport] + ) + + value = globals()[attr_name] = locals()[attr_name] + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.repository.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.repository' 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[reportMissingImport] + wrap_sqlalchemy_exception, + ) + from advanced_alchemy.repository import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImport] + ModelT, + SQLAlchemyAsyncRepository, + SQLAlchemySyncRepository, + ) diff --git a/litestar/contrib/sqlalchemy/repository/_async.py b/litestar/contrib/sqlalchemy/repository/_async.py index 417ec35e05..2145db2c26 100644 --- a/litestar/contrib/sqlalchemy/repository/_async.py +++ b/litestar/contrib/sqlalchemy/repository/_async.py @@ -1,5 +1,34 @@ +# ruff: noqa: TCH004, F401 from __future__ import annotations -from advanced_alchemy.repository import SQLAlchemyAsyncRepository +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("SQLAlchemyAsyncRepository",) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.repository import ( + SQLAlchemyAsyncRepository, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports,reportUnusedImport] + ) + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.repository.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.repository._async' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy.repository' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.repository import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + SQLAlchemyAsyncRepository, + ) diff --git a/litestar/contrib/sqlalchemy/repository/_sync.py b/litestar/contrib/sqlalchemy/repository/_sync.py index 58ccbb8109..a546ff0b12 100644 --- a/litestar/contrib/sqlalchemy/repository/_sync.py +++ b/litestar/contrib/sqlalchemy/repository/_sync.py @@ -1,7 +1,36 @@ +# ruff: noqa: TCH004, F401 # Do not edit this file directly. It has been autogenerated from # litestar/contrib/sqlalchemy/repository/_async.py from __future__ import annotations -from advanced_alchemy.repository import SQLAlchemySyncRepository +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ("SQLAlchemySyncRepository",) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.repository import ( + SQLAlchemySyncRepository, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports,reportUnusedImport] + ) + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.repository.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.repository._sync' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy.repository' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.repository import ( + SQLAlchemySyncRepository, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ) diff --git a/litestar/contrib/sqlalchemy/repository/_util.py b/litestar/contrib/sqlalchemy/repository/_util.py index c0ce7476f4..2f8c438006 100644 --- a/litestar/contrib/sqlalchemy/repository/_util.py +++ b/litestar/contrib/sqlalchemy/repository/_util.py @@ -1,8 +1,43 @@ +# ruff: noqa: TCH004, F401 from __future__ import annotations -from advanced_alchemy.repository._util import get_instrumented_attr, wrap_sqlalchemy_exception +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "wrap_sqlalchemy_exception", "get_instrumented_attr", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.exceptions import ( + wrap_sqlalchemy_exception, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ) + from advanced_alchemy.repository import ( + get_instrumented_attr, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ) + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.repository._util.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.repository._util' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy.repository' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + 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 ( + wrap_sqlalchemy_exception, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ) + from advanced_alchemy.repository import ( + get_instrumented_attr, # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ) diff --git a/litestar/contrib/sqlalchemy/repository/types.py b/litestar/contrib/sqlalchemy/repository/types.py index 2a4204cb62..f92a23cfa2 100644 --- a/litestar/contrib/sqlalchemy/repository/types.py +++ b/litestar/contrib/sqlalchemy/repository/types.py @@ -1,10 +1,10 @@ -from advanced_alchemy.repository.typing import ( - ModelT, - RowT, - SelectT, - SQLAlchemyAsyncRepositoryT, - SQLAlchemySyncRepositoryT, -) +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false +from __future__ import annotations + +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "ModelT", @@ -13,3 +13,37 @@ "SQLAlchemySyncRepositoryT", "SQLAlchemyAsyncRepositoryT", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.repository.typing import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ModelT, + RowT, + SelectT, + SQLAlchemyAsyncRepositoryT, + SQLAlchemySyncRepositoryT, + ) + + warn_deprecation( + deprecated_name=f"litestar.contrib.sqlalchemy.repository.types.{attr_name}", + version="2.12", + kind="import", + removal_in="3.0", + info=f"importing {attr_name} from 'litestar.contrib.sqlalchemy.repository.types' is deprecated, please " + f"import it from 'litestar.plugins.sqlalchemy.repository.typing' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.repository.typing import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] + ModelT, + RowT, + SelectT, + SQLAlchemyAsyncRepositoryT, + SQLAlchemySyncRepositoryT, + ) diff --git a/litestar/contrib/sqlalchemy/types.py b/litestar/contrib/sqlalchemy/types.py index 61fb75a0c8..82646fa240 100644 --- a/litestar/contrib/sqlalchemy/types.py +++ b/litestar/contrib/sqlalchemy/types.py @@ -1,6 +1,10 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from advanced_alchemy.types import GUID, ORA_JSONB, BigIntIdentity, DateTimeUTC, JsonB +from typing import TYPE_CHECKING + +from litestar.utils import warn_deprecation __all__ = ( "GUID", @@ -9,3 +13,37 @@ "BigIntIdentity", "JsonB", ) + + +def __getattr__(attr_name: str) -> object: + if attr_name in __all__: + from advanced_alchemy.types import ( + GUID, + ORA_JSONB, + BigIntIdentity, + DateTimeUTC, + JsonB, + ) + + 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 'advanced_alchemy.extensions.litestar.types' instead", + ) + value = globals()[attr_name] = locals()[attr_name] + return value + + raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") # pragma: no cover + + +if TYPE_CHECKING: + from advanced_alchemy.types import ( + GUID, + ORA_JSONB, + BigIntIdentity, + DateTimeUTC, + JsonB, + ) diff --git a/litestar/plugins/sqlalchemy.py b/litestar/plugins/sqlalchemy.py index 35d8c3e7e6..f00f430df6 100644 --- a/litestar/plugins/sqlalchemy.py +++ b/litestar/plugins/sqlalchemy.py @@ -1,37 +1,8 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations -from advanced_alchemy.extensions.litestar import ( - AlembicAsyncConfig, - AlembicCommands, - AlembicSyncConfig, - AsyncSessionConfig, - EngineConfig, - SQLAlchemyAsyncConfig, - SQLAlchemyDTO, - SQLAlchemyDTOConfig, - SQLAlchemyInitPlugin, - SQLAlchemyPlugin, - SQLAlchemySerializationPlugin, - SQLAlchemySyncConfig, - SyncSessionConfig, - async_autocommit_before_send_handler, - async_autocommit_handler_maker, - async_default_before_send_handler, - async_default_handler_maker, - base, - exceptions, - filters, - mixins, - operations, - repository, - service, - sync_autocommit_before_send_handler, - sync_autocommit_handler_maker, - sync_default_before_send_handler, - sync_default_handler_maker, - types, - utils, -) +from typing import TYPE_CHECKING from litestar.utils import warn_deprecation @@ -66,11 +37,21 @@ "SQLAlchemySerializationPlugin", "SQLAlchemySyncConfig", "EngineConfig", + # deprecated + "AuditColumns", + "BigIntAuditBase", + "BigIntBase", + "BigIntPrimaryKey", + "CommonTableAttributes", + "UUIDAuditBase", + "UUIDBase", + "UUIDPrimaryKey", + "orm_registry", ) def __getattr__(attr_name: str) -> object: - if attr_name in { + _deprecated_attrs = { "AuditColumns", "BigIntAuditBase", "BigIntBase", @@ -80,7 +61,21 @@ def __getattr__(attr_name: str) -> object: "UUIDBase", "UUIDPrimaryKey", "orm_registry", - }: + } + + if attr_name in _deprecated_attrs: + from advanced_alchemy.base import ( + AuditColumns, + BigIntAuditBase, + BigIntBase, + BigIntPrimaryKey, + CommonTableAttributes, + UUIDAuditBase, + UUIDBase, + UUIDPrimaryKey, + orm_registry, + ) + warn_deprecation( deprecated_name=f"litestar.plugins.sqlalchemy.{attr_name}", version="2.9.0", @@ -89,8 +84,92 @@ def __getattr__(attr_name: str) -> object: info=f"importing {attr_name} from 'litestar.plugins.sqlalchemy' is deprecated, please" f"import it from 'litestar.plugins.sqlalchemy.base.{attr_name}' instead", ) - value = globals()[attr_name] = getattr(base, attr_name) + value = globals()[attr_name] = locals()[attr_name] + return value + if attr_name in set(__all__).difference(_deprecated_attrs): + from advanced_alchemy import ( + base, + exceptions, + filters, + mixins, + operations, + repository, + service, + types, + utils, + ) + from advanced_alchemy.extensions.litestar import ( + AlembicAsyncConfig, + AlembicCommands, + AlembicSyncConfig, + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyDTO, + SQLAlchemyDTOConfig, + SQLAlchemyInitPlugin, + SQLAlchemyPlugin, + SQLAlchemySerializationPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + async_autocommit_before_send_handler, + async_autocommit_handler_maker, + async_default_before_send_handler, + async_default_handler_maker, + sync_autocommit_before_send_handler, + sync_autocommit_handler_maker, + sync_default_before_send_handler, + sync_default_handler_maker, + ) + + value = globals()[attr_name] = locals()[attr_name] return value - if attr_name in __all__: - return getattr(attr_name, attr_name) raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}") + + +if TYPE_CHECKING: + from advanced_alchemy import ( + base, + exceptions, + filters, + mixins, + operations, + repository, + service, + types, + utils, + ) + from advanced_alchemy.base import ( + AuditColumns, + BigIntAuditBase, + BigIntBase, + BigIntPrimaryKey, + CommonTableAttributes, + UUIDAuditBase, + UUIDBase, + UUIDPrimaryKey, + orm_registry, + ) + from advanced_alchemy.extensions.litestar import ( + AlembicAsyncConfig, + AlembicCommands, + AlembicSyncConfig, + AsyncSessionConfig, + EngineConfig, + SQLAlchemyAsyncConfig, + SQLAlchemyDTO, + SQLAlchemyDTOConfig, + SQLAlchemyInitPlugin, + SQLAlchemyPlugin, + SQLAlchemySerializationPlugin, + SQLAlchemySyncConfig, + SyncSessionConfig, + async_autocommit_before_send_handler, + async_autocommit_handler_maker, + async_default_before_send_handler, + async_default_handler_maker, + sync_autocommit_before_send_handler, + sync_autocommit_handler_maker, + sync_default_before_send_handler, + sync_default_handler_maker, + ) diff --git a/pyproject.toml b/pyproject.toml index fdf58954a4..e718c7a629 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -284,6 +284,13 @@ module = [ "exceptiongroup", ] +[[tool.mypy.overrides]] +warn_unused_ignores = false +module = [ + "litestar.contrib.sqlalchemy.*", + "tests.unit.test_contrib.test_sqlalchemy", +] + [tool.pydantic-mypy] init_forbid_extra = true init_typed = true @@ -377,6 +384,7 @@ lint.ignore = [ "PLW2901", # pylint - for loop variable overwritten by assignment target "RUF012", # Ruff-specific rule - annotated with classvar "ISC001", # Ruff formatter incompatible + "CPY001", # ruff - copyright notice at the top of the file ] src = ["litestar", "tests", "docs/examples"] target-version = "py38" diff --git a/tests/unit/test_contrib/test_sqlalchemy.py b/tests/unit/test_contrib/test_sqlalchemy.py index d5d95307d6..af833809bd 100644 --- a/tests/unit/test_contrib/test_sqlalchemy.py +++ b/tests/unit/test_contrib/test_sqlalchemy.py @@ -1,41 +1,60 @@ +# ruff: noqa: TCH004, F401 +# pyright: reportUnusedImport=false from __future__ import annotations +import importlib +import sys +from pathlib import Path + import pytest +from advanced_alchemy import exceptions as advanced_alchemy_exceptions from advanced_alchemy import repository as advanced_alchemy_repo from advanced_alchemy import types as advanced_alchemy_types from advanced_alchemy.repository import typing as advanced_alchemy_typing from sqlalchemy import Engine, create_engine from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine -from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import SQLAlchemyAsyncConfig -from litestar.contrib.sqlalchemy.plugins.init.config.sync import SQLAlchemySyncConfig + +def purge_module(module_names: list[str], path: str | Path) -> None: + for name in module_names: + if name in sys.modules: + del sys.modules[name] + Path(importlib.util.cache_from_source(path)).unlink(missing_ok=True) # type: ignore[arg-type] def test_create_engine_with_engine_instance() -> None: + from litestar.contrib.sqlalchemy.plugins.init.config.sync import SQLAlchemySyncConfig + engine = create_engine("sqlite:///:memory:") config = SQLAlchemySyncConfig(engine_instance=engine) with pytest.deprecated_call(): - assert engine is config.create_engine() + assert engine is config.create_engine() # type: ignore[attr-defined] def test_create_engine_with_connection_string() -> None: + from litestar.contrib.sqlalchemy.plugins.init.config.sync import SQLAlchemySyncConfig + config = SQLAlchemySyncConfig(connection_string="sqlite:///:memory:") with pytest.deprecated_call(): - engine = config.create_engine() + engine = config.create_engine() # type: ignore[attr-defined] assert isinstance(engine, Engine) def test_async_create_engine_with_engine_instance() -> None: + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import SQLAlchemyAsyncConfig + engine = create_async_engine("sqlite+aiosqlite:///:memory:") config = SQLAlchemyAsyncConfig(engine_instance=engine) with pytest.deprecated_call(): - assert engine is config.create_engine() + assert engine is config.create_engine() # type: ignore[attr-defined] def test_async_create_engine_with_connection_string() -> None: + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import SQLAlchemyAsyncConfig + config = SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///:memory:") with pytest.deprecated_call(): - engine = config.create_engine() + engine = config.create_engine() # type: ignore[attr-defined] assert isinstance(engine, AsyncEngine) @@ -48,17 +67,309 @@ def test_repository_re_exports() -> None: ) from litestar.contrib.sqlalchemy.repository import types as repository_types + assert wrap_sqlalchemy_exception is advanced_alchemy_exceptions.wrap_sqlalchemy_exception assert SQLAlchemySyncRepository is advanced_alchemy_repo.SQLAlchemySyncRepository assert SQLAlchemyAsyncRepository is advanced_alchemy_repo.SQLAlchemyAsyncRepository - assert wrap_sqlalchemy_exception is advanced_alchemy_repo._util.wrap_sqlalchemy_exception - - assert repository_types.ModelT is advanced_alchemy_typing.ModelT - assert repository_types.RowT is advanced_alchemy_typing.RowT - assert repository_types.SQLAlchemyAsyncRepositoryT is advanced_alchemy_typing.SQLAlchemyAsyncRepositoryT - assert repository_types.SQLAlchemySyncRepositoryT is advanced_alchemy_typing.SQLAlchemySyncRepositoryT + assert repository_types.ModelT is advanced_alchemy_typing.ModelT # pyright: ignore[reportGeneralTypeIssues] + assert repository_types.RowT is advanced_alchemy_typing.RowT # pyright: ignore[reportGeneralTypeIssues] + assert repository_types.SQLAlchemyAsyncRepositoryT is advanced_alchemy_typing.SQLAlchemyAsyncRepositoryT # pyright: ignore[reportGeneralTypeIssues] + assert repository_types.SQLAlchemySyncRepositoryT is advanced_alchemy_typing.SQLAlchemySyncRepositoryT # pyright: ignore[reportGeneralTypeIssues] assert types.GUID is advanced_alchemy_types.GUID assert types.ORA_JSONB is advanced_alchemy_types.ORA_JSONB assert types.BigIntIdentity is advanced_alchemy_types.BigIntIdentity assert types.DateTimeUTC is advanced_alchemy_types.DateTimeUTC assert types.JsonB is advanced_alchemy_types.JsonB + + +def test_deprecated_sqlalchemy_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy"], __file__) + with pytest.warns( + DeprecationWarning, match="importing SQLAlchemyAsyncRepository from 'litestar.contrib.sqlalchemy' is deprecated" + ): + from litestar.contrib.sqlalchemy import SQLAlchemyAsyncRepository + purge_module(["litestar.contrib.sqlalchemy"], __file__) + with pytest.warns( + DeprecationWarning, match="importing SQLAlchemySyncRepository from 'litestar.contrib.sqlalchemy' is deprecated" + ): + from litestar.contrib.sqlalchemy import SQLAlchemySyncRepository + purge_module(["litestar.contrib.sqlalchemy"], __file__) + with pytest.warns(DeprecationWarning, match="importing ModelT from 'litestar.contrib.sqlalchemy' is deprecated"): + from litestar.contrib.sqlalchemy import ModelT + purge_module(["litestar.contrib.sqlalchemy"], __file__) + with pytest.warns( + DeprecationWarning, match="importing wrap_sqlalchemy_exception from 'litestar.contrib.sqlalchemy' is deprecated" + ): + from litestar.contrib.sqlalchemy import wrap_sqlalchemy_exception + + +def test_deprecated_sqlalchemy_plugins_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AsyncSessionConfig from 'litestar.contrib.sqlalchemy.plugins' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins import AsyncSessionConfig + purge_module(["litestar.contrib.sqlalchemy.plugins"], __file__) + with pytest.warns( + DeprecationWarning, match="importing EngineConfig from 'litestar.contrib.sqlalchemy.plugins' is deprecated" + ): + from litestar.contrib.sqlalchemy.plugins import EngineConfig + purge_module(["litestar.contrib.sqlalchemy.plugins"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing GenericSQLAlchemyConfig from 'litestar.contrib.sqlalchemy.plugins' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins import GenericSQLAlchemyConfig + purge_module(["litestar.contrib.sqlalchemy.plugins"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyAsyncConfig from 'litestar.contrib.sqlalchemy.plugins' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins import SQLAlchemyAsyncConfig + purge_module(["litestar.contrib.sqlalchemy.plugins"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyInitPlugin from 'litestar.contrib.sqlalchemy.plugins' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins import SQLAlchemyInitPlugin + + +def test_deprecated_sqlalchemy_plugins_init_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AsyncSessionConfig from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init import AsyncSessionConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init"], __file__) + with pytest.warns( + DeprecationWarning, match="importing EngineConfig from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated" + ): + from litestar.contrib.sqlalchemy.plugins.init import EngineConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing GenericSQLAlchemyConfig from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init import GenericSQLAlchemyConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyAsyncConfig from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init import SQLAlchemyAsyncConfig + + +def test_deprecated_sqlalchemy_plugins_init_config_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AsyncSessionConfig from 'litestar.contrib.sqlalchemy.plugins.init.config' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config import AsyncSessionConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing EngineConfig from 'litestar.contrib.sqlalchemy.plugins.init.config' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config import EngineConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing GenericSQLAlchemyConfig from 'litestar.contrib.sqlalchemy.plugins.init.config' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config import GenericSQLAlchemyConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyAsyncConfig from 'litestar.contrib.sqlalchemy.plugins.init.config' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config import SQLAlchemyAsyncConfig + + +def test_deprecated_sqlalchemy_plugins_init_config_common_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.common"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SESSION_SCOPE_KEY from 'litestar.contrib.sqlalchemy.plugins.init.config.common' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.common import SESSION_SCOPE_KEY + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.common"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SESSION_TERMINUS_ASGI_EVENTS from 'litestar.contrib.sqlalchemy.plugins.init.config.common' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.common import SESSION_TERMINUS_ASGI_EVENTS + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.common"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing GenericSQLAlchemyConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.common' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.common import GenericSQLAlchemyConfig + + +def test_deprecated_sqlalchemy_plugins_init_config_sync_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemySyncConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.sync import SQLAlchemySyncConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AlembicSyncConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.sync import AlembicSyncConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SyncSessionConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.sync import SyncSessionConfig + + +def test_deprecated_sqlalchemy_plugins_init_config_asyncio_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.asyncio"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyAsyncConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import SQLAlchemyAsyncConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.asyncio"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AlembicAsyncConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import AlembicAsyncConfig + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.asyncio"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing AsyncSessionConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import AsyncSessionConfig + + +def test_deprecated_sqlalchemy_plugins_init_config_engine_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.engine"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing EngineConfig from 'litestar.contrib.sqlalchemy.plugins.init.config.engine' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.engine import EngineConfig + + +def test_deprecated_sqlalchemy_dto_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.dto"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyDTOConfig from 'litestar.contrib.sqlalchemy.dto' is deprecated", + ): + from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTOConfig + + +def test_deprecated_sqlalchemy_plugins_init_plugin_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.plugin"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyInitPlugin from 'litestar.contrib.sqlalchemy.plugins.init' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.plugin import SQLAlchemyInitPlugin + + +def test_deprecated_sqlalchemy_plugins_serialization_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.serialization"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemySerializationPlugin from 'litestar.contrib.sqlalchemy.plugins.serialization' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.serialization import SQLAlchemySerializationPlugin + + +def test_deprecated_sqlalchemy_repository_async_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.repository._async"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemyAsyncRepository from 'litestar.contrib.sqlalchemy.repository._async' is deprecated", + ): + from litestar.contrib.sqlalchemy.repository._async import SQLAlchemyAsyncRepository + + +def test_deprecated_sqlalchemy_repository_sync_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.repository._sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing SQLAlchemySyncRepository from 'litestar.contrib.sqlalchemy.repository._sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.repository._sync import SQLAlchemySyncRepository + + +def test_deprecated_sqlalchemy_base_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.base"], __file__) + with pytest.warns( + DeprecationWarning, + match="from 'litestar.contrib.sqlalchemy.base' is deprecated", + ): + from litestar.contrib.sqlalchemy.base import ( + AuditColumns, + BigIntAuditBase, + BigIntBase, + BigIntPrimaryKey, + CommonTableAttributes, + ModelProtocol, + UUIDAuditBase, + UUIDBase, + UUIDPrimaryKey, + create_registry, + orm_registry, + touch_updated_timestamp, + ) + + +def test_deprecated_sqlalchemy_plugins_init_config_asyncio_handlers() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.asyncio"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing default_before_send_handler from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import default_before_send_handler + + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.asyncio"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing autocommit_before_send_handler from 'litestar.contrib.sqlalchemy.plugins.init.config.asyncio' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.asyncio import autocommit_before_send_handler + + +def test_deprecated_sqlalchemy_plugins_init_config_sync_handlers() -> None: + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing default_before_send_handler from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.sync import default_before_send_handler + + purge_module(["litestar.contrib.sqlalchemy.plugins.init.config.sync"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing autocommit_before_send_handler from 'litestar.contrib.sqlalchemy.plugins.init.config.sync' is deprecated", + ): + from litestar.contrib.sqlalchemy.plugins.init.config.sync import autocommit_before_send_handler + + +def test_deprecated_sqlalchemy_repository_util_imports() -> None: + purge_module(["litestar.contrib.sqlalchemy.repository._util"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing wrap_sqlalchemy_exception from 'litestar.contrib.sqlalchemy.repository._util' is deprecated", + ): + from litestar.contrib.sqlalchemy.repository._util import wrap_sqlalchemy_exception + + purge_module(["litestar.contrib.sqlalchemy.repository._util"], __file__) + with pytest.warns( + DeprecationWarning, + match="importing get_instrumented_attr from 'litestar.contrib.sqlalchemy.repository._util' is deprecated", + ): + from litestar.contrib.sqlalchemy.repository._util import get_instrumented_attr diff --git a/tests/unit/test_dto/test_factory/test_integration.py b/tests/unit/test_dto/test_factory/test_integration.py index f14aada5e6..93063b0d42 100644 --- a/tests/unit/test_dto/test_factory/test_integration.py +++ b/tests/unit/test_dto/test_factory/test_integration.py @@ -967,7 +967,7 @@ def test_openapi_schema_for_type_with_custom_generic_type( from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from litestar import Litestar, get -from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO +from litestar.plugins.sqlalchemy import SQLAlchemyDTO from litestar.dto import DTOConfig T = TypeVar("T")