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,9 +1,11 @@
1
1
  from asyncio import Future
2
- from typing import Callable, Optional, TypeVar, Union
2
+ from collections.abc import Callable
3
+ from typing import TypeVar, Union
3
4
 
4
5
  import reactivex
5
6
  from reactivex import Observable, abc
6
7
  from reactivex.disposable import SerialDisposable, SingleAssignmentDisposable
8
+ from reactivex.internal import curry_flip
7
9
 
8
10
  _T = TypeVar("_T")
9
11
 
@@ -13,7 +15,7 @@ def catch_handler(
13
15
  handler: Callable[[Exception, Observable[_T]], Union[Observable[_T], "Future[_T]"]],
14
16
  ) -> Observable[_T]:
15
17
  def subscribe(
16
- observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None
18
+ observer: abc.ObserverBase[_T], scheduler: abc.SchedulerBase | None = None
17
19
  ) -> abc.DisposableBase:
18
20
  d1 = SingleAssignmentDisposable()
19
21
  subscription = SerialDisposable()
@@ -42,37 +44,36 @@ def catch_handler(
42
44
  return Observable(subscribe)
43
45
 
44
46
 
47
+ @curry_flip
45
48
  def catch_(
46
- handler: Union[
47
- Observable[_T], Callable[[Exception, Observable[_T]], Observable[_T]]
48
- ]
49
- ) -> Callable[[Observable[_T]], Observable[_T]]:
50
- def catch(source: Observable[_T]) -> Observable[_T]:
51
- """Continues an observable sequence that is terminated by an
52
- exception with the next observable sequence.
53
-
54
- Examples:
55
- >>> op = catch(ys)
56
- >>> op = catch(lambda ex, src: ys(ex))
57
-
58
- Args:
59
- handler: Second observable sequence used to produce
60
- results when an error occurred in the first sequence, or an
61
- exception handler function that returns an observable sequence
62
- given the error and source observable that occurred in the
63
- first sequence.
64
-
65
- Returns:
66
- An observable sequence containing the first sequence's
67
- elements, followed by the elements of the handler sequence
68
- in case an exception occurred.
69
- """
70
- if callable(handler):
71
- return catch_handler(source, handler)
72
- else:
73
- return reactivex.catch(source, handler)
74
-
75
- return catch
49
+ source: Observable[_T],
50
+ handler: Observable[_T] | Callable[[Exception, Observable[_T]], Observable[_T]],
51
+ ) -> Observable[_T]:
52
+ """Continues an observable sequence that is terminated by an
53
+ exception with the next observable sequence.
54
+
55
+ Examples:
56
+ >>> res = source.pipe(catch(ys))
57
+ >>> res = catch(ys)(source)
58
+ >>> res = source.pipe(catch(lambda ex, src: ys(ex)))
59
+
60
+ Args:
61
+ source: The source observable sequence.
62
+ handler: Second observable sequence used to produce
63
+ results when an error occurred in the first sequence, or an
64
+ exception handler function that returns an observable sequence
65
+ given the error and source observable that occurred in the
66
+ first sequence.
67
+
68
+ Returns:
69
+ An observable sequence containing the first sequence's
70
+ elements, followed by the elements of the handler sequence
71
+ in case an exception occurred.
72
+ """
73
+ if callable(handler):
74
+ return catch_handler(source, handler)
75
+ else:
76
+ return reactivex.catch(source, handler)
76
77
 
77
78
 
78
79
  __all__ = ["catch_"]
@@ -1,30 +1,38 @@
1
- from typing import Any, Callable
1
+ from typing import Any, cast
2
2
 
3
3
  import reactivex
4
4
  from reactivex import Observable
5
+ from reactivex.internal import curry_flip
5
6
 
6
7
 
8
+ @curry_flip
7
9
  def combine_latest_(
10
+ source: Observable[Any],
8
11
  *others: Observable[Any],
9
- ) -> Callable[[Observable[Any]], Observable[Any]]:
10
- def combine_latest(source: Observable[Any]) -> Observable[Any]:
11
- """Merges the specified observable sequences into one
12
- observable sequence by creating a tuple whenever any
13
- of the observable sequences produces an element.
14
-
15
- Examples:
16
- >>> obs = combine_latest(source)
17
-
18
- Returns:
19
- An observable sequence containing the result of combining
20
- elements of the sources into a tuple.
21
- """
22
-
23
- sources = (source,) + others
24
-
25
- return reactivex.combine_latest(*sources)
26
-
27
- return combine_latest
12
+ ) -> Observable[tuple[Any, ...]]:
13
+ """Merges the specified observable sequences into one
14
+ observable sequence by creating a tuple whenever any
15
+ of the observable sequences produces an element.
16
+
17
+ Examples:
18
+ >>> result = source.pipe(combine_latest(other1, other2))
19
+ >>> result = combine_latest(other1, other2)(source)
20
+
21
+ Args:
22
+ source: The source observable sequence.
23
+ others: Additional observable sequences to combine.
24
+
25
+ Returns:
26
+ An observable sequence containing the result of combining
27
+ elements of the sources into a tuple.
28
+ """
29
+
30
+ sources: tuple[Observable[Any], ...] = (source, *others)
31
+
32
+ ret: Observable[tuple[Any, ...]] = cast(
33
+ Observable[tuple[Any, ...]], reactivex.combine_latest(*sources)
34
+ )
35
+ return ret
28
36
 
29
37
 
30
38
  __all__ = ["combine_latest_"]
@@ -1,26 +1,29 @@
1
- from typing import Callable, TypeVar
1
+ from typing import TypeVar
2
2
 
3
3
  import reactivex
4
4
  from reactivex import Observable
5
+ from reactivex.internal import curry_flip
5
6
 
6
7
  _T = TypeVar("_T")
7
8
 
8
9
 
9
- def concat_(*sources: Observable[_T]) -> Callable[[Observable[_T]], Observable[_T]]:
10
- def concat(source: Observable[_T]) -> Observable[_T]:
11
- """Concatenates all the observable sequences.
10
+ @curry_flip
11
+ def concat_(source: Observable[_T], *sources: Observable[_T]) -> Observable[_T]:
12
+ """Concatenates all the observable sequences.
12
13
 
13
- Examples:
14
- >>> op = concat(xs, ys, zs)
14
+ Examples:
15
+ >>> result = source.pipe(concat(xs, ys, zs))
16
+ >>> result = concat(xs, ys, zs)(source)
15
17
 
16
- Returns:
17
- An operator function that takes one or more observable sources and
18
- returns an observable sequence that contains the elements of
19
- each given sequence, in sequential order.
20
- """
21
- return reactivex.concat(source, *sources)
18
+ Args:
19
+ source: The source observable sequence.
20
+ sources: Additional observable sequences to concatenate.
22
21
 
23
- return concat
22
+ Returns:
23
+ An observable sequence that contains the elements of
24
+ each given sequence, in sequential order.
25
+ """
26
+ return reactivex.concat(source, *sources)
24
27
 
25
28
 
26
29
  __all__ = ["concat_"]
@@ -1,22 +1,41 @@
1
- from typing import Callable, Optional, TypeVar
1
+ from typing import TypeVar
2
2
 
3
- from reactivex import Observable, compose
3
+ from reactivex import Observable, typing
4
4
  from reactivex import operators as ops
5
- from reactivex import typing
5
+ from reactivex.internal import curry_flip
6
6
  from reactivex.internal.basic import default_comparer
7
7
 
8
8
  _T = TypeVar("_T")
9
9
 
10
10
 
11
+ @curry_flip
11
12
  def contains_(
12
- value: _T, comparer: Optional[typing.Comparer[_T]] = None
13
- ) -> Callable[[Observable[_T]], Observable[bool]]:
13
+ source: Observable[_T],
14
+ value: _T,
15
+ comparer: typing.Comparer[_T] | None = None,
16
+ ) -> Observable[bool]:
17
+ """Determines whether an observable sequence contains a specified element.
18
+
19
+ Examples:
20
+ >>> result = source.pipe(contains(42))
21
+ >>> result = contains(42)(source)
22
+ >>> result = source.pipe(contains(42, custom_comparer))
23
+
24
+ Args:
25
+ source: The source observable sequence.
26
+ value: The value to locate in the source sequence.
27
+ comparer: Optional equality comparer to compare elements.
28
+
29
+ Returns:
30
+ An observable sequence containing a single element determining
31
+ whether the source sequence contains the specified value.
32
+ """
14
33
  comparer_ = comparer or default_comparer
15
34
 
16
35
  def predicate(v: _T) -> bool:
17
36
  return comparer_(v, value)
18
37
 
19
- return compose(
38
+ return source.pipe(
20
39
  ops.filter(predicate),
21
40
  ops.some(),
22
41
  )
@@ -1,18 +1,35 @@
1
- from typing import Callable, Optional, 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
 
11
+ @curry_flip
10
12
  def count_(
11
- predicate: Optional[Predicate[_T]] = None,
12
- ) -> Callable[[Observable[_T]], Observable[int]]:
13
-
13
+ source: Observable[_T],
14
+ predicate: Predicate[_T] | None = None,
15
+ ) -> Observable[int]:
16
+ """Returns an observable sequence containing a single element with the
17
+ number of elements in the source sequence.
18
+
19
+ Examples:
20
+ >>> result = source.pipe(count())
21
+ >>> result = count()(source)
22
+ >>> result = source.pipe(count(lambda x: x > 5))
23
+
24
+ Args:
25
+ source: The source observable.
26
+ predicate: Optional predicate to filter elements before counting.
27
+
28
+ Returns:
29
+ An observable sequence containing a single element with the count.
30
+ """
14
31
  if predicate:
15
- return compose(
32
+ return source.pipe(
16
33
  ops.filter(predicate),
17
34
  ops.count(),
18
35
  )
@@ -20,8 +37,7 @@ def count_(
20
37
  def reducer(n: int, _: _T) -> int:
21
38
  return n + 1
22
39
 
23
- counter = ops.reduce(reducer, seed=0)
24
- return counter
40
+ return source.pipe(ops.reduce(reducer, seed=0))
25
41
 
26
42
 
27
43
  __all__ = ["count_"]
@@ -1,4 +1,5 @@
1
- from typing import Any, Callable, List, Optional, TypeVar, cast
1
+ from collections.abc import Callable
2
+ from typing import Any, TypeVar, cast
2
3
 
3
4
  from reactivex import Observable, abc, typing
4
5
  from reactivex.disposable import (
@@ -6,169 +7,171 @@ from reactivex.disposable import (
6
7
  SerialDisposable,
7
8
  SingleAssignmentDisposable,
8
9
  )
10
+ from reactivex.internal import curry_flip
9
11
  from reactivex.scheduler import TimeoutScheduler
10
12
 
11
13
  _T = TypeVar("_T")
12
14
 
13
15
 
16
+ @curry_flip
14
17
  def debounce_(
15
- duetime: typing.RelativeTime, scheduler: Optional[abc.SchedulerBase]
16
- ) -> Callable[[Observable[_T]], Observable[_T]]:
17
- def debounce(source: Observable[_T]) -> Observable[_T]:
18
- """Ignores values from an observable sequence which are followed by
19
- another value before duetime.
20
-
21
- Example:
22
- >>> res = debounce(source)
23
-
24
- Args:
25
- source: Source observable to debounce.
26
-
27
- Returns:
28
- An operator function that takes the source observable and
29
- returns the debounced observable sequence.
30
- """
31
-
32
- def subscribe(
33
- observer: abc.ObserverBase[_T],
34
- scheduler_: Optional[abc.SchedulerBase] = None,
35
- ) -> abc.DisposableBase:
36
- _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
37
- cancelable = SerialDisposable()
38
- has_value = [False]
39
- value: List[_T] = [cast(_T, None)]
40
- _id: List[int] = [0]
41
-
42
- def on_next(x: _T) -> None:
43
- has_value[0] = True
44
- value[0] = x
45
- _id[0] += 1
46
- current_id = _id[0]
47
- d = SingleAssignmentDisposable()
48
- cancelable.disposable = d
49
-
50
- def action(scheduler: abc.SchedulerBase, state: Any = None) -> None:
51
- if has_value[0] and _id[0] == current_id:
52
- observer.on_next(value[0])
53
- has_value[0] = False
54
-
55
- d.disposable = _scheduler.schedule_relative(duetime, action)
56
-
57
- def on_error(exception: Exception) -> None:
58
- cancelable.dispose()
59
- observer.on_error(exception)
18
+ source: Observable[_T],
19
+ duetime: typing.RelativeTime,
20
+ scheduler: abc.SchedulerBase | None = None,
21
+ ) -> Observable[_T]:
22
+ """Ignores values from an observable sequence which are followed by
23
+ another value before duetime.
24
+
25
+ Examples:
26
+ >>> res = source.pipe(debounce(0.5))
27
+ >>> res = debounce(0.5)(source)
28
+
29
+ Args:
30
+ source: Source observable to debounce.
31
+ duetime: Duration to wait before emitting.
32
+ scheduler: Scheduler to use.
33
+
34
+ Returns:
35
+ The debounced observable sequence.
36
+ """
37
+
38
+ def subscribe(
39
+ observer: abc.ObserverBase[_T],
40
+ scheduler_: abc.SchedulerBase | None = None,
41
+ ) -> abc.DisposableBase:
42
+ _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
43
+ cancelable = SerialDisposable()
44
+ has_value = [False]
45
+ value: list[_T] = [cast(_T, None)]
46
+ _id: list[int] = [0]
47
+
48
+ def on_next(x: _T) -> None:
49
+ has_value[0] = True
50
+ value[0] = x
51
+ _id[0] += 1
52
+ current_id = _id[0]
53
+ d = SingleAssignmentDisposable()
54
+ cancelable.disposable = d
55
+
56
+ def action(scheduler: abc.SchedulerBase, state: Any = None) -> None:
57
+ if has_value[0] and _id[0] == current_id:
58
+ observer.on_next(value[0])
60
59
  has_value[0] = False
61
- _id[0] += 1
62
60
 
63
- def on_completed() -> None:
64
- cancelable.dispose()
65
- if has_value[0]:
66
- observer.on_next(value[0])
61
+ d.disposable = _scheduler.schedule_relative(duetime, action)
67
62
 
68
- observer.on_completed()
69
- has_value[0] = False
70
- _id[0] += 1
63
+ def on_error(exception: Exception) -> None:
64
+ cancelable.dispose()
65
+ observer.on_error(exception)
66
+ has_value[0] = False
67
+ _id[0] += 1
71
68
 
72
- subscription = source.subscribe(
73
- on_next, on_error, on_completed, scheduler=scheduler_
74
- )
75
- return CompositeDisposable(subscription, cancelable)
69
+ def on_completed() -> None:
70
+ cancelable.dispose()
71
+ if has_value[0]:
72
+ observer.on_next(value[0])
73
+
74
+ observer.on_completed()
75
+ has_value[0] = False
76
+ _id[0] += 1
76
77
 
77
- return Observable(subscribe)
78
+ subscription = source.subscribe(
79
+ on_next, on_error, on_completed, scheduler=scheduler_
80
+ )
81
+ return CompositeDisposable(subscription, cancelable)
78
82
 
79
- return debounce
83
+ return Observable(subscribe)
80
84
 
81
85
 
86
+ @curry_flip
82
87
  def throttle_with_mapper_(
83
- throttle_duration_mapper: Callable[[Any], Observable[Any]]
84
- ) -> Callable[[Observable[_T]], Observable[_T]]:
85
- def throttle_with_mapper(source: Observable[_T]) -> Observable[_T]:
86
- """Partially applied throttle_with_mapper operator.
87
-
88
- Ignores values from an observable sequence which are followed by
89
- another value within a computed throttle duration.
90
-
91
- Example:
92
- >>> obs = throttle_with_mapper(source)
93
-
94
- Args:
95
- source: The observable source to throttle.
96
-
97
- Returns:
98
- The throttled observable sequence.
99
- """
100
-
101
- def subscribe(
102
- observer: abc.ObserverBase[_T],
103
- scheduler: Optional[abc.SchedulerBase] = None,
104
- ) -> abc.DisposableBase:
105
- cancelable = SerialDisposable()
106
- has_value: bool = False
107
- value: _T = cast(_T, None)
108
- _id = [0]
109
-
110
- def on_next(x: _T) -> None:
111
- nonlocal value, has_value
112
-
113
- throttle = None
114
- try:
115
- throttle = throttle_duration_mapper(x)
116
- except Exception as e: # pylint: disable=broad-except
117
- observer.on_error(e)
118
- return
119
-
120
- has_value = True
121
- value = x
122
- _id[0] += 1
123
- current_id = _id[0]
124
- d = SingleAssignmentDisposable()
125
- cancelable.disposable = d
126
-
127
- def on_next(x: Any) -> None:
128
- nonlocal has_value
129
- if has_value and _id[0] == current_id:
130
- observer.on_next(value)
131
-
132
- has_value = False
133
- d.dispose()
134
-
135
- def on_completed() -> None:
136
- nonlocal has_value
137
- if has_value and _id[0] == current_id:
138
- observer.on_next(value)
139
-
140
- has_value = False
141
- d.dispose()
142
-
143
- d.disposable = throttle.subscribe(
144
- on_next, observer.on_error, on_completed, scheduler=scheduler
145
- )
146
-
147
- def on_error(e: Exception) -> None:
148
- nonlocal has_value
149
- cancelable.dispose()
88
+ source: Observable[_T],
89
+ throttle_duration_mapper: Callable[[Any], Observable[Any]],
90
+ ) -> Observable[_T]:
91
+ """Ignores values from an observable sequence which are followed by
92
+ another value within a computed throttle duration.
93
+
94
+ Examples:
95
+ >>> res = source.pipe(throttle_with_mapper(lambda x: timer(x)))
96
+ >>> res = throttle_with_mapper(lambda x: timer(x))(source)
97
+
98
+ Args:
99
+ source: The observable source to throttle.
100
+ throttle_duration_mapper: Function to compute throttle duration.
101
+
102
+ Returns:
103
+ The throttled observable sequence.
104
+ """
105
+
106
+ def subscribe(
107
+ observer: abc.ObserverBase[_T],
108
+ scheduler: abc.SchedulerBase | None = None,
109
+ ) -> abc.DisposableBase:
110
+ cancelable = SerialDisposable()
111
+ has_value: bool = False
112
+ value: _T = cast(_T, None)
113
+ _id = [0]
114
+
115
+ def on_next(x: _T) -> None:
116
+ nonlocal value, has_value
117
+
118
+ throttle = None
119
+ try:
120
+ throttle = throttle_duration_mapper(x)
121
+ except Exception as e: # pylint: disable=broad-except
150
122
  observer.on_error(e)
123
+ return
124
+
125
+ has_value = True
126
+ value = x
127
+ _id[0] += 1
128
+ current_id = _id[0]
129
+ d = SingleAssignmentDisposable()
130
+ cancelable.disposable = d
131
+
132
+ def on_next(x: Any) -> None:
133
+ nonlocal has_value
134
+ if has_value and _id[0] == current_id:
135
+ observer.on_next(value)
136
+
151
137
  has_value = False
152
- _id[0] += 1
138
+ d.dispose()
153
139
 
154
140
  def on_completed() -> None:
155
141
  nonlocal has_value
156
- cancelable.dispose()
157
- if has_value:
142
+ if has_value and _id[0] == current_id:
158
143
  observer.on_next(value)
159
144
 
160
- observer.on_completed()
161
145
  has_value = False
162
- _id[0] += 1
146
+ d.dispose()
163
147
 
164
- subscription = source.subscribe(
165
- on_next, on_error, on_completed, scheduler=scheduler
148
+ d.disposable = throttle.subscribe(
149
+ on_next, observer.on_error, on_completed, scheduler=scheduler
166
150
  )
167
- return CompositeDisposable(subscription, cancelable)
168
-
169
- return Observable(subscribe)
170
151
 
171
- return throttle_with_mapper
152
+ def on_error(e: Exception) -> None:
153
+ nonlocal has_value
154
+ cancelable.dispose()
155
+ observer.on_error(e)
156
+ has_value = False
157
+ _id[0] += 1
158
+
159
+ def on_completed() -> None:
160
+ nonlocal has_value
161
+ cancelable.dispose()
162
+ if has_value:
163
+ observer.on_next(value)
164
+
165
+ observer.on_completed()
166
+ has_value = False
167
+ _id[0] += 1
168
+
169
+ subscription = source.subscribe(
170
+ on_next, on_error, on_completed, scheduler=scheduler
171
+ )
172
+ return CompositeDisposable(subscription, cancelable)
173
+
174
+ return Observable(subscribe)
172
175
 
173
176
 
174
177
  __all__ = ["debounce_", "throttle_with_mapper_"]