summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/event
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-02-15 23:43:51 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2022-02-17 14:45:04 -0500
commit5157e0aa542f390242dd7a6d27a6ce1663230e46 (patch)
tree113f0e5a83e8229c7d0cb9e9c47387e1d703cb29 /lib/sqlalchemy/event
parent20213fd1f27fea51015d753bf94c6f40674ae86f (diff)
downloadsqlalchemy-5157e0aa542f390242dd7a6d27a6ce1663230e46.tar.gz
pep-484 for pool
also extends into some areas of utils, events and others as needed. Formalizes a public hierarchy for pool API, with ManagesConnection -> PoolProxiedConnection / ConnectionPoolEntry for connectionfairy / connectionrecord, which are now what's exposed in the event API and other APIs. all public API docs moved to the new objects. Corrects the mypy plugin's check for sqlalchemy-stubs not being insatlled, which has to be imported using the dash in the name to be effective. Change-Id: I16c2cb43b2e840d28e70a015f370a768e70f3581
Diffstat (limited to 'lib/sqlalchemy/event')
-rw-r--r--lib/sqlalchemy/event/__init__.py6
-rw-r--r--lib/sqlalchemy/event/attr.py45
-rw-r--r--lib/sqlalchemy/event/base.py18
-rw-r--r--lib/sqlalchemy/event/registry.py13
4 files changed, 68 insertions, 14 deletions
diff --git a/lib/sqlalchemy/event/__init__.py b/lib/sqlalchemy/event/__init__.py
index 2d10372ab..0dfb39e1a 100644
--- a/lib/sqlalchemy/event/__init__.py
+++ b/lib/sqlalchemy/event/__init__.py
@@ -14,6 +14,10 @@ from .api import listens_for as listens_for
from .api import NO_RETVAL as NO_RETVAL
from .api import remove as remove
from .attr import RefCollection as RefCollection
+from .base import _Dispatch as _Dispatch
from .base import dispatcher as dispatcher
from .base import Events as Events
-from .legacy import _legacy_signature
+from .legacy import _legacy_signature as _legacy_signature
+from .registry import _EventKey as _EventKey
+from .registry import _ListenerFnType as _ListenerFnType
+from .registry import EventTarget as EventTarget
diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py
index d1ae7a845..9692894fe 100644
--- a/lib/sqlalchemy/event/attr.py
+++ b/lib/sqlalchemy/event/attr.py
@@ -68,6 +68,7 @@ _T = TypeVar("_T", bound=Any)
if typing.TYPE_CHECKING:
from .base import _Dispatch
+ from .base import _DispatchCommon
from .base import _HasEventsDispatch
from .base import _JoinedDispatcher
@@ -280,6 +281,38 @@ class _InstanceLevelDispatch(RefCollection[_ET], Collection[_ListenerFnType]):
def __bool__(self) -> bool:
raise NotImplementedError()
+ def exec_once(self, *args: Any, **kw: Any) -> None:
+ raise NotImplementedError()
+
+ def exec_once_unless_exception(self, *args: Any, **kw: Any) -> None:
+ raise NotImplementedError()
+
+ def _exec_w_sync_on_first_run(self, *args: Any, **kw: Any) -> None:
+ raise NotImplementedError()
+
+ def __call__(self, *args: Any, **kw: Any) -> None:
+ raise NotImplementedError()
+
+ def insert(self, event_key: _EventKey[_ET], propagate: bool) -> None:
+ raise NotImplementedError()
+
+ def append(self, event_key: _EventKey[_ET], propagate: bool) -> None:
+ raise NotImplementedError()
+
+ def remove(self, event_key: _EventKey[_ET]) -> None:
+ raise NotImplementedError()
+
+ def for_modify(
+ self, obj: _DispatchCommon[_ET]
+ ) -> _InstanceLevelDispatch[_ET]:
+ """Return an event collection which can be modified.
+
+ For _ClsLevelDispatch at the class level of
+ a dispatcher, this returns self.
+
+ """
+ return self
+
class _EmptyListener(_InstanceLevelDispatch[_ET]):
"""Serves as a proxy interface to the events
@@ -306,7 +339,9 @@ class _EmptyListener(_InstanceLevelDispatch[_ET]):
self.parent_listeners = parent._clslevel[target_cls]
self.name = parent.name
- def for_modify(self, obj: _Dispatch[_ET]) -> _ListenerCollection[_ET]:
+ def for_modify(
+ self, obj: _DispatchCommon[_ET]
+ ) -> _ListenerCollection[_ET]:
"""Return an event collection which can be modified.
For _EmptyListener at the instance level of
@@ -315,6 +350,8 @@ class _EmptyListener(_InstanceLevelDispatch[_ET]):
and returns it.
"""
+ obj = cast("_Dispatch[_ET]", obj)
+
assert obj._instance_cls is not None
result = _ListenerCollection(self.parent, obj._instance_cls)
if getattr(obj, self.name) is self:
@@ -512,7 +549,9 @@ class _ListenerCollection(_CompoundListener[_ET]):
self.listeners = collections.deque()
self.propagate = set()
- def for_modify(self, obj: _Dispatch[_ET]) -> _ListenerCollection[_ET]:
+ def for_modify(
+ self, obj: _DispatchCommon[_ET]
+ ) -> _ListenerCollection[_ET]:
"""Return an event collection which can be modified.
For _ListenerCollection at the instance level of
@@ -599,7 +638,7 @@ class _JoinedListener(_CompoundListener[_ET]):
) -> _ListenerFnType:
return self.local._adjust_fn_spec(fn, named)
- def for_modify(self, obj: _JoinedDispatcher[_ET]) -> _JoinedListener[_ET]:
+ def for_modify(self, obj: _DispatchCommon[_ET]) -> _JoinedListener[_ET]:
self.local = self.parent_listeners = self.local.for_modify(obj)
return self
diff --git a/lib/sqlalchemy/event/base.py b/lib/sqlalchemy/event/base.py
index 0e0647036..ef3ff9dab 100644
--- a/lib/sqlalchemy/event/base.py
+++ b/lib/sqlalchemy/event/base.py
@@ -17,6 +17,7 @@ instances of ``_Dispatch``.
"""
from __future__ import annotations
+import typing
from typing import Any
from typing import cast
from typing import Dict
@@ -71,7 +72,11 @@ class _UnpickleDispatch:
raise AttributeError("No class with a 'dispatch' member present.")
-class _Dispatch(Generic[_ET]):
+class _DispatchCommon(Generic[_ET]):
+ __slots__ = ()
+
+
+class _Dispatch(_DispatchCommon[_ET]):
"""Mirror the event listening definitions of an Events class with
listener collections.
@@ -218,6 +223,11 @@ class _HasEventsDispatch(Generic[_ET]):
"""
+ 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."""
@@ -357,7 +367,7 @@ class Events(_HasEventsDispatch[_ET]):
cls.dispatch._clear()
-class _JoinedDispatcher(Generic[_ET]):
+class _JoinedDispatcher(_DispatchCommon[_ET]):
"""Represent a connection between two _Dispatch objects."""
__slots__ = "local", "parent", "_instance_cls"
@@ -402,11 +412,11 @@ class dispatcher(Generic[_ET]):
@overload
def __get__(
self, obj: Literal[None], cls: Type[Any]
- ) -> Type[_HasEventsDispatch[_ET]]:
+ ) -> Type[_Dispatch[_ET]]:
...
@overload
- def __get__(self, obj: Any, cls: Type[Any]) -> _HasEventsDispatch[_ET]:
+ def __get__(self, obj: Any, cls: Type[Any]) -> _Dispatch[_ET]:
...
def __get__(self, obj: Any, cls: Type[Any]) -> Any:
diff --git a/lib/sqlalchemy/event/registry.py b/lib/sqlalchemy/event/registry.py
index e20d3e0b5..449f39187 100644
--- a/lib/sqlalchemy/event/registry.py
+++ b/lib/sqlalchemy/event/registry.py
@@ -22,7 +22,6 @@ import typing
from typing import Any
from typing import Callable
from typing import cast
-from typing import ClassVar
from typing import Deque
from typing import Dict
from typing import Generic
@@ -35,7 +34,6 @@ import weakref
from .. import exc
from .. import util
-from ..util.typing import Protocol
if typing.TYPE_CHECKING:
from .attr import RefCollection
@@ -46,7 +44,10 @@ _ListenerFnKeyType = Union[int, Tuple[int, int]]
_EventKeyTupleType = Tuple[int, str, _ListenerFnKeyType]
-class _EventTargetType(Protocol):
+_ET = TypeVar("_ET", bound="EventTarget")
+
+
+class EventTarget:
"""represents an event target, that is, something we can listen on
either with that target as a class or as an instance.
@@ -55,10 +56,10 @@ class _EventTargetType(Protocol):
"""
- dispatch: ClassVar[dispatcher[Any]]
+ __slots__ = ()
+ dispatch: dispatcher[Any]
-_ET = TypeVar("_ET", bound=_EventTargetType)
_RefCollectionToListenerType = Dict[
"weakref.ref[RefCollection[Any]]",
@@ -104,7 +105,7 @@ def _collection_gced(ref: weakref.ref[Any]) -> None:
if not _collection_to_key or ref not in _collection_to_key:
return
- ref = cast("weakref.ref[RefCollection[_EventTargetType]]", ref)
+ ref = cast("weakref.ref[RefCollection[EventTarget]]", ref)
listener_to_key = _collection_to_key.pop(ref)
for key in listener_to_key.values():