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,9 @@
1
1
  import logging
2
- from typing import Callable, List, Optional, TypeVar
2
+ from typing import TypeVar
3
3
 
4
4
  from reactivex import Observable, abc
5
5
  from reactivex.disposable import RefCountDisposable, SingleAssignmentDisposable
6
- from reactivex.internal import ArgumentOutOfRangeException, add_ref
6
+ from reactivex.internal import ArgumentOutOfRangeException, add_ref, curry_flip
7
7
  from reactivex.subject import Subject
8
8
 
9
9
  log = logging.getLogger("Rx")
@@ -11,17 +11,22 @@ log = logging.getLogger("Rx")
11
11
  _T = TypeVar("_T")
12
12
 
13
13
 
14
+ @curry_flip
14
15
  def window_with_count_(
15
- count: int, skip: Optional[int] = None
16
- ) -> Callable[[Observable[_T]], Observable[Observable[_T]]]:
16
+ source: Observable[_T],
17
+ count: int,
18
+ skip: int | None = None,
19
+ ) -> Observable[Observable[_T]]:
17
20
  """Projects each element of an observable sequence into zero or more
18
21
  windows which are produced based on element count information.
19
22
 
20
23
  Examples:
21
- >>> window_with_count(10)
22
- >>> window_with_count(10, 1)
24
+ >>> source.pipe(window_with_count(10))
25
+ >>> source.pipe(window_with_count(10, 1))
26
+ >>> window_with_count(10)(source)
23
27
 
24
28
  Args:
29
+ source: Source observable to window.
25
30
  count: Length of each window.
26
31
  skip: [Optional] Number of elements to skip between creation of
27
32
  consecutive windows. If not specified, defaults to the
@@ -39,54 +44,51 @@ def window_with_count_(
39
44
  if skip_ <= 0:
40
45
  raise ArgumentOutOfRangeException()
41
46
 
42
- def window_with_count(source: Observable[_T]) -> Observable[Observable[_T]]:
43
- def subscribe(
44
- observer: abc.ObserverBase[Observable[_T]],
45
- scheduler: Optional[abc.SchedulerBase] = None,
46
- ):
47
- m = SingleAssignmentDisposable()
48
- refCountDisposable = RefCountDisposable(m)
49
- n = [0]
50
- q: List[Subject[_T]] = []
51
-
52
- def create_window():
53
- s: Subject[_T] = Subject()
54
- q.append(s)
55
- observer.on_next(add_ref(s, refCountDisposable))
56
-
57
- create_window()
58
-
59
- def on_next(x: _T) -> None:
60
- for item in q:
61
- item.on_next(x)
62
-
63
- c = n[0] - count + 1
64
- if c >= 0 and c % skip_ == 0:
65
- s = q.pop(0)
66
- s.on_completed()
67
-
68
- n[0] += 1
69
- if (n[0] % skip_) == 0:
70
- create_window()
71
-
72
- def on_error(exception: Exception) -> None:
73
- while q:
74
- q.pop(0).on_error(exception)
75
- observer.on_error(exception)
76
-
77
- def on_completed() -> None:
78
- while q:
79
- q.pop(0).on_completed()
80
- observer.on_completed()
81
-
82
- m.disposable = source.subscribe(
83
- on_next, on_error, on_completed, scheduler=scheduler
84
- )
85
- return refCountDisposable
86
-
87
- return Observable(subscribe)
88
-
89
- return window_with_count
47
+ def subscribe(
48
+ observer: abc.ObserverBase[Observable[_T]],
49
+ scheduler: abc.SchedulerBase | None = None,
50
+ ):
51
+ m = SingleAssignmentDisposable()
52
+ refCountDisposable = RefCountDisposable(m)
53
+ n = [0]
54
+ q: list[Subject[_T]] = []
55
+
56
+ def create_window():
57
+ s: Subject[_T] = Subject()
58
+ q.append(s)
59
+ observer.on_next(add_ref(s, refCountDisposable))
60
+
61
+ create_window()
62
+
63
+ def on_next(x: _T) -> None:
64
+ for item in q:
65
+ item.on_next(x)
66
+
67
+ c = n[0] - count + 1
68
+ if c >= 0 and c % skip_ == 0:
69
+ s = q.pop(0)
70
+ s.on_completed()
71
+
72
+ n[0] += 1
73
+ if (n[0] % skip_) == 0:
74
+ create_window()
75
+
76
+ def on_error(exception: Exception) -> None:
77
+ while q:
78
+ q.pop(0).on_error(exception)
79
+ observer.on_error(exception)
80
+
81
+ def on_completed() -> None:
82
+ while q:
83
+ q.pop(0).on_completed()
84
+ observer.on_completed()
85
+
86
+ m.disposable = source.subscribe(
87
+ on_next, on_error, on_completed, scheduler=scheduler
88
+ )
89
+ return refCountDisposable
90
+
91
+ return Observable(subscribe)
90
92
 
91
93
 
92
94
  __all__ = ["window_with_count_"]
@@ -1,5 +1,5 @@
1
1
  from datetime import timedelta
2
- from typing import Any, Callable, List, Optional, TypeVar
2
+ from typing import Any, TypeVar
3
3
 
4
4
  from reactivex import Observable, abc, typing
5
5
  from reactivex.disposable import (
@@ -8,18 +8,37 @@ from reactivex.disposable import (
8
8
  SerialDisposable,
9
9
  SingleAssignmentDisposable,
10
10
  )
11
- from reactivex.internal import DELTA_ZERO, add_ref, synchronized
11
+ from reactivex.internal import DELTA_ZERO, add_ref, curry_flip, synchronized
12
12
  from reactivex.scheduler import TimeoutScheduler
13
13
  from reactivex.subject import Subject
14
14
 
15
15
  _T = TypeVar("_T")
16
16
 
17
17
 
18
+ @curry_flip
18
19
  def window_with_time_(
20
+ source: Observable[_T],
19
21
  timespan: typing.RelativeTime,
20
- timeshift: Optional[typing.RelativeTime] = None,
21
- scheduler: Optional[abc.SchedulerBase] = None,
22
- ) -> Callable[[Observable[_T]], Observable[Observable[_T]]]:
22
+ timeshift: typing.RelativeTime | None = None,
23
+ scheduler: abc.SchedulerBase | None = None,
24
+ ) -> Observable[Observable[_T]]:
25
+ """Projects each element of an observable sequence into zero or more
26
+ windows which are produced based on timing information.
27
+
28
+ Examples:
29
+ >>> res = source.pipe(window_with_time(1.0))
30
+ >>> res = source.pipe(window_with_time(1.0, 0.5))
31
+ >>> res = window_with_time(1.0)(source)
32
+
33
+ Args:
34
+ source: Source observable to window.
35
+ timespan: Length of each window.
36
+ timeshift: Interval between creation of consecutive windows.
37
+ scheduler: Scheduler to use for timing.
38
+
39
+ Returns:
40
+ An observable sequence of windows.
41
+ """
23
42
  if timeshift is None:
24
43
  timeshift = timespan
25
44
 
@@ -28,94 +47,91 @@ def window_with_time_(
28
47
  if not isinstance(timeshift, timedelta):
29
48
  timeshift = timedelta(seconds=timeshift)
30
49
 
31
- def window_with_time(source: Observable[_T]) -> Observable[Observable[_T]]:
32
- def subscribe(
33
- observer: abc.ObserverBase[Observable[_T]],
34
- scheduler_: Optional[abc.SchedulerBase] = None,
35
- ):
36
- _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
37
-
38
- timer_d = SerialDisposable()
39
- next_shift = [timeshift]
40
- next_span = [timespan]
41
- total_time = [DELTA_ZERO]
42
- queue: List[Subject[_T]] = []
43
-
44
- group_disposable = CompositeDisposable(timer_d)
45
- ref_count_disposable = RefCountDisposable(group_disposable)
46
-
47
- def create_timer():
48
- m = SingleAssignmentDisposable()
49
- timer_d.disposable = m
50
- is_span = False
51
- is_shift = False
52
-
53
- if next_span[0] == next_shift[0]:
54
- is_span = True
55
- is_shift = True
56
- elif next_span[0] < next_shift[0]:
57
- is_span = True
58
- else:
59
- is_shift = True
60
-
61
- new_total_time = next_span[0] if is_span else next_shift[0]
62
-
63
- ts = new_total_time - total_time[0]
64
- total_time[0] = new_total_time
65
- if is_span:
66
- next_span[0] += timeshift
67
-
68
- if is_shift:
69
- next_shift[0] += timeshift
50
+ def subscribe(
51
+ observer: abc.ObserverBase[Observable[_T]],
52
+ scheduler_: abc.SchedulerBase | None = None,
53
+ ):
54
+ _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
55
+
56
+ timer_d = SerialDisposable()
57
+ next_shift = [timeshift]
58
+ next_span = [timespan]
59
+ total_time = [DELTA_ZERO]
60
+ queue: list[Subject[_T]] = []
61
+
62
+ group_disposable = CompositeDisposable(timer_d)
63
+ ref_count_disposable = RefCountDisposable(group_disposable)
64
+
65
+ def create_timer():
66
+ m = SingleAssignmentDisposable()
67
+ timer_d.disposable = m
68
+ is_span = False
69
+ is_shift = False
70
+
71
+ if next_span[0] == next_shift[0]:
72
+ is_span = True
73
+ is_shift = True
74
+ elif next_span[0] < next_shift[0]:
75
+ is_span = True
76
+ else:
77
+ is_shift = True
78
+
79
+ new_total_time = next_span[0] if is_span else next_shift[0]
80
+
81
+ ts = new_total_time - total_time[0]
82
+ total_time[0] = new_total_time
83
+ if is_span:
84
+ next_span[0] += timeshift
85
+
86
+ if is_shift:
87
+ next_shift[0] += timeshift
70
88
 
71
- @synchronized(source.lock)
72
- def action(scheduler: abc.SchedulerBase, state: Any = None):
73
- s: Optional[Subject[_T]] = None
74
-
75
- if is_shift:
76
- s = Subject()
77
- queue.append(s)
78
- observer.on_next(add_ref(s, ref_count_disposable))
89
+ @synchronized(source.lock)
90
+ def action(scheduler: abc.SchedulerBase, state: Any = None):
91
+ s: Subject[_T] | None = None
79
92
 
80
- if is_span:
81
- s = queue.pop(0)
82
- s.on_completed()
93
+ if is_shift:
94
+ s = Subject()
95
+ queue.append(s)
96
+ observer.on_next(add_ref(s, ref_count_disposable))
83
97
 
84
- create_timer()
98
+ if is_span:
99
+ s = queue.pop(0)
100
+ s.on_completed()
85
101
 
86
- m.disposable = _scheduler.schedule_relative(ts, action)
102
+ create_timer()
87
103
 
88
- queue.append(Subject())
89
- observer.on_next(add_ref(queue[0], ref_count_disposable))
90
- create_timer()
104
+ m.disposable = _scheduler.schedule_relative(ts, action)
91
105
 
92
- def on_next(x: _T) -> None:
93
- with source.lock:
94
- for s in queue:
95
- s.on_next(x)
106
+ queue.append(Subject())
107
+ observer.on_next(add_ref(queue[0], ref_count_disposable))
108
+ create_timer()
96
109
 
97
- @synchronized(source.lock)
98
- def on_error(e: Exception) -> None:
110
+ def on_next(x: _T) -> None:
111
+ with source.lock:
99
112
  for s in queue:
100
- s.on_error(e)
113
+ s.on_next(x)
101
114
 
102
- observer.on_error(e)
115
+ @synchronized(source.lock)
116
+ def on_error(e: Exception) -> None:
117
+ for s in queue:
118
+ s.on_error(e)
103
119
 
104
- @synchronized(source.lock)
105
- def on_completed() -> None:
106
- for s in queue:
107
- s.on_completed()
120
+ observer.on_error(e)
108
121
 
109
- observer.on_completed()
122
+ @synchronized(source.lock)
123
+ def on_completed() -> None:
124
+ for s in queue:
125
+ s.on_completed()
110
126
 
111
- group_disposable.add(
112
- source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)
113
- )
114
- return ref_count_disposable
127
+ observer.on_completed()
115
128
 
116
- return Observable(subscribe)
129
+ group_disposable.add(
130
+ source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)
131
+ )
132
+ return ref_count_disposable
117
133
 
118
- return window_with_time
134
+ return Observable(subscribe)
119
135
 
120
136
 
121
137
  __all__ = ["window_with_time_"]
@@ -1,4 +1,4 @@
1
- from typing import Any, Callable, Optional, TypeVar
1
+ from typing import Any, TypeVar
2
2
 
3
3
  from reactivex import Observable, abc, typing
4
4
  from reactivex.disposable import (
@@ -7,90 +7,106 @@ from reactivex.disposable import (
7
7
  SerialDisposable,
8
8
  SingleAssignmentDisposable,
9
9
  )
10
- from reactivex.internal import add_ref
10
+ from reactivex.internal import add_ref, curry_flip
11
11
  from reactivex.scheduler import TimeoutScheduler
12
12
  from reactivex.subject import Subject
13
13
 
14
14
  _T = TypeVar("_T")
15
15
 
16
16
 
17
+ @curry_flip
17
18
  def window_with_time_or_count_(
19
+ source: Observable[_T],
18
20
  timespan: typing.RelativeTime,
19
21
  count: int,
20
- scheduler: Optional[abc.SchedulerBase] = None,
21
- ) -> Callable[[Observable[_T]], Observable[Observable[_T]]]:
22
- def window_with_time_or_count(source: Observable[_T]) -> Observable[Observable[_T]]:
23
- def subscribe(
24
- observer: abc.ObserverBase[Observable[_T]],
25
- scheduler_: Optional[abc.SchedulerBase] = None,
26
- ) -> abc.DisposableBase:
27
- _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
28
-
29
- n: int = 0
30
- s: Subject[_T] = Subject()
31
- timer_d = SerialDisposable()
32
- window_id = 0
33
- group_disposable = CompositeDisposable(timer_d)
34
- ref_count_disposable = RefCountDisposable(group_disposable)
35
-
36
- def create_timer(_id: int):
22
+ scheduler: abc.SchedulerBase | None = None,
23
+ ) -> Observable[Observable[_T]]:
24
+ """Projects each element of an observable sequence into zero or more
25
+ windows which are produced based on timing information and element count.
26
+
27
+ Examples:
28
+ >>> res = source.pipe(window_with_time_or_count(1.0, 10))
29
+ >>> res = window_with_time_or_count(1.0, 10)(source)
30
+
31
+ Args:
32
+ source: Source observable to window.
33
+ timespan: Maximum time length of a window.
34
+ count: Maximum element count of a window.
35
+ scheduler: Scheduler to use for timing.
36
+
37
+ Returns:
38
+ An observable sequence of windows.
39
+ """
40
+
41
+ def subscribe(
42
+ observer: abc.ObserverBase[Observable[_T]],
43
+ scheduler_: abc.SchedulerBase | None = None,
44
+ ) -> abc.DisposableBase:
45
+ _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
46
+
47
+ n: int = 0
48
+ s: Subject[_T] = Subject()
49
+ timer_d = SerialDisposable()
50
+ window_id = 0
51
+ group_disposable = CompositeDisposable(timer_d)
52
+ ref_count_disposable = RefCountDisposable(group_disposable)
53
+
54
+ def create_timer(_id: int):
55
+ nonlocal n, s, window_id
56
+ m = SingleAssignmentDisposable()
57
+ timer_d.disposable = m
58
+
59
+ def action(scheduler: abc.SchedulerBase, state: Any = None):
37
60
  nonlocal n, s, window_id
38
- m = SingleAssignmentDisposable()
39
- timer_d.disposable = m
61
+ if _id != window_id:
62
+ return
40
63
 
41
- def action(scheduler: abc.SchedulerBase, state: Any = None):
42
- nonlocal n, s, window_id
43
- if _id != window_id:
44
- return
45
-
46
- n = 0
47
- window_id += 1
48
- new_id = window_id
49
- s.on_completed()
50
- s = Subject()
51
- observer.on_next(add_ref(s, ref_count_disposable))
52
- create_timer(new_id)
53
-
54
- m.disposable = _scheduler.schedule_relative(timespan, action)
64
+ n = 0
65
+ window_id += 1
66
+ new_id = window_id
67
+ s.on_completed()
68
+ s = Subject()
69
+ observer.on_next(add_ref(s, ref_count_disposable))
70
+ create_timer(new_id)
71
+
72
+ m.disposable = _scheduler.schedule_relative(timespan, action)
73
+
74
+ observer.on_next(add_ref(s, ref_count_disposable))
75
+ create_timer(0)
76
+
77
+ def on_next(x: _T) -> None:
78
+ nonlocal n, s, window_id
79
+ new_window = False
80
+ new_id = 0
81
+
82
+ s.on_next(x)
83
+ n += 1
84
+ if n == count:
85
+ new_window = True
86
+ n = 0
87
+ window_id += 1
88
+ new_id = window_id
89
+ s.on_completed()
90
+ s = Subject()
91
+ observer.on_next(add_ref(s, ref_count_disposable))
55
92
 
56
- observer.on_next(add_ref(s, ref_count_disposable))
57
- create_timer(0)
93
+ if new_window:
94
+ create_timer(new_id)
58
95
 
59
- def on_next(x: _T) -> None:
60
- nonlocal n, s, window_id
61
- new_window = False
62
- new_id = 0
63
-
64
- s.on_next(x)
65
- n += 1
66
- if n == count:
67
- new_window = True
68
- n = 0
69
- window_id += 1
70
- new_id = window_id
71
- s.on_completed()
72
- s = Subject()
73
- observer.on_next(add_ref(s, ref_count_disposable))
74
-
75
- if new_window:
76
- create_timer(new_id)
77
-
78
- def on_error(e: Exception) -> None:
79
- s.on_error(e)
80
- observer.on_error(e)
81
-
82
- def on_completed() -> None:
83
- s.on_completed()
84
- observer.on_completed()
96
+ def on_error(e: Exception) -> None:
97
+ s.on_error(e)
98
+ observer.on_error(e)
85
99
 
86
- group_disposable.add(
87
- source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)
88
- )
89
- return ref_count_disposable
100
+ def on_completed() -> None:
101
+ s.on_completed()
102
+ observer.on_completed()
90
103
 
91
- return Observable(subscribe)
104
+ group_disposable.add(
105
+ source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)
106
+ )
107
+ return ref_count_disposable
92
108
 
93
- return window_with_time_or_count
109
+ return Observable(subscribe)
94
110
 
95
111
 
96
112
  __all__ = ["window_with_time_or_count_"]
@@ -1,12 +1,15 @@
1
- from typing import Any, Callable
1
+ from typing import Any
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 with_latest_from_(
10
+ source: Observable[Any],
8
11
  *sources: Observable[Any],
9
- ) -> Callable[[Observable[Any]], Observable[Any]]:
12
+ ) -> Observable[Any]:
10
13
  """With latest from operator.
11
14
 
12
15
  Merges the specified observable sequences into one observable
@@ -15,18 +18,19 @@ def with_latest_from_(
15
18
  passed either as seperate arguments or as a list.
16
19
 
17
20
  Examples:
18
- >>> op = with_latest_from(obs1)
19
- >>> op = with_latest_from(obs1, obs2, obs3)
21
+ >>> res = source.pipe(with_latest_from(obs1))
22
+ >>> res = source.pipe(with_latest_from(obs1, obs2, obs3))
23
+ >>> res = with_latest_from(obs1)(source)
24
+
25
+ Args:
26
+ source: Source observable.
27
+ *sources: Additional observables to combine with.
20
28
 
21
29
  Returns:
22
30
  An observable sequence containing the result of combining
23
31
  elements of the sources into a tuple.
24
32
  """
25
-
26
- def with_latest_from(source: Observable[Any]) -> Observable[Any]:
27
- return reactivex.with_latest_from(source, *sources)
28
-
29
- return with_latest_from
33
+ return reactivex.with_latest_from(source, *sources)
30
34
 
31
35
 
32
36
  __all__ = ["with_latest_from_"]