Skip to content

Commit

Permalink
Bundle type stubs
Browse files Browse the repository at this point in the history
Add to package per PEP561. The type stubs have various gaps, but
are good enough for mypy and for vscode autocomplete to work
correctly in typical scenarios.
  • Loading branch information
rohanpm committed Jul 13, 2021
1 parent 5b8d2b8 commit 5cb850f
Show file tree
Hide file tree
Showing 56 changed files with 741 additions and 4 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ from version 1.20.0 onwards.

## [Unreleased]

- n/a
### Added
- Type stubs are now included. These have been tested with mypy and pylance.
Type information is not complete, but is sufficient for most typical
scenarios for composing executors and futures. Requires Python 3.9 or later.

## [2.7.0] - 2021-07-11

Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ include README.md
include CHANGELOG.md
include LICENSE
include requirements.in
include more_executors/py.typed
recursive-include more_executors *.pyi
2 changes: 2 additions & 0 deletions more_executors/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import futures as futures
from ._impl.executors import Executors as Executors
Empty file.
9 changes: 9 additions & 0 deletions more_executors/_impl/asyncio.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .metrics import metrics as metrics
from concurrent.futures import Executor
from typing import Any

class AsyncioExecutor(Executor):
def __init__(self, delegate, loop: Any | None = ..., logger: Any | None = ..., name: str = ...) -> None: ...
def submit(self, *args, **kwargs): ...
def submit_with_loop(self, loop, fn, *args, **kwargs): ...
def shutdown(self, wait: bool = ..., **_kwargs) -> None: ...
5 changes: 5 additions & 0 deletions more_executors/_impl/bind.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .wrap import CanCustomize as CanCustomize

class BoundCallable(CanCustomize):
def __init__(self, executor, fn) -> None: ...
def __call__(self, *args, **kwargs): ...
19 changes: 19 additions & 0 deletions more_executors/_impl/cancel_on_shutdown.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import logging
from typing import TypeVar

from .shared_types import ExecutorProtocol, TypedExecutorProtocol

A = TypeVar("A")
B = TypeVar("B")

class CancelOnShutdownExecutor(ExecutorProtocol):
def __init__(
self,
delegate: ExecutorProtocol,
logger: logging.Logger | None = ...,
name: str = ...,
) -> None: ...
def __enter__(self) -> CancelOnShutdownExecutor: ...

class TypedCancelOnShutdownExecutor(TypedExecutorProtocol[A, B]):
def __enter__(self) -> TypedCancelOnShutdownExecutor[A, B]: ...
44 changes: 44 additions & 0 deletions more_executors/_impl/executors.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from .asyncio import AsyncioExecutor as AsyncioExecutor
from .bind import BoundCallable as BoundCallable
from .cancel_on_shutdown import CancelOnShutdownExecutor as CancelOnShutdownExecutor
from .flat_map import FlatMapExecutor as FlatMapExecutor
from .map import MapExecutor as MapExecutor
from .poll import PollExecutor as PollExecutor
from .retry import RetryExecutor as RetryExecutor
from .sync import SyncExecutor as SyncExecutor
from .throttle import ThrottleExecutor as ThrottleExecutor
from .timeout import TimeoutExecutor as TimeoutExecutor
from .wrapped import (
CustomizableProcessPoolExecutor as CustomizableProcessPoolExecutor,
CustomizableThreadPoolExecutor as CustomizableThreadPoolExecutor,
)

from .shared_types import ExecutorProtocol

class Executors:
@classmethod
def bind(cls, executor, fn): ...
@classmethod
def flat_bind(cls, executor, fn): ...
@classmethod
def thread_pool(cls, *args, **kwargs) -> ExecutorProtocol: ...
@classmethod
def process_pool(cls, *args, **kwargs): ...
@classmethod
def sync(cls, *args, **kwargs) -> SyncExecutor: ...
@classmethod
def with_retry(cls, executor, *args, **kwargs): ...
@classmethod
def with_map(cls, executor, *args, **kwargs): ...
@classmethod
def with_flat_map(cls, executor, *args, **kwargs): ...
@classmethod
def with_poll(cls, executor, *args, **kwargs): ...
@classmethod
def with_timeout(cls, executor, *args, **kwargs): ...
@classmethod
def with_throttle(cls, executor, *args, **kwargs): ...
@classmethod
def with_cancel_on_shutdown(cls, executor, *args, **kwargs): ...
@classmethod
def with_asyncio(cls, executor, *args, **kwargs): ...
8 changes: 8 additions & 0 deletions more_executors/_impl/flat_map.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import TypeVar
from .map import MapExecutor

A = TypeVar("A")
B = TypeVar("B")

class FlatMapExecutor(MapExecutor[A, B]):
def __enter__(self) -> FlatMapExecutor[A, B]: ...
9 changes: 9 additions & 0 deletions more_executors/_impl/futures/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .apply import f_apply as f_apply
from .base import f_return as f_return, f_return_cancelled as f_return_cancelled, f_return_error as f_return_error
from .bool import f_and as f_and, f_or as f_or
from .map import f_flat_map as f_flat_map, f_map as f_map
from .nocancel import f_nocancel as f_nocancel
from .proxy import f_proxy as f_proxy
from .sequence import f_sequence as f_sequence, f_traverse as f_traverse
from .timeout import f_timeout as f_timeout
from .zip import f_zip as f_zip
9 changes: 9 additions & 0 deletions more_executors/_impl/futures/apply.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from typing import Any, TypeVar
from collections.abc import Callable
from concurrent.futures import Future

T = TypeVar("T")

def f_apply(
future_fn: Future[Callable[..., T]], *future_args: Future, **future_kwargs: Future
) -> Future[T]: ...
8 changes: 8 additions & 0 deletions more_executors/_impl/futures/base.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import TypeVar, Any
from concurrent.futures import Future

T = TypeVar("T")

def f_return(x: T) -> Future[T]: ...
def f_return_error(x: BaseException, traceback: Any = ...) -> Future[None]: ...
def f_return_cancelled() -> Future[None]: ...
8 changes: 8 additions & 0 deletions more_executors/_impl/futures/bool.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import Any, TypeVar
from concurrent.futures import Future

A = TypeVar("A")
B = TypeVar("B")

def f_or(f: Future[A], *fs: Future[B]) -> Future[A | B]: ...
def f_and(f: Future[A], *fs: Future[B]) -> Future[A | B]: ...
26 changes: 26 additions & 0 deletions more_executors/_impl/futures/map.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from concurrent.futures import Future
from typing import Any, Callable, TypeVar, overload

A = TypeVar("A")
B = TypeVar("B")

@overload
def f_map(
future: Future[A],
) -> Future[A]: ...
@overload
def f_map(
future: Future[A],
fn: Callable[[A], B] | None = ...,
error_fn: Callable[[Exception], B] | None = ...,
) -> Future[B]: ...
@overload
def f_flat_map(
future: Future[A],
) -> Future[A]: ...
@overload
def f_flat_map(
future: Future[A],
fn: Callable[[A], Future[B]] | None = ...,
error_fn: Callable[[Exception], Future[B]] | None = ...,
) -> Future[B]: ...
6 changes: 6 additions & 0 deletions more_executors/_impl/futures/nocancel.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from concurrent.futures import Future
from typing import TypeVar

T = TypeVar("T")

def f_nocancel(future: Future[T]) -> Future[T]: ...
8 changes: 8 additions & 0 deletions more_executors/_impl/futures/proxy.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from concurrent.futures import Future
from typing import TypeVar

T = TypeVar("T")

# TODO: is there any way we can express that the returned value
# will share most of the properties of T?
def f_proxy(f: Future[T], **kwargs) -> Future[T]: ...
10 changes: 10 additions & 0 deletions more_executors/_impl/futures/sequence.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from concurrent.futures import Future
from typing import TypeVar
from collections.abc import Iterable, Callable

T = TypeVar("T")
A = TypeVar("A")
B = TypeVar("B")

def f_sequence(futures: Iterable[Future[T]]) -> Future[list[T]]: ...
def f_traverse(fn: Callable[[A], Future[B]], xs: Iterable[A]) -> Future[list[B]]: ...
6 changes: 6 additions & 0 deletions more_executors/_impl/futures/timeout.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from typing import TypeVar
from concurrent.futures import Future

T = TypeVar("T")

def f_timeout(future: Future[T], timeout: float | int) -> Future[T]: ...
21 changes: 21 additions & 0 deletions more_executors/_impl/futures/zip.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from concurrent.futures import Future
from typing import TypeVar, overload

A = TypeVar("A")
B = TypeVar("B")
C = TypeVar("C")

@overload
def f_zip() -> Future[tuple]: ...
@overload
def f_zip(f1: Future[A]) -> Future[tuple[A]]: ...
@overload
def f_zip(f1: Future[A], f2: Future[B]) -> Future[tuple[A, B]]: ...
@overload
def f_zip(f1: Future[A], f2: Future[B], f3: Future[C]) -> Future[tuple[A, B, C]]: ...

# TODO: is there any way to make this work perfectly for arbitrary number of futures?
@overload
def f_zip(
f1: Future, f2: Future, f3: Future, f4: Future, *fs: Future
) -> Future[tuple]: ...
18 changes: 18 additions & 0 deletions more_executors/_impl/map.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Any, Generic, TypeVar
from collections.abc import Callable

from .shared_types import ExecutorProtocol, TypedExecutorProtocol

A = TypeVar("A")
B = TypeVar("B")

class MapExecutor(TypedExecutorProtocol[A, B]):
def __init__(
self,
delegate: ExecutorProtocol,
fn: Callable[[A], B] = ...,
logger: Any | None = ...,
name: str = ...,
**kwargs
) -> None: ...
def __enter__(self) -> MapExecutor[A, B]: ...
5 changes: 2 additions & 3 deletions more_executors/_impl/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@

LOG = logging.getLogger("more-executors.metrics")

metrics = NullMetrics()
try: # pylint: disable=import-error
from .prometheus import PrometheusMetrics

metrics = PrometheusMetrics()
except Exception:
LOG.debug("disabling prometheus support", exc_info=1)
LOG.debug("disabling prometheus support", exc_info=True)

metrics = NullMetrics()
metrics = NullMetrics() # type: ignore


def record_done(f, started_when, time, inprogress, cancelled, failed):
Expand Down
30 changes: 30 additions & 0 deletions more_executors/_impl/poll.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from concurrent.futures import Executor
from typing import Any, Generic, TypeVar
from collections.abc import Callable
import logging

from .shared_types import ExecutorProtocol, TypedExecutorProtocol

A = TypeVar("A")
B = TypeVar("B")

class PollDescriptor(Generic[A, B]):
@property
def result(self) -> A: ...
def yield_result(self, result: B) -> None: ...
def yield_exception(
self, exception: BaseException, traceback: Any | None = ...
) -> None: ...

class PollExecutor(TypedExecutorProtocol[A, B]):
def __init__(
self,
delegate: ExecutorProtocol,
poll_fn: Callable[[list[PollDescriptor[A, B]]], int | float | None],
cancel_fn: Callable[[A], bool] | None = ...,
default_interval: float = ...,
logger: logging.Logger | None = ...,
name: str = ...,
): ...
def notify(self) -> None: ...
def __enter__(self) -> PollExecutor[A, B]: ...
35 changes: 35 additions & 0 deletions more_executors/_impl/retry.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from concurrent.futures import Future
from typing import Any, TypeVar
import logging
from collections.abc import Callable

from .shared_types import ExecutorProtocol, TypedExecutorProtocol

A = TypeVar("A")
B = TypeVar("B")
T = TypeVar("T")

class RetryPolicy(object): ...

class ExceptionRetryPolicy(RetryPolicy):
def __init__(self, **kwargs): ...

class RetryExecutor(ExecutorProtocol):
def __init__(
self,
delegate,
retry_policy: Any | None = ...,
logger: logging.Logger | None = ...,
name: str = ...,
**kwargs
): ...
def submit_retry(
self, retry_policy: RetryPolicy, fn: Callable[..., T], *args, **kwargs
) -> Future[T]: ...
def __enter__(self) -> RetryExecutor: ...

class TypedRetryExecutor(TypedExecutorProtocol[A, B]):
def submit_retry(
self, retry_policy: RetryPolicy, fn: Callable[..., A], *args, **kwargs
) -> Future[B]: ...
def __enter__(self) -> TypedRetryExecutor[A, B]: ...
Loading

0 comments on commit 5cb850f

Please sign in to comment.