Source code for looptime._internal.patchers

from __future__ import annotations

import asyncio
from typing import Any, Type, cast

from . import loops

_class_cache: dict[Type[asyncio.BaseEventLoop], Type[loops.LoopTimeEventLoop]] = {}


[docs] def reset_caches() -> None: """ Purge all caches populated by the patching function of ``looptime``. The classes themselves are not destroyed, so if there are event loops that were created before the caches are cleared, they will continue to work. """ _class_cache.clear()
[docs] def make_event_loop_class( cls: Type[asyncio.BaseEventLoop], *, prefix: str = 'Looptime', ) -> Type[loops.LoopTimeEventLoop]: """ Create a new looptime-enabled event loop class from the original class. Technically, it is equivalent to creating a new class that inherits from the original class and :class:`looptime.LoopTimeEventLoop` as a mixin, with no content (methods or fields) of its own: .. code-block:: python # Not the actual code, just the idea of what happens under the hood. class NewEventLoop(loops.LoopTimeEventLoop, cls): pass New classes are cached, so the same original class always produces the same derived class, not a new one on every call. """ if issubclass(cls, loops.LoopTimeEventLoop): return cls elif cls not in _class_cache: new_class = type(f'{prefix}{cls.__name__}', (loops.LoopTimeEventLoop, cls), {}) _class_cache[cls] = new_class return _class_cache[cls]
[docs] def patch_event_loop( loop: asyncio.BaseEventLoop, **kwargs: Any, ) -> loops.LoopTimeEventLoop: """ Patch an existing event loop to be looptime-ready. This operation is idempotent and can be safely called multiple times. Internally, it takes the existing class of the event loop and replaces it with the new class, which is a mix of the original class and :class:`looptime.LoopTimeEventLoop` as a mixin. The new classes are cached. """ result: loops.LoopTimeEventLoop match loop: case loops.LoopTimeEventLoop(): return loop case _: new_class = make_event_loop_class(loop.__class__) loop.__class__ = new_class loop = cast(loops.LoopTimeEventLoop, loop) loop.setup_looptime(**kwargs) return loop
[docs] def new_event_loop(**kwargs: Any) -> loops.LoopTimeEventLoop: """ Create a new event loop as :func:`asyncio.new_event_loop`, but patched. """ return patch_event_loop(cast(asyncio.BaseEventLoop, asyncio.new_event_loop()), **kwargs)