0.8.0 improve (experimental) Waiter + add sqlalchemy.username_column()

This commit is contained in:
Yusur 2025-11-05 10:47:08 +01:00
parent 0ca2fde687
commit 4a31fbc14f
7 changed files with 39 additions and 6 deletions

View file

@ -1,5 +1,14 @@
# Changelog # Changelog
## 0.8.0
+ Add `username_column()` to `.sqlalchemy`
+ Improve (experimental) `Waiter`
## 0.7.7
+ Fix imports in `.sqlalchemy`
## 0.7.5 ## 0.7.5
+ Delay release of `FakeModule` to 0.9.0 + Delay release of `FakeModule` to 0.9.0

View file

@ -10,7 +10,7 @@ license = "Apache-2.0"
readme = "README.md" readme = "README.md"
dependencies = [ dependencies = [
"suou==0.7.6", "suou==0.7.7",
"itsdangerous", "itsdangerous",
"toml", "toml",
"pydantic", "pydantic",

View file

@ -25,6 +25,8 @@ Columns
.. autofunction:: bool_column .. autofunction:: bool_column
.. autofunction:: username_column
.. autofunction:: unbound_fk .. autofunction:: unbound_fk
.. autofunction:: bound_fk .. autofunction:: bound_fk

View file

@ -37,7 +37,7 @@ from .redact import redact_url_password
from .http import WantsContentType from .http import WantsContentType
from .color import chalk from .color import chalk
__version__ = "0.7.7" __version__ = "0.8.0"
__all__ = ( __all__ = (
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',

View file

@ -113,7 +113,7 @@ class AuthSrc(metaclass=ABCMeta):
pass pass
@deprecated('not working and too complex to use') @deprecated('not working and too complex to use. Will be removed in 0.9.0')
def require_auth_base(cls: type[DeclarativeBase], *, src: AuthSrc, column: str | Column[_T] = 'id', dest: str = 'user', def require_auth_base(cls: type[DeclarativeBase], *, src: AuthSrc, column: str | Column[_T] = 'id', dest: str = 'user',
required: bool = False, signed: bool = False, sig_dest: str = 'signature', validators: Callable | Iterable[Callable] | None = None): required: bool = False, signed: bool = False, sig_dest: str = 'signature', validators: Callable | Iterable[Callable] | None = None):
''' '''
@ -161,7 +161,7 @@ def require_auth_base(cls: type[DeclarativeBase], *, src: AuthSrc, column: str |
from .asyncio import SQLAlchemy, AsyncSelectPagination, async_query from .asyncio import SQLAlchemy, AsyncSelectPagination, async_query
from .orm import ( from .orm import (
id_column, snowflake_column, match_column, match_constraint, bool_column, declarative_base, parent_children, 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 author_pair, age_pair, bound_fk, unbound_fk, want_column, a_relationship, BitSelector, secret_column, username_column
) )
# Optional dependency: do not import into __init__.py # Optional dependency: do not import into __init__.py
@ -169,7 +169,7 @@ __all__ = (
'IdType', 'id_column', 'snowflake_column', 'entity_base', 'declarative_base', 'token_signer', 'IdType', 'id_column', 'snowflake_column', 'entity_base', 'declarative_base', 'token_signer',
'match_column', 'match_constraint', 'bool_column', 'parent_children', 'match_column', 'match_constraint', 'bool_column', 'parent_children',
'author_pair', 'age_pair', 'bound_fk', 'unbound_fk', 'want_column', 'author_pair', 'age_pair', 'bound_fk', 'unbound_fk', 'want_column',
'a_relationship', 'BitSelector', 'secret_column', 'a_relationship', 'BitSelector', 'secret_column', 'username_column',
# .asyncio # .asyncio
'SQLAlchemy', 'AsyncSelectPagination', 'async_query', 'SessionWrapper' 'SQLAlchemy', 'AsyncSelectPagination', 'async_query', 'SessionWrapper'
) )

View file

@ -115,7 +115,6 @@ def match_column(length: int, regex: str | re.Pattern, /, case: StringCase = Str
constraint_name=constraint_name or f'{x.__tablename__}_{n}_valid')), *args, **kwargs) constraint_name=constraint_name or f'{x.__tablename__}_{n}_valid')), *args, **kwargs)
@future(version='0.8.0')
def username_column( def username_column(
length: int = 32, regex: str | re.Pattern = '[a-z_][a-z0-9_-]+', *args, case: StringCase = StringCase.LOWER, length: int = 32, regex: str | re.Pattern = '[a-z_][a-z0-9_-]+', *args, case: StringCase = StringCase.LOWER,
nullable : bool = False, **kwargs) -> Incomplete[Column[str] | Column[str | None]]: nullable : bool = False, **kwargs) -> Incomplete[Column[str] | Column[str | None]]:

View file

@ -16,11 +16,13 @@ This software is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
""" """
import warnings import warnings
from starlette.applications import Starlette from starlette.applications import Starlette
from starlette.responses import JSONResponse, PlainTextResponse, Response from starlette.responses import JSONResponse, PlainTextResponse, Response
from starlette.routing import Route from starlette.routing import Route
from suou.itertools import makelist
from suou.functools import future from suou.functools import future
@future() @future()
@ -35,6 +37,27 @@ class Waiter():
routes= self.routes routes= self.routes
) )
def get(self, endpoint: str, *a, **k):
return self._route('GET', endpoint, *a, **k)
def post(self, endpoint: str, *a, **k):
return self._route('POST', endpoint, *a, **k)
def delete(self, endpoint: str, *a, **k):
return self._route('DELETE', endpoint, *a, **k)
def put(self, endpoint: str, *a, **k):
return self._route('PUT', endpoint, *a, **k)
def patch(self, endpoint: str, *a, **k):
return self._route('PATCH', endpoint, *a, **k)
def _route(self, methods: list[str], endpoint: str, **kwargs):
def decorator(func):
self.routes.append(Route(endpoint, func, methods=makelist(methods, False), **kwargs))
return func
return decorator
## TODO get, post, etc. ## TODO get, post, etc.
def ok(content = None, **ka): def ok(content = None, **ka):