0.7.2 add version= to @future(), support Py3.14, mark .waiter as future
This commit is contained in:
parent
be4404c520
commit
7e80c84de6
6 changed files with 43 additions and 6 deletions
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## 0.7.2
|
||||
|
||||
+ `@future()` now can take a `version=` argument
|
||||
+ `Waiter()` got marked `@future` indefinitely
|
||||
+ Stage `username_column()` for release in 0.8.0
|
||||
+ Explicit support for Python 3.14 (aka python pi)
|
||||
|
||||
## 0.7.1
|
||||
|
||||
+ Add documentation ([Read The Docs](https://suou.readthedocs.io/))
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ classifiers = [
|
|||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13"
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14"
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from .redact import redact_url_password
|
|||
from .http import WantsContentType
|
||||
from .color import chalk
|
||||
|
||||
__version__ = "0.7.1"
|
||||
__version__ = "0.7.2"
|
||||
|
||||
__all__ = (
|
||||
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
||||
|
|
|
|||
|
|
@ -80,17 +80,23 @@ def not_implemented(msg: Callable | str | None = None):
|
|||
return decorator(msg)
|
||||
return decorator
|
||||
|
||||
def future(message: str | None = None):
|
||||
def future(message: str | None = None, *, version: str = None):
|
||||
"""
|
||||
Describes experimental or future API's introduced as bug fixes (including as backports)
|
||||
but not yet intended for general use (mostly to keep semver consistent).
|
||||
|
||||
version= is the intended version release.
|
||||
|
||||
NEW 0.7.0
|
||||
"""
|
||||
def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]:
|
||||
@wraps(func)
|
||||
def wrapper(*a, **k) -> _U:
|
||||
warnings.warn(message or f'{func.__name__}() is intended for a future release and not intended for use right now', FutureWarning)
|
||||
warnings.warn(message or (
|
||||
f'{func.__name__}() is intended for release on {version} and not ready for use right now'
|
||||
if version else
|
||||
f'{func.__name__}() is intended for a future release and not ready for use right now'
|
||||
), FutureWarning)
|
||||
return func(*a, **k)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Utilities for SQLAlchemy; ORM
|
||||
|
||||
NEW 0.6.0
|
||||
NEW 0.6.0 (moved)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -20,12 +20,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
||||
from binascii import Incomplete
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Callable, TypeVar
|
||||
import warnings
|
||||
from sqlalchemy import BigInteger, Boolean, CheckConstraint, Column, Date, ForeignKey, LargeBinary, MetaData, SmallInteger, String, text
|
||||
from sqlalchemy.orm import DeclarativeBase, InstrumentedAttribute, Relationship, declarative_base as _declarative_base, relationship
|
||||
from sqlalchemy.types import TypeEngine
|
||||
from sqlalchemy.ext.hybrid import Comparator
|
||||
from suou.functools import future
|
||||
from suou.classtools import Wanted, Incomplete
|
||||
from suou.codecs import StringCase
|
||||
from suou.dei import dei_args
|
||||
|
|
@ -101,7 +103,7 @@ match_constraint.TEXT_DIALECTS = {
|
|||
'mariadb': ':n RLIKE :re'
|
||||
}
|
||||
|
||||
def match_column(length: int, regex: str, /, case: StringCase = StringCase.AS_IS, *args, constraint_name: str | None = None, **kwargs) -> Incomplete[Column[str]]:
|
||||
def match_column(length: int, regex: str | re.Pattern, /, case: StringCase = StringCase.AS_IS, *args, constraint_name: str | None = None, **kwargs) -> Incomplete[Column[str]]:
|
||||
"""
|
||||
Syntactic sugar to create a String() column with a check constraint matching the given regular expression.
|
||||
|
||||
|
|
@ -112,6 +114,24 @@ def match_column(length: int, regex: str, /, case: StringCase = StringCase.AS_IS
|
|||
return Incomplete(Column, String(length), Wanted(lambda x, n: match_constraint(n, regex, #dialect=x.metadata.engine.dialect.name,
|
||||
constraint_name=constraint_name or f'{x.__tablename__}_{n}_valid')), *args, **kwargs)
|
||||
|
||||
|
||||
@future(version='0.8.0')
|
||||
def username_column(
|
||||
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]]:
|
||||
"""
|
||||
Construct a column containing a unique handle / username.
|
||||
|
||||
Username must match the given `regex` and be at most `length` characters long.
|
||||
|
||||
NEW 0.8.0
|
||||
"""
|
||||
if case is StringCase.AS_IS:
|
||||
warnings.warn('case sensitive usernames may lead to impersonation and unexpected behavior', UserWarning)
|
||||
|
||||
return match_column(length, regex, case=case, nullable=nullable, unique=True, *args, **kwargs)
|
||||
|
||||
|
||||
def bool_column(value: bool = False, nullable: bool = False, **kwargs) -> Column[bool]:
|
||||
"""
|
||||
Column for a single boolean value.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ from starlette.applications import Starlette
|
|||
from starlette.responses import JSONResponse, PlainTextResponse, Response
|
||||
from starlette.routing import Route
|
||||
|
||||
from suou.functools import future
|
||||
|
||||
@future()
|
||||
class Waiter():
|
||||
def __init__(self):
|
||||
self.routes: list[Route] = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue