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
|
# 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
|
## 0.7.1
|
||||||
|
|
||||||
+ Add documentation ([Read The Docs](https://suou.readthedocs.io/))
|
+ Add documentation ([Read The Docs](https://suou.readthedocs.io/))
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13"
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14"
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
||||||
|
|
@ -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.1"
|
__version__ = "0.7.2"
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
||||||
|
|
|
||||||
|
|
@ -80,17 +80,23 @@ def not_implemented(msg: Callable | str | None = None):
|
||||||
return decorator(msg)
|
return decorator(msg)
|
||||||
return decorator
|
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)
|
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).
|
but not yet intended for general use (mostly to keep semver consistent).
|
||||||
|
|
||||||
|
version= is the intended version release.
|
||||||
|
|
||||||
NEW 0.7.0
|
NEW 0.7.0
|
||||||
"""
|
"""
|
||||||
def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]:
|
def decorator(func: Callable[_T, _U]) -> Callable[_T, _U]:
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*a, **k) -> _U:
|
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 func(*a, **k)
|
||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Utilities for SQLAlchemy; ORM
|
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
|
from binascii import Incomplete
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from typing import Any, Callable, TypeVar
|
from typing import Any, Callable, TypeVar
|
||||||
import warnings
|
import warnings
|
||||||
from sqlalchemy import BigInteger, Boolean, CheckConstraint, Column, Date, ForeignKey, LargeBinary, MetaData, SmallInteger, String, text
|
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.orm import DeclarativeBase, InstrumentedAttribute, Relationship, declarative_base as _declarative_base, relationship
|
||||||
from sqlalchemy.types import TypeEngine
|
from sqlalchemy.types import TypeEngine
|
||||||
from sqlalchemy.ext.hybrid import Comparator
|
from sqlalchemy.ext.hybrid import Comparator
|
||||||
|
from suou.functools import future
|
||||||
from suou.classtools import Wanted, Incomplete
|
from suou.classtools import Wanted, Incomplete
|
||||||
from suou.codecs import StringCase
|
from suou.codecs import StringCase
|
||||||
from suou.dei import dei_args
|
from suou.dei import dei_args
|
||||||
|
|
@ -101,7 +103,7 @@ match_constraint.TEXT_DIALECTS = {
|
||||||
'mariadb': ':n RLIKE :re'
|
'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.
|
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,
|
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)
|
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]:
|
def bool_column(value: bool = False, nullable: bool = False, **kwargs) -> Column[bool]:
|
||||||
"""
|
"""
|
||||||
Column for a single boolean value.
|
Column for a single boolean value.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ 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.functools import future
|
||||||
|
|
||||||
|
@future()
|
||||||
class Waiter():
|
class Waiter():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.routes: list[Route] = []
|
self.routes: list[Route] = []
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue