ai_v/venv/Lib/site-packages/sqlalchemy/event/base.py
24024 af7c11d7f9 feat(api): 实现图像生成及后台同步功能
- 新增图像生成接口,支持试用、积分和自定义API Key模式
- 实现生成图片结果异步上传至MinIO存储,带重试机制
- 优化积分预扣除和异常退还逻辑,保障用户积分准确
- 添加获取生成历史记录接口,支持时间范围和分页
- 提供本地字典配置接口,支持模型、比例、提示模板和尺寸
- 实现图片批量上传接口,支持S3兼容对象存储

feat(admin): 增加管理员角色管理与权限分配接口

- 实现角色列表查询、角色创建、更新及删除功能
- 增加权限列表查询接口
- 实现用户角色分配接口,便于统一管理用户权限
- 增加系统字典增删查改接口,支持分类过滤和排序
- 权限控制全面覆盖管理接口,保证安全访问

feat(auth): 完善用户登录注册及权限相关接口与页面

- 实现手机号验证码发送及校验功能,保障注册安全
- 支持手机号注册、登录及退出接口,集成日志记录
- 增加修改密码功能,验证原密码后更新
- 提供动态导航菜单接口,基于权限展示不同菜单
- 实现管理界面路由及日志、角色、字典管理页面访问权限控制
- 添加系统日志查询接口,支持关键词和等级筛选

feat(app): 初始化Flask应用并配置蓝图与数据库

- 创建应用程序工厂,加载配置,初始化数据库和Redis客户端
- 注册认证、API及管理员蓝图,整合路由
- 根路由渲染主页模板
- 应用上下文中自动创建数据库表,保证运行环境准备完毕

feat(database): 提供数据库创建与迁移支持脚本

- 新增数据库创建脚本,支持自动检测是否已存在
- 添加数据库表初始化脚本,支持创建和删除所有表
- 实现RBAC权限初始化,包含基础权限和角色创建
- 新增字段手动修复脚本,添加用户API Key和积分字段
- 强制迁移脚本支持清理连接和修复表结构,初始化默认数据及角色分配

feat(config): 新增系统配置参数

- 配置数据库、Redis、Session和MinIO相关参数
- 添加AI接口地址及试用Key配置
- 集成阿里云短信服务配置及开发模式相关参数

feat(extensions): 初始化数据库、Redis和MinIO客户端

- 创建全局SQLAlchemy数据库实例和Redis客户端
- 配置基于boto3的MinIO兼容S3客户端

chore(logs): 添加示例系统日志文件

- 记录用户请求、验证码发送成功与失败的日志信息
2026-01-12 00:53:31 +08:00

473 lines
15 KiB
Python

# event/base.py
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: https://www.opensource.org/licenses/mit-license.php
"""Base implementation classes.
The public-facing ``Events`` serves as the base class for an event interface;
its public attributes represent different kinds of events. These attributes
are mirrored onto a ``_Dispatch`` class, which serves as a container for
collections of listener functions. These collections are represented both
at the class level of a particular ``_Dispatch`` class as well as within
instances of ``_Dispatch``.
"""
from __future__ import annotations
import typing
from typing import Any
from typing import cast
from typing import Dict
from typing import Generic
from typing import Iterator
from typing import List
from typing import Mapping
from typing import MutableMapping
from typing import Optional
from typing import overload
from typing import Tuple
from typing import Type
from typing import Union
import weakref
from .attr import _ClsLevelDispatch
from .attr import _EmptyListener
from .attr import _InstanceLevelDispatch
from .attr import _JoinedListener
from .registry import _ET
from .registry import _EventKey
from .. import util
from ..util.typing import Literal
_registrars: MutableMapping[str, List[Type[_HasEventsDispatch[Any]]]] = (
util.defaultdict(list)
)
def _is_event_name(name: str) -> bool:
# _sa_event prefix is special to support internal-only event names.
# most event names are just plain method names that aren't
# underscored.
return (
not name.startswith("_") and name != "dispatch"
) or name.startswith("_sa_event")
class _UnpickleDispatch:
"""Serializable callable that re-generates an instance of
:class:`_Dispatch` given a particular :class:`.Events` subclass.
"""
def __call__(self, _instance_cls: Type[_ET]) -> _Dispatch[_ET]:
for cls in _instance_cls.__mro__:
if "dispatch" in cls.__dict__:
return cast(
"_Dispatch[_ET]", cls.__dict__["dispatch"].dispatch
)._for_class(_instance_cls)
else:
raise AttributeError("No class with a 'dispatch' member present.")
class _DispatchCommon(Generic[_ET]):
__slots__ = ()
_instance_cls: Optional[Type[_ET]]
def _join(self, other: _DispatchCommon[_ET]) -> _JoinedDispatcher[_ET]:
raise NotImplementedError()
def __getattr__(self, name: str) -> _InstanceLevelDispatch[_ET]:
raise NotImplementedError()
@property
def _events(self) -> Type[_HasEventsDispatch[_ET]]:
raise NotImplementedError()
class _Dispatch(_DispatchCommon[_ET]):
"""Mirror the event listening definitions of an Events class with
listener collections.
Classes which define a "dispatch" member will return a
non-instantiated :class:`._Dispatch` subclass when the member
is accessed at the class level. When the "dispatch" member is
accessed at the instance level of its owner, an instance
of the :class:`._Dispatch` class is returned.
A :class:`._Dispatch` class is generated for each :class:`.Events`
class defined, by the :meth:`._HasEventsDispatch._create_dispatcher_class`
method. The original :class:`.Events` classes remain untouched.
This decouples the construction of :class:`.Events` subclasses from
the implementation used by the event internals, and allows
inspecting tools like Sphinx to work in an unsurprising
way against the public API.
"""
# "active_history" is an ORM case we add here. ideally a better
# system would be in place for ad-hoc attributes.
__slots__ = "_parent", "_instance_cls", "__dict__", "_empty_listeners"
_active_history: bool
_empty_listener_reg: MutableMapping[
Type[_ET], Dict[str, _EmptyListener[_ET]]
] = weakref.WeakKeyDictionary()
_empty_listeners: Dict[str, _EmptyListener[_ET]]
_event_names: List[str]
_instance_cls: Optional[Type[_ET]]
_joined_dispatch_cls: Type[_JoinedDispatcher[_ET]]
_events: Type[_HasEventsDispatch[_ET]]
"""reference back to the Events class.
Bidirectional against _HasEventsDispatch.dispatch
"""
def __init__(
self,
parent: Optional[_Dispatch[_ET]],
instance_cls: Optional[Type[_ET]] = None,
):
self._parent = parent
self._instance_cls = instance_cls
if instance_cls:
assert parent is not None
try:
self._empty_listeners = self._empty_listener_reg[instance_cls]
except KeyError:
self._empty_listeners = self._empty_listener_reg[
instance_cls
] = {
ls.name: _EmptyListener(ls, instance_cls)
for ls in parent._event_descriptors
}
else:
self._empty_listeners = {}
def __getattr__(self, name: str) -> _InstanceLevelDispatch[_ET]:
# Assign EmptyListeners as attributes on demand
# to reduce startup time for new dispatch objects.
try:
ls = self._empty_listeners[name]
except KeyError:
raise AttributeError(name)
else:
setattr(self, ls.name, ls)
return ls
@property
def _event_descriptors(self) -> Iterator[_ClsLevelDispatch[_ET]]:
for k in self._event_names:
# Yield _ClsLevelDispatch related
# to relevant event name.
yield getattr(self, k)
def _listen(self, event_key: _EventKey[_ET], **kw: Any) -> None:
return self._events._listen(event_key, **kw)
def _for_class(self, instance_cls: Type[_ET]) -> _Dispatch[_ET]:
return self.__class__(self, instance_cls)
def _for_instance(self, instance: _ET) -> _Dispatch[_ET]:
instance_cls = instance.__class__
return self._for_class(instance_cls)
def _join(self, other: _DispatchCommon[_ET]) -> _JoinedDispatcher[_ET]:
"""Create a 'join' of this :class:`._Dispatch` and another.
This new dispatcher will dispatch events to both
:class:`._Dispatch` objects.
"""
assert "_joined_dispatch_cls" in self.__class__.__dict__
return self._joined_dispatch_cls(self, other)
def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
return _UnpickleDispatch(), (self._instance_cls,)
def _update(
self, other: _Dispatch[_ET], only_propagate: bool = True
) -> None:
"""Populate from the listeners in another :class:`_Dispatch`
object."""
for ls in other._event_descriptors:
if isinstance(ls, _EmptyListener):
continue
getattr(self, ls.name).for_modify(self)._update(
ls, only_propagate=only_propagate
)
def _clear(self) -> None:
for ls in self._event_descriptors:
ls.for_modify(self).clear()
def _remove_dispatcher(cls: Type[_HasEventsDispatch[_ET]]) -> None:
for k in cls.dispatch._event_names:
_registrars[k].remove(cls)
if not _registrars[k]:
del _registrars[k]
class _HasEventsDispatch(Generic[_ET]):
_dispatch_target: Optional[Type[_ET]]
"""class which will receive the .dispatch collection"""
dispatch: _Dispatch[_ET]
"""reference back to the _Dispatch class.
Bidirectional against _Dispatch._events
"""
if typing.TYPE_CHECKING:
def __getattr__(self, name: str) -> _InstanceLevelDispatch[_ET]: ...
def __init_subclass__(cls) -> None:
"""Intercept new Event subclasses and create associated _Dispatch
classes."""
cls._create_dispatcher_class(cls.__name__, cls.__bases__, cls.__dict__)
@classmethod
def _accept_with(
cls, target: Union[_ET, Type[_ET]], identifier: str
) -> Optional[Union[_ET, Type[_ET]]]:
raise NotImplementedError()
@classmethod
def _listen(
cls,
event_key: _EventKey[_ET],
*,
propagate: bool = False,
insert: bool = False,
named: bool = False,
asyncio: bool = False,
) -> None:
raise NotImplementedError()
@staticmethod
def _set_dispatch(
klass: Type[_HasEventsDispatch[_ET]],
dispatch_cls: Type[_Dispatch[_ET]],
) -> _Dispatch[_ET]:
# This allows an Events subclass to define additional utility
# methods made available to the target via
# "self.dispatch._events.<utilitymethod>"
# @staticmethod to allow easy "super" calls while in a metaclass
# constructor.
klass.dispatch = dispatch_cls(None)
dispatch_cls._events = klass
return klass.dispatch
@classmethod
def _create_dispatcher_class(
cls, classname: str, bases: Tuple[type, ...], dict_: Mapping[str, Any]
) -> None:
"""Create a :class:`._Dispatch` class corresponding to an
:class:`.Events` class."""
# there's all kinds of ways to do this,
# i.e. make a Dispatch class that shares the '_listen' method
# of the Event class, this is the straight monkeypatch.
if hasattr(cls, "dispatch"):
dispatch_base = cls.dispatch.__class__
else:
dispatch_base = _Dispatch
event_names = [k for k in dict_ if _is_event_name(k)]
dispatch_cls = cast(
"Type[_Dispatch[_ET]]",
type(
"%sDispatch" % classname,
(dispatch_base,),
{"__slots__": event_names},
),
)
dispatch_cls._event_names = event_names
dispatch_inst = cls._set_dispatch(cls, dispatch_cls)
for k in dispatch_cls._event_names:
setattr(dispatch_inst, k, _ClsLevelDispatch(cls, dict_[k]))
_registrars[k].append(cls)
for super_ in dispatch_cls.__bases__:
if issubclass(super_, _Dispatch) and super_ is not _Dispatch:
for ls in super_._events.dispatch._event_descriptors:
setattr(dispatch_inst, ls.name, ls)
dispatch_cls._event_names.append(ls.name)
if getattr(cls, "_dispatch_target", None):
dispatch_target_cls = cls._dispatch_target
assert dispatch_target_cls is not None
if (
hasattr(dispatch_target_cls, "__slots__")
and "_slots_dispatch" in dispatch_target_cls.__slots__
):
dispatch_target_cls.dispatch = slots_dispatcher(cls)
else:
dispatch_target_cls.dispatch = dispatcher(cls)
klass = type(
"Joined%s" % dispatch_cls.__name__,
(_JoinedDispatcher,),
{"__slots__": event_names},
)
dispatch_cls._joined_dispatch_cls = klass
# establish pickle capability by adding it to this module
globals()[klass.__name__] = klass
class _JoinedDispatcher(_DispatchCommon[_ET]):
"""Represent a connection between two _Dispatch objects."""
__slots__ = "local", "parent", "_instance_cls"
local: _DispatchCommon[_ET]
parent: _DispatchCommon[_ET]
_instance_cls: Optional[Type[_ET]]
def __init__(
self, local: _DispatchCommon[_ET], parent: _DispatchCommon[_ET]
):
self.local = local
self.parent = parent
self._instance_cls = self.local._instance_cls
def __reduce__(self) -> Any:
return (self.__class__, (self.local, self.parent))
def __getattr__(self, name: str) -> _JoinedListener[_ET]:
# Assign _JoinedListeners as attributes on demand
# to reduce startup time for new dispatch objects.
ls = getattr(self.local, name)
jl = _JoinedListener(self.parent, ls.name, ls)
setattr(self, ls.name, jl)
return jl
def _listen(self, event_key: _EventKey[_ET], **kw: Any) -> None:
return self.parent._listen(event_key, **kw)
@property
def _events(self) -> Type[_HasEventsDispatch[_ET]]:
return self.parent._events
class Events(_HasEventsDispatch[_ET]):
"""Define event listening functions for a particular target type."""
@classmethod
def _accept_with(
cls, target: Union[_ET, Type[_ET]], identifier: str
) -> Optional[Union[_ET, Type[_ET]]]:
def dispatch_is(*types: Type[Any]) -> bool:
return all(isinstance(target.dispatch, t) for t in types)
def dispatch_parent_is(t: Type[Any]) -> bool:
parent = cast("_JoinedDispatcher[_ET]", target.dispatch).parent
while isinstance(parent, _JoinedDispatcher):
parent = cast("_JoinedDispatcher[_ET]", parent).parent
return isinstance(parent, t)
# Mapper, ClassManager, Session override this to
# also accept classes, scoped_sessions, sessionmakers, etc.
if hasattr(target, "dispatch"):
if (
dispatch_is(cls.dispatch.__class__)
or dispatch_is(type, cls.dispatch.__class__)
or (
dispatch_is(_JoinedDispatcher)
and dispatch_parent_is(cls.dispatch.__class__)
)
):
return target
return None
@classmethod
def _listen(
cls,
event_key: _EventKey[_ET],
*,
propagate: bool = False,
insert: bool = False,
named: bool = False,
asyncio: bool = False,
) -> None:
event_key.base_listen(
propagate=propagate, insert=insert, named=named, asyncio=asyncio
)
@classmethod
def _remove(cls, event_key: _EventKey[_ET]) -> None:
event_key.remove()
@classmethod
def _clear(cls) -> None:
cls.dispatch._clear()
class dispatcher(Generic[_ET]):
"""Descriptor used by target classes to
deliver the _Dispatch class at the class level
and produce new _Dispatch instances for target
instances.
"""
def __init__(self, events: Type[_HasEventsDispatch[_ET]]):
self.dispatch = events.dispatch
self.events = events
@overload
def __get__(
self, obj: Literal[None], cls: Type[Any]
) -> Type[_Dispatch[_ET]]: ...
@overload
def __get__(self, obj: Any, cls: Type[Any]) -> _DispatchCommon[_ET]: ...
def __get__(self, obj: Any, cls: Type[Any]) -> Any:
if obj is None:
return self.dispatch
disp = self.dispatch._for_instance(obj)
try:
obj.__dict__["dispatch"] = disp
except AttributeError as ae:
raise TypeError(
"target %r doesn't have __dict__, should it be "
"defining _slots_dispatch?" % (obj,)
) from ae
return disp
class slots_dispatcher(dispatcher[_ET]):
def __get__(self, obj: Any, cls: Type[Any]) -> Any:
if obj is None:
return self.dispatch
if hasattr(obj, "_slots_dispatch"):
return obj._slots_dispatch
disp = self.dispatch._for_instance(obj)
obj._slots_dispatch = disp
return disp