添加注册登录功能

This commit is contained in:
2025-08-29 00:34:40 +08:00
parent 09065f2ce7
commit 2fe3474d9e
3060 changed files with 29217 additions and 87137 deletions

View File

@@ -9,7 +9,6 @@
from collections import defaultdict as defaultdict
from functools import partial as partial
from functools import update_wrapper as update_wrapper
from typing import TYPE_CHECKING
from . import preloaded as preloaded
from ._collections import coerce_generator_arg as coerce_generator_arg
@@ -66,6 +65,7 @@ from .compat import py310 as py310
from .compat import py311 as py311
from .compat import py312 as py312
from .compat import py313 as py313
from .compat import py314 as py314
from .compat import py38 as py38
from .compat import py39 as py39
from .compat import pypy as pypy

View File

@@ -454,7 +454,9 @@ def to_column_set(x: Any) -> Set[Any]:
return x
def update_copy(d, _new=None, **kw):
def update_copy(
d: Dict[Any, Any], _new: Optional[Dict[Any, Any]] = None, **kw: Any
) -> Dict[Any, Any]:
"""Copy the given dict and update with the given values."""
d = d.copy()

View File

@@ -104,7 +104,7 @@ class immutabledict(ImmutableDictBase[_KT, _VT]):
new = ImmutableDictBase.__new__(self.__class__)
dict.__init__(new, self)
dict.update(new, __d) # type: ignore
dict.update(new, __d)
return new
def _union_w_kw(
@@ -117,8 +117,8 @@ class immutabledict(ImmutableDictBase[_KT, _VT]):
new = ImmutableDictBase.__new__(self.__class__)
dict.__init__(new, self)
if __d:
dict.update(new, __d) # type: ignore
dict.update(new, kw) # type: ignore
dict.update(new, __d)
dict.update(new, kw)
return new
def merge_with(
@@ -130,7 +130,7 @@ class immutabledict(ImmutableDictBase[_KT, _VT]):
if new is None:
new = ImmutableDictBase.__new__(self.__class__)
dict.__init__(new, self)
dict.update(new, d) # type: ignore
dict.update(new, d)
if new is None:
return self

View File

@@ -32,6 +32,8 @@ from typing import Type
from typing import TypeVar
py314b1 = sys.version_info >= (3, 14, 0, "beta", 1)
py314 = sys.version_info >= (3, 14)
py313 = sys.version_info >= (3, 13)
py312 = sys.version_info >= (3, 12)
py311 = sys.version_info >= (3, 11)

View File

@@ -60,7 +60,85 @@ _HP = TypeVar("_HP", bound="hybridproperty[Any]")
_HM = TypeVar("_HM", bound="hybridmethod[Any]")
if compat.py310:
if compat.py314:
# vendor a minimal form of get_annotations per
# https://github.com/python/cpython/issues/133684#issuecomment-2863841891
from annotationlib import call_annotate_function # type: ignore
from annotationlib import Format
def _get_and_call_annotate(obj, format): # noqa: A002
annotate = getattr(obj, "__annotate__", None)
if annotate is not None:
ann = call_annotate_function(annotate, format, owner=obj)
if not isinstance(ann, dict):
raise ValueError(f"{obj!r}.__annotate__ returned a non-dict")
return ann
return None
# this is ported from py3.13.0a7
_BASE_GET_ANNOTATIONS = type.__dict__["__annotations__"].__get__ # type: ignore # noqa: E501
def _get_dunder_annotations(obj):
if isinstance(obj, type):
try:
ann = _BASE_GET_ANNOTATIONS(obj)
except AttributeError:
# For static types, the descriptor raises AttributeError.
return {}
else:
ann = getattr(obj, "__annotations__", None)
if ann is None:
return {}
if not isinstance(ann, dict):
raise ValueError(
f"{obj!r}.__annotations__ is neither a dict nor None"
)
return dict(ann)
def _vendored_get_annotations(
obj: Any, *, format: Format # noqa: A002
) -> Mapping[str, Any]:
"""A sparse implementation of annotationlib.get_annotations()"""
try:
ann = _get_dunder_annotations(obj)
except Exception:
pass
else:
if ann is not None:
return dict(ann)
# But if __annotations__ threw a NameError, we try calling __annotate__
ann = _get_and_call_annotate(obj, format)
if ann is None:
# If that didn't work either, we have a very weird object:
# evaluating
# __annotations__ threw NameError and there is no __annotate__.
# In that case,
# we fall back to trying __annotations__ again.
ann = _get_dunder_annotations(obj)
if ann is None:
if isinstance(obj, type) or callable(obj):
return {}
raise TypeError(f"{obj!r} does not have annotations")
if not ann:
return {}
return dict(ann)
def get_annotations(obj: Any) -> Mapping[str, Any]:
# FORWARDREF has the effect of giving us ForwardRefs and not
# actually trying to evaluate the annotations. We need this so
# that the annotations act as much like
# "from __future__ import annotations" as possible, which is going
# away in future python as a separate mode
return _vendored_get_annotations(obj, format=Format.FORWARDREF)
elif compat.py310:
def get_annotations(obj: Any) -> Mapping[str, Any]:
return inspect.get_annotations(obj)
@@ -250,10 +328,30 @@ def decorator(target: Callable[..., Any]) -> Callable[[_Fn], _Fn]:
if not inspect.isfunction(fn) and not inspect.ismethod(fn):
raise Exception("not a decoratable function")
spec = compat.inspect_getfullargspec(fn)
env: Dict[str, Any] = {}
# Python 3.14 defer creating __annotations__ until its used.
# We do not want to create __annotations__ now.
annofunc = getattr(fn, "__annotate__", None)
if annofunc is not None:
fn.__annotate__ = None # type: ignore[union-attr]
try:
spec = compat.inspect_getfullargspec(fn)
finally:
fn.__annotate__ = annofunc # type: ignore[union-attr]
else:
spec = compat.inspect_getfullargspec(fn)
spec = _update_argspec_defaults_into_env(spec, env)
# Do not generate code for annotations.
# update_wrapper() copies the annotation from fn to decorated.
# We use dummy defaults for code generation to avoid having
# copy of large globals for compiling.
# We copy __defaults__ and __kwdefaults__ from fn to decorated.
empty_defaults = (None,) * len(spec.defaults or ())
empty_kwdefaults = dict.fromkeys(spec.kwonlydefaults or ())
spec = spec._replace(
annotations={},
defaults=empty_defaults,
kwonlydefaults=empty_kwdefaults,
)
names = (
tuple(cast("Tuple[str, ...]", spec[0]))
@@ -298,43 +396,23 @@ def decorator(target: Callable[..., Any]) -> Callable[[_Fn], _Fn]:
% metadata
)
mod = sys.modules[fn.__module__]
env.update(vars(mod))
env.update({targ_name: target, fn_name: fn, "__name__": fn.__module__})
env: Dict[str, Any] = {
targ_name: target,
fn_name: fn,
"__name__": fn.__module__,
}
decorated = cast(
types.FunctionType,
_exec_code_in_env(code, env, fn.__name__),
)
decorated.__defaults__ = getattr(fn, "__func__", fn).__defaults__
decorated.__wrapped__ = fn # type: ignore[attr-defined]
decorated.__defaults__ = fn.__defaults__
decorated.__kwdefaults__ = fn.__kwdefaults__ # type: ignore
return update_wrapper(decorated, fn) # type: ignore[return-value]
return update_wrapper(decorate, target) # type: ignore[return-value]
def _update_argspec_defaults_into_env(spec, env):
"""given a FullArgSpec, convert defaults to be symbol names in an env."""
if spec.defaults:
new_defaults = []
i = 0
for arg in spec.defaults:
if type(arg).__module__ not in ("builtins", "__builtin__"):
name = "x%d" % i
env[name] = arg
new_defaults.append(name)
i += 1
else:
new_defaults.append(arg)
elem = list(spec)
elem[3] = tuple(new_defaults)
return compat.FullArgSpec(*elem)
else:
return spec
def _exec_code_in_env(
code: Union[str, types.CodeType], env: Dict[str, Any], fn_name: str
) -> Callable[..., Any]:
@@ -385,6 +463,9 @@ class PluginLoader:
self.impls[name] = load
def deregister(self, name: str) -> None:
del self.impls[name]
def _inspect_func_args(fn):
try:

View File

@@ -112,7 +112,7 @@ def find_cycles(
todo.remove(node)
break
else:
node = stack.pop()
stack.pop()
return output

View File

@@ -16,7 +16,6 @@ import sys
import typing
from typing import Any
from typing import Callable
from typing import cast
from typing import Dict
from typing import ForwardRef
from typing import Generic
@@ -33,6 +32,8 @@ from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union
import typing_extensions
from . import compat
if True: # zimports removes the tailing comments
@@ -56,6 +57,7 @@ if True: # zimports removes the tailing comments
from typing_extensions import Self as Self # 3.11
from typing_extensions import TypeAliasType as TypeAliasType # 3.12
from typing_extensions import Never as Never # 3.11
from typing_extensions import LiteralString as LiteralString # 3.11
_T = TypeVar("_T", bound=Any)
_KT = TypeVar("_KT")
@@ -64,14 +66,6 @@ _KT_contra = TypeVar("_KT_contra", contravariant=True)
_VT = TypeVar("_VT")
_VT_co = TypeVar("_VT_co", covariant=True)
if compat.py38:
# typing_extensions.Literal is different from typing.Literal until
# Python 3.10.1
LITERAL_TYPES = frozenset([typing.Literal, Literal])
else:
LITERAL_TYPES = frozenset([Literal])
if compat.py310:
# why they took until py310 to put this in stdlib is beyond me,
# I've been wanting it since py27
@@ -79,7 +73,9 @@ if compat.py310:
else:
NoneType = type(None) # type: ignore
NoneFwd = ForwardRef("None")
def is_fwd_none(typ: Any) -> bool:
return isinstance(typ, ForwardRef) and typ.__forward_arg__ == "None"
_AnnotationScanType = Union[
@@ -330,7 +326,7 @@ def resolve_name_to_real_class_name(name: str, module_name: str) -> str:
def is_pep593(type_: Optional[Any]) -> bool:
return type_ is not None and get_origin(type_) is Annotated
return type_ is not None and get_origin(type_) in _type_tuples.Annotated
def is_non_string_iterable(obj: Any) -> TypeGuard[Iterable[Any]]:
@@ -340,7 +336,7 @@ def is_non_string_iterable(obj: Any) -> TypeGuard[Iterable[Any]]:
def is_literal(type_: Any) -> bool:
return get_origin(type_) in LITERAL_TYPES
return get_origin(type_) in _type_tuples.Literal
def is_newtype(type_: Optional[_AnnotationScanType]) -> TypeGuard[NewType]:
@@ -348,7 +344,7 @@ def is_newtype(type_: Optional[_AnnotationScanType]) -> TypeGuard[NewType]:
# doesn't work in 3.8, 3.7 as it passes a closure, not an
# object instance
# return isinstance(type_, NewType)
# isinstance(type, type_instances.NewType)
def is_generic(type_: _AnnotationScanType) -> TypeGuard[GenericProtocol[Any]]:
@@ -356,7 +352,13 @@ def is_generic(type_: _AnnotationScanType) -> TypeGuard[GenericProtocol[Any]]:
def is_pep695(type_: _AnnotationScanType) -> TypeGuard[TypeAliasType]:
return isinstance(type_, TypeAliasType)
# NOTE: a generic TAT does not instance check as TypeAliasType outside of
# python 3.10. For sqlalchemy use cases it's fine to consider it a TAT
# though.
# NOTE: things seems to work also without this additional check
if is_generic(type_):
return is_pep695(type_.__origin__)
return isinstance(type_, _type_instances.TypeAliasType)
def flatten_newtype(type_: NewType) -> Type[Any]:
@@ -375,15 +377,15 @@ def pep695_values(type_: _AnnotationScanType) -> Set[Any]:
"""
_seen = set()
def recursive_value(type_):
if type_ in _seen:
def recursive_value(inner_type):
if inner_type in _seen:
# recursion are not supported (at least it's flagged as
# an error by pyright). Just avoid infinite loop
return type_
_seen.add(type_)
if not is_pep695(type_):
return type_
value = type_.__value__
return inner_type
_seen.add(inner_type)
if not is_pep695(inner_type):
return inner_type
value = inner_type.__value__
if not is_union(value):
return value
return [recursive_value(t) for t in value.__args__]
@@ -397,7 +399,7 @@ def pep695_values(type_: _AnnotationScanType) -> Set[Any]:
if isinstance(t, list):
stack.extend(t)
else:
types.add(None if t in {NoneType, NoneFwd} else t)
types.add(None if t is NoneType or is_fwd_none(t) else t)
return types
else:
return {res}
@@ -410,7 +412,7 @@ def is_fwd_ref(
) -> TypeGuard[ForwardRef]:
if check_for_plain_string and isinstance(type_, str):
return True
elif isinstance(type_, ForwardRef):
elif isinstance(type_, _type_instances.ForwardRef):
return True
elif check_generic and is_generic(type_):
return any(
@@ -469,8 +471,7 @@ def de_optionalize_union_types(
typ.discard(None) # type: ignore
typ.discard(NoneType)
typ.discard(NoneFwd)
typ = {t for t in typ if t is not NoneType and not is_fwd_none(t)}
return make_union_type(*typ)
@@ -546,7 +547,8 @@ def _de_optionalize_fwd_ref_union_types(
def make_union_type(*types: _AnnotationScanType) -> Type[Any]:
"""Make a Union type."""
return Union.__getitem__(types) # type: ignore
return Union[types] # type: ignore
def includes_none(type_: Any) -> bool:
@@ -571,7 +573,22 @@ def includes_none(type_: Any) -> bool:
return any(includes_none(t) for t in pep695_values(type_))
if is_newtype(type_):
return includes_none(type_.__supertype__)
return type_ in (NoneFwd, NoneType, None)
try:
return type_ in (NoneType, None) or is_fwd_none(type_)
except TypeError:
# if type_ is Column, mapped_column(), etc. the use of "in"
# resolves to ``__eq__()`` which then gives us an expression object
# that can't resolve to boolean. just catch it all via exception
return False
def is_a_type(type_: Any) -> bool:
return (
isinstance(type_, type)
or hasattr(type_, "__origin__")
or type_.__module__ in ("typing", "typing_extensions")
or type(type_).__mro__[0].__module__ in ("typing", "typing_extensions")
)
def is_union(type_: Any) -> TypeGuard[ArgsTypeProtocol]:
@@ -687,3 +704,30 @@ class CallableReference(Generic[_FN]):
def __set__(self, instance: Any, value: _FN) -> None: ...
def __delete__(self, instance: Any) -> None: ...
class _TypingInstances:
def __getattr__(self, key: str) -> tuple[type, ...]:
types = tuple(
{
t
for t in [
getattr(typing, key, None),
getattr(typing_extensions, key, None),
]
if t is not None
}
)
if not types:
raise AttributeError(key)
self.__dict__[key] = types
return types
_type_tuples = _TypingInstances()
if TYPE_CHECKING:
_type_instances = typing_extensions
else:
_type_instances = _type_tuples
LITERAL_TYPES = _type_tuples.Literal