reactivex 4.1.0__py3-none-any.whl → 5.0.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. reactivex/__init__.py +35 -39
  2. reactivex/_version.py +1 -1
  3. reactivex/abc/disposable.py +3 -4
  4. reactivex/abc/observable.py +13 -6
  5. reactivex/abc/observer.py +2 -1
  6. reactivex/abc/periodicscheduler.py +7 -6
  7. reactivex/abc/scheduler.py +10 -9
  8. reactivex/abc/subject.py +5 -5
  9. reactivex/disposable/compositedisposable.py +4 -4
  10. reactivex/disposable/disposable.py +1 -2
  11. reactivex/disposable/multipleassignmentdisposable.py +2 -3
  12. reactivex/disposable/refcountdisposable.py +1 -2
  13. reactivex/disposable/serialdisposable.py +4 -5
  14. reactivex/disposable/singleassignmentdisposable.py +3 -4
  15. reactivex/internal/__init__.py +2 -0
  16. reactivex/internal/basic.py +2 -2
  17. reactivex/internal/concurrency.py +2 -1
  18. reactivex/internal/curry.py +59 -0
  19. reactivex/internal/exceptions.py +7 -12
  20. reactivex/internal/priorityqueue.py +2 -2
  21. reactivex/internal/utils.py +3 -2
  22. reactivex/notification.py +22 -21
  23. reactivex/observable/case.py +5 -6
  24. reactivex/observable/catch.py +3 -2
  25. reactivex/observable/combinelatest.py +4 -5
  26. reactivex/observable/concat.py +3 -2
  27. reactivex/observable/connectableobservable.py +7 -7
  28. reactivex/observable/defer.py +4 -3
  29. reactivex/observable/empty.py +3 -4
  30. reactivex/observable/forkjoin.py +5 -5
  31. reactivex/observable/fromcallback.py +4 -3
  32. reactivex/observable/fromfuture.py +2 -2
  33. reactivex/observable/fromiterable.py +4 -3
  34. reactivex/observable/generate.py +2 -2
  35. reactivex/observable/generatewithrelativetime.py +4 -3
  36. reactivex/observable/groupedobservable.py +4 -4
  37. reactivex/observable/ifthen.py +3 -2
  38. reactivex/observable/interval.py +1 -4
  39. reactivex/observable/marbles.py +18 -17
  40. reactivex/observable/mixins/__init__.py +32 -0
  41. reactivex/observable/mixins/combination.py +481 -0
  42. reactivex/observable/mixins/conditional.py +135 -0
  43. reactivex/observable/mixins/error_handling.py +130 -0
  44. reactivex/observable/mixins/filtering.py +1119 -0
  45. reactivex/observable/mixins/mathematical.py +277 -0
  46. reactivex/observable/mixins/multicasting.py +306 -0
  47. reactivex/observable/mixins/testing.py +193 -0
  48. reactivex/observable/mixins/time_based.py +209 -0
  49. reactivex/observable/mixins/transformation.py +632 -0
  50. reactivex/observable/mixins/utility.py +811 -0
  51. reactivex/observable/mixins/windowing.py +688 -0
  52. reactivex/observable/never.py +2 -2
  53. reactivex/observable/observable.py +72 -25
  54. reactivex/observable/onerrorresumenext.py +7 -6
  55. reactivex/observable/range.py +6 -6
  56. reactivex/observable/repeat.py +2 -2
  57. reactivex/observable/returnvalue.py +6 -5
  58. reactivex/observable/start.py +3 -2
  59. reactivex/observable/startasync.py +2 -1
  60. reactivex/observable/throw.py +3 -3
  61. reactivex/observable/timer.py +12 -12
  62. reactivex/observable/toasync.py +3 -2
  63. reactivex/observable/using.py +5 -4
  64. reactivex/observable/withlatestfrom.py +4 -5
  65. reactivex/observable/zip.py +7 -6
  66. reactivex/observer/autodetachobserver.py +4 -4
  67. reactivex/observer/observer.py +5 -4
  68. reactivex/observer/scheduledobserver.py +2 -2
  69. reactivex/operators/__init__.py +162 -208
  70. reactivex/operators/_all.py +23 -6
  71. reactivex/operators/_amb.py +88 -75
  72. reactivex/operators/_asobservable.py +20 -17
  73. reactivex/operators/_average.py +48 -45
  74. reactivex/operators/_buffer.py +81 -35
  75. reactivex/operators/_bufferwithtime.py +29 -9
  76. reactivex/operators/_bufferwithtimeorcount.py +27 -8
  77. reactivex/operators/_catch.py +33 -32
  78. reactivex/operators/_combinelatest.py +28 -20
  79. reactivex/operators/_concat.py +16 -13
  80. reactivex/operators/_contains.py +25 -6
  81. reactivex/operators/_count.py +24 -8
  82. reactivex/operators/_debounce.py +141 -138
  83. reactivex/operators/_defaultifempty.py +45 -42
  84. reactivex/operators/_delay.py +24 -23
  85. reactivex/operators/_delaysubscription.py +23 -21
  86. reactivex/operators/_delaywithmapper.py +10 -11
  87. reactivex/operators/_dematerialize.py +25 -21
  88. reactivex/operators/_distinct.py +50 -46
  89. reactivex/operators/_distinctuntilchanged.py +60 -57
  90. reactivex/operators/_do.py +123 -116
  91. reactivex/operators/_dowhile.py +3 -2
  92. reactivex/operators/_elementatordefault.py +57 -33
  93. reactivex/operators/_exclusive.py +59 -53
  94. reactivex/operators/_expand.py +82 -77
  95. reactivex/operators/_filter.py +63 -68
  96. reactivex/operators/_finallyaction.py +3 -2
  97. reactivex/operators/_find.py +49 -32
  98. reactivex/operators/_first.py +18 -11
  99. reactivex/operators/_firstordefault.py +5 -4
  100. reactivex/operators/_flatmap.py +89 -83
  101. reactivex/operators/_forkjoin.py +23 -18
  102. reactivex/operators/_groupby.py +27 -6
  103. reactivex/operators/_groupbyuntil.py +8 -5
  104. reactivex/operators/_groupjoin.py +7 -6
  105. reactivex/operators/_ignoreelements.py +20 -15
  106. reactivex/operators/_isempty.py +15 -4
  107. reactivex/operators/_join.py +6 -5
  108. reactivex/operators/_last.py +36 -31
  109. reactivex/operators/_lastordefault.py +8 -8
  110. reactivex/operators/_map.py +54 -39
  111. reactivex/operators/_materialize.py +30 -31
  112. reactivex/operators/_max.py +18 -11
  113. reactivex/operators/_maxby.py +5 -5
  114. reactivex/operators/_merge.py +132 -129
  115. reactivex/operators/_min.py +16 -10
  116. reactivex/operators/_minby.py +9 -8
  117. reactivex/operators/_multicast.py +9 -9
  118. reactivex/operators/_observeon.py +35 -31
  119. reactivex/operators/_onerrorresumenext.py +2 -1
  120. reactivex/operators/_pairwise.py +38 -34
  121. reactivex/operators/_partition.py +80 -73
  122. reactivex/operators/_pluck.py +4 -3
  123. reactivex/operators/_publish.py +36 -21
  124. reactivex/operators/_publishvalue.py +8 -7
  125. reactivex/operators/_reduce.py +16 -12
  126. reactivex/operators/_repeat.py +33 -30
  127. reactivex/operators/_replay.py +9 -9
  128. reactivex/operators/_retry.py +12 -10
  129. reactivex/operators/_sample.py +31 -27
  130. reactivex/operators/_scan.py +41 -39
  131. reactivex/operators/_sequenceequal.py +8 -7
  132. reactivex/operators/_single.py +20 -13
  133. reactivex/operators/_singleordefault.py +6 -5
  134. reactivex/operators/_skip.py +35 -32
  135. reactivex/operators/_skiplast.py +38 -34
  136. reactivex/operators/_skiplastwithtime.py +5 -4
  137. reactivex/operators/_skipuntil.py +40 -35
  138. reactivex/operators/_skipuntilwithtime.py +4 -3
  139. reactivex/operators/_skipwhile.py +65 -44
  140. reactivex/operators/_skipwithtime.py +50 -46
  141. reactivex/operators/_slice.py +58 -53
  142. reactivex/operators/_some.py +48 -47
  143. reactivex/operators/_startswith.py +17 -15
  144. reactivex/operators/_subscribeon.py +44 -41
  145. reactivex/operators/_sum.py +23 -6
  146. reactivex/operators/_switchlatest.py +71 -69
  147. reactivex/operators/_take.py +37 -33
  148. reactivex/operators/_takelast.py +37 -36
  149. reactivex/operators/_takelastbuffer.py +38 -37
  150. reactivex/operators/_takelastwithtime.py +60 -56
  151. reactivex/operators/_takeuntil.py +33 -32
  152. reactivex/operators/_takeuntilwithtime.py +42 -39
  153. reactivex/operators/_takewhile.py +108 -100
  154. reactivex/operators/_takewithtime.py +46 -41
  155. reactivex/operators/_throttlefirst.py +52 -45
  156. reactivex/operators/_timeinterval.py +40 -36
  157. reactivex/operators/_timeout.py +81 -79
  158. reactivex/operators/_timeoutwithmapper.py +6 -5
  159. reactivex/operators/_timestamp.py +24 -22
  160. reactivex/operators/_todict.py +51 -43
  161. reactivex/operators/_tofuture.py +24 -15
  162. reactivex/operators/_toiterable.py +33 -27
  163. reactivex/operators/_tomarbles.py +5 -5
  164. reactivex/operators/_toset.py +29 -19
  165. reactivex/operators/_whiledo.py +2 -1
  166. reactivex/operators/_window.py +100 -99
  167. reactivex/operators/_windowwithcount.py +56 -54
  168. reactivex/operators/_windowwithtime.py +95 -79
  169. reactivex/operators/_windowwithtimeorcount.py +85 -69
  170. reactivex/operators/_withlatestfrom.py +13 -9
  171. reactivex/operators/_zip.py +67 -63
  172. reactivex/operators/connectable/_refcount.py +4 -3
  173. reactivex/pipe.py +2 -1
  174. reactivex/run.py +8 -4
  175. reactivex/scheduler/catchscheduler.py +11 -10
  176. reactivex/scheduler/currentthreadscheduler.py +2 -3
  177. reactivex/scheduler/eventloop/asyncioscheduler.py +7 -6
  178. reactivex/scheduler/eventloop/asynciothreadsafescheduler.py +12 -14
  179. reactivex/scheduler/eventloop/eventletscheduler.py +4 -4
  180. reactivex/scheduler/eventloop/geventscheduler.py +4 -4
  181. reactivex/scheduler/eventloop/ioloopscheduler.py +4 -4
  182. reactivex/scheduler/eventloop/twistedscheduler.py +4 -4
  183. reactivex/scheduler/eventloopscheduler.py +9 -12
  184. reactivex/scheduler/historicalscheduler.py +1 -2
  185. reactivex/scheduler/immediatescheduler.py +5 -4
  186. reactivex/scheduler/mainloop/gtkscheduler.py +6 -7
  187. reactivex/scheduler/mainloop/pygamescheduler.py +4 -4
  188. reactivex/scheduler/mainloop/qtscheduler.py +6 -6
  189. reactivex/scheduler/mainloop/tkinterscheduler.py +4 -4
  190. reactivex/scheduler/mainloop/wxscheduler.py +7 -7
  191. reactivex/scheduler/newthreadscheduler.py +6 -8
  192. reactivex/scheduler/periodicscheduler.py +4 -4
  193. reactivex/scheduler/scheduleditem.py +4 -4
  194. reactivex/scheduler/scheduler.py +5 -5
  195. reactivex/scheduler/threadpoolscheduler.py +3 -3
  196. reactivex/scheduler/timeoutscheduler.py +5 -4
  197. reactivex/scheduler/trampoline.py +1 -2
  198. reactivex/scheduler/trampolinescheduler.py +5 -6
  199. reactivex/scheduler/virtualtimescheduler.py +4 -4
  200. reactivex/subject/asyncsubject.py +2 -2
  201. reactivex/subject/behaviorsubject.py +2 -2
  202. reactivex/subject/innersubscription.py +2 -2
  203. reactivex/subject/replaysubject.py +8 -8
  204. reactivex/subject/subject.py +4 -4
  205. reactivex/testing/coldobservable.py +5 -5
  206. reactivex/testing/hotobservable.py +6 -6
  207. reactivex/testing/marbles.py +21 -20
  208. reactivex/testing/mockdisposable.py +1 -3
  209. reactivex/testing/mockobserver.py +2 -2
  210. reactivex/testing/reactivetest.py +2 -2
  211. reactivex/testing/recorded.py +1 -1
  212. reactivex/testing/subscription.py +3 -3
  213. reactivex/testing/testscheduler.py +13 -12
  214. reactivex/typing.py +25 -14
  215. {reactivex-4.1.0.dist-info → reactivex-5.0.0a2.dist-info}/METADATA +59 -26
  216. reactivex-5.0.0a2.dist-info/RECORD +236 -0
  217. {reactivex-4.1.0.dist-info → reactivex-5.0.0a2.dist-info}/WHEEL +1 -1
  218. reactivex-4.1.0.dist-info/RECORD +0 -223
  219. {reactivex-4.1.0.dist-info → reactivex-5.0.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,21 +1,38 @@
1
- from typing import Callable, TypeVar
1
+ from typing import TypeVar
2
2
 
3
- from reactivex import Observable, compose
3
+ from reactivex import Observable
4
4
  from reactivex import operators as ops
5
+ from reactivex.internal import curry_flip
5
6
  from reactivex.typing import Predicate
6
7
 
7
8
  _T = TypeVar("_T")
8
9
 
9
10
 
10
- def all_(predicate: Predicate[_T]) -> Callable[[Observable[_T]], Observable[bool]]:
11
- def filter(v: _T):
11
+ @curry_flip
12
+ def all_(source: Observable[_T], predicate: Predicate[_T]) -> Observable[bool]:
13
+ """Determines whether all elements of an observable sequence satisfy a condition.
14
+
15
+ Examples:
16
+ >>> result = source.pipe(all(lambda x: x > 0))
17
+ >>> result = all(lambda x: x > 0)(source)
18
+
19
+ Args:
20
+ source: The source observable sequence.
21
+ predicate: A function to test each element for a condition.
22
+
23
+ Returns:
24
+ An observable sequence containing a single element determining
25
+ whether all elements in the source sequence pass the test.
26
+ """
27
+
28
+ def filter_fn(v: _T):
12
29
  return not predicate(v)
13
30
 
14
31
  def mapping(b: bool) -> bool:
15
32
  return not b
16
33
 
17
- return compose(
18
- ops.filter(filter),
34
+ return source.pipe(
35
+ ops.filter(filter_fn),
19
36
  ops.some(),
20
37
  ops.map(mapping),
21
38
  )
@@ -1,92 +1,105 @@
1
1
  from asyncio import Future
2
- from typing import Callable, List, Optional, TypeVar, Union
2
+ from typing import TypeVar, Union
3
3
 
4
4
  from reactivex import Observable, abc, from_future
5
5
  from reactivex.disposable import CompositeDisposable, SingleAssignmentDisposable
6
+ from reactivex.internal import curry_flip
6
7
 
7
8
  _T = TypeVar("_T")
8
9
 
9
10
 
11
+ @curry_flip
10
12
  def amb_(
11
- right_source: Union[Observable[_T], "Future[_T]"]
12
- ) -> Callable[[Observable[_T]], Observable[_T]]:
13
-
13
+ left_source: Observable[_T],
14
+ right_source: Union[Observable[_T], "Future[_T]"],
15
+ ) -> Observable[_T]:
16
+ """Propagates the observable sequence that reacts first.
17
+
18
+ Examples:
19
+ >>> result = source.pipe(amb(other_source))
20
+ >>> result = amb(other_source)(source)
21
+
22
+ Args:
23
+ left_source: The left source observable.
24
+ right_source: The right source observable or future.
25
+
26
+ Returns:
27
+ An observable sequence that surfaces either of the given sequences,
28
+ whichever reacted first.
29
+ """
14
30
  if isinstance(right_source, Future):
15
31
  obs: Observable[_T] = from_future(right_source)
16
32
  else:
17
33
  obs = right_source
18
34
 
19
- def amb(left_source: Observable[_T]) -> Observable[_T]:
20
- def subscribe(
21
- observer: abc.ObserverBase[_T],
22
- scheduler: Optional[abc.SchedulerBase] = None,
23
- ) -> abc.DisposableBase:
24
- choice: List[Optional[str]] = [None]
25
- left_choice = "L"
26
- right_choice = "R"
27
- left_subscription = SingleAssignmentDisposable()
28
- right_subscription = SingleAssignmentDisposable()
29
-
30
- def choice_left():
31
- if not choice[0]:
32
- choice[0] = left_choice
33
- right_subscription.dispose()
34
-
35
- def choice_right():
36
- if not choice[0]:
37
- choice[0] = right_choice
38
- left_subscription.dispose()
39
-
40
- def on_next_left(value: _T) -> None:
41
- with left_source.lock:
42
- choice_left()
43
- if choice[0] == left_choice:
44
- observer.on_next(value)
45
-
46
- def on_error_left(err: Exception) -> None:
47
- with left_source.lock:
48
- choice_left()
49
- if choice[0] == left_choice:
50
- observer.on_error(err)
51
-
52
- def on_completed_left() -> None:
53
- with left_source.lock:
54
- choice_left()
55
- if choice[0] == left_choice:
56
- observer.on_completed()
57
-
58
- left_d = left_source.subscribe(
59
- on_next_left, on_error_left, on_completed_left, scheduler=scheduler
60
- )
61
- left_subscription.disposable = left_d
62
-
63
- def send_right(value: _T) -> None:
64
- with left_source.lock:
65
- choice_right()
66
- if choice[0] == right_choice:
67
- observer.on_next(value)
68
-
69
- def on_error_right(err: Exception) -> None:
70
- with left_source.lock:
71
- choice_right()
72
- if choice[0] == right_choice:
73
- observer.on_error(err)
74
-
75
- def on_completed_right() -> None:
76
- with left_source.lock:
77
- choice_right()
78
- if choice[0] == right_choice:
79
- observer.on_completed()
80
-
81
- right_d = obs.subscribe(
82
- send_right, on_error_right, on_completed_right, scheduler=scheduler
83
- )
84
- right_subscription.disposable = right_d
85
- return CompositeDisposable(left_subscription, right_subscription)
86
-
87
- return Observable(subscribe)
88
-
89
- return amb
35
+ def subscribe(
36
+ observer: abc.ObserverBase[_T],
37
+ scheduler: abc.SchedulerBase | None = None,
38
+ ) -> abc.DisposableBase:
39
+ choice: list[str | None] = [None]
40
+ left_choice = "L"
41
+ right_choice = "R"
42
+ left_subscription = SingleAssignmentDisposable()
43
+ right_subscription = SingleAssignmentDisposable()
44
+
45
+ def choice_left():
46
+ if not choice[0]:
47
+ choice[0] = left_choice
48
+ right_subscription.dispose()
49
+
50
+ def choice_right():
51
+ if not choice[0]:
52
+ choice[0] = right_choice
53
+ left_subscription.dispose()
54
+
55
+ def on_next_left(value: _T) -> None:
56
+ with left_source.lock:
57
+ choice_left()
58
+ if choice[0] == left_choice:
59
+ observer.on_next(value)
60
+
61
+ def on_error_left(err: Exception) -> None:
62
+ with left_source.lock:
63
+ choice_left()
64
+ if choice[0] == left_choice:
65
+ observer.on_error(err)
66
+
67
+ def on_completed_left() -> None:
68
+ with left_source.lock:
69
+ choice_left()
70
+ if choice[0] == left_choice:
71
+ observer.on_completed()
72
+
73
+ left_d = left_source.subscribe(
74
+ on_next_left, on_error_left, on_completed_left, scheduler=scheduler
75
+ )
76
+ left_subscription.disposable = left_d
77
+
78
+ def send_right(value: _T) -> None:
79
+ with left_source.lock:
80
+ choice_right()
81
+ if choice[0] == right_choice:
82
+ observer.on_next(value)
83
+
84
+ def on_error_right(err: Exception) -> None:
85
+ with left_source.lock:
86
+ choice_right()
87
+ if choice[0] == right_choice:
88
+ observer.on_error(err)
89
+
90
+ def on_completed_right() -> None:
91
+ with left_source.lock:
92
+ choice_right()
93
+ if choice[0] == right_choice:
94
+ observer.on_completed()
95
+
96
+ right_d = obs.subscribe(
97
+ send_right, on_error_right, on_completed_right, scheduler=scheduler
98
+ )
99
+ right_subscription.disposable = right_d
100
+ return CompositeDisposable(left_subscription, right_subscription)
101
+
102
+ return Observable(subscribe)
90
103
 
91
104
 
92
105
  __all__ = ["amb_"]
@@ -1,31 +1,34 @@
1
- from typing import Callable, Optional, TypeVar
1
+ from typing import TypeVar
2
2
 
3
3
  from reactivex import Observable, abc
4
+ from reactivex.internal import curry_flip
4
5
 
5
6
  _T = TypeVar("_T")
6
7
 
7
8
 
8
- def as_observable_() -> Callable[[Observable[_T]], Observable[_T]]:
9
- def as_observable(source: Observable[_T]) -> Observable[_T]:
10
- """Hides the identity of an observable sequence.
9
+ @curry_flip
10
+ def as_observable_(source: Observable[_T]) -> Observable[_T]:
11
+ """Hides the identity of an observable sequence.
11
12
 
12
- Args:
13
- source: Observable source to hide identity from.
13
+ Examples:
14
+ >>> res = source.pipe(as_observable())
15
+ >>> res = as_observable()(source)
14
16
 
15
- Returns:
16
- An observable sequence that hides the identity of the
17
- source sequence.
18
- """
17
+ Args:
18
+ source: Observable source to hide identity from.
19
19
 
20
- def subscribe(
21
- observer: abc.ObserverBase[_T],
22
- scheduler: Optional[abc.SchedulerBase] = None,
23
- ) -> abc.DisposableBase:
24
- return source.subscribe(observer, scheduler=scheduler)
20
+ Returns:
21
+ An observable sequence that hides the identity of the
22
+ source sequence.
23
+ """
25
24
 
26
- return Observable(subscribe)
25
+ def subscribe(
26
+ observer: abc.ObserverBase[_T],
27
+ scheduler: abc.SchedulerBase | None = None,
28
+ ) -> abc.DisposableBase:
29
+ return source.subscribe(observer, scheduler=scheduler)
27
30
 
28
- return as_observable
31
+ return Observable(subscribe)
29
32
 
30
33
 
31
34
  __all__ = ["as_observable_"]
@@ -1,7 +1,8 @@
1
1
  from dataclasses import dataclass
2
- from typing import Any, Callable, Optional, TypeVar, cast
2
+ from typing import Any, TypeVar, cast
3
3
 
4
4
  from reactivex import Observable, operators, typing
5
+ from reactivex.internal import curry_flip
5
6
 
6
7
  _T = TypeVar("_T")
7
8
 
@@ -12,51 +13,53 @@ class AverageValue:
12
13
  count: int
13
14
 
14
15
 
16
+ @curry_flip
15
17
  def average_(
16
- key_mapper: Optional[typing.Mapper[_T, float]] = None,
17
- ) -> Callable[[Observable[_T]], Observable[float]]:
18
- def average(source: Observable[Any]) -> Observable[float]:
19
- """Partially applied average operator.
20
-
21
- Computes the average of an observable sequence of values that
22
- are in the sequence or obtained by invoking a transform
23
- function on each element of the input sequence if present.
24
-
25
- Examples:
26
- >>> res = average(source)
27
-
28
- Args:
29
- source: Source observable to average.
30
-
31
- Returns:
32
- An observable sequence containing a single element with the
33
- average of the sequence of values.
34
- """
35
-
36
- key_mapper_: typing.Mapper[_T, float] = key_mapper or (
37
- lambda x: float(cast(Any, x))
38
- )
39
-
40
- def accumulator(prev: AverageValue, cur: float) -> AverageValue:
41
- return AverageValue(sum=prev.sum + cur, count=prev.count + 1)
42
-
43
- def mapper(s: AverageValue) -> float:
44
- if s.count == 0:
45
- raise Exception("The input sequence was empty")
46
-
47
- return s.sum / float(s.count)
48
-
49
- seed = AverageValue(sum=0, count=0)
50
-
51
- ret = source.pipe(
52
- operators.map(key_mapper_),
53
- operators.scan(accumulator, seed),
54
- operators.last(),
55
- operators.map(mapper),
56
- )
57
- return ret
58
-
59
- return average
18
+ source: Observable[_T],
19
+ key_mapper: typing.Mapper[_T, float] | None = None,
20
+ ) -> Observable[float]:
21
+ """Computes the average of an observable sequence of values.
22
+
23
+ Computes the average of an observable sequence of values that
24
+ are in the sequence or obtained by invoking a transform
25
+ function on each element of the input sequence if present.
26
+
27
+ Examples:
28
+ >>> result = source.pipe(average())
29
+ >>> result = average()(source)
30
+ >>> result = source.pipe(average(lambda x: x.value))
31
+
32
+ Args:
33
+ source: Source observable to average.
34
+ key_mapper: Optional mapper to extract numeric values.
35
+
36
+ Returns:
37
+ An observable sequence containing a single element with the
38
+ average of the sequence of values.
39
+ """
40
+
41
+ key_mapper_: typing.Mapper[_T, float] = key_mapper or (
42
+ lambda x: float(cast(Any, x))
43
+ )
44
+
45
+ def accumulator(prev: AverageValue, cur: float) -> AverageValue:
46
+ return AverageValue(sum=prev.sum + cur, count=prev.count + 1)
47
+
48
+ def mapper(s: AverageValue) -> float:
49
+ if s.count == 0:
50
+ raise Exception("The input sequence was empty")
51
+
52
+ return s.sum / float(s.count)
53
+
54
+ seed = AverageValue(sum=0, count=0)
55
+
56
+ ret = source.pipe(
57
+ operators.map(key_mapper_),
58
+ operators.scan(accumulator, seed),
59
+ operators.last(),
60
+ operators.map(mapper),
61
+ )
62
+ return ret
60
63
 
61
64
 
62
65
  __all__ = ["average_"]
@@ -1,80 +1,126 @@
1
- from typing import Any, Callable, List, Optional, TypeVar
1
+ from collections.abc import Callable
2
+ from typing import Any, TypeVar
2
3
 
3
- from reactivex import Observable, compose
4
+ from reactivex import Observable
4
5
  from reactivex import operators as ops
6
+ from reactivex.internal import curry_flip
5
7
 
6
8
  _T = TypeVar("_T")
7
9
 
8
10
 
11
+ @curry_flip
9
12
  def buffer_(
13
+ source: Observable[_T],
10
14
  boundaries: Observable[Any],
11
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
12
- return compose(
15
+ ) -> Observable[list[_T]]:
16
+ """Buffers elements from the source based on boundary notifications.
17
+
18
+ Examples:
19
+ >>> res = source.pipe(buffer(boundaries))
20
+ >>> res = buffer(boundaries)(source)
21
+
22
+ Args:
23
+ source: Source observable to buffer.
24
+ boundaries: Observable that triggers buffer emissions.
25
+
26
+ Returns:
27
+ Observable of lists of buffered elements.
28
+ """
29
+ return source.pipe(
13
30
  ops.window(boundaries),
14
31
  ops.flat_map(ops.to_list()),
15
32
  )
16
33
 
17
34
 
35
+ @curry_flip
18
36
  def buffer_when_(
19
- closing_mapper: Callable[[], Observable[Any]]
20
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
21
- return compose(
37
+ source: Observable[_T],
38
+ closing_mapper: Callable[[], Observable[Any]],
39
+ ) -> Observable[list[_T]]:
40
+ """Buffers elements using a closing mapper function.
41
+
42
+ Examples:
43
+ >>> res = source.pipe(buffer_when(lambda: timer(1.0)))
44
+ >>> res = buffer_when(lambda: timer(1.0))(source)
45
+
46
+ Args:
47
+ source: Source observable to buffer.
48
+ closing_mapper: Function that returns an observable signaling buffer close.
49
+
50
+ Returns:
51
+ Observable of lists of buffered elements.
52
+ """
53
+ return source.pipe(
22
54
  ops.window_when(closing_mapper),
23
55
  ops.flat_map(ops.to_list()),
24
56
  )
25
57
 
26
58
 
59
+ @curry_flip
27
60
  def buffer_toggle_(
28
- openings: Observable[Any], closing_mapper: Callable[[Any], Observable[Any]]
29
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
30
- return compose(
61
+ source: Observable[_T],
62
+ openings: Observable[Any],
63
+ closing_mapper: Callable[[Any], Observable[Any]],
64
+ ) -> Observable[list[_T]]:
65
+ """Buffers elements using opening/closing observables.
66
+
67
+ Examples:
68
+ >>> res = source.pipe(buffer_toggle(opens, lambda x: timer(x)))
69
+ >>> res = buffer_toggle(opens, lambda x: timer(x))(source)
70
+
71
+ Args:
72
+ source: Source observable to buffer.
73
+ openings: Observable that triggers buffer opening.
74
+ closing_mapper: Function to create closing observable.
75
+
76
+ Returns:
77
+ Observable of lists of buffered elements.
78
+ """
79
+ return source.pipe(
31
80
  ops.window_toggle(openings, closing_mapper),
32
81
  ops.flat_map(ops.to_list()),
33
82
  )
34
83
 
35
84
 
85
+ @curry_flip
36
86
  def buffer_with_count_(
37
- count: int, skip: Optional[int] = None
38
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
87
+ source: Observable[_T],
88
+ count: int,
89
+ skip: int | None = None,
90
+ ) -> Observable[list[_T]]:
39
91
  """Projects each element of an observable sequence into zero or more
40
92
  buffers which are produced based on element count information.
41
93
 
42
94
  Examples:
43
- >>> res = buffer_with_count(10)(xs)
44
- >>> res = buffer_with_count(10, 1)(xs)
95
+ >>> res = source.pipe(buffer_with_count(10))
96
+ >>> res = buffer_with_count(10)(source)
97
+ >>> res = source.pipe(buffer_with_count(10, 1))
45
98
 
46
99
  Args:
100
+ source: Source observable to buffer.
47
101
  count: Length of each buffer.
48
102
  skip: [Optional] Number of elements to skip between
49
103
  creation of consecutive buffers. If not provided, defaults to
50
104
  the count.
51
105
 
52
106
  Returns:
53
- A function that takes an observable source and returns an
54
- observable sequence of buffers.
107
+ An observable sequence of buffers.
55
108
  """
109
+ skip_ = skip if skip is not None else count
56
110
 
57
- def buffer_with_count(source: Observable[_T]) -> Observable[List[_T]]:
58
- nonlocal skip
59
-
60
- if skip is None:
61
- skip = count
62
-
63
- def mapper(value: Observable[_T]) -> Observable[List[_T]]:
64
- return value.pipe(
65
- ops.to_list(),
66
- )
67
-
68
- def predicate(value: List[_T]) -> bool:
69
- return len(value) > 0
70
-
71
- return source.pipe(
72
- ops.window_with_count(count, skip),
73
- ops.flat_map(mapper),
74
- ops.filter(predicate),
111
+ def mapper(value: Observable[_T]) -> Observable[list[_T]]:
112
+ return value.pipe(
113
+ ops.to_list(),
75
114
  )
76
115
 
77
- return buffer_with_count
116
+ def predicate(value: list[_T]) -> bool:
117
+ return len(value) > 0
118
+
119
+ return source.pipe(
120
+ ops.window_with_count(count, skip_),
121
+ ops.flat_map(mapper),
122
+ ops.filter(predicate),
123
+ )
78
124
 
79
125
 
80
126
  __all__ = ["buffer_", "buffer_with_count_", "buffer_when_", "buffer_toggle_"]
@@ -1,23 +1,43 @@
1
- from typing import Callable, List, Optional, TypeVar
1
+ from typing import TypeVar
2
2
 
3
- from reactivex import Observable, abc, compose
3
+ from reactivex import Observable, abc, compose, typing
4
4
  from reactivex import operators as ops
5
- from reactivex import typing
5
+ from reactivex.internal import curry_flip
6
6
 
7
7
  _T = TypeVar("_T")
8
8
 
9
9
 
10
+ @curry_flip
10
11
  def buffer_with_time_(
12
+ source: Observable[_T],
11
13
  timespan: typing.RelativeTime,
12
- timeshift: Optional[typing.RelativeTime] = None,
13
- scheduler: Optional[abc.SchedulerBase] = None,
14
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
14
+ timeshift: typing.RelativeTime | None = None,
15
+ scheduler: abc.SchedulerBase | None = None,
16
+ ) -> Observable[list[_T]]:
17
+ """Buffers elements based on timing information.
18
+
19
+ Examples:
20
+ >>> source.pipe(buffer_with_time(1.0))
21
+ >>> source.pipe(buffer_with_time(1.0, 0.5))
22
+ >>> buffer_with_time(1.0)(source)
23
+
24
+ Args:
25
+ source: Source observable to buffer.
26
+ timespan: Length of each buffer.
27
+ timeshift: Interval between creation of consecutive buffers.
28
+ scheduler: Scheduler to use for timing.
29
+
30
+ Returns:
31
+ An observable sequence of buffers.
32
+ """
15
33
  if not timeshift:
16
34
  timeshift = timespan
17
35
 
18
- return compose(
19
- ops.window_with_time(timespan, timeshift, scheduler),
20
- ops.flat_map(ops.to_list()),
36
+ return source.pipe(
37
+ compose(
38
+ ops.window_with_time(timespan, timeshift, scheduler),
39
+ ops.flat_map(ops.to_list()),
40
+ )
21
41
  )
22
42
 
23
43
 
@@ -1,20 +1,39 @@
1
- from typing import Callable, List, Optional, TypeVar
1
+ from typing import TypeVar
2
2
 
3
- from reactivex import Observable, abc, compose
3
+ from reactivex import Observable, abc, compose, typing
4
4
  from reactivex import operators as ops
5
- from reactivex import typing
5
+ from reactivex.internal import curry_flip
6
6
 
7
7
  _T = TypeVar("_T")
8
8
 
9
9
 
10
+ @curry_flip
10
11
  def buffer_with_time_or_count_(
12
+ source: Observable[_T],
11
13
  timespan: typing.RelativeTime,
12
14
  count: int,
13
- scheduler: Optional[abc.SchedulerBase] = None,
14
- ) -> Callable[[Observable[_T]], Observable[List[_T]]]:
15
- return compose(
16
- ops.window_with_time_or_count(timespan, count, scheduler),
17
- ops.flat_map(ops.to_iterable()),
15
+ scheduler: abc.SchedulerBase | None = None,
16
+ ) -> Observable[list[_T]]:
17
+ """Buffers elements based on timing and count information.
18
+
19
+ Examples:
20
+ >>> source.pipe(buffer_with_time_or_count(1.0, 10))
21
+ >>> buffer_with_time_or_count(1.0, 10)(source)
22
+
23
+ Args:
24
+ source: Source observable to buffer.
25
+ timespan: Maximum time length of each buffer.
26
+ count: Maximum element count of each buffer.
27
+ scheduler: Scheduler to use for timing.
28
+
29
+ Returns:
30
+ An observable sequence of buffers.
31
+ """
32
+ return source.pipe(
33
+ compose(
34
+ ops.window_with_time_or_count(timespan, count, scheduler),
35
+ ops.flat_map(ops.to_iterable()),
36
+ )
18
37
  )
19
38
 
20
39