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.
- reactivex/__init__.py +35 -39
- reactivex/_version.py +1 -1
- reactivex/abc/disposable.py +3 -4
- reactivex/abc/observable.py +13 -6
- reactivex/abc/observer.py +2 -1
- reactivex/abc/periodicscheduler.py +7 -6
- reactivex/abc/scheduler.py +10 -9
- reactivex/abc/subject.py +5 -5
- reactivex/disposable/compositedisposable.py +4 -4
- reactivex/disposable/disposable.py +1 -2
- reactivex/disposable/multipleassignmentdisposable.py +2 -3
- reactivex/disposable/refcountdisposable.py +1 -2
- reactivex/disposable/serialdisposable.py +4 -5
- reactivex/disposable/singleassignmentdisposable.py +3 -4
- reactivex/internal/__init__.py +2 -0
- reactivex/internal/basic.py +2 -2
- reactivex/internal/concurrency.py +2 -1
- reactivex/internal/curry.py +59 -0
- reactivex/internal/exceptions.py +7 -12
- reactivex/internal/priorityqueue.py +2 -2
- reactivex/internal/utils.py +3 -2
- reactivex/notification.py +22 -21
- reactivex/observable/case.py +5 -6
- reactivex/observable/catch.py +3 -2
- reactivex/observable/combinelatest.py +4 -5
- reactivex/observable/concat.py +3 -2
- reactivex/observable/connectableobservable.py +7 -7
- reactivex/observable/defer.py +4 -3
- reactivex/observable/empty.py +3 -4
- reactivex/observable/forkjoin.py +5 -5
- reactivex/observable/fromcallback.py +4 -3
- reactivex/observable/fromfuture.py +2 -2
- reactivex/observable/fromiterable.py +4 -3
- reactivex/observable/generate.py +2 -2
- reactivex/observable/generatewithrelativetime.py +4 -3
- reactivex/observable/groupedobservable.py +4 -4
- reactivex/observable/ifthen.py +3 -2
- reactivex/observable/interval.py +1 -4
- reactivex/observable/marbles.py +18 -17
- reactivex/observable/mixins/__init__.py +32 -0
- reactivex/observable/mixins/combination.py +481 -0
- reactivex/observable/mixins/conditional.py +135 -0
- reactivex/observable/mixins/error_handling.py +130 -0
- reactivex/observable/mixins/filtering.py +1119 -0
- reactivex/observable/mixins/mathematical.py +277 -0
- reactivex/observable/mixins/multicasting.py +306 -0
- reactivex/observable/mixins/testing.py +193 -0
- reactivex/observable/mixins/time_based.py +209 -0
- reactivex/observable/mixins/transformation.py +632 -0
- reactivex/observable/mixins/utility.py +811 -0
- reactivex/observable/mixins/windowing.py +688 -0
- reactivex/observable/never.py +2 -2
- reactivex/observable/observable.py +72 -25
- reactivex/observable/onerrorresumenext.py +7 -6
- reactivex/observable/range.py +6 -6
- reactivex/observable/repeat.py +2 -2
- reactivex/observable/returnvalue.py +6 -5
- reactivex/observable/start.py +3 -2
- reactivex/observable/startasync.py +2 -1
- reactivex/observable/throw.py +3 -3
- reactivex/observable/timer.py +12 -12
- reactivex/observable/toasync.py +3 -2
- reactivex/observable/using.py +5 -4
- reactivex/observable/withlatestfrom.py +4 -5
- reactivex/observable/zip.py +7 -6
- reactivex/observer/autodetachobserver.py +4 -4
- reactivex/observer/observer.py +5 -4
- reactivex/observer/scheduledobserver.py +2 -2
- reactivex/operators/__init__.py +162 -208
- reactivex/operators/_all.py +23 -6
- reactivex/operators/_amb.py +88 -75
- reactivex/operators/_asobservable.py +20 -17
- reactivex/operators/_average.py +48 -45
- reactivex/operators/_buffer.py +81 -35
- reactivex/operators/_bufferwithtime.py +29 -9
- reactivex/operators/_bufferwithtimeorcount.py +27 -8
- reactivex/operators/_catch.py +33 -32
- reactivex/operators/_combinelatest.py +28 -20
- reactivex/operators/_concat.py +16 -13
- reactivex/operators/_contains.py +25 -6
- reactivex/operators/_count.py +24 -8
- reactivex/operators/_debounce.py +141 -138
- reactivex/operators/_defaultifempty.py +45 -42
- reactivex/operators/_delay.py +24 -23
- reactivex/operators/_delaysubscription.py +23 -21
- reactivex/operators/_delaywithmapper.py +10 -11
- reactivex/operators/_dematerialize.py +25 -21
- reactivex/operators/_distinct.py +50 -46
- reactivex/operators/_distinctuntilchanged.py +60 -57
- reactivex/operators/_do.py +123 -116
- reactivex/operators/_dowhile.py +3 -2
- reactivex/operators/_elementatordefault.py +57 -33
- reactivex/operators/_exclusive.py +59 -53
- reactivex/operators/_expand.py +82 -77
- reactivex/operators/_filter.py +63 -68
- reactivex/operators/_finallyaction.py +3 -2
- reactivex/operators/_find.py +49 -32
- reactivex/operators/_first.py +18 -11
- reactivex/operators/_firstordefault.py +5 -4
- reactivex/operators/_flatmap.py +89 -83
- reactivex/operators/_forkjoin.py +23 -18
- reactivex/operators/_groupby.py +27 -6
- reactivex/operators/_groupbyuntil.py +8 -5
- reactivex/operators/_groupjoin.py +7 -6
- reactivex/operators/_ignoreelements.py +20 -15
- reactivex/operators/_isempty.py +15 -4
- reactivex/operators/_join.py +6 -5
- reactivex/operators/_last.py +36 -31
- reactivex/operators/_lastordefault.py +8 -8
- reactivex/operators/_map.py +54 -39
- reactivex/operators/_materialize.py +30 -31
- reactivex/operators/_max.py +18 -11
- reactivex/operators/_maxby.py +5 -5
- reactivex/operators/_merge.py +132 -129
- reactivex/operators/_min.py +16 -10
- reactivex/operators/_minby.py +9 -8
- reactivex/operators/_multicast.py +9 -9
- reactivex/operators/_observeon.py +35 -31
- reactivex/operators/_onerrorresumenext.py +2 -1
- reactivex/operators/_pairwise.py +38 -34
- reactivex/operators/_partition.py +80 -73
- reactivex/operators/_pluck.py +4 -3
- reactivex/operators/_publish.py +36 -21
- reactivex/operators/_publishvalue.py +8 -7
- reactivex/operators/_reduce.py +16 -12
- reactivex/operators/_repeat.py +33 -30
- reactivex/operators/_replay.py +9 -9
- reactivex/operators/_retry.py +12 -10
- reactivex/operators/_sample.py +31 -27
- reactivex/operators/_scan.py +41 -39
- reactivex/operators/_sequenceequal.py +8 -7
- reactivex/operators/_single.py +20 -13
- reactivex/operators/_singleordefault.py +6 -5
- reactivex/operators/_skip.py +35 -32
- reactivex/operators/_skiplast.py +38 -34
- reactivex/operators/_skiplastwithtime.py +5 -4
- reactivex/operators/_skipuntil.py +40 -35
- reactivex/operators/_skipuntilwithtime.py +4 -3
- reactivex/operators/_skipwhile.py +65 -44
- reactivex/operators/_skipwithtime.py +50 -46
- reactivex/operators/_slice.py +58 -53
- reactivex/operators/_some.py +48 -47
- reactivex/operators/_startswith.py +17 -15
- reactivex/operators/_subscribeon.py +44 -41
- reactivex/operators/_sum.py +23 -6
- reactivex/operators/_switchlatest.py +71 -69
- reactivex/operators/_take.py +37 -33
- reactivex/operators/_takelast.py +37 -36
- reactivex/operators/_takelastbuffer.py +38 -37
- reactivex/operators/_takelastwithtime.py +60 -56
- reactivex/operators/_takeuntil.py +33 -32
- reactivex/operators/_takeuntilwithtime.py +42 -39
- reactivex/operators/_takewhile.py +108 -100
- reactivex/operators/_takewithtime.py +46 -41
- reactivex/operators/_throttlefirst.py +52 -45
- reactivex/operators/_timeinterval.py +40 -36
- reactivex/operators/_timeout.py +81 -79
- reactivex/operators/_timeoutwithmapper.py +6 -5
- reactivex/operators/_timestamp.py +24 -22
- reactivex/operators/_todict.py +51 -43
- reactivex/operators/_tofuture.py +24 -15
- reactivex/operators/_toiterable.py +33 -27
- reactivex/operators/_tomarbles.py +5 -5
- reactivex/operators/_toset.py +29 -19
- reactivex/operators/_whiledo.py +2 -1
- reactivex/operators/_window.py +100 -99
- reactivex/operators/_windowwithcount.py +56 -54
- reactivex/operators/_windowwithtime.py +95 -79
- reactivex/operators/_windowwithtimeorcount.py +85 -69
- reactivex/operators/_withlatestfrom.py +13 -9
- reactivex/operators/_zip.py +67 -63
- reactivex/operators/connectable/_refcount.py +4 -3
- reactivex/pipe.py +2 -1
- reactivex/run.py +8 -4
- reactivex/scheduler/catchscheduler.py +11 -10
- reactivex/scheduler/currentthreadscheduler.py +2 -3
- reactivex/scheduler/eventloop/asyncioscheduler.py +7 -6
- reactivex/scheduler/eventloop/asynciothreadsafescheduler.py +12 -14
- reactivex/scheduler/eventloop/eventletscheduler.py +4 -4
- reactivex/scheduler/eventloop/geventscheduler.py +4 -4
- reactivex/scheduler/eventloop/ioloopscheduler.py +4 -4
- reactivex/scheduler/eventloop/twistedscheduler.py +4 -4
- reactivex/scheduler/eventloopscheduler.py +9 -12
- reactivex/scheduler/historicalscheduler.py +1 -2
- reactivex/scheduler/immediatescheduler.py +5 -4
- reactivex/scheduler/mainloop/gtkscheduler.py +6 -7
- reactivex/scheduler/mainloop/pygamescheduler.py +4 -4
- reactivex/scheduler/mainloop/qtscheduler.py +6 -6
- reactivex/scheduler/mainloop/tkinterscheduler.py +4 -4
- reactivex/scheduler/mainloop/wxscheduler.py +7 -7
- reactivex/scheduler/newthreadscheduler.py +6 -8
- reactivex/scheduler/periodicscheduler.py +4 -4
- reactivex/scheduler/scheduleditem.py +4 -4
- reactivex/scheduler/scheduler.py +5 -5
- reactivex/scheduler/threadpoolscheduler.py +3 -3
- reactivex/scheduler/timeoutscheduler.py +5 -4
- reactivex/scheduler/trampoline.py +1 -2
- reactivex/scheduler/trampolinescheduler.py +5 -6
- reactivex/scheduler/virtualtimescheduler.py +4 -4
- reactivex/subject/asyncsubject.py +2 -2
- reactivex/subject/behaviorsubject.py +2 -2
- reactivex/subject/innersubscription.py +2 -2
- reactivex/subject/replaysubject.py +8 -8
- reactivex/subject/subject.py +4 -4
- reactivex/testing/coldobservable.py +5 -5
- reactivex/testing/hotobservable.py +6 -6
- reactivex/testing/marbles.py +21 -20
- reactivex/testing/mockdisposable.py +1 -3
- reactivex/testing/mockobserver.py +2 -2
- reactivex/testing/reactivetest.py +2 -2
- reactivex/testing/recorded.py +1 -1
- reactivex/testing/subscription.py +3 -3
- reactivex/testing/testscheduler.py +13 -12
- reactivex/typing.py +25 -14
- {reactivex-4.1.0.dist-info → reactivex-5.0.0a2.dist-info}/METADATA +59 -26
- reactivex-5.0.0a2.dist-info/RECORD +236 -0
- {reactivex-4.1.0.dist-info → reactivex-5.0.0a2.dist-info}/WHEEL +1 -1
- reactivex-4.1.0.dist-info/RECORD +0 -223
- {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
|
|
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
|
-
|
|
16
|
-
|
|
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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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,
|
|
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:
|
|
21
|
-
scheduler:
|
|
22
|
-
) ->
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
if is_shift:
|
|
94
|
+
s = Subject()
|
|
95
|
+
queue.append(s)
|
|
96
|
+
observer.on_next(add_ref(s, ref_count_disposable))
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
if is_span:
|
|
99
|
+
s = queue.pop(0)
|
|
100
|
+
s.on_completed()
|
|
85
101
|
|
|
86
|
-
|
|
102
|
+
create_timer()
|
|
87
103
|
|
|
88
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
98
|
-
|
|
110
|
+
def on_next(x: _T) -> None:
|
|
111
|
+
with source.lock:
|
|
99
112
|
for s in queue:
|
|
100
|
-
s.
|
|
113
|
+
s.on_next(x)
|
|
101
114
|
|
|
102
|
-
|
|
115
|
+
@synchronized(source.lock)
|
|
116
|
+
def on_error(e: Exception) -> None:
|
|
117
|
+
for s in queue:
|
|
118
|
+
s.on_error(e)
|
|
103
119
|
|
|
104
|
-
|
|
105
|
-
def on_completed() -> None:
|
|
106
|
-
for s in queue:
|
|
107
|
-
s.on_completed()
|
|
120
|
+
observer.on_error(e)
|
|
108
121
|
|
|
109
|
-
|
|
122
|
+
@synchronized(source.lock)
|
|
123
|
+
def on_completed() -> None:
|
|
124
|
+
for s in queue:
|
|
125
|
+
s.on_completed()
|
|
110
126
|
|
|
111
|
-
|
|
112
|
-
source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)
|
|
113
|
-
)
|
|
114
|
-
return ref_count_disposable
|
|
127
|
+
observer.on_completed()
|
|
115
128
|
|
|
116
|
-
|
|
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
|
|
134
|
+
return Observable(subscribe)
|
|
119
135
|
|
|
120
136
|
|
|
121
137
|
__all__ = ["window_with_time_"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any,
|
|
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:
|
|
21
|
-
) ->
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
61
|
+
if _id != window_id:
|
|
62
|
+
return
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
93
|
+
if new_window:
|
|
94
|
+
create_timer(new_id)
|
|
58
95
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
return ref_count_disposable
|
|
100
|
+
def on_completed() -> None:
|
|
101
|
+
s.on_completed()
|
|
102
|
+
observer.on_completed()
|
|
90
103
|
|
|
91
|
-
|
|
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
|
|
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
|
|
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
|
-
) ->
|
|
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
|
-
>>>
|
|
19
|
-
>>>
|
|
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_"]
|