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
@@ -0,0 +1,632 @@
1
+ """Transformation operators mixin for Observable."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast, overload
7
+
8
+ from typing_extensions import TypeVarTuple, Unpack
9
+
10
+ from reactivex import typing
11
+ from reactivex.internal.utils import NotSet
12
+
13
+ if TYPE_CHECKING:
14
+ from reactivex.observable import Observable
15
+
16
+ _T = TypeVar("_T", covariant=True)
17
+ _A = TypeVar("_A")
18
+ _B = TypeVar("_B")
19
+ _Ts = TypeVarTuple("_Ts")
20
+
21
+
22
+ class TransformationMixin(Generic[_T]):
23
+ """Mixin providing transformation operators for Observable.
24
+
25
+ This mixin adds operators that transform elements in various ways,
26
+ including mapping, flattening, and accumulation.
27
+
28
+ Generic over _T to preserve the Observable's element type and provide
29
+ full type safety without Any types.
30
+ """
31
+
32
+ def _as_observable(self) -> Observable[_T]:
33
+ """Cast mixin instance to Observable preserving type parameter.
34
+
35
+ This is safe because this mixin is only ever used as part of the Observable
36
+ class through multiple inheritance. At runtime, `self` in mixin methods will
37
+ always be an Observable[_T] instance. The type checker cannot infer this
38
+ because it analyzes mixins in isolation.
39
+
40
+ Returns:
41
+ The instance cast to Observable[_T] for type-safe method access.
42
+ """
43
+ return cast("Observable[_T]", self)
44
+
45
+ def map(self, mapper: typing.Mapper[_T, _B]) -> Observable[_B]:
46
+ """Map each element to a new value.
47
+
48
+ Projects each element of an observable sequence into a new form by applying
49
+ a transform function to each element.
50
+
51
+ Examples:
52
+ Fluent style:
53
+ >>> result = source.map(lambda x: x * 2)
54
+ >>> result = source.map(str) # Transform int to str
55
+
56
+ Equivalent pipe style:
57
+ >>> from reactivex import operators as ops
58
+ >>> result = source.pipe(ops.map(lambda x: x * 2))
59
+
60
+ Args:
61
+ mapper: A transform function to apply to each source element.
62
+
63
+ Returns:
64
+ An observable sequence whose elements are the result of invoking
65
+ the transform function on each element of the source.
66
+
67
+ See Also:
68
+ - :func:`map <reactivex.operators.map>`
69
+ - :meth:`map_indexed`
70
+ """
71
+ from reactivex import operators as ops
72
+
73
+ return self._as_observable().pipe(ops.map(mapper))
74
+
75
+ @overload
76
+ def reduce(self, accumulator: typing.Accumulator[_T, _T]) -> Observable[_T]: ...
77
+
78
+ @overload
79
+ def reduce(
80
+ self, accumulator: typing.Accumulator[_A, _T], seed: _A
81
+ ) -> Observable[_A]: ...
82
+
83
+ def reduce(
84
+ self,
85
+ accumulator: typing.Accumulator[_A, _T],
86
+ seed: _A | type[NotSet] = NotSet,
87
+ ) -> Observable[_T] | Observable[_A]:
88
+ """Apply an accumulator function and return the final accumulated result.
89
+
90
+ Applies an accumulator function over an observable sequence, returning the
91
+ result of the aggregation as a single element in the result sequence.
92
+
93
+ Examples:
94
+ Fluent style:
95
+ >>> result = source.reduce(lambda acc, x: acc + x)
96
+ >>> result = source.reduce(lambda acc, x: acc + x, 0)
97
+ >>> # Concatenate strings
98
+ >>> result = source.reduce(lambda acc, x: acc + x, "")
99
+
100
+ Equivalent pipe style:
101
+ >>> from reactivex import operators as ops
102
+ >>> result = source.pipe(ops.reduce(lambda acc, x: acc + x))
103
+ >>> result = source.pipe(ops.reduce(lambda acc, x: acc + x, 0))
104
+
105
+ Args:
106
+ accumulator: An accumulator function to be invoked on each element.
107
+ seed: Optional initial accumulator value.
108
+
109
+ Returns:
110
+ An observable sequence containing a single element with the final
111
+ accumulated value.
112
+
113
+ See Also:
114
+ - :func:`reduce <reactivex.operators.reduce>`
115
+ - :meth:`scan`
116
+ """
117
+ from reactivex import operators as ops
118
+
119
+ if seed is NotSet:
120
+ return self._as_observable().pipe(ops.reduce(accumulator))
121
+ # After the guard above, seed is guaranteed to be _A (not type[NotSet]).
122
+ # Cast is needed because pyright doesn't narrow union types with `is` checks.
123
+ seed_value = cast(_A, seed)
124
+ return self._as_observable().pipe(ops.reduce(accumulator, seed_value))
125
+
126
+ @overload
127
+ def scan(self, accumulator: typing.Accumulator[_T, _T]) -> Observable[_T]: ...
128
+
129
+ @overload
130
+ def scan(
131
+ self, accumulator: typing.Accumulator[_A, _T], seed: _A
132
+ ) -> Observable[_A]: ...
133
+
134
+ def scan(
135
+ self,
136
+ accumulator: typing.Accumulator[_A, _T],
137
+ seed: _A | type[NotSet] = NotSet,
138
+ ) -> Observable[_T] | Observable[_A]:
139
+ """Apply an accumulator function and return each intermediate result.
140
+
141
+ Applies an accumulator function over an observable sequence and returns
142
+ each intermediate result. Similar to reduce, but emits the current
143
+ accumulation after each element.
144
+
145
+ Examples:
146
+ Fluent style:
147
+ >>> result = source.scan(lambda acc, x: acc + x)
148
+ >>> result = source.scan(lambda acc, x: acc + x, 0)
149
+ >>> result = source.scan(lambda acc, x: acc + [x], []) # Collect into list
150
+
151
+ Equivalent pipe style:
152
+ >>> from reactivex import operators as ops
153
+ >>> result = source.pipe(ops.scan(lambda acc, x: acc + x))
154
+ >>> result = source.pipe(ops.scan(lambda acc, x: acc + x, 0))
155
+
156
+ Args:
157
+ accumulator: An accumulator function to be invoked on each element.
158
+ seed: Optional initial accumulator value.
159
+
160
+ Returns:
161
+ An observable sequence containing the accumulated values.
162
+
163
+ See Also:
164
+ - :func:`scan <reactivex.operators.scan>`
165
+ - :meth:`reduce`
166
+ """
167
+ from reactivex import operators as ops
168
+
169
+ return self._as_observable().pipe(ops.scan(accumulator, seed))
170
+
171
+ @overload
172
+ def flat_map(self, mapper: typing.Mapper[_T, Observable[_B]]) -> Observable[_B]: ...
173
+
174
+ @overload
175
+ def flat_map(self, mapper: None = None) -> Observable[object]: ...
176
+
177
+ def flat_map(
178
+ self,
179
+ mapper: typing.Mapper[_T, Observable[_B]] | None = None,
180
+ ) -> Observable[_B]:
181
+ """Transform elements into observables and flatten (also known as merge_map).
182
+
183
+ Projects each element of an observable sequence to an observable sequence
184
+ and merges the resulting observable sequences into one observable sequence.
185
+
186
+ Examples:
187
+ Fluent style:
188
+ >>> result = source.flat_map(lambda x: rx.of(x, x * 2))
189
+ >>> result = rx.of(rx.of(1, 2), rx.of(3, 4)).flat_map() # Flatten
190
+
191
+ Equivalent pipe style:
192
+ >>> from reactivex import operators as ops
193
+ >>> result = source.pipe(ops.flat_map(lambda x: rx.of(x, x * 2)))
194
+
195
+ Args:
196
+ mapper: A transform function to apply to each element, or None to
197
+ flatten nested observables.
198
+
199
+ Returns:
200
+ An observable sequence whose elements are the result of invoking the
201
+ one-to-many transform function on each element of the input sequence
202
+ and merging all the resulting sequences.
203
+
204
+ See Also:
205
+ - :func:`flat_map <reactivex.operators.flat_map>`
206
+ - :meth:`concat_map`
207
+ - :meth:`switch_map`
208
+ """
209
+ from reactivex import operators as ops
210
+
211
+ return self._as_observable().pipe(ops.flat_map(mapper))
212
+
213
+ def concat_map(self, project: typing.Mapper[_T, Observable[_B]]) -> Observable[_B]:
214
+ """Transform and concatenate observables in order.
215
+
216
+ Projects each source value to an observable which is merged in the output
217
+ observable, in a serialized fashion waiting for each one to complete before
218
+ merging the next.
219
+
220
+ Examples:
221
+ Fluent style:
222
+ >>> result = source.concat_map(lambda x: rx.of(x, x * 2))
223
+ >>> result = source.concat_map(lambda x: delayed_observable(x))
224
+
225
+ Equivalent pipe style:
226
+ >>> from reactivex import operators as ops
227
+ >>> result = source.pipe(ops.concat_map(lambda x: rx.of(x, x * 2)))
228
+
229
+ Args:
230
+ project: A transform function to apply to each element.
231
+
232
+ Returns:
233
+ An observable sequence whose elements are the result of invoking the
234
+ transform function on each element and concatenating all the sequences.
235
+
236
+ See Also:
237
+ - :func:`concat_map <reactivex.operators.concat_map>`
238
+ - :meth:`flat_map`
239
+ - :meth:`switch_map`
240
+ """
241
+ from reactivex import operators as ops
242
+
243
+ return self._as_observable().pipe(ops.concat_map(project))
244
+
245
+ def switch_map(self, project: typing.Mapper[_T, Observable[_B]]) -> Observable[_B]:
246
+ """Transform and switch to the latest observable.
247
+
248
+ Projects each source value to an observable which is merged in the output
249
+ observable, emitting values only from the most recently projected observable.
250
+
251
+ Examples:
252
+ Fluent style:
253
+ >>> result = source.switch_map(lambda x: rx.of(x, x * 2))
254
+ >>> result = source.switch_map(lambda x: delayed_observable(x))
255
+
256
+ Equivalent pipe style:
257
+ >>> from reactivex import operators as ops
258
+ >>> result = source.pipe(ops.switch_map(lambda x: rx.of(x, x * 2)))
259
+
260
+ Args:
261
+ project: A transform function to apply to each element.
262
+
263
+ Returns:
264
+ An observable sequence whose elements are the result of invoking the
265
+ transform function on each element and merging only the most recent
266
+ inner observable sequence.
267
+
268
+ See Also:
269
+ - :func:`switch_map <reactivex.operators.switch_map>`
270
+ - :meth:`flat_map`
271
+ - :meth:`concat_map`
272
+ """
273
+ from reactivex import operators as ops
274
+
275
+ return self._as_observable().pipe(ops.switch_map(project))
276
+
277
+ def map_indexed(
278
+ self, mapper_indexed: typing.MapperIndexed[_T, _B] | None = None
279
+ ) -> Observable[_B]:
280
+ """Map each element to a new value with its index.
281
+
282
+ Projects each element of an observable sequence into a new form by
283
+ incorporating the element's index.
284
+
285
+ Examples:
286
+ Fluent style:
287
+ >>> result = source.map_indexed(lambda x, i: f"{i}: {x}")
288
+ >>> result = source.map_indexed(lambda x, i: x * i)
289
+
290
+ Equivalent pipe style:
291
+ >>> from reactivex import operators as ops
292
+ >>> result = source.pipe(ops.map_indexed(lambda x, i: f"{i}: {x}"))
293
+
294
+ Args:
295
+ mapper_indexed: A transform function to apply to each element and
296
+ its index. The function receives (value, index) and returns the
297
+ transformed value.
298
+
299
+ Returns:
300
+ An observable sequence whose elements are the result of invoking
301
+ the indexed transform function on each element of the source.
302
+
303
+ See Also:
304
+ - :func:`map_indexed <reactivex.operators.map_indexed>`
305
+ - :meth:`map`
306
+ """
307
+ from reactivex import operators as ops
308
+
309
+ return self._as_observable().pipe(ops.map_indexed(mapper_indexed))
310
+
311
+ def flat_map_indexed(
312
+ self, mapper_indexed: typing.MapperIndexed[_T, Observable[_B]] | None = None
313
+ ) -> Observable[_B]:
314
+ """Transform elements into observables and flatten, with index.
315
+
316
+ Projects each element of an observable sequence to an observable sequence
317
+ by incorporating the element's index, and merges the resulting observable
318
+ sequences into one observable sequence.
319
+
320
+ Examples:
321
+ Fluent style:
322
+ >>> result = source.flat_map_indexed(lambda x, i: rx.of(x, i))
323
+ >>> result = source.flat_map_indexed(lambda x, i: fetch_data(x, i))
324
+
325
+ Equivalent pipe style:
326
+ >>> from reactivex import operators as ops
327
+ >>> result = source.pipe(ops.flat_map_indexed(lambda x, i: rx.of(x, i)))
328
+
329
+ Args:
330
+ mapper_indexed: A transform function to apply to each element and its
331
+ index. The function receives (value, index) and returns an Observable.
332
+
333
+ Returns:
334
+ An observable sequence whose elements are the result of invoking the
335
+ indexed transform function on each element and merging all sequences.
336
+
337
+ See Also:
338
+ - :func:`flat_map_indexed <reactivex.operators.flat_map_indexed>`
339
+ - :meth:`flat_map`
340
+ - :meth:`map_indexed`
341
+ """
342
+ from reactivex import operators as ops
343
+
344
+ return self._as_observable().pipe(ops.flat_map_indexed(mapper_indexed))
345
+
346
+ def flat_map_latest(
347
+ self, mapper: typing.Mapper[_T, Observable[_B]]
348
+ ) -> Observable[_B]:
349
+ """Transform and flatten, canceling previous inner observables.
350
+
351
+ Projects each element to an observable, merges the resulting observables,
352
+ and emits only from the most recently projected observable.
353
+
354
+ Examples:
355
+ Fluent style:
356
+ >>> result = source.flat_map_latest(lambda x: fetch_data(x))
357
+
358
+ Equivalent pipe style:
359
+ >>> from reactivex import operators as ops
360
+ >>> result = source.pipe(ops.flat_map_latest(lambda x: fetch_data(x)))
361
+
362
+ Args:
363
+ mapper: A transform function to apply to each element.
364
+
365
+ Returns:
366
+ An observable sequence containing the merged results from the
367
+ most recent inner observable.
368
+
369
+ See Also:
370
+ - :func:`flat_map_latest <reactivex.operators.flat_map_latest>`
371
+ - :meth:`flat_map`
372
+ - :meth:`switch_map`
373
+ """
374
+ from reactivex import operators as ops
375
+
376
+ return self._as_observable().pipe(ops.flat_map_latest(mapper))
377
+
378
+ def switch_map_indexed(
379
+ self, mapper_indexed: typing.MapperIndexed[_T, Observable[_B]]
380
+ ) -> Observable[_B]:
381
+ """Transform and switch to latest observable, with index.
382
+
383
+ Projects each element to an observable by incorporating the element's index,
384
+ and emits values only from the most recently projected observable.
385
+
386
+ Examples:
387
+ Fluent style:
388
+ >>> result = source.switch_map_indexed(lambda x, i: fetch_data(x, i))
389
+
390
+ Equivalent pipe style:
391
+ >>> from reactivex import operators as ops
392
+ >>> result = source.pipe(
393
+ ... ops.switch_map_indexed(lambda x, i: fetch_data(x, i))
394
+ ... )
395
+
396
+ Args:
397
+ mapper_indexed: A transform function to apply to each element and its index.
398
+
399
+ Returns:
400
+ An observable sequence whose elements are the result of invoking the
401
+ indexed transform function and switching to the most recent sequence.
402
+
403
+ See Also:
404
+ - :func:`switch_map_indexed <reactivex.operators.switch_map_indexed>`
405
+ - :meth:`switch_map`
406
+ - :meth:`flat_map_indexed`
407
+ """
408
+ from reactivex import operators as ops
409
+
410
+ return self._as_observable().pipe(ops.switch_map_indexed(mapper_indexed))
411
+
412
+ @overload
413
+ def starmap(self: TransformationMixin[_T]) -> Observable[_T]:
414
+ """Identity overload when no mapper provided."""
415
+ ...
416
+
417
+ @overload
418
+ def starmap(
419
+ self: TransformationMixin[tuple[Unpack[_Ts]]],
420
+ mapper: Callable[[Unpack[_Ts]], _B],
421
+ ) -> Observable[_B]:
422
+ """Typed overload with variadic generics."""
423
+ ...
424
+
425
+ def starmap(self, mapper: Any = None) -> Observable[Any]:
426
+ """Unpack arguments from tuples and apply to mapper function.
427
+
428
+ Projects each element of an observable sequence of tuples into a new form
429
+ by unpacking the tuple as arguments to a function.
430
+
431
+ Examples:
432
+ Fluent style:
433
+ >>> result = rx.of((1, 2), (3, 4)).starmap(lambda x, y: x + y)
434
+ >>> result = rx.of(("a", 1), ("b", 2)).starmap(lambda s, n: s * n)
435
+
436
+ Equivalent pipe style:
437
+ >>> from reactivex import operators as ops
438
+ >>> result = source.pipe(ops.starmap(lambda x, y: x + y))
439
+
440
+ Args:
441
+ mapper: A transform function that receives unpacked tuple elements.
442
+ If not provided, returns the tuple unchanged.
443
+
444
+ Returns:
445
+ An observable sequence whose elements are the result of invoking
446
+ the transform function with unpacked tuple arguments.
447
+
448
+ See Also:
449
+ - :func:`starmap <reactivex.operators.starmap>`
450
+ - :meth:`map`
451
+ """
452
+ from reactivex import operators as ops
453
+
454
+ # Cast is safe: The overloads above provide type safety for callers.
455
+ # The implementation uses Any because variadic generics can't be
456
+ # perfectly expressed in the implementation signature.
457
+ source = cast("Observable[Any]", self._as_observable())
458
+ return source.pipe(ops.starmap(mapper))
459
+
460
+ @overload
461
+ def starmap_indexed(
462
+ self: TransformationMixin[tuple[Unpack[_Ts]]],
463
+ mapper_indexed: Callable[[Unpack[_Ts], int], _B],
464
+ ) -> Observable[_B]: ...
465
+
466
+ @overload
467
+ def starmap_indexed(self, mapper_indexed: None = None) -> Observable[Any]: ...
468
+
469
+ def starmap_indexed(self, mapper_indexed: Any = None) -> Observable[Any]:
470
+ """Unpack tuple arguments and apply to indexed mapper function.
471
+
472
+ Projects each element of an observable sequence of tuples into a new form
473
+ by unpacking the tuple as arguments to a function, with index.
474
+
475
+ Examples:
476
+ Fluent style:
477
+ >>> result = rx.of((1, 2), (3, 4)).starmap_indexed(
478
+ ... lambda x, y, i: (x + y) * i
479
+ ... )
480
+
481
+ Equivalent pipe style:
482
+ >>> from reactivex import operators as ops
483
+ >>> result = source.pipe(ops.starmap_indexed(lambda x, y, i: (x + y) * i))
484
+
485
+ Args:
486
+ mapper_indexed: A transform function that receives unpacked tuple
487
+ elements and the index.
488
+
489
+ Returns:
490
+ An observable sequence whose elements are the result of invoking
491
+ the indexed transform function with unpacked tuple arguments.
492
+
493
+ See Also:
494
+ - :func:`starmap_indexed <reactivex.operators.starmap_indexed>`
495
+ - :meth:`starmap`
496
+ - :meth:`map_indexed`
497
+ """
498
+ from reactivex import operators as ops
499
+
500
+ # Cast is safe: The overload above provides type safety for callers.
501
+ # The implementation uses Any because variadic generics can't be
502
+ # perfectly expressed in the implementation signature.
503
+ source = cast("Observable[Any]", self._as_observable())
504
+ return source.pipe(ops.starmap_indexed(mapper_indexed))
505
+
506
+ def pluck(self, key: str) -> Observable[Any]:
507
+ """Extract a property from each element.
508
+
509
+ Returns an observable sequence of values corresponding to a property
510
+ with the given name from all elements in the source sequence.
511
+
512
+ Examples:
513
+ Fluent style:
514
+ >>> result = source.pluck("name")
515
+ >>> result = rx.of({"x": 1}, {"x": 2}).pluck("x")
516
+
517
+ Equivalent pipe style:
518
+ >>> from reactivex import operators as ops
519
+ >>> result = source.pipe(ops.pluck("name"))
520
+
521
+ Args:
522
+ key: The property name to extract.
523
+
524
+ Returns:
525
+ An observable sequence of property values.
526
+
527
+ See Also:
528
+ - :func:`pluck <reactivex.operators.pluck>`
529
+ - :meth:`pluck_attr`
530
+ - :meth:`map`
531
+ """
532
+ from reactivex import operators as ops
533
+
534
+ # Cast is safe: pluck expects Observable[dict[str, Any]] but
535
+ # we have Observable[_T]. The fluent API allows calling this
536
+ # on sequences of dictionaries.
537
+ source: Observable[Any] = cast("Observable[Any]", self._as_observable())
538
+ return ops.pluck(key)(source)
539
+
540
+ def pluck_attr(self, attr: str) -> Observable[Any]:
541
+ """Extract an attribute from each element.
542
+
543
+ Returns an observable sequence of values corresponding to an attribute
544
+ with the given name from all elements in the source sequence.
545
+
546
+ Examples:
547
+ Fluent style:
548
+ >>> result = source.pluck_attr("name")
549
+ >>> result = source.pluck_attr("value")
550
+
551
+ Equivalent pipe style:
552
+ >>> from reactivex import operators as ops
553
+ >>> result = source.pipe(ops.pluck_attr("name"))
554
+
555
+ Args:
556
+ attr: The attribute name to extract.
557
+
558
+ Returns:
559
+ An observable sequence of attribute values.
560
+
561
+ See Also:
562
+ - :func:`pluck_attr <reactivex.operators.pluck_attr>`
563
+ - :meth:`pluck`
564
+ - :meth:`map`
565
+ """
566
+ from reactivex import operators as ops
567
+
568
+ return self._as_observable().pipe(ops.pluck_attr(attr))
569
+
570
+ def expand(self, mapper: typing.Mapper[_T, Observable[_T]]) -> Observable[_T]:
571
+ """Recursively expand observable sequences.
572
+
573
+ Recursively projects each source value to an observable which is merged
574
+ in the output observable.
575
+
576
+ Examples:
577
+ Fluent style:
578
+ >>> result = rx.of(1).expand(
579
+ ... lambda x: rx.of(x + 1) if x < 10 else rx.empty()
580
+ ... )
581
+
582
+ Equivalent pipe style:
583
+ >>> from reactivex import operators as ops
584
+ >>> result = source.pipe(
585
+ ... ops.expand(lambda x: rx.of(x + 1) if x < 10 else rx.empty())
586
+ ... )
587
+
588
+ Args:
589
+ mapper: A transform function to apply to each element, returning an
590
+ observable sequence.
591
+
592
+ Returns:
593
+ An observable sequence containing all values from the source and
594
+ recursively expanded observables.
595
+
596
+ See Also:
597
+ - :func:`expand <reactivex.operators.expand>`
598
+ - :meth:`flat_map`
599
+ """
600
+ from reactivex import operators as ops
601
+
602
+ return self._as_observable().pipe(ops.expand(mapper))
603
+
604
+ def exclusive(self) -> Observable[_T]:
605
+ """Projects and merges observables exclusively.
606
+
607
+ Projects each element of the source observable to an observable,
608
+ emitting only from the first inner observable until it completes.
609
+
610
+ Examples:
611
+ Fluent style:
612
+ >>> result = source_of_observables.exclusive()
613
+
614
+ Equivalent pipe style:
615
+ >>> from reactivex import operators as ops
616
+ >>> result = source.pipe(ops.exclusive())
617
+
618
+ Returns:
619
+ An observable sequence containing elements from the first inner
620
+ observable until completion, then the next, and so on.
621
+
622
+ See Also:
623
+ - :func:`exclusive <reactivex.operators.exclusive>`
624
+ - :meth:`concat_map`
625
+ """
626
+ from reactivex import operators as ops
627
+
628
+ # Cast is safe: exclusive expects Observable[Observable[T]] but
629
+ # we have Observable[_T]. The fluent API allows calling this on
630
+ # sequences of observables.
631
+ source: Observable[Any] = cast("Observable[Any]", self._as_observable())
632
+ return cast("Observable[_T]", ops.exclusive()(source))