|
1 | 1 | from collections.abc import Callable |
2 | 2 | from typing import Any, TypeVar |
3 | 3 |
|
4 | | -from reactivex import Observable, compose |
| 4 | +from reactivex import Observable |
5 | 5 | from reactivex import operators as ops |
| 6 | +from reactivex.internal import curry_flip |
6 | 7 |
|
7 | 8 | _T = TypeVar("_T") |
8 | 9 |
|
9 | 10 |
|
| 11 | +@curry_flip |
10 | 12 | def buffer_( |
| 13 | + source: Observable[_T], |
11 | 14 | boundaries: Observable[Any], |
12 | | -) -> Callable[[Observable[_T]], Observable[list[_T]]]: |
13 | | - return compose( |
| 15 | +) -> Observable[list[_T]]: |
| 16 | + """Buffers elements from the source based on boundary notifications. |
| 17 | +
|
| 18 | + Examples: |
| 19 | + >>> res = source.pipe(buffer(boundaries)) |
| 20 | + >>> res = buffer(boundaries)(source) |
| 21 | +
|
| 22 | + Args: |
| 23 | + source: Source observable to buffer. |
| 24 | + boundaries: Observable that triggers buffer emissions. |
| 25 | +
|
| 26 | + Returns: |
| 27 | + Observable of lists of buffered elements. |
| 28 | + """ |
| 29 | + return source.pipe( |
14 | 30 | ops.window(boundaries), |
15 | 31 | ops.flat_map(ops.to_list()), |
16 | 32 | ) |
17 | 33 |
|
18 | 34 |
|
| 35 | +@curry_flip |
19 | 36 | def buffer_when_( |
| 37 | + source: Observable[_T], |
20 | 38 | closing_mapper: Callable[[], Observable[Any]], |
21 | | -) -> Callable[[Observable[_T]], Observable[list[_T]]]: |
22 | | - return compose( |
| 39 | +) -> Observable[list[_T]]: |
| 40 | + """Buffers elements using a closing mapper function. |
| 41 | +
|
| 42 | + Examples: |
| 43 | + >>> res = source.pipe(buffer_when(lambda: timer(1.0))) |
| 44 | + >>> res = buffer_when(lambda: timer(1.0))(source) |
| 45 | +
|
| 46 | + Args: |
| 47 | + source: Source observable to buffer. |
| 48 | + closing_mapper: Function that returns an observable signaling buffer close. |
| 49 | +
|
| 50 | + Returns: |
| 51 | + Observable of lists of buffered elements. |
| 52 | + """ |
| 53 | + return source.pipe( |
23 | 54 | ops.window_when(closing_mapper), |
24 | 55 | ops.flat_map(ops.to_list()), |
25 | 56 | ) |
26 | 57 |
|
27 | 58 |
|
| 59 | +@curry_flip |
28 | 60 | def buffer_toggle_( |
29 | | - openings: Observable[Any], closing_mapper: Callable[[Any], Observable[Any]] |
30 | | -) -> Callable[[Observable[_T]], Observable[list[_T]]]: |
31 | | - return compose( |
| 61 | + source: Observable[_T], |
| 62 | + openings: Observable[Any], |
| 63 | + closing_mapper: Callable[[Any], Observable[Any]], |
| 64 | +) -> Observable[list[_T]]: |
| 65 | + """Buffers elements using opening/closing observables. |
| 66 | +
|
| 67 | + Examples: |
| 68 | + >>> res = source.pipe(buffer_toggle(opens, lambda x: timer(x))) |
| 69 | + >>> res = buffer_toggle(opens, lambda x: timer(x))(source) |
| 70 | +
|
| 71 | + Args: |
| 72 | + source: Source observable to buffer. |
| 73 | + openings: Observable that triggers buffer opening. |
| 74 | + closing_mapper: Function to create closing observable. |
| 75 | +
|
| 76 | + Returns: |
| 77 | + Observable of lists of buffered elements. |
| 78 | + """ |
| 79 | + return source.pipe( |
32 | 80 | ops.window_toggle(openings, closing_mapper), |
33 | 81 | ops.flat_map(ops.to_list()), |
34 | 82 | ) |
35 | 83 |
|
36 | 84 |
|
| 85 | +@curry_flip |
37 | 86 | def buffer_with_count_( |
38 | | - count: int, skip: int | None = None |
39 | | -) -> Callable[[Observable[_T]], Observable[list[_T]]]: |
| 87 | + source: Observable[_T], |
| 88 | + count: int, |
| 89 | + skip: int | None = None, |
| 90 | +) -> Observable[list[_T]]: |
40 | 91 | """Projects each element of an observable sequence into zero or more |
41 | 92 | buffers which are produced based on element count information. |
42 | 93 |
|
43 | 94 | Examples: |
44 | | - >>> res = buffer_with_count(10)(xs) |
45 | | - >>> res = buffer_with_count(10, 1)(xs) |
| 95 | + >>> res = source.pipe(buffer_with_count(10)) |
| 96 | + >>> res = buffer_with_count(10)(source) |
| 97 | + >>> res = source.pipe(buffer_with_count(10, 1)) |
46 | 98 |
|
47 | 99 | Args: |
| 100 | + source: Source observable to buffer. |
48 | 101 | count: Length of each buffer. |
49 | 102 | skip: [Optional] Number of elements to skip between |
50 | 103 | creation of consecutive buffers. If not provided, defaults to |
51 | 104 | the count. |
52 | 105 |
|
53 | 106 | Returns: |
54 | | - A function that takes an observable source and returns an |
55 | | - observable sequence of buffers. |
| 107 | + An observable sequence of buffers. |
56 | 108 | """ |
| 109 | + skip_ = skip if skip is not None else count |
57 | 110 |
|
58 | | - def buffer_with_count(source: Observable[_T]) -> Observable[list[_T]]: |
59 | | - nonlocal skip |
60 | | - |
61 | | - if skip is None: |
62 | | - skip = count |
63 | | - |
64 | | - def mapper(value: Observable[_T]) -> Observable[list[_T]]: |
65 | | - return value.pipe( |
66 | | - ops.to_list(), |
67 | | - ) |
68 | | - |
69 | | - def predicate(value: list[_T]) -> bool: |
70 | | - return len(value) > 0 |
71 | | - |
72 | | - return source.pipe( |
73 | | - ops.window_with_count(count, skip), |
74 | | - ops.flat_map(mapper), |
75 | | - ops.filter(predicate), |
| 111 | + def mapper(value: Observable[_T]) -> Observable[list[_T]]: |
| 112 | + return value.pipe( |
| 113 | + ops.to_list(), |
76 | 114 | ) |
77 | 115 |
|
78 | | - return buffer_with_count |
| 116 | + def predicate(value: list[_T]) -> bool: |
| 117 | + return len(value) > 0 |
| 118 | + |
| 119 | + return source.pipe( |
| 120 | + ops.window_with_count(count, skip_), |
| 121 | + ops.flat_map(mapper), |
| 122 | + ops.filter(predicate), |
| 123 | + ) |
79 | 124 |
|
80 | 125 |
|
81 | 126 | __all__ = ["buffer_", "buffer_with_count_", "buffer_when_", "buffer_toggle_"] |
0 commit comments