Skip to content

Commit 9bb8393

Browse files
authored
Type fixes (#629)
- Add dependency on typing extensions to we can use param specifiers for wrapper functions - Fix for typing of aliased functions - Fix for typing of synchronized functions - Fix type error in flat-map
1 parent 0e5a07b commit 9bb8393

File tree

9 files changed

+34
-19
lines changed

9 files changed

+34
-19
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ repos:
2626
language: node
2727
pass_filenames: false
2828
types: [python]
29-
additional_dependencies: ["[email protected].227"]
29+
additional_dependencies: ["[email protected].228"]
3030
repo: local
3131
- hooks:
3232
- id: mypy

examples/timeflies/timeflies_tkinter.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ def label2stream(
3838
def char2label(char: str) -> Label:
3939
return Label(frame, text=char)
4040

41-
reactivex.from_(text).pipe(
41+
xs = reactivex.of(text).pipe(
4242
ops.map(char2label),
4343
ops.flat_map_indexed(label2stream),
44-
).subscribe(on_next, on_error=print, scheduler=scheduler)
44+
)
45+
46+
xs.subscribe(on_next, on_error=print, scheduler=scheduler)
4547

4648
frame.pack()
4749
root.mainloop()

poetry.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ packages = [
2929

3030
[tool.poetry.dependencies]
3131
python = ">= 3.7, < 3.11"
32+
typing-extensions = "^4.1.1"
3233

3334
[tool.poetry.dev-dependencies]
3435
pytest-asyncio = "^0.18.1"

reactivex/abc/observer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
OnCompleted = Callable[[], None]
1010

1111

12-
class ObserverBase(Generic[_T], ABC):
12+
class ObserverBase(Generic[_T_in], ABC):
1313
"""Observer abstract base class
1414
1515
An Observer is the entity that receives all emissions of a
@@ -19,7 +19,7 @@ class ObserverBase(Generic[_T], ABC):
1919
__slots__ = ()
2020

2121
@abstractmethod
22-
def on_next(self, value: _T) -> None:
22+
def on_next(self, value: _T_in) -> None:
2323
"""Notifies the observer of a new element in the sequence.
2424
2525
Args:

reactivex/abc/scheduler.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
RelativeTime = Union[timedelta, float]
1111
AbsoluteOrRelativeTime = Union[datetime, timedelta, float]
1212
ScheduledAction = Callable[
13-
["SchedulerBase", Optional[_TState]], Optional[DisposableBase]
13+
["SchedulerBase", Optional[_TState]],
14+
Optional[DisposableBase],
1415
]
1516

1617

reactivex/internal/concurrency.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
from threading import RLock, Thread
2-
from typing import Any, Callable
2+
from typing import Any, Callable, TypeVar
3+
4+
from typing_extensions import ParamSpec
35

46
from reactivex.typing import StartableTarget
57

8+
_T = TypeVar("_T")
9+
_P = ParamSpec("_P")
10+
611

712
def default_thread_factory(target: StartableTarget) -> Thread:
813
return Thread(target=target, daemon=True)
914

1015

11-
def synchronized(lock: RLock) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
16+
def synchronized(lock: RLock) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
1217
"""A decorator for synchronizing access to a given function."""
1318

14-
def wrapper(fn: Callable[..., Any]) -> Callable[..., Any]:
15-
def inner(*args: Any, **kw: Any) -> Any:
19+
def wrapper(fn: Callable[_P, _T]) -> Callable[_P, _T]:
20+
def inner(*args: _P.args, **kw: _P.kwargs) -> Any:
1621
with lock:
1722
return fn(*args, **kw)
1823

reactivex/internal/utils.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from types import FunctionType
33
from typing import TYPE_CHECKING, Any, Callable, Iterable, Optional, TypeVar, cast
44

5+
from typing_extensions import ParamSpec
6+
57
from reactivex import abc
68
from reactivex.disposable import CompositeDisposable
79
from reactivex.disposable.refcountdisposable import RefCountDisposable
@@ -10,6 +12,7 @@
1012
from reactivex import Observable
1113

1214
_T = TypeVar("_T")
15+
_P = ParamSpec("_P")
1316

1417

1518
def add_ref(xs: "Observable[_T]", r: RefCountDisposable) -> "Observable[_T]":
@@ -30,7 +33,7 @@ def infinite() -> Iterable[int]:
3033
n += 1
3134

3235

33-
def alias(name: str, doc: str, fun: Callable[..., Any]) -> Callable[..., Any]:
36+
def alias(name: str, doc: str, fun: Callable[_P, _T]) -> Callable[_P, _T]:
3437
# Adapted from
3538
# https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function#
3639
# See also help(type(lambda: 0))

reactivex/operators/_flatmap.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from asyncio import Future
2-
from typing import Any, Callable, Iterable, Optional, TypeVar, Union, cast
2+
from typing import Any, Callable, Optional, TypeVar, Union, cast
33

44
from reactivex import Observable, from_, from_future
55
from reactivex import operators as ops
6+
from reactivex.internal.basic import identity
67
from reactivex.typing import Mapper, MapperIndexed
78

89
_T1 = TypeVar("_T1")
@@ -14,14 +15,16 @@ def _flat_map_internal(
1415
mapper: Optional[Mapper[_T1, Any]] = None,
1516
mapper_indexed: Optional[MapperIndexed[_T1, Any]] = None,
1617
) -> Observable[Any]:
17-
def projection(x: _T1, i: int):
18-
mapper_result = (
19-
mapper(x) if mapper else mapper_indexed(x, i) if mapper_indexed else None
18+
def projection(x: _T1, i: int) -> Observable[Any]:
19+
mapper_result: Any = (
20+
mapper(x)
21+
if mapper
22+
else mapper_indexed(x, i)
23+
if mapper_indexed
24+
else identity
2025
)
2126
if isinstance(mapper_result, Future):
2227
result: Observable[Any] = from_future(cast("Future[Any]", mapper_result))
23-
elif isinstance(mapper_result, Iterable):
24-
result = from_(mapper_result)
2528
elif isinstance(mapper_result, Observable):
2629
result = mapper_result
2730
else:

0 commit comments

Comments
 (0)