diff --git a/docs/examples/contrib/sqlalchemy/sqlalchemy_declarative_models.py b/docs/examples/contrib/sqlalchemy/sqlalchemy_declarative_models.py index 2a4f7e302c..251f98b63f 100644 --- a/docs/examples/contrib/sqlalchemy/sqlalchemy_declarative_models.py +++ b/docs/examples/contrib/sqlalchemy/sqlalchemy_declarative_models.py @@ -10,13 +10,13 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship from litestar import Litestar, get -from litestar.contrib.sqlalchemy.base import UUIDAuditBase, UUIDBase -from litestar.contrib.sqlalchemy.plugins import AsyncSessionConfig, SQLAlchemyAsyncConfig, SQLAlchemyPlugin +from litestar.plugins.sqlalchemy import AsyncSessionConfig, SQLAlchemyAsyncConfig, SQLAlchemyPlugin, base # The SQLAlchemy base includes a declarative model for you to use in your models. # The `UUIDBase` class includes a `UUID` based primary key (`id`) -class Author(UUIDBase): +class Author(base.UUIDBase): + __tablename__ = "author" name: Mapped[str] dob: Mapped[date] books: Mapped[List[Book]] = relationship(back_populates="author", lazy="selectin") @@ -25,7 +25,8 @@ class Author(UUIDBase): # The `UUIDAuditBase` class includes the same UUID` based primary key (`id`) and 2 # additional columns: `created_at` and `updated_at`. `created_at` is a timestamp of when the # record created, and `updated_at` is the last time the record was modified. -class Book(UUIDAuditBase): +class Book(base.UUIDAuditBase): + __tablename__ = "book" title: Mapped[str] author_id: Mapped[UUID] = mapped_column(ForeignKey("author.id")) author: Mapped[Author] = relationship(lazy="joined", innerjoin=True, viewonly=True) @@ -37,7 +38,7 @@ class Book(UUIDAuditBase): ) # Create 'async_session' dependency. -async def on_startup() -> None: +async def on_startup(app: Litestar) -> None: """Adds some dummy data if no data is present.""" async with sqlalchemy_config.get_session() as session: statement = select(func.count()).select_from(Author) diff --git a/litestar/contrib/sqlalchemy/base.py b/litestar/contrib/sqlalchemy/base.py index 4cb13e0d7e..1a1e147eb1 100644 --- a/litestar/contrib/sqlalchemy/base.py +++ b/litestar/contrib/sqlalchemy/base.py @@ -43,18 +43,20 @@ def __getattr__(attr_name: str) -> object: 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, ) + from advanced_alchemy.mixins import ( # pyright: ignore[reportMissingImports] + AuditColumns, + BigIntPrimaryKey, + UUIDPrimaryKey, + ) warn_deprecation( deprecated_name=f"litestar.contrib.sqlalchemy.base.{attr_name}", @@ -78,15 +80,17 @@ def __getattr__(attr_name: str) -> object: 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, ) + from advanced_alchemy.mixins import ( # pyright: ignore[reportMissingImports] + AuditColumns, + BigIntPrimaryKey, + UUIDPrimaryKey, + ) diff --git a/tests/examples/test_contrib/test_sqlalchemy/test_sqlalchemy_examples.py b/tests/examples/test_contrib/test_sqlalchemy/test_sqlalchemy_examples.py index 0aa531bd33..55b48776c9 100644 --- a/tests/examples/test_contrib/test_sqlalchemy/test_sqlalchemy_examples.py +++ b/tests/examples/test_contrib/test_sqlalchemy/test_sqlalchemy_examples.py @@ -1,14 +1,32 @@ +from pathlib import Path + import pytest +from pytest import MonkeyPatch +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.pool import NullPool +from litestar.plugins.sqlalchemy import AsyncSessionConfig, SQLAlchemyAsyncConfig from litestar.testing import TestClient pytestmark = pytest.mark.xdist_group("sqlalchemy_examples") -def test_sqlalchemy_declarative_models() -> None: - from docs.examples.contrib.sqlalchemy.sqlalchemy_declarative_models import app +async def test_sqlalchemy_declarative_models(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: + engine = create_async_engine("sqlite+aiosqlite:///test.sqlite", poolclass=NullPool) + + session_config = AsyncSessionConfig(expire_on_commit=False) + sqlalchemy_config = SQLAlchemyAsyncConfig( + session_config=session_config, + create_all=True, + engine_instance=engine, + ) # Create 'async_session' dependency. + from docs.examples.contrib.sqlalchemy import sqlalchemy_declarative_models - with TestClient(app) as client: + monkeypatch.setattr(sqlalchemy_declarative_models, "sqlalchemy_config", sqlalchemy_config) + async with engine.begin() as connection: + await connection.run_sync(sqlalchemy_declarative_models.Author.metadata.create_all) + await connection.commit() + with TestClient(sqlalchemy_declarative_models.app) as client: response = client.get("/authors") assert response.status_code == 200 assert len(response.json()) > 0 diff --git a/tests/unit/test_plugins/test_sqlalchemy.py b/tests/unit/test_plugins/test_sqlalchemy.py index 69512e1a9b..8100f8377d 100644 --- a/tests/unit/test_plugins/test_sqlalchemy.py +++ b/tests/unit/test_plugins/test_sqlalchemy.py @@ -1,3 +1,4 @@ +import pytest from advanced_alchemy.extensions import litestar as sa_litestar from advanced_alchemy.extensions.litestar import base as sa_base from advanced_alchemy.extensions.litestar import exceptions as sa_exceptions @@ -38,12 +39,13 @@ def test_re_exports() -> None: assert sqlalchemy.SyncSessionConfig is sa_litestar.SyncSessionConfig # deprecated, to be removed later - assert sqlalchemy.AuditColumns is sa_base.AuditColumns - assert sqlalchemy.BigIntAuditBase is sa_base.BigIntAuditBase - assert sqlalchemy.BigIntBase is sa_base.BigIntBase - assert sqlalchemy.BigIntPrimaryKey is sa_base.BigIntPrimaryKey - assert sqlalchemy.CommonTableAttributes is sa_base.CommonTableAttributes - assert sqlalchemy.UUIDAuditBase is sa_base.UUIDAuditBase - assert sqlalchemy.UUIDBase is sa_base.UUIDBase - assert sqlalchemy.UUIDPrimaryKey is sa_base.UUIDPrimaryKey - assert sqlalchemy.orm_registry is sa_base.orm_registry + with pytest.warns(DeprecationWarning): + assert sqlalchemy.AuditColumns is sa_base.AuditColumns + assert sqlalchemy.BigIntAuditBase is sa_base.BigIntAuditBase + assert sqlalchemy.BigIntBase is sa_base.BigIntBase + assert sqlalchemy.BigIntPrimaryKey is sa_base.BigIntPrimaryKey + assert sqlalchemy.CommonTableAttributes is sa_base.CommonTableAttributes + assert sqlalchemy.UUIDAuditBase is sa_base.UUIDAuditBase + assert sqlalchemy.UUIDBase is sa_base.UUIDBase + assert sqlalchemy.UUIDPrimaryKey is sa_base.UUIDPrimaryKey + assert sqlalchemy.orm_registry is sa_base.orm_registry diff --git a/uv.lock b/uv.lock index 20157cb2e5..9dcc5cc9c1 100644 --- a/uv.lock +++ b/uv.lock @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "advanced-alchemy" -version = "0.25.0" +version = "0.26.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alembic" }, @@ -30,9 +30,9 @@ dependencies = [ { name = "sqlalchemy" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cc/61/5a9049b3300306b21344203243cd8103e8cc9d96747c76d7b9480f994965/advanced_alchemy-0.25.0.tar.gz", hash = "sha256:42cd1249e4f06568690af4183519d50a058cffb53104dda50b9e7ad1fc8b5844", size = 934683 } +sdist = { url = "https://files.pythonhosted.org/packages/3e/94/8783c58213448ae3fe44615e3efd2eb5bfc3d90a8fe47d29f9e6164681f2/advanced_alchemy-0.26.2.tar.gz", hash = "sha256:b56a9c42b7c1b1ab322cccb39b5fd0601232850b10191337f0504debc71735d2", size = 983000 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/2b/0d4705ed21912c508b5be22533003f3cc0b640e267210ce3d4612de58594/advanced_alchemy-0.25.0-py3-none-any.whl", hash = "sha256:c2783278fbe5a75c3eeba2ae041e9985e17ecaafb5d388ec9dd6d5765218428b", size = 142942 }, + { url = "https://files.pythonhosted.org/packages/9e/ef/35219f6be810e636fbe26e05af6c767d02de825075b7e633f49cf886b355/advanced_alchemy-0.26.2-py3-none-any.whl", hash = "sha256:1f9b1207e757076e13a41782e76ac32f50ab5851a88d40f27321005cd46b6b94", size = 147848 }, ] [[package]] @@ -851,7 +851,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, { url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 }, { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, - { url = "https://files.pythonhosted.org/packages/4e/d5/9cc182bf24c86f542129565976c21301d4ac397e74bf5a16e48241aab8a6/cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385", size = 4164756 }, { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, @@ -862,7 +861,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, { url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 }, { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, - { url = "https://files.pythonhosted.org/packages/31/d9/90409720277f88eb3ab72f9a32bfa54acdd97e94225df699e7713e850bd4/cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba", size = 4165207 }, { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 },