diff --git a/requirements.txt b/requirements.txt index e818cd6..1efa301 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,3 @@ -# This file is only used for Sphinx. -# End users should use pyproject.toml instead - itsdangerous==2.2.0 libsass==0.23.0 peewee==3.18.1 @@ -8,7 +5,5 @@ pydantic==2.12.0 quart_schema==0.22.0 setuptools==80.9.0 starlette==0.48.0 -SQLAlchemy==2.0.40 toml==0.10.2 -sphinx_rtd_theme==3.0.2 - +sphinx_rtd_theme diff --git a/src/suou/dei.py b/src/suou/dei.py index d114289..0f7a7a0 100644 --- a/src/suou/dei.py +++ b/src/suou/dei.py @@ -19,10 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. from __future__ import annotations from functools import wraps -from typing import Callable, TypeVar - -_T = TypeVar('_T') -_U = TypeVar('_U') +from typing import Callable BRICKS = '@abcdefghijklmnopqrstuvwxyz+?-\'/' @@ -125,7 +122,7 @@ def dei_args(**renames): Dear conservatives, this does not influence the ability to call the wrapped function with the original parameter names. """ - def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]: + def decorator(func: Callable): @wraps(func) def wrapper(*args, **kwargs): for alias_name, actual_name in renames.items(): diff --git a/src/suou/functools.py b/src/suou/functools.py index f07ea81..b841a00 100644 --- a/src/suou/functools.py +++ b/src/suou/functools.py @@ -19,7 +19,7 @@ import math from threading import RLock import time from types import CoroutineType, NoneType -from typing import Any, Callable, Iterable, Mapping, Never, TypeVar +from typing import Callable, Iterable, Mapping, TypeVar import warnings from functools import update_wrapper, wraps, lru_cache @@ -70,7 +70,7 @@ def not_implemented(msg: Callable | str | None = None): """ A more elegant way to say a method is not implemented, but may get in the future. """ - def decorator(func: Callable[_T, Any]) -> Callable[_T, Never]: + def decorator(func: Callable) -> Callable: da_msg = msg if isinstance(msg, str) else 'method {name}() is not implemented'.format(name=func.__name__) @wraps(func) def wrapper(*a, **k): @@ -288,7 +288,7 @@ def timed_cache(ttl: int, maxsize: int = 128, typed: bool = False, *, async_: bo NEW 0.5.0 """ - def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]: + def decorator(func): start_time = None if async_: @@ -318,7 +318,7 @@ def timed_cache(ttl: int, maxsize: int = 128, typed: bool = False, *, async_: bo return wrapper return decorator -def none_pass(func: Callable[_T, _U], *args, **kwargs) -> Callable[_T, _U]: +def none_pass(func: Callable, *args, **kwargs) -> Callable: """ Wrap callable so that gets called only on not None values. diff --git a/src/suou/luck.py b/src/suou/luck.py index 1ea9039..669025c 100644 --- a/src/suou/luck.py +++ b/src/suou/luck.py @@ -35,7 +35,7 @@ def lucky(validators: Iterable[Callable[[_U], bool]] = ()): NEW 0.7.0 """ - def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]: + def decorator(func: Callable[..., _U]): @wraps(func) def wrapper(*args, **kwargs) -> _U: try: @@ -102,7 +102,7 @@ def rng_overload(prev_func: RngCallable[..., _U] | int | None, /, *, weight: int if isinstance(prev_func, int) and weight == 1: weight, prev_func = prev_func, None - def decorator(func: Callable[_T, _U]) -> RngCallable[_T, _U]: + def decorator(func: Callable[_T, _U]): nonlocal prev_func if prev_func is None: prev_func = RngCallable(func, weight=weight) diff --git a/src/suou/sqlalchemy/__init__.py b/src/suou/sqlalchemy/__init__.py index 7794f39..63216b6 100644 --- a/src/suou/sqlalchemy/__init__.py +++ b/src/suou/sqlalchemy/__init__.py @@ -1,5 +1,5 @@ """ -Utilities for SQLAlchemy. +Utilities for SQLAlchemy --- @@ -33,16 +33,12 @@ from ..iding import Siq, SiqGen, SiqType, SiqCache from ..classtools import Incomplete, Wanted + _T = TypeVar('_T') -_U = TypeVar('_U') +# SIQs are 14 bytes long. Storage is padded for alignment +# Not to be confused with SiqType. IdType: TypeEngine = LargeBinary(16) -""" -Database type for SIQ. - -SIQs are 14 bytes long. Storage is padded for alignment -Not to be confused with SiqType. -""" def create_session(url: str) -> Session: """ @@ -56,6 +52,7 @@ def create_session(url: str) -> Session: return Session(bind = engine) + def token_signer(id_attr: Column | str, secret_attr: Column | str) -> Incomplete[UserSigner]: """ Generate a user signing function. @@ -83,6 +80,9 @@ def token_signer(id_attr: Column | str, secret_attr: Column | str) -> Incomplete return Incomplete(Wanted(token_signer_factory)) + + + ## (in)Utilities for use in web apps below @deprecated('not part of the public API and not even working') @@ -93,8 +93,6 @@ class AuthSrc(metaclass=ABCMeta): This is an abstract class and is NOT usable directly. This is not part of the public API - - DEPRECATED ''' def required_exc(self) -> Never: raise ValueError('required field missing') @@ -142,7 +140,7 @@ def require_auth_base(cls: type[DeclarativeBase], *, src: AuthSrc, column: str | invalid_exc = src.invalid_exc or _default_invalid required_exc = src.required_exc or (lambda: _default_invalid('Login required')) - def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]: + def decorator(func: Callable): @wraps(func) def wrapper(*a, **ka): ka[dest] = get_user(src.get_token()) diff --git a/src/suou/sqlalchemy/asyncio.py b/src/suou/sqlalchemy/asyncio.py index 331407b..02a8949 100644 --- a/src/suou/sqlalchemy/asyncio.py +++ b/src/suou/sqlalchemy/asyncio.py @@ -21,17 +21,14 @@ from __future__ import annotations from functools import wraps from contextvars import ContextVar, Token -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.classtools import MISSING from suou.exceptions import NotFoundError -_T = TypeVar('_T') -_U = TypeVar('_U') - class SQLAlchemy: """ Drop-in (in fact, almost) replacement for flask_sqlalchemy.SQLAlchemy() @@ -189,7 +186,7 @@ def async_query(db: SQLAlchemy, multi: False): The query function remains available as the .q or .query attribute. """ - def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]: + def decorator(func): @wraps(func) async def executor(*args, **kwargs): async with db as session: