Commit 3cd9fbcf authored by Nathan Graule's avatar Nathan Graule 🤾🏻

Set Call as subclass of Generic, allowing for dynamic return values on class methods

parent 0db3ad2a
Pipeline #27380568 passed with stages
in 1 minute and 24 seconds
from threading import Thread
from typing import Callable, Any, TypeVar, Optional, GenericMeta
from typing import Callable, Any, TypeVar, Optional, Generic, List
from typing import Iterable
__all__ = ['Call']
T = TypeVar('T')
TT = TypeVar('TT')
E = TypeVar('E')
E = TypeVar('E', bound=Exception)
Thenable = Callable[[T], TT]
Resolvable = Callable[[T], None]
......@@ -14,19 +14,14 @@ Rejectable = Callable[[E], None]
Callback = Callable[[Callable, Callable], Any]
class CallMeta(GenericMeta):
class Call:
class Call(Generic[T]):
"""Asynchronously run code, letting further code subscribe to resolved values or failed exceptions."""
__metaclass__ = CallMeta
def __init__(self, callback):
# type: (Callback) -> Call
# type: (Callback) -> Call[T]
"""Initialize a new asynchronous Call.
The callback must have signature (resolve, reject), which are two callback functions of their own; the first one
is to be called with the resulting value, while the second one is to be called with an error.
......@@ -35,12 +30,12 @@ class Call:
:param callback: Callback function. Must have (resolve, reject) functions."""
self.status = self.PENDING = None # type: T
self.error = None # type: E
self.error = None # type: Optional[E]
self.t = Thread(target=callback, args=(self._on_resolve, self._on_rejected))
def then(self, callback):
# type: (Thenable) -> Call
# type: (Thenable) -> Call[TT]
"""Chain callback, called with the resolved value of the previous Call.
:param callback: Callback function to be called with the resolved value of the current Call."""
......@@ -95,7 +90,7 @@ class Call:
def resolve(cls, value=None):
# type: (Optional[T]) -> Call
# type: (TT) -> Call[TT]
"""Create a Call that immediately resolves with the value
:param value: Value to be resolved to"""
......@@ -103,7 +98,7 @@ class Call:
def reject(cls, error):
# type: (E) -> Call
# type: (E) -> Call[None]
"""Create a Call that immediately rejects with the error
:param error: Error to be passed. If not an exception, will be turned into one."""
......@@ -113,7 +108,7 @@ class Call:
def all(cls, calls):
# type: (Iterable[Call]) -> Call
# type: (Iterable[Call[TT]]) -> Call[List[TT]]
"""Resolve a list of calls' resolved values, or fail with the first exception
:param calls: List of calls to resolve, in the same order than the Calls list"""
......@@ -131,7 +126,7 @@ class Call:
def from_function(cls, func, *args, **kwargs):
# type: (Callable[[Any], T], *Any, **Any) -> Call
# type: (Callable[[Any], TT], *Any, **Any) -> Call[TT]
"""Create a Call from a synchronous function. The function will then be called asynchronously, its return
value used as the resolved value, and any exception raised as a reject error value.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment