0.6.1 pypi name change

This commit is contained in:
Yusur 2025-09-13 21:04:22 +02:00
parent 886da11ade
commit da0caadf08
6 changed files with 39 additions and 22 deletions

View file

@ -1,8 +1,13 @@
# Changelog
## 0.6.1
- First release on PyPI under the name `suou`.
- Fix `sqlalchemy.asyncio.SQLAlchemy()` to use context vars; `expire_on_commit=` is now configurable at instantiation. Fix some missing re-exports.
## 0.6.0
+ `.sqlalchemy` has been made a subpackage and split; `sqlalchemy_async` has been deprecated. Update your imports.
+ `.sqlalchemy` has been made a subpackage and split; `sqlalchemy_async` (moved to `sqlalchemy.asyncio`) has been deprecated. Update your imports.
+ Add several new utilities to `.sqlalchemy`: `BitSelector`, `secret_column`, `a_relationship`, `SessionWrapper`,
`wrap=` argument to SQLAlchemy. Also removed dead batteries
+ Add `.waiter` module. For now, non-functional ~

View file

@ -0,0 +1 @@

View file

@ -1,5 +1,6 @@
[project]
name = "sakuragasaki46_suou"
name = "suou"
description = "casual utility library for coding QoL"
authors = [
{ name = "Sakuragasaki46" }
]
@ -30,7 +31,7 @@ classifiers = [
]
[project.urls]
Repository = "https://github.com/sakuragasaki46/suou"
Repository = "https://nekode.yusur.moe/yusur/suou"
[project.optional-dependencies]
# the below are all dev dependencies (and probably already installed)
@ -62,13 +63,13 @@ sass = [
]
full = [
"sakuragasaki46-suou[sqlalchemy]",
"sakuragasaki46-suou[flask]",
"sakuragasaki46-suou[quart]",
"sakuragasaki46-suou[peewee]",
"sakuragasaki46-suou[markdown]",
"sakuragasaki46-suou[flask-sqlalchemy]",
"sakuragasaki46-suou[sass]"
"suou[sqlalchemy]",
"suou[flask]",
"suou[quart]",
"suou[peewee]",
"suou[markdown]",
"suou[flask-sqlalchemy]",
"suou[sass]"
]

View file

@ -36,7 +36,7 @@ from .validators import matches
from .redact import redact_url_password
from .http import WantsContentType
__version__ = "0.6.0"
__version__ = "0.6.1"
__all__ = (
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',

View file

@ -158,7 +158,7 @@ def require_auth_base(cls: type[DeclarativeBase], *, src: AuthSrc, column: str |
from .asyncio import SQLAlchemy, AsyncSelectPagination, async_query
from .orm import (
id_column, snowflake_column, match_column, match_constraint, bool_column, declarative_base,
id_column, snowflake_column, match_column, match_constraint, bool_column, declarative_base, parent_children,
author_pair, age_pair, bound_fk, unbound_fk, want_column, a_relationship, BitSelector, secret_column
)

View file

@ -20,12 +20,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from __future__ import annotations
from functools import wraps
from sqlalchemy import Engine, Select, Table, func, select
from contextvars import ContextVar, Token
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.classtools import MISSING
from suou.exceptions import NotFoundError
class SQLAlchemy:
@ -45,36 +46,44 @@ class SQLAlchemy:
NEW 0.5.0
UPDATED 0.6.0: added wrap=True
UPDATED 0.6.1: expire_on_commit is now configurable per-SQLAlchemy();
now sessions are stored as context variables
"""
base: DeclarativeBase
engine: AsyncEngine
_sessions: list[AsyncSession]
_session_tok: list[Token[AsyncSession]]
_wrapsessions: bool
_xocommit: bool
NotFound = NotFoundError
def __init__(self, model_class: DeclarativeBase, *, wrap = False):
def __init__(self, model_class: DeclarativeBase, *, expire_on_commit = False, wrap = False):
self.base = model_class
self.engine = None
self._wrapsessions = wrap
self._sessions = []
self._xocommit = expire_on_commit
def bind(self, url: str):
self.engine = create_async_engine(url)
def _ensure_engine(self):
if self.engine is None:
raise RuntimeError('database is not connected')
async def begin(self, *, expire_on_commit = False, wrap = False, **kw) -> AsyncSession:
async def begin(self, *, expire_on_commit = None, wrap = False, **kw) -> AsyncSession:
self._ensure_engine()
## XXX is it accurate?
s = AsyncSession(self.engine, expire_on_commit=expire_on_commit, **kw)
s = AsyncSession(self.engine,
expire_on_commit=expire_on_commit if expire_on_commit is not None else self._xocommit,
**kw)
if wrap:
s = SessionWrapper(s)
self._sessions.append(s)
current_session.set(s)
return s
async def __aenter__(self) -> AsyncSession:
return await self.begin()
async def __aexit__(self, e1, e2, e3):
## XXX is it accurate?
s = self._sessions.pop()
s = current_session.get()
if not s:
raise RuntimeError('session not closed')
if e1:
await s.rollback()
else:
@ -104,7 +113,8 @@ class SQLAlchemy:
self.engine, checkfirst=checkfirst
)
# XXX NOT public API! DO NOT USE
current_session: ContextVar[AsyncSession] = ContextVar('current_session')
class AsyncSelectPagination(Pagination):
"""