diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-02-15 23:43:51 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-02-17 14:45:04 -0500 |
| commit | 5157e0aa542f390242dd7a6d27a6ce1663230e46 (patch) | |
| tree | 113f0e5a83e8229c7d0cb9e9c47387e1d703cb29 /lib/sqlalchemy/event | |
| parent | 20213fd1f27fea51015d753bf94c6f40674ae86f (diff) | |
| download | sqlalchemy-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__.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/event/attr.py | 45 | ||||
| -rw-r--r-- | lib/sqlalchemy/event/base.py | 18 | ||||
| -rw-r--r-- | lib/sqlalchemy/event/registry.py | 13 |
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(): |
