Skip to content

Commit

Permalink
feat(sanic): restructure extension and enabled API docs (#353)
Browse files Browse the repository at this point in the history
The Sanic integration now uses the same patterns from the other extensions.
  • Loading branch information
cofin authored Jan 19, 2025
1 parent d51a0de commit ee4e07d
Show file tree
Hide file tree
Showing 17 changed files with 267 additions and 194 deletions.
88 changes: 46 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,35 +74,31 @@ operations on your SQLAlchemy models.
<!-- markdownlint-restore -->

```python
from advanced_alchemy.base import UUIDBase
from advanced_alchemy.filters import LimitOffset
from advanced_alchemy.repository import SQLAlchemySyncRepository
from advanced_alchemy import base, repository, config
from sqlalchemy import create_engine
from sqlalchemy.orm import Mapped, sessionmaker


class User(UUIDBase):
class User(base.UUIDBase):
# you can optionally override the generated table name by manually setting it.
__tablename__ = "user_account" # type: ignore[assignment]
email: Mapped[str]
name: Mapped[str]


class UserRepository(SQLAlchemySyncRepository[User]):
class UserRepository(repository.SQLAlchemySyncRepository[User]):
"""User repository."""

model_type = User


# use any compatible sqlalchemy engine.
engine = create_engine("duckdb:///:memory:")
session_factory = sessionmaker(engine, expire_on_commit=False)
db = config.SQLAlchemySyncConfig(connection_string="duckdb:///:memory:", session_config=config.SyncSessionConfig(expire_on_commit=False))

# Initializes the database.
with engine.begin() as conn:
with db.get_engine().begin() as conn:
User.metadata.create_all(conn)

with session_factory() as db_session:
with db.get_session() as db_session:
repo = UserRepository(session=db_session)
# 1) Create multiple users with `add_many`
bulk_users = [
Expand Down Expand Up @@ -143,41 +139,33 @@ and it will handle the type conversions for you.
<!-- markdownlint-restore -->

```python
from advanced_alchemy.base import UUIDBase
from advanced_alchemy.filters import LimitOffset
from advanced_alchemy import SQLAlchemySyncRepository, SQLAlchemySyncRepositoryService
from advanced_alchemy import base, repository, filters, service, config
from sqlalchemy import create_engine
from sqlalchemy.orm import Mapped, sessionmaker


class User(UUIDBase):
class User(base.UUIDBase):
# you can optionally override the generated table name by manually setting it.
__tablename__ = "user_account" # type: ignore[assignment]
email: Mapped[str]
name: Mapped[str]


class UserRepository(SQLAlchemySyncRepository[User]):
"""User repository."""

model_type = User


class UserService(SQLAlchemySyncRepositoryService[User]):
class UserService(service.SQLAlchemySyncRepositoryService[User]):
"""User repository."""
class Repo(repository.SQLAlchemySyncRepository[User]):
"""User repository."""

repository_type = UserRepository
model_type = User

repository_type = Repo

# use any compatible sqlalchemy engine.
engine = create_engine("duckdb:///:memory:")
session_factory = sessionmaker(engine, expire_on_commit=False)
db = config.SQLAlchemySyncConfig(connection_string="duckdb:///:memory:", session_config=config.SyncSessionConfig(expire_on_commit=False))

# Initializes the database.
with engine.begin() as conn:
with db.get_engine().begin() as conn:
User.metadata.create_all(conn)

with session_factory() as db_session:
with db.get_session() as db_session:
service = UserService(session=db_session)
# 1) Create multiple users with `add_many`
objs = service.create_many([
Expand Down Expand Up @@ -225,8 +213,7 @@ it can also be installed as a Litestar extra with `pip install litestar[sqlalche
from litestar import Litestar
from litestar.plugins.sqlalchemy import SQLAlchemyPlugin, SQLAlchemyAsyncConfig
# alternately...
# from advanced_alchemy.extensions.litestar.plugins import SQLAlchemyPlugin
# from advanced_alchemy.extensions.litestar.plugins.init.config import SQLAlchemyAsyncConfig
# from advanced_alchemy.extensions.litestar import SQLAlchemyAsyncConfig, SQLAlchemyPlugin

alchemy = SQLAlchemyPlugin(
config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),
Expand All @@ -238,6 +225,27 @@ app = Litestar(plugins=[alchemy])

For a full Litestar example, check [here][litestar-example]

#### Flask

<!-- markdownlint-disable -->
<details>
<summary>Flask Example</summary>
<!-- markdownlint-restore -->

```python
from flask import Flask
from advanced_alchemy.extensions.flask import AdvancedAlchemy, SQLAlchemySyncConfig

app = Flask(__name__)
alchemy = AdvancedAlchemy(
config=SQLAlchemySyncConfig(connection_string="duckdb:///:memory:"), app=app,
)
```

</details>

For a full Flask example, see [here][flask-example]

#### FastAPI

<!-- markdownlint-disable -->
Expand All @@ -246,20 +254,18 @@ For a full Litestar example, check [here][litestar-example]
<!-- markdownlint-restore -->

```python
from advanced_alchemy.extensions.fastapi import AdvancedAlchemy, SQLAlchemyAsyncConfig
from fastapi import FastAPI

from advanced_alchemy.config import SQLAlchemyAsyncConfig
from advanced_alchemy.extensions.starlette import StarletteAdvancedAlchemy

app = FastAPI()
alchemy = StarletteAdvancedAlchemy(
alchemy = AdvancedAlchemy(
config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"), app=app,
)
```

</details>

For a full FastAPI example, see [here][fastapi-example]
For a full FastAPI example with optional CLI integration, see [here][fastapi-example]

#### Starlette

Expand All @@ -269,13 +275,11 @@ For a full FastAPI example, see [here][fastapi-example]
<!-- markdownlint-restore -->

```python
from advanced_alchemy.extensions.starlette import AdvancedAlchemy, SQLAlchemyAsyncConfig
from starlette.applications import Starlette

from advanced_alchemy.config import SQLAlchemyAsyncConfig
from advanced_alchemy.extensions.starlette import StarletteAdvancedAlchemy

app = Starlette()
alchemy = StarletteAdvancedAlchemy(
alchemy = AdvancedAlchemy(
config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"), app=app,
)
```
Expand All @@ -293,11 +297,10 @@ alchemy = StarletteAdvancedAlchemy(
from sanic import Sanic
from sanic_ext import Extend

from advanced_alchemy.config import SQLAlchemyAsyncConfig
from advanced_alchemy.extensions.sanic import SanicAdvancedAlchemy
from advanced_alchemy.extensions.sanic import AdvancedAlchemy, SQLAlchemyAsyncConfig

app = Sanic("AlchemySanicApp")
alchemy = SanicAdvancedAlchemy(
alchemy = AdvancedAlchemy(
sqlalchemy_config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),
)
Extend.register(alchemy)
Expand Down Expand Up @@ -331,5 +334,6 @@ or the [project-specific GitHub discussions page][project-discussions].
[project-docs]: https://docs.advanced-alchemy.litestar.dev
[install-guide]: https://docs.advanced-alchemy.litestar.dev/latest/#installation
[fastapi-example]: https://github.com/litestar-org/advanced-alchemy/blob/main/examples/fastapi.py
[flask-example]: https://github.com/litestar-org/advanced-alchemy/blob/main/examples/flask/flask_services.py
[litestar-example]: https://github.com/litestar-org/advanced-alchemy/blob/main/examples/litestar.py
[standalone-example]: https://github.com/litestar-org/advanced-alchemy/blob/main/examples/standalone.py
52 changes: 2 additions & 50 deletions advanced_alchemy/extensions/flask/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,10 @@
This module provides Flask integration for Advanced Alchemy, including session management,
database migrations, and service utilities.
Example:
Basic usage with synchronous SQLAlchemy:
.. code-block:: python
from flask import Flask
from advanced_alchemy.extensions.flask import (
AdvancedAlchemy,
SQLAlchemySyncConfig,
EngineConfig,
)
app = Flask(__name__)
db_config = SQLAlchemySyncConfig(
engine_config=EngineConfig(url="sqlite:///db.sqlite3"),
create_all=True, # Create tables on startup
)
db = AdvancedAlchemy(config=db_config)
db.init_app(app)
# Get a session in your route
@app.route("/")
def index():
session = db.get_session()
# Use session...
Using async SQLAlchemy:
.. code-block:: python
from advanced_alchemy.extensions.flask import (
AdvancedAlchemy,
SQLAlchemyAsyncConfig,
)
app = Flask(__name__)
db_config = SQLAlchemyAsyncConfig(
engine_config=EngineConfig(
url="postgresql+asyncpg://user:pass@localhost/db"
),
create_all=True,
)
db = AdvancedAlchemy(config=db_config)
db.init_app(app)
"""

from __future__ import annotations

from advanced_alchemy import base, exceptions, filters, mixins, operations, repository, service, types, utils
from advanced_alchemy.alembic.commands import AlembicCommands
from advanced_alchemy.config import AlembicAsyncConfig, AlembicSyncConfig, AsyncSessionConfig, SyncSessionConfig
Expand Down
11 changes: 0 additions & 11 deletions advanced_alchemy/extensions/flask/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,6 @@ def get_database_migration_plugin(app: Flask) -> AdvancedAlchemy:
Raises:
:exc:`advanced_alchemy.exceptions.ImproperConfigurationError`: If the extension is not found.
Example:
```python
from flask import Flask
from advanced_alchemy.extensions.flask import (
get_database_migration_plugin,
)
app = Flask(__name__)
db = get_database_migration_plugin(app)
```
"""
from advanced_alchemy.exceptions import ImproperConfigurationError

Expand Down
26 changes: 2 additions & 24 deletions advanced_alchemy/extensions/flask/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,9 @@


class FlaskServiceMixin:
"""A mixin class that adds Flask-specific functionality to services.
"""Flask service mixin.
This mixin provides methods and utilities for handling Flask-specific operations
when working with service classes.
:param serializer: The serializer instance to use for data transformation
:type serializer: :class:`advanced_alchemy.extensions.flask.config.Serializer`
Example:
-------
.. code-block:: python
from advanced_alchemy.service import (
SQLAlchemyAsyncRepositoryService,
)
from advanced_alchemy.extensions.flask import (
FlaskServiceMixin,
)
class MyService(
FlaskServiceMixin, SQLAlchemyAsyncRepositoryService
):
pass
This mixin provides Flask-specific functionality for services.
"""

def jsonify(
Expand Down
30 changes: 30 additions & 0 deletions advanced_alchemy/extensions/sanic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from advanced_alchemy import base, exceptions, filters, mixins, operations, repository, service, types, utils
from advanced_alchemy.config import (
AlembicAsyncConfig,
AlembicSyncConfig,
AsyncSessionConfig,
SQLAlchemyAsyncConfig,
SQLAlchemySyncConfig,
SyncSessionConfig,
)
from advanced_alchemy.extensions.sanic.extension import AdvancedAlchemy, CommitStrategyExecutor

__all__ = (
"AdvancedAlchemy",
"AlembicAsyncConfig",
"AlembicSyncConfig",
"AsyncSessionConfig",
"CommitStrategyExecutor",
"SQLAlchemyAsyncConfig",
"SQLAlchemySyncConfig",
"SyncSessionConfig",
"base",
"exceptions",
"filters",
"mixins",
"operations",
"repository",
"service",
"types",
"utils",
)
Loading

0 comments on commit ee4e07d

Please sign in to comment.