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,4 +1,4 @@
1
- from typing import Any, Callable, List, Optional, TypeVar
1
+ from typing import Any, TypeVar
2
2
 
3
3
  from reactivex import Observable, abc, typing
4
4
  from reactivex.disposable import (
@@ -6,97 +6,102 @@ from reactivex.disposable import (
6
6
  SerialDisposable,
7
7
  SingleAssignmentDisposable,
8
8
  )
9
+ from reactivex.internal import curry_flip
9
10
  from reactivex.scheduler import ImmediateScheduler
10
11
 
11
12
  _T = TypeVar("_T")
12
13
 
13
14
 
15
+ @curry_flip
14
16
  def expand_(
15
- mapper: typing.Mapper[_T, Observable[_T]]
16
- ) -> Callable[[Observable[_T]], Observable[_T]]:
17
- def expand(source: Observable[_T]) -> Observable[_T]:
18
- """Expands an observable sequence by recursively invoking
19
- mapper.
20
-
21
- Args:
22
- source: Source obserable to expand.
23
-
24
- Returns:
25
- An observable sequence containing all the elements produced
26
- by the recursive expansion.
27
- """
28
-
29
- def subscribe(
30
- observer: abc.ObserverBase[_T],
31
- scheduler: Optional[abc.SchedulerBase] = None,
32
- ) -> abc.DisposableBase:
33
- scheduler = scheduler or ImmediateScheduler.singleton()
34
-
35
- queue: List[Observable[_T]] = []
36
- m = SerialDisposable()
37
- d = CompositeDisposable(m)
38
- active_count = 0
39
- is_acquired = False
40
-
41
- def ensure_active():
42
- nonlocal is_acquired
43
-
44
- is_owner = False
45
- if queue:
46
- is_owner = not is_acquired
47
- is_acquired = True
48
-
49
- def action(scheduler: abc.SchedulerBase, state: Any = None):
50
- nonlocal is_acquired, active_count
17
+ source: Observable[_T],
18
+ mapper: typing.Mapper[_T, Observable[_T]],
19
+ ) -> Observable[_T]:
20
+ """Expands an observable sequence by recursively invoking
21
+ mapper.
22
+
23
+ Examples:
24
+ >>> source.pipe(expand(lambda x: of(x * 2)))
25
+ >>> expand(lambda x: of(x * 2))(source)
26
+
27
+ Args:
28
+ source: Source observable to expand.
29
+ mapper: Function to recursively map elements.
30
+
31
+ Returns:
32
+ An observable sequence containing all the elements produced
33
+ by the recursive expansion.
34
+ """
35
+
36
+ def subscribe(
37
+ observer: abc.ObserverBase[_T],
38
+ scheduler: abc.SchedulerBase | None = None,
39
+ ) -> abc.DisposableBase:
40
+ scheduler = scheduler or ImmediateScheduler.singleton()
41
+
42
+ queue: list[Observable[_T]] = []
43
+ m = SerialDisposable()
44
+ d = CompositeDisposable(m)
45
+ active_count = 0
46
+ is_acquired = False
47
+
48
+ def ensure_active():
49
+ nonlocal is_acquired
50
+
51
+ is_owner = False
52
+ if queue:
53
+ is_owner = not is_acquired
54
+ is_acquired = True
55
+
56
+ def action(scheduler: abc.SchedulerBase, state: Any = None):
57
+ nonlocal is_acquired, active_count
51
58
 
52
- if queue:
53
- work = queue.pop(0)
54
- else:
55
- is_acquired = False
59
+ if queue:
60
+ work = queue.pop(0)
61
+ else:
62
+ is_acquired = False
63
+ return
64
+
65
+ sad = SingleAssignmentDisposable()
66
+ d.add(sad)
67
+
68
+ def on_next(value: _T) -> None:
69
+ nonlocal active_count
70
+
71
+ observer.on_next(value)
72
+ result = None
73
+ try:
74
+ result = mapper(value)
75
+ except Exception as ex:
76
+ observer.on_error(ex)
56
77
  return
57
78
 
58
- sad = SingleAssignmentDisposable()
59
- d.add(sad)
60
-
61
- def on_next(value: _T) -> None:
62
- nonlocal active_count
63
-
64
- observer.on_next(value)
65
- result = None
66
- try:
67
- result = mapper(value)
68
- except Exception as ex:
69
- observer.on_error(ex)
70
- return
71
-
72
- queue.append(result)
73
- active_count += 1
74
- ensure_active()
75
-
76
- def on_complete() -> None:
77
- nonlocal active_count
79
+ queue.append(result)
80
+ active_count += 1
81
+ ensure_active()
78
82
 
79
- d.remove(sad)
80
- active_count -= 1
81
- if active_count == 0:
82
- observer.on_completed()
83
+ def on_complete() -> None:
84
+ nonlocal active_count
83
85
 
84
- sad.disposable = work.subscribe(
85
- on_next, observer.on_error, on_complete, scheduler=scheduler
86
- )
87
- m.disposable = scheduler.schedule(action)
86
+ d.remove(sad)
87
+ active_count -= 1
88
+ if active_count == 0:
89
+ observer.on_completed()
88
90
 
89
- if is_owner:
90
- m.disposable = scheduler.schedule(action)
91
+ sad.disposable = work.subscribe(
92
+ on_next, observer.on_error, on_complete, scheduler=scheduler
93
+ )
94
+ m.disposable = scheduler.schedule(action)
91
95
 
92
- queue.append(source)
93
- active_count += 1
94
- ensure_active()
95
- return d
96
+ if is_owner:
97
+ m.disposable = scheduler.schedule(action)
96
98
 
97
- return Observable(subscribe)
99
+ queue.append(source)
100
+ active_count += 1
101
+ ensure_active()
102
+ return d
98
103
 
99
- return expand
104
+ return Observable(subscribe)
100
105
 
101
106
 
102
107
  __all__ = ["expand_"]
@@ -1,98 +1,93 @@
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
  from reactivex.typing import Predicate, PredicateIndexed
5
6
 
6
7
  _T = TypeVar("_T")
7
8
 
8
9
 
9
10
  # pylint: disable=redefined-builtin
10
- def filter_(predicate: Predicate[_T]) -> Callable[[Observable[_T]], Observable[_T]]:
11
- def filter(source: Observable[_T]) -> Observable[_T]:
12
- """Partially applied filter operator.
11
+ @curry_flip
12
+ def filter_(source: Observable[_T], predicate: Predicate[_T]) -> Observable[_T]:
13
+ """Filters the elements of an observable sequence based on a predicate.
13
14
 
14
- Filters the elements of an observable sequence based on a
15
- predicate.
15
+ Example:
16
+ >>> result = source.pipe(filter(lambda x: x > 5))
17
+ >>> result = filter(lambda x: x > 5)(source)
16
18
 
17
- Example:
18
- >>> filter(source)
19
+ Args:
20
+ source: Source observable to filter.
21
+ predicate: A function to test each element for a condition.
19
22
 
20
- Args:
21
- source: Source observable to filter.
23
+ Returns:
24
+ A filtered observable sequence.
25
+ """
22
26
 
23
- Returns:
24
- A filtered observable sequence.
25
- """
27
+ def subscribe(
28
+ observer: abc.ObserverBase[_T], scheduler: abc.SchedulerBase | None
29
+ ) -> abc.DisposableBase:
30
+ def on_next(value: _T):
31
+ try:
32
+ should_run = predicate(value)
33
+ except Exception as ex: # pylint: disable=broad-except
34
+ observer.on_error(ex)
35
+ return
26
36
 
27
- def subscribe(
28
- observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase]
29
- ) -> abc.DisposableBase:
30
- def on_next(value: _T):
31
- try:
32
- should_run = predicate(value)
33
- except Exception as ex: # pylint: disable=broad-except
34
- observer.on_error(ex)
35
- return
36
-
37
- if should_run:
38
- observer.on_next(value)
39
-
40
- return source.subscribe(
41
- on_next, observer.on_error, observer.on_completed, scheduler=scheduler
42
- )
37
+ if should_run:
38
+ observer.on_next(value)
43
39
 
44
- return Observable(subscribe)
40
+ return source.subscribe(
41
+ on_next, observer.on_error, observer.on_completed, scheduler=scheduler
42
+ )
45
43
 
46
- return filter
44
+ return Observable(subscribe)
47
45
 
48
46
 
47
+ @curry_flip
49
48
  def filter_indexed_(
50
- predicate_indexed: Optional[PredicateIndexed[_T]] = None,
51
- ) -> Callable[[Observable[_T]], Observable[_T]]:
52
- def filter_indexed(source: Observable[_T]) -> Observable[_T]:
53
- """Partially applied indexed filter operator.
49
+ source: Observable[_T],
50
+ predicate_indexed: PredicateIndexed[_T] | None = None,
51
+ ) -> Observable[_T]:
52
+ """Filters the elements of an observable sequence based on a predicate
53
+ by incorporating the element's index.
54
54
 
55
- Filters the elements of an observable sequence based on a
56
- predicate by incorporating the element's index.
55
+ Example:
56
+ >>> result = source.pipe(filter_indexed(lambda x, i: i % 2 == 0))
57
+ >>> result = filter_indexed(lambda x, i: i % 2 == 0)(source)
57
58
 
58
- Example:
59
- >>> filter_indexed(source)
59
+ Args:
60
+ source: Source observable to filter.
61
+ predicate_indexed: A function to test each element with its index.
60
62
 
61
- Args:
62
- source: Source observable to filter.
63
+ Returns:
64
+ A filtered observable sequence.
65
+ """
63
66
 
64
- Returns:
65
- A filtered observable sequence.
66
- """
67
+ def subscribe(observer: abc.ObserverBase[_T], scheduler: abc.SchedulerBase | None):
68
+ count = 0
67
69
 
68
- def subscribe(
69
- observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase]
70
- ):
71
- count = 0
70
+ def on_next(value: _T):
71
+ nonlocal count
72
+ should_run = True
72
73
 
73
- def on_next(value: _T):
74
- nonlocal count
75
- should_run = True
76
-
77
- if predicate_indexed:
78
- try:
79
- should_run = predicate_indexed(value, count)
80
- except Exception as ex: # pylint: disable=broad-except
81
- observer.on_error(ex)
82
- return
83
- else:
84
- count += 1
85
-
86
- if should_run:
87
- observer.on_next(value)
74
+ if predicate_indexed:
75
+ try:
76
+ should_run = predicate_indexed(value, count)
77
+ except Exception as ex: # pylint: disable=broad-except
78
+ observer.on_error(ex)
79
+ return
80
+ else:
81
+ count += 1
88
82
 
89
- return source.subscribe(
90
- on_next, observer.on_error, observer.on_completed, scheduler=scheduler
91
- )
83
+ if should_run:
84
+ observer.on_next(value)
92
85
 
93
- return Observable(subscribe)
86
+ return source.subscribe(
87
+ on_next, observer.on_error, observer.on_completed, scheduler=scheduler
88
+ )
94
89
 
95
- return filter_indexed
90
+ return Observable(subscribe)
96
91
 
97
92
 
98
93
  __all__ = ["filter_", "filter_indexed_"]
@@ -1,4 +1,5 @@
1
- from typing import Callable, Optional, TypeVar
1
+ from collections.abc import Callable
2
+ from typing import TypeVar
2
3
 
3
4
  from reactivex import Observable, abc, typing
4
5
  from reactivex.disposable import Disposable
@@ -26,7 +27,7 @@ def finally_action_(
26
27
 
27
28
  def subscribe(
28
29
  observer: abc.ObserverBase[_T],
29
- scheduler: Optional[abc.SchedulerBase] = None,
30
+ scheduler: abc.SchedulerBase | None = None,
30
31
  ) -> abc.DisposableBase:
31
32
  try:
32
33
  subscription = source.subscribe(observer, scheduler=scheduler)
@@ -1,46 +1,63 @@
1
- from typing import Callable, Optional, TypeVar, Union
1
+ from collections.abc import Callable
2
+ from typing import TypeVar
2
3
 
3
4
  from reactivex import Observable, abc
5
+ from reactivex.internal import curry_flip
4
6
 
5
7
  _T = TypeVar("_T")
6
8
 
7
9
 
10
+ @curry_flip
8
11
  def find_value_(
9
- predicate: Callable[[_T, int, Observable[_T]], bool], yield_index: bool
10
- ) -> Callable[[Observable[_T]], Observable[Union[_T, int, None]]]:
11
- def find_value(source: Observable[_T]) -> Observable[Union[_T, int, None]]:
12
- def subscribe(
13
- observer: abc.ObserverBase[Union[_T, int, None]],
14
- scheduler: Optional[abc.SchedulerBase] = None,
15
- ) -> abc.DisposableBase:
16
- index = 0
17
-
18
- def on_next(x: _T) -> None:
19
- nonlocal index
20
- should_run = False
21
- try:
22
- should_run = predicate(x, index, source)
23
- except Exception as ex: # pylint: disable=broad-except
24
- observer.on_error(ex)
25
- return
26
-
27
- if should_run:
28
- observer.on_next(index if yield_index else x)
29
- observer.on_completed()
30
- else:
31
- index += 1
32
-
33
- def on_completed():
34
- observer.on_next(-1 if yield_index else None)
12
+ source: Observable[_T],
13
+ predicate: Callable[[_T, int, Observable[_T]], bool],
14
+ yield_index: bool,
15
+ ) -> Observable[_T | int | None]:
16
+ """Searches for an element in an observable sequence.
17
+
18
+ Examples:
19
+ >>> res = source.pipe(find_value(lambda x, i, s: x > 3, False))
20
+ >>> res = find_value(lambda x, i, s: x > 3, False)(source)
21
+
22
+ Args:
23
+ source: The source observable sequence.
24
+ predicate: A function to test each element.
25
+ yield_index: Whether to yield the index or the value.
26
+
27
+ Returns:
28
+ An observable sequence containing the found element or index.
29
+ """
30
+
31
+ def subscribe(
32
+ observer: abc.ObserverBase[_T | int | None],
33
+ scheduler: abc.SchedulerBase | None = None,
34
+ ) -> abc.DisposableBase:
35
+ index = 0
36
+
37
+ def on_next(x: _T) -> None:
38
+ nonlocal index
39
+ should_run = False
40
+ try:
41
+ should_run = predicate(x, index, source)
42
+ except Exception as ex: # pylint: disable=broad-except
43
+ observer.on_error(ex)
44
+ return
45
+
46
+ if should_run:
47
+ observer.on_next(index if yield_index else x)
35
48
  observer.on_completed()
49
+ else:
50
+ index += 1
36
51
 
37
- return source.subscribe(
38
- on_next, observer.on_error, on_completed, scheduler=scheduler
39
- )
52
+ def on_completed():
53
+ observer.on_next(-1 if yield_index else None)
54
+ observer.on_completed()
40
55
 
41
- return Observable(subscribe)
56
+ return source.subscribe(
57
+ on_next, observer.on_error, on_completed, scheduler=scheduler
58
+ )
42
59
 
43
- return find_value
60
+ return Observable(subscribe)
44
61
 
45
62
 
46
63
  __all__ = ["find_value_"]
@@ -1,7 +1,8 @@
1
- from typing import Callable, Optional, TypeVar
1
+ from typing import TypeVar, cast
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
  from ._firstordefault import first_or_default_async_
@@ -9,32 +10,38 @@ from ._firstordefault import first_or_default_async_
9
10
  _T = TypeVar("_T")
10
11
 
11
12
 
13
+ @curry_flip
12
14
  def first_(
13
- predicate: Optional[Predicate[_T]] = None,
14
- ) -> Callable[[Observable[_T]], Observable[_T]]:
15
+ source: Observable[_T],
16
+ predicate: Predicate[_T] | None = None,
17
+ ) -> Observable[_T]:
15
18
  """Returns the first element of an observable sequence that
16
19
  satisfies the condition in the predicate if present else the first
17
20
  item in the sequence.
18
21
 
19
22
  Examples:
20
- >>> res = res = first()(source)
21
- >>> res = res = first(lambda x: x > 3)(source)
23
+ >>> res = source.pipe(first())
24
+ >>> res = first()(source)
25
+ >>> res = source.pipe(first(lambda x: x > 3))
22
26
 
23
27
  Args:
24
- predicate -- [Optional] A predicate function to evaluate for
28
+ source: The source observable sequence.
29
+ predicate: [Optional] A predicate function to evaluate for
25
30
  elements in the source sequence.
26
31
 
27
32
  Returns:
28
- A function that takes an observable source and returns an
29
- observable sequence containing the first element in the
33
+ An observable sequence containing the first element in the
30
34
  observable sequence that satisfies the condition in the predicate if
31
35
  provided, else the first item in the sequence.
32
36
  """
33
37
 
34
38
  if predicate:
35
- return compose(ops.filter(predicate), ops.first())
39
+ return source.pipe(ops.filter(predicate), ops.first())
36
40
 
37
- return first_or_default_async_(False)
41
+ # first_or_default_async_(False) returns
42
+ # Callable[[Observable[_T]], Observable[_T]] but the type checker
43
+ # cannot infer it. This cast is safe - implementation preserves type.
44
+ return cast(Observable[_T], first_or_default_async_(False)(source))
38
45
 
39
46
 
40
47
  __all__ = ["first_"]
@@ -1,4 +1,5 @@
1
- from typing import Callable, Optional, TypeVar, cast
1
+ from collections.abc import Callable
2
+ from typing import TypeVar, cast
2
3
 
3
4
  from reactivex import Observable, abc, compose
4
5
  from reactivex import operators as ops
@@ -9,12 +10,12 @@ _T = TypeVar("_T")
9
10
 
10
11
 
11
12
  def first_or_default_async_(
12
- has_default: bool = False, default_value: Optional[_T] = None
13
+ has_default: bool = False, default_value: _T | None = None
13
14
  ) -> Callable[[Observable[_T]], Observable[_T]]:
14
15
  def first_or_default_async(source: Observable[_T]) -> Observable[_T]:
15
16
  def subscribe(
16
17
  observer: abc.ObserverBase[_T],
17
- scheduler: Optional[abc.SchedulerBase] = None,
18
+ scheduler: abc.SchedulerBase | None = None,
18
19
  ):
19
20
  def on_next(x: _T):
20
21
  observer.on_next(x)
@@ -37,7 +38,7 @@ def first_or_default_async_(
37
38
 
38
39
 
39
40
  def first_or_default_(
40
- predicate: Optional[Predicate[_T]] = None, default_value: Optional[_T] = None
41
+ predicate: Predicate[_T] | None = None, default_value: _T | None = None
41
42
  ) -> Callable[[Observable[_T]], Observable[_T]]:
42
43
  """Returns the first element of an observable sequence that
43
44
  satisfies the condition in the predicate, or a default value if no