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,86 +1,86 @@
1
- from typing import Any, Callable, List, Optional, TypeVar
1
+ from collections.abc import Callable
2
+ from typing import Any, TypeVar
2
3
 
3
4
  from reactivex import Observable, abc, typing
4
5
  from reactivex.disposable import CompositeDisposable
6
+ from reactivex.internal import curry_flip
5
7
 
6
8
  _T = TypeVar("_T")
7
9
 
8
10
 
11
+ @curry_flip
9
12
  def do_action_(
10
- on_next: Optional[typing.OnNext[_T]] = None,
11
- on_error: Optional[typing.OnError] = None,
12
- on_completed: Optional[typing.OnCompleted] = None,
13
- ) -> Callable[[Observable[_T]], Observable[_T]]:
14
- def do_action(source: Observable[_T]) -> Observable[_T]:
15
- """Invokes an action for each element in the observable
16
- sequence and invokes an action on graceful or exceptional
17
- termination of the observable sequence. This method can be used
18
- for debugging, logging, etc. of query behavior by intercepting
19
- the message stream to run arbitrary actions for messages on the
20
- pipeline.
21
-
22
- Examples:
23
- >>> do_action(send)(observable)
24
- >>> do_action(on_next, on_error)(observable)
25
- >>> do_action(on_next, on_error, on_completed)(observable)
26
-
27
- Args:
28
- on_next: [Optional] Action to invoke for each element in
29
- the observable sequence.
30
- on_error: [Optional] Action to invoke on exceptional
31
- termination of the observable sequence.
32
- on_completed: [Optional] Action to invoke on graceful
33
- termination of the observable sequence.
34
-
35
- Returns:
36
- An observable source sequence with the side-effecting
37
- behavior applied.
38
- """
39
-
40
- def subscribe(
41
- observer: abc.ObserverBase[_T],
42
- scheduler: Optional[abc.SchedulerBase] = None,
43
- ) -> abc.DisposableBase:
44
- def _on_next(x: _T) -> None:
45
- if not on_next:
46
- observer.on_next(x)
47
- else:
48
- try:
49
- on_next(x)
50
- except Exception as e: # pylint: disable=broad-except
51
- observer.on_error(e)
52
-
53
- observer.on_next(x)
54
-
55
- def _on_error(exception: Exception) -> None:
56
- if not on_error:
57
- observer.on_error(exception)
58
- else:
59
- try:
60
- on_error(exception)
61
- except Exception as e: # pylint: disable=broad-except
62
- observer.on_error(e)
63
-
64
- observer.on_error(exception)
65
-
66
- def _on_completed() -> None:
67
- if not on_completed:
68
- observer.on_completed()
69
- else:
70
- try:
71
- on_completed()
72
- except Exception as e: # pylint: disable=broad-except
73
- observer.on_error(e)
74
-
75
- observer.on_completed()
76
-
77
- return source.subscribe(
78
- _on_next, _on_error, _on_completed, scheduler=scheduler
79
- )
80
-
81
- return Observable(subscribe)
82
-
83
- return do_action
13
+ source: Observable[_T],
14
+ on_next: typing.OnNext[_T] | None = None,
15
+ on_error: typing.OnError | None = None,
16
+ on_completed: typing.OnCompleted | None = None,
17
+ ) -> Observable[_T]:
18
+ """Invokes an action for each element in the observable
19
+ sequence and invokes an action on graceful or exceptional
20
+ termination of the observable sequence. This method can be used
21
+ for debugging, logging, etc. of query behavior by intercepting
22
+ the message stream to run arbitrary actions for messages on the
23
+ pipeline.
24
+
25
+ Examples:
26
+ >>> res = source.pipe(do_action(send))
27
+ >>> res = source.pipe(do_action(on_next, on_error))
28
+ >>> res = source.pipe(do_action(on_next, on_error, on_completed))
29
+
30
+ Args:
31
+ source: Source observable.
32
+ on_next: [Optional] Action to invoke for each element in
33
+ the observable sequence.
34
+ on_error: [Optional] Action to invoke on exceptional
35
+ termination of the observable sequence.
36
+ on_completed: [Optional] Action to invoke on graceful
37
+ termination of the observable sequence.
38
+
39
+ Returns:
40
+ An observable source sequence with the side-effecting
41
+ behavior applied.
42
+ """
43
+
44
+ def subscribe(
45
+ observer: abc.ObserverBase[_T],
46
+ scheduler: abc.SchedulerBase | None = None,
47
+ ) -> abc.DisposableBase:
48
+ def _on_next(x: _T) -> None:
49
+ if not on_next:
50
+ observer.on_next(x)
51
+ else:
52
+ try:
53
+ on_next(x)
54
+ except Exception as e: # pylint: disable=broad-except
55
+ observer.on_error(e)
56
+
57
+ observer.on_next(x)
58
+
59
+ def _on_error(exception: Exception) -> None:
60
+ if not on_error:
61
+ observer.on_error(exception)
62
+ else:
63
+ try:
64
+ on_error(exception)
65
+ except Exception as e: # pylint: disable=broad-except
66
+ observer.on_error(e)
67
+
68
+ observer.on_error(exception)
69
+
70
+ def _on_completed() -> None:
71
+ if not on_completed:
72
+ observer.on_completed()
73
+ else:
74
+ try:
75
+ on_completed()
76
+ except Exception as e: # pylint: disable=broad-except
77
+ observer.on_error(e)
78
+
79
+ observer.on_completed()
80
+
81
+ return source.subscribe(_on_next, _on_error, _on_completed, scheduler=scheduler)
82
+
83
+ return Observable(subscribe)
84
84
 
85
85
 
86
86
  def do_(observer: abc.ObserverBase[_T]) -> Callable[[Observable[_T]], Observable[_T]]:
@@ -114,7 +114,7 @@ def do_after_next(
114
114
  """
115
115
 
116
116
  def subscribe(
117
- observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None
117
+ observer: abc.ObserverBase[_T], scheduler: abc.SchedulerBase | None = None
118
118
  ) -> abc.DisposableBase:
119
119
  def on_next(value: _T):
120
120
  try:
@@ -139,7 +139,7 @@ def do_on_subscribe(source: Observable[Any], on_subscribe: typing.Action):
139
139
  """
140
140
 
141
141
  def subscribe(
142
- observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
142
+ observer: abc.ObserverBase[Any], scheduler: abc.SchedulerBase | None = None
143
143
  ) -> abc.DisposableBase:
144
144
  on_subscribe()
145
145
  return source.subscribe(
@@ -167,7 +167,7 @@ def do_on_dispose(source: Observable[Any], on_dispose: typing.Action):
167
167
  on_dispose()
168
168
 
169
169
  def subscribe(
170
- observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
170
+ observer: abc.ObserverBase[Any], scheduler: abc.SchedulerBase | None = None
171
171
  ) -> abc.DisposableBase:
172
172
  composite_disposable = CompositeDisposable()
173
173
  composite_disposable.add(OnDispose())
@@ -193,7 +193,7 @@ def do_on_terminate(source: Observable[Any], on_terminate: typing.Action):
193
193
  """
194
194
 
195
195
  def subscribe(
196
- observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
196
+ observer: abc.ObserverBase[Any], scheduler: abc.SchedulerBase | None = None
197
197
  ) -> abc.DisposableBase:
198
198
  def on_completed():
199
199
  try:
@@ -228,7 +228,7 @@ def do_after_terminate(source: Observable[Any], after_terminate: typing.Action):
228
228
  """
229
229
 
230
230
  def subscribe(
231
- observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
231
+ observer: abc.ObserverBase[Any], scheduler: abc.SchedulerBase | None = None
232
232
  ) -> abc.DisposableBase:
233
233
  def on_completed():
234
234
  observer.on_completed()
@@ -251,9 +251,11 @@ def do_after_terminate(source: Observable[Any], after_terminate: typing.Action):
251
251
  return Observable(subscribe)
252
252
 
253
253
 
254
+ @curry_flip
254
255
  def do_finally(
256
+ source: Observable[_T],
255
257
  finally_action: typing.Action,
256
- ) -> Callable[[Observable[_T]], Observable[_T]]:
258
+ ) -> Observable[_T]:
257
259
  """Invokes an action after an on_complete(), on_error(), or disposal
258
260
  event occurs.
259
261
 
@@ -263,13 +265,21 @@ def do_finally(
263
265
  Note this operator will strive to execute the finally_action once,
264
266
  and prevent any redudant calls
265
267
 
268
+ Examples:
269
+ >>> res = source.pipe(do_finally(lambda: print("done")))
270
+ >>> res = do_finally(lambda: print("done"))(source)
271
+
266
272
  Args:
267
- finally_action -- Action to invoke after on_complete, on_error,
268
- or disposal is called
273
+ source: Source observable.
274
+ finally_action: Action to invoke after on_complete, on_error,
275
+ or disposal is called
276
+
277
+ Returns:
278
+ An observable sequence with the finally action applied.
269
279
  """
270
280
 
271
281
  class OnDispose(abc.DisposableBase):
272
- def __init__(self, was_invoked: List[bool]):
282
+ def __init__(self, was_invoked: list[bool]):
273
283
  self.was_invoked = was_invoked
274
284
 
275
285
  def dispose(self) -> None:
@@ -277,43 +287,40 @@ def do_finally(
277
287
  finally_action()
278
288
  self.was_invoked[0] = True
279
289
 
280
- def partial(source: Observable[_T]) -> Observable[_T]:
281
- def subscribe(
282
- observer: abc.ObserverBase[_T],
283
- scheduler: Optional[abc.SchedulerBase] = None,
284
- ) -> abc.DisposableBase:
285
- was_invoked = [False]
286
-
287
- def on_completed():
288
- observer.on_completed()
289
- try:
290
- if not was_invoked[0]:
291
- finally_action()
292
- was_invoked[0] = True
293
- except Exception as err: # pylint: disable=broad-except
294
- observer.on_error(err)
290
+ def subscribe(
291
+ observer: abc.ObserverBase[_T],
292
+ scheduler: abc.SchedulerBase | None = None,
293
+ ) -> abc.DisposableBase:
294
+ was_invoked = [False]
295
295
 
296
- def on_error(exception: Exception):
297
- observer.on_error(exception)
298
- try:
299
- if not was_invoked[0]:
300
- finally_action()
301
- was_invoked[0] = True
302
- except Exception as err: # pylint: disable=broad-except
303
- observer.on_error(err)
296
+ def on_completed():
297
+ observer.on_completed()
298
+ try:
299
+ if not was_invoked[0]:
300
+ finally_action()
301
+ was_invoked[0] = True
302
+ except Exception as err: # pylint: disable=broad-except
303
+ observer.on_error(err)
304
304
 
305
- composite_disposable = CompositeDisposable()
306
- composite_disposable.add(OnDispose(was_invoked))
307
- subscription = source.subscribe(
308
- observer.on_next, on_error, on_completed, scheduler=scheduler
309
- )
310
- composite_disposable.add(subscription)
305
+ def on_error(exception: Exception):
306
+ observer.on_error(exception)
307
+ try:
308
+ if not was_invoked[0]:
309
+ finally_action()
310
+ was_invoked[0] = True
311
+ except Exception as err: # pylint: disable=broad-except
312
+ observer.on_error(err)
311
313
 
312
- return composite_disposable
314
+ composite_disposable = CompositeDisposable()
315
+ composite_disposable.add(OnDispose(was_invoked))
316
+ subscription = source.subscribe(
317
+ observer.on_next, on_error, on_completed, scheduler=scheduler
318
+ )
319
+ composite_disposable.add(subscription)
313
320
 
314
- return Observable(subscribe)
321
+ return composite_disposable
315
322
 
316
- return partial
323
+ return Observable(subscribe)
317
324
 
318
325
 
319
326
  __all__ = [
@@ -1,4 +1,5 @@
1
- from typing import Callable, TypeVar
1
+ from collections.abc import Callable
2
+ from typing import TypeVar
2
3
 
3
4
  from reactivex import Observable
4
5
  from reactivex import operators as ops
@@ -7,7 +8,7 @@ _T = TypeVar("_T")
7
8
 
8
9
 
9
10
  def do_while_(
10
- condition: Callable[[Observable[_T]], bool]
11
+ condition: Callable[[Observable[_T]], bool],
11
12
  ) -> Callable[[Observable[_T]], Observable[_T]]:
12
13
  """Repeats source as long as condition holds emulating a do while
13
14
  loop.
@@ -1,51 +1,75 @@
1
- from typing import Callable, Optional, TypeVar, cast
1
+ from typing import TypeVar, cast
2
2
 
3
3
  from reactivex import Observable, abc
4
+ from reactivex.internal import curry_flip
4
5
  from reactivex.internal.exceptions import ArgumentOutOfRangeException
5
6
 
6
7
  _T = TypeVar("_T")
7
8
 
8
9
 
10
+ @curry_flip
9
11
  def element_at_or_default_(
10
- index: int, has_default: bool = False, default_value: Optional[_T] = None
11
- ) -> Callable[[Observable[_T]], Observable[_T]]:
12
+ source: Observable[_T],
13
+ index: int,
14
+ has_default: bool = False,
15
+ default_value: _T | None = None,
16
+ ) -> Observable[_T]:
17
+ """Returns the element at a specified index in a sequence or a default value
18
+ if the index is out of range.
19
+
20
+ Examples:
21
+ >>> result = source.pipe(element_at_or_default(5))
22
+ >>> result = element_at_or_default(5)(source)
23
+ >>> result = source.pipe(element_at_or_default(5, True, 0))
24
+
25
+ Args:
26
+ source: The source observable sequence.
27
+ index: The zero-based index of the element to retrieve.
28
+ has_default: Whether to return a default value if index is out of range.
29
+ default_value: The default value to return if has_default is True.
30
+
31
+ Returns:
32
+ An observable sequence that produces the element at the specified
33
+ position in the source sequence, or a default value if the index is
34
+ out of range.
35
+
36
+ Raises:
37
+ ArgumentOutOfRangeException: If index is negative.
38
+ """
12
39
  if index < 0:
13
40
  raise ArgumentOutOfRangeException()
14
41
 
15
- def element_at_or_default(source: Observable[_T]) -> Observable[_T]:
16
- def subscribe(
17
- observer: abc.ObserverBase[_T],
18
- scheduler: Optional[abc.SchedulerBase] = None,
19
- ) -> abc.DisposableBase:
20
- index_ = index
21
-
22
- def on_next(x: _T) -> None:
23
- nonlocal index_
24
- found = False
25
- with source.lock:
26
- if index_:
27
- index_ -= 1
28
- else:
29
- found = True
30
-
31
- if found:
32
- observer.on_next(x)
33
- observer.on_completed()
34
-
35
- def on_completed():
36
- if not has_default:
37
- observer.on_error(ArgumentOutOfRangeException())
42
+ def subscribe(
43
+ observer: abc.ObserverBase[_T],
44
+ scheduler: abc.SchedulerBase | None = None,
45
+ ) -> abc.DisposableBase:
46
+ index_ = index
47
+
48
+ def on_next(x: _T) -> None:
49
+ nonlocal index_
50
+ found = False
51
+ with source.lock:
52
+ if index_:
53
+ index_ -= 1
38
54
  else:
39
- observer.on_next(cast(_T, default_value))
40
- observer.on_completed()
55
+ found = True
56
+
57
+ if found:
58
+ observer.on_next(x)
59
+ observer.on_completed()
41
60
 
42
- return source.subscribe(
43
- on_next, observer.on_error, on_completed, scheduler=scheduler
44
- )
61
+ def on_completed():
62
+ if not has_default:
63
+ observer.on_error(ArgumentOutOfRangeException())
64
+ else:
65
+ observer.on_next(cast(_T, default_value))
66
+ observer.on_completed()
45
67
 
46
- return Observable(subscribe)
68
+ return source.subscribe(
69
+ on_next, observer.on_error, on_completed, scheduler=scheduler
70
+ )
47
71
 
48
- return element_at_or_default
72
+ return Observable(subscribe)
49
73
 
50
74
 
51
75
  __all__ = ["element_at_or_default_"]
@@ -1,74 +1,80 @@
1
1
  from asyncio import Future
2
- from typing import Callable, Optional, TypeVar, Union
2
+ from typing import TypeVar, Union
3
3
 
4
4
  import reactivex
5
5
  from reactivex import Observable, abc
6
6
  from reactivex.disposable import CompositeDisposable, SingleAssignmentDisposable
7
+ from reactivex.internal import curry_flip
7
8
 
8
9
  _T = TypeVar("_T")
9
10
 
10
11
 
11
- def exclusive_() -> Callable[[Observable[Observable[_T]]], Observable[_T]]:
12
+ @curry_flip
13
+ def exclusive_(source: Observable[Observable[_T]]) -> Observable[_T]:
12
14
  """Performs a exclusive waiting for the first to finish before
13
15
  subscribing to another observable. Observables that come in between
14
16
  subscriptions will be dropped on the floor.
15
17
 
18
+ Examples:
19
+ >>> res = source.pipe(exclusive())
20
+ >>> res = exclusive()(source)
21
+
22
+ Args:
23
+ source: Source observable of observables.
24
+
16
25
  Returns:
17
26
  An exclusive observable with only the results that
18
27
  happen when subscribed.
19
28
  """
20
29
 
21
- def exclusive(source: Observable[Observable[_T]]) -> Observable[_T]:
22
- def subscribe(
23
- observer: abc.ObserverBase[_T],
24
- scheduler: Optional[abc.SchedulerBase] = None,
25
- ) -> abc.DisposableBase:
26
- has_current = [False]
27
- is_stopped = [False]
28
- m = SingleAssignmentDisposable()
29
- g = CompositeDisposable()
30
-
31
- g.add(m)
32
-
33
- def on_next(inner_source: Union[Observable[_T], "Future[_T]"]) -> None:
34
- if not has_current[0]:
35
- has_current[0] = True
36
-
37
- inner_source = (
38
- reactivex.from_future(inner_source)
39
- if isinstance(inner_source, Future)
40
- else inner_source
41
- )
42
-
43
- inner_subscription = SingleAssignmentDisposable()
44
- g.add(inner_subscription)
45
-
46
- def on_completed_inner():
47
- g.remove(inner_subscription)
48
- has_current[0] = False
49
- if is_stopped[0] and len(g) == 1:
50
- observer.on_completed()
51
-
52
- inner_subscription.disposable = inner_source.subscribe(
53
- observer.on_next,
54
- observer.on_error,
55
- on_completed_inner,
56
- scheduler=scheduler,
57
- )
58
-
59
- def on_completed() -> None:
60
- is_stopped[0] = True
61
- if not has_current[0] and len(g) == 1:
62
- observer.on_completed()
63
-
64
- m.disposable = source.subscribe(
65
- on_next, observer.on_error, on_completed, scheduler=scheduler
66
- )
67
- return g
68
-
69
- return Observable(subscribe)
70
-
71
- return exclusive
30
+ def subscribe(
31
+ observer: abc.ObserverBase[_T],
32
+ scheduler: abc.SchedulerBase | None = None,
33
+ ) -> abc.DisposableBase:
34
+ has_current = [False]
35
+ is_stopped = [False]
36
+ m = SingleAssignmentDisposable()
37
+ g = CompositeDisposable()
38
+
39
+ g.add(m)
40
+
41
+ def on_next(inner_source: Union[Observable[_T], "Future[_T]"]) -> None:
42
+ if not has_current[0]:
43
+ has_current[0] = True
44
+
45
+ inner_source = (
46
+ reactivex.from_future(inner_source)
47
+ if isinstance(inner_source, Future)
48
+ else inner_source
49
+ )
50
+
51
+ inner_subscription = SingleAssignmentDisposable()
52
+ g.add(inner_subscription)
53
+
54
+ def on_completed_inner():
55
+ g.remove(inner_subscription)
56
+ has_current[0] = False
57
+ if is_stopped[0] and len(g) == 1:
58
+ observer.on_completed()
59
+
60
+ inner_subscription.disposable = inner_source.subscribe(
61
+ observer.on_next,
62
+ observer.on_error,
63
+ on_completed_inner,
64
+ scheduler=scheduler,
65
+ )
66
+
67
+ def on_completed() -> None:
68
+ is_stopped[0] = True
69
+ if not has_current[0] and len(g) == 1:
70
+ observer.on_completed()
71
+
72
+ m.disposable = source.subscribe(
73
+ on_next, observer.on_error, on_completed, scheduler=scheduler
74
+ )
75
+ return g
76
+
77
+ return Observable(subscribe)
72
78
 
73
79
 
74
80
  __all__ = ["exclusive_"]