spyder.api.asyncdispatcher#

Class decorator and helpers for running code in async loops within Spyder.

This module provides a class decorator AsyncDispatcher to run coroutines in dedicated async loops, as well as including utilities for patching loops, managing concurrency tasks, and executing callbacks safely within Qt applications.

Module Attributes

LoopID

Type alias, the union of a loop itself or the ID of one.

Functions

run_coroutine_threadsafe(coro, loop)

Submit a coroutine object to run in the given event loop.

Classes

AsyncDispatcher()

Decorator to run a coroutine in a specific event loop.

DispatcherFuture()

Represents the result of an asynchronous computation.

spyder.api.asyncdispatcher.LoopID#

Type alias, the union of a loop itself or the ID of one.

Either an existing asyncio.AbstractEventLoop or a Hashable to identify an existing or new one.

alias of Hashable | AbstractEventLoop

class spyder.api.asyncdispatcher.AsyncDispatcher(*, loop: LoopID | None = ..., early_return: Literal[True] = ..., return_awaitable: Literal[False] = ...)[source]#
class spyder.api.asyncdispatcher.AsyncDispatcher(*, loop: LoopID | None = ..., early_return: Literal[True] = ..., return_awaitable: Literal[True] = ...)
class spyder.api.asyncdispatcher.AsyncDispatcher(*, loop: LoopID | None = ..., early_return: Literal[False] = ..., return_awaitable: Literal[False] = ...)
class spyder.api.asyncdispatcher.AsyncDispatcher(*, loop: LoopID | None = ..., early_return: Literal[False] = ..., return_awaitable: Literal[True] = ...)

Bases: Generic[_RT]

Decorator to run a coroutine in a specific event loop.

__init__(*, loop: LoopID | None = None, early_return: Literal[True] = True, return_awaitable: Literal[False] = False) None[source]#
__init__(*, loop: LoopID | None = None, early_return: Literal[True] = True, return_awaitable: Literal[True] = False) None
__init__(*, loop: LoopID | None = None, early_return: Literal[False] = True, return_awaitable: Literal[False] = False) None
__init__(*, loop: LoopID | None = None, early_return: Literal[False] = True, return_awaitable: Literal[True] = False) None

Decorate a coroutine to run in a specific event loop.

The loop parameter can be an existing asyncio.AbstractEventLoop or a Hashable to identify an existing or new one created by the AsyncDispatcher. If the loop is not running, it will be started in a new thread and managed by the AsyncDispatcher.

This instance can be called with the same arguments as the coroutine it wraps and will return a concurrent.futures.Future object, or an awaitable asyncio.Future for the current running event loop or the result of the coroutine depending on the early_return and return_awaitable parameters.

Parameters:
  • loop (LoopID | None, optional) – The event loop to be used, by default the current event loop.

  • early_return (bool, optional) – Return the coroutine as a concurrent.futures.Future before it is done. True by default.

  • return_awaitable (bool, optional) – Return the coroutine as an awaitable asyncio.Future instead of a concurrent.futures.Future, independent of the value of early_return. False by default.

Examples

Non-blocking usage (returns a concurrent.futures.Future):

@AsyncDispatcher()
async def my_coroutine(...):
    ...

future = my_coroutine(...)  # Non-blocking call

result = future.result()  # Blocking call

Blocking usage (returns the result):

@AsyncDispatcher(early_return=False)
async def my_coroutine(...):
    ...

result = my_coroutine(...)  # Blocking call

Coroutine usage (returns an awaitable asyncio.Future):

@AsyncDispatcher(return_awaitable=True)
async def my_coroutine(...):
    ...

result = await my_coroutine(...)  # Wait for the result to be ready
__call__(async_func: Callable[[_P], Awaitable[_T]]) Callable[[_P], Awaitable[_T]][source]#
__call__(async_func: Callable[[_P], Awaitable[_T]]) Callable[[_P], DispatcherFuture[_T]]
__call__(async_func: Callable[[_P], Awaitable[_T]]) Callable[[_P], _T]

Run the coroutine in the event loop.

Parameters:
  • *args (tuple) – The positional arguments to be passed to the coroutine.

  • **kwargs (dict) – The keyword arguments to be passed to the coroutine.

Return type:

concurrent.futures.Future or asyncio.Future or _T

Raises:

TypeError – If async_func is not a coroutine function.

classmethod get_event_loop(loop_id: LoopID | None = None) asyncio.AbstractEventLoop[source]#

Get the event loop to run the coroutine.

If the loop is not running, it will be started in a new thread and managed by the AsyncDispatcher.

Parameters:

loop_id (LoopID | None, optional) –

The event loop to use, by default the current thread event loop.

Note

  • If a Hashable is provided, it will be used to identify the loop in the AsyncDispatcher.

  • If an event loop is provided, it will be used as the event loop in the AsyncDispatcher.

Returns:

The event loop to be used.

Return type:

asyncio.AbstractEventLoop

static close() None[source]#

Close the thread pool.

Return type:

None

classmethod cancel_all() None[source]#

Cancel all running tasks.

Return type:

None

classmethod join(timeout: float | None = None) None[source]#

Close all running loops and join the threads.

Parameters:

timeout (float | None, optional) – Seconds to wait for loops to exit and their threads to be joined. By default, waits indefinitely.

Return type:

None

static QtSlot(func: Callable[[_P], None]) Callable[[_P], None][source]#

Mark a function to be executed inside the main Qt loop.

Sets the DispatcherFuture.QT_SLOT_ATTRIBUTE attribute on the function to mark it as a slot to be executed in the main Qt loop.

Parameters:

func (Callable) – The function to be marked.

Returns:

The marked function.

Return type:

Callable

class spyder.api.asyncdispatcher.DispatcherFuture[source]#

Bases: Future, Generic[_T]

Represents the result of an asynchronous computation.

This class is a subclass of concurrent.futures.Future that adds a connect() method to allow attaching callbacks to be executed in the main Qt loop.

QT_SLOT_ATTRIBUTE: str = '__dispatch_qt_slot__'#

Attribute set on functions to be used as slots in the event loop.

Normally set by by the AsyncDispatcher.QtSlot() decorator.

result(timeout: float | None = None) _T[source]#

Return the result of the call that the future represents.

Parameters:

timeout (float | None, optional) – The number of seconds to wait for the result. If None, then wait indefinitely.

Returns:

The result of the call that the future represents.

Return type:

DispatchedFuture@_T

Raises:
connect(fn: Callable[[DispatcherFuture[_T]], None]) None[source]#

Attaches a callable that will be called when the future finishes.

The callable will be called by a thread in the same process in which it was added if the it was not marked with DispatcherFuture.QT_SLOT_ATTRIBUTE.

If the future has already been cancelld or completed then the callable will be executed immediately. These callables are called in the order that they were added.

Parameters:

fn (Callable) – A callable that will be executed with this future as its argument once the future completes or is cancelled.

Return type:

None

spyder.api.asyncdispatcher.run_coroutine_threadsafe(coro: Coroutine[_T, None, _RT], loop: asyncio.AbstractEventLoop) DispatcherFuture[_RT][source]#

Submit a coroutine object to run in the given event loop.

Parameters:
  • coro (Coroutine) – The coroutine object to be submitted.

  • loop (asyncio.AbstractEventLoop) – The event loop in which to run the coroutine.

Returns:

A future object representing the result of the coroutine.

Return type:

DispatcherFuture

Raises:

TypeError – If the object is not a coroutine.