From 5bdf13b104758fbac3a1be71745d33c036e06f8c Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Fri, 8 Aug 2025 07:58:17 +0200 Subject: [PATCH] add SQLAlchemy.create_all() --- CHANGELOG.md | 3 ++- src/suou/sass.py | 2 +- src/suou/sqlalchemy_async.py | 23 ++++++++++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdeaef..7815fb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## 0.5.0 + `sqlalchemy`: add `unbound_fk()`, `bound_fk()` -+ Add `sqlalchemy_async` module with `SQLAlchemy()` ++ Add `sqlalchemy_async` module with `SQLAlchemy()` async database binding. + * Supports being used as an async context manager + Add `timed_cache()`, `TimedDict()`, `none_pass()`, `twocolon_list()`, `quote_css_string()`, `must_be()` + Add module `calendar` with `want_*` date type conversion utilities and `age_and_days()` + Move obsolete stuff to `obsolete` package (includes configparse 0.3 as of now) diff --git a/src/suou/sass.py b/src/suou/sass.py index c986d63..7c2b82d 100644 --- a/src/suou/sass.py +++ b/src/suou/sass.py @@ -62,7 +62,7 @@ class SassAsyncMiddleware(_MiddlewareFactory): ## WSGI path — is it valid for ASGI as well?? asgi_path = f'/{manifest.wsgi_path.strip('/')}/' pkg_dir = self.package_dir[pkgname] - self.paths.append((asgi_path, package_dir, manifest)) + self.paths.append((asgi_path, pkg_dir, manifest)) async def __call__(self, /, scope: ASGIScope, receive: ASGIReceive, send: ASGISend): path: str = scope.get('path') diff --git a/src/suou/sqlalchemy_async.py b/src/suou/sqlalchemy_async.py index 2f9274f..6838329 100644 --- a/src/suou/sqlalchemy_async.py +++ b/src/suou/sqlalchemy_async.py @@ -19,7 +19,7 @@ from __future__ import annotations from sqlalchemy import Engine, Select, func, select from sqlalchemy.orm import DeclarativeBase, lazyload -from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine +from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine from flask_sqlalchemy.pagination import Pagination from suou.exceptions import NotFoundError @@ -32,7 +32,7 @@ class SQLAlchemy: NEW 0.5.0 """ base: DeclarativeBase - engine: Engine + engine: AsyncEngine _sessions: list[AsyncSession] NotFound = NotFoundError @@ -42,9 +42,11 @@ class SQLAlchemy: self._sessions = [] def bind(self, url: str): self.engine = create_async_engine(url) - async def begin(self) -> AsyncSession: + def _ensure_engine(self): if self.engine is None: raise RuntimeError('database is not connected') + async def begin(self) -> AsyncSession: + self._ensure_engine() ## XXX is it accurate? s = AsyncSession(self.engine) self._sessions.append(s) @@ -64,7 +66,7 @@ class SQLAlchemy: max_per_page: int | None = None, error_out: bool = True, count: bool = True) -> AsyncSelectPagination: """ - ... + Return a pagination. Analogous to flask_sqlalchemy.SQLAlchemy.paginate(). """ async with self as session: return AsyncSelectPagination( @@ -74,11 +76,22 @@ class SQLAlchemy: per_page=per_page, max_per_page=max_per_page, error_out=self.NotFound if error_out else None, count=count ) + async def create_all(self, *, checkfirst = True): + """ + Initialize database + """ + self._ensure_engine() + self.base.metadata.create_all( + self.engine, checkfirst=checkfirst + ) + class AsyncSelectPagination(Pagination): """ - flask_sqlalchemy.SelectPagination but asynchronous + flask_sqlalchemy.SelectPagination but asynchronous. + + Pagination is not part of the public API, therefore expect that it may break """ async def _query_items(self) -> list: