0.12.0a9 new sqlalchemy.quart submodule
This commit is contained in:
parent
09ac75f07e
commit
fb245f7d12
5 changed files with 90 additions and 77 deletions
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
## 0.12.0 "The Color Update"
|
||||
|
||||
* Moved `AsyncSelectPagination` to submodule `sqlalchemy.quart`. If you need to use it, specify `suou[quart_sqlalchemy]` in requirements.
|
||||
* All `AuthSrc()` derivatives, deprecated and never used, have been removed.
|
||||
* New module `mat` adds a shallow reimplementation of `Matrix()` in order to implement matrix multiplication
|
||||
* Removed obsolete `configparse` implementation that has been around since 0.3 and shelved since 0.4.
|
||||
* `color`: added support for conversion from RGB to sRGB, XYZ, OKLab and OKLCH.
|
||||
* `color`: added support for conversion from RGB to linear RGB, XYZ, OKLab and OKLCH.
|
||||
* Added `user-loader` for Quart-Auth and SQLAlchemy
|
||||
|
||||
## 0.11.2
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ Documentation = "https://suou.readthedocs.io"
|
|||
# the below are all dev dependencies (and probably already installed)
|
||||
sqlalchemy = [
|
||||
"SQLAlchemy[asyncio]>=2.0.0",
|
||||
"flask-sqlalchemy" # glue code
|
||||
]
|
||||
flask = [
|
||||
"Flask>=2.0.0",
|
||||
|
|
@ -62,8 +61,13 @@ quart = [
|
|||
"starlette>=0.47.2"
|
||||
]
|
||||
quart_auth = [
|
||||
"Quart-Auth",
|
||||
"suou[sqlalchemy]" # glue code
|
||||
"suou[quart_sqlalchemy]", # glue code
|
||||
"Quart-Auth"
|
||||
]
|
||||
quart_sqlalchemy = [
|
||||
"suou[quart]",
|
||||
"suou[sqlalchemy]",
|
||||
"flask-sqlalchemy"
|
||||
]
|
||||
sass = [
|
||||
## HEADS UP!! libsass carries a C extension + uses setup.py
|
||||
|
|
@ -71,10 +75,8 @@ sass = [
|
|||
]
|
||||
|
||||
full = [
|
||||
"suou[sqlalchemy]",
|
||||
"suou[flask]",
|
||||
"suou[quart]",
|
||||
"suou[quart_auth]",
|
||||
"suou[quart_auth]", # includes quart, sqlalchemy and quart_sqlalchemy
|
||||
"suou[peewee]",
|
||||
"suou[markdown]",
|
||||
"suou[sass]"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ from .http import WantsContentType
|
|||
from .color import OKLabColor, chalk, WebColor, RGBColor, LinearRGBColor, XYZColor, OKLabColor
|
||||
from .mat import Matrix
|
||||
|
||||
__version__ = "0.12.0a8"
|
||||
__version__ = "0.12.0a9"
|
||||
|
||||
__all__ = (
|
||||
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from typing import Callable, TypeVar
|
|||
from sqlalchemy import Select, Table, func, select
|
||||
from sqlalchemy.orm import DeclarativeBase, lazyload
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
|
||||
from flask_sqlalchemy.pagination import Pagination
|
||||
|
||||
|
||||
from suou.exceptions import NotFoundError
|
||||
from suou.glue import glue
|
||||
|
|
@ -123,73 +123,6 @@ class SQLAlchemy:
|
|||
current_session: ContextVar[AsyncSession] = ContextVar('current_session')
|
||||
|
||||
|
||||
|
||||
|
||||
class AsyncSelectPagination(Pagination):
|
||||
"""
|
||||
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:
|
||||
select_q: Select = self._query_args["select"]
|
||||
select = select_q.limit(self.per_page).offset(self._query_offset)
|
||||
session: AsyncSession = self._query_args["session"]
|
||||
out = (await session.execute(select)).scalars()
|
||||
return out
|
||||
|
||||
async def _query_count(self) -> int:
|
||||
select_q: Select = self._query_args["select"]
|
||||
sub = select_q.options(lazyload("*")).order_by(None).subquery()
|
||||
session: AsyncSession = self._query_args["session"]
|
||||
out = (await session.execute(select(func.count()).select_from(sub))).scalar()
|
||||
return out
|
||||
|
||||
def __init__(self,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
max_per_page: int | None = 100,
|
||||
error_out: Exception | None = NotFoundError,
|
||||
count: bool = True,
|
||||
**kwargs):
|
||||
## XXX flask-sqlalchemy says Pagination() is not public API.
|
||||
## Things may break; beware.
|
||||
self._query_args = kwargs
|
||||
page, per_page = self._prepare_page_args(
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
max_per_page=max_per_page,
|
||||
error_out=error_out,
|
||||
)
|
||||
|
||||
self.page: int = page
|
||||
"""The current page."""
|
||||
|
||||
self.per_page: int = per_page
|
||||
"""The maximum number of items on a page."""
|
||||
|
||||
self.max_per_page: int | None = max_per_page
|
||||
"""The maximum allowed value for ``per_page``."""
|
||||
|
||||
self.items = None
|
||||
self.total = None
|
||||
self.error_out = error_out
|
||||
self.has_count = count
|
||||
|
||||
async def __aiter__(self):
|
||||
self.items = await self._query_items()
|
||||
if self.items is None:
|
||||
raise RuntimeError('query returned None')
|
||||
if not self.items and self.page != 1 and self.error_out:
|
||||
raise self.error_out
|
||||
if self.has_count:
|
||||
self.total = await self._query_count()
|
||||
for i in self.items:
|
||||
yield i
|
||||
|
||||
|
||||
|
||||
def async_query(db: SQLAlchemy, multi: False):
|
||||
"""
|
||||
Wraps a query returning function into an executor coroutine.
|
||||
|
|
@ -206,6 +139,7 @@ def async_query(db: SQLAlchemy, multi: False):
|
|||
return executor
|
||||
return decorator
|
||||
|
||||
|
||||
class SessionWrapper:
|
||||
"""
|
||||
Wrap a SQLAlchemy() session (context manager) adding several QoL utilitites.
|
||||
|
|
@ -257,5 +191,7 @@ class SessionWrapper:
|
|||
def __del__(self):
|
||||
self._session.close()
|
||||
|
||||
|
||||
|
||||
# Optional dependency: do not import into __init__.py
|
||||
__all__ = ('SQLAlchemy', 'AsyncSelectPagination', 'async_query', 'SessionWrapper')
|
||||
|
|
|
|||
74
src/suou/sqlalchemy/quart.py
Normal file
74
src/suou/sqlalchemy/quart.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"""
|
||||
SQLAlchemy-Quart bindings
|
||||
"""
|
||||
|
||||
|
||||
from flask_sqlalchemy.pagination import Pagination
|
||||
|
||||
|
||||
class AsyncSelectPagination(Pagination):
|
||||
"""
|
||||
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:
|
||||
select_q: Select = self._query_args["select"]
|
||||
select = select_q.limit(self.per_page).offset(self._query_offset)
|
||||
session: AsyncSession = self._query_args["session"]
|
||||
out = (await session.execute(select)).scalars()
|
||||
return out
|
||||
|
||||
async def _query_count(self) -> int:
|
||||
select_q: Select = self._query_args["select"]
|
||||
sub = select_q.options(lazyload("*")).order_by(None).subquery()
|
||||
session: AsyncSession = self._query_args["session"]
|
||||
out = (await session.execute(select(func.count()).select_from(sub))).scalar()
|
||||
return out
|
||||
|
||||
def __init__(self,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
max_per_page: int | None = 100,
|
||||
error_out: Exception | None = NotFoundError,
|
||||
count: bool = True,
|
||||
**kwargs):
|
||||
## XXX flask-sqlalchemy says Pagination() is not public API.
|
||||
## Things may break; beware.
|
||||
self._query_args = kwargs
|
||||
page, per_page = self._prepare_page_args(
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
max_per_page=max_per_page,
|
||||
error_out=error_out,
|
||||
)
|
||||
|
||||
self.page: int = page
|
||||
"""The current page."""
|
||||
|
||||
self.per_page: int = per_page
|
||||
"""The maximum number of items on a page."""
|
||||
|
||||
self.max_per_page: int | None = max_per_page
|
||||
"""The maximum allowed value for ``per_page``."""
|
||||
|
||||
self.items = None
|
||||
self.total = None
|
||||
self.error_out = error_out
|
||||
self.has_count = count
|
||||
|
||||
async def __aiter__(self):
|
||||
self.items = await self._query_items()
|
||||
if self.items is None:
|
||||
raise RuntimeError('query returned None')
|
||||
if not self.items and self.page != 1 and self.error_out:
|
||||
raise self.error_out
|
||||
if self.has_count:
|
||||
self.total = await self._query_count()
|
||||
for i in self.items:
|
||||
yield i
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue