Beispiel #1
0
def loop_flowables(
    func: Callable[[MultiCastItem], MultiCastItem],
    initial: ValueType,
):
    """
    Create a MultiCast of multi-casted Flowables that are either emitted by the
    source or looped back inside the `loop_flowables`. The looped Flowable sequences
    are defined by an initial value and some recursive logic.

    :param func: a function that exposes (a shared MultiCast emitting)
    a dictionary of Flowables consisting of the incoming Flowables
    and the looped Flowables.
    :param initial: initial values of the looped Flowables
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        def lifted_func(multicast: MultiCastMixin):
            return func(init_multicast(multicast))

        return source.loop_flowables(
            func=lifted_func,
            initial=initial,
            stack=stack,
        )

    return MultiCastOperator(func=op_func)
Beispiel #2
0
def controlled_zip(
    right: FlowableMixin,
    request_left: Callable[[Any, Any], bool] = None,
    request_right: Callable[[Any, Any], bool] = None,
    match_func: Callable[[Any, Any], bool] = None,
):
    """
    Creates a new Flowable from two Flowables by combining their elements in pairs. Which
    element gets paired with an element from the other Flowable is determined by two functions
    called `request_left` and `request_right`.

    :param right: other Flowable
    :param request_left: a function that returns True, if a new element from the left \
    Flowable is requested to build the the next pair
    :param request_right: a function that returns True, if a new element from the left \
    Flowable is requested to build the the next pair
    :param match_func: a filter function that returns True, if the current pair is sent \
    downstream
    :return: zipped Flowable
    """

    stack = get_stack_lines()

    def op_func(left: Flowable):
        return left.controlled_zip(
            right=right,
            stack=stack,
            request_left=request_left,
            request_right=request_right,
            match_func=match_func,
        )

    return PipeOperation(op_func)
Beispiel #3
0
def assert_single_subscription():
    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.assert_single_subscription(stack=stack)

    return MultiCastOperator(op_func)
Beispiel #4
0
def flatten():
    stack = get_stack_lines()

    def op_func(source: Flowable):
        return source.flat_map(func=lambda v: v, stack=stack)

    return PipeOperation(op_func)
Beispiel #5
0
def join_flowables(*others: MultiCastOpMixin, ):
    """
    Zip one or more *Multicasts* (each emitting a single *Flowable*) to a *Multicast*
    emitting a single element (tuple of *Flowables*).

    The number of Flowables contained in the tuple is equal to the number of collected
    MultiCasts.

    ::

        # collect two Flowables emitted by two different MultiCast
        rxbp.multicast.return_flowable(rxbp.range(10)).pipe(
            rxbp.multicast.op.join_flowables(
                rxbp.multicast.return_flowable(rxbp.range(10)),
            ),
        )

    :param others: other MultiCasts that all emit a single Flowable
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.join_flowables(list(others), stack=stack)

    return MultiCastOperator(op_func)
Beispiel #6
0
def debug(
    name: str,
    on_next: Callable[[Any], None] = None,
    on_completed: Callable[[], None] = None,
    on_error: Callable[[Exception], None] = None,
    on_subscribe: Callable[[MultiCastObserverInfo, MultiCastSubscriber],
                           None] = None,
    on_observe: Callable[[MultiCastObserverInfo], None] = None,
    on_dispose: Callable[[], None] = None,
    verbose: bool = None,
):
    """
    Print debug messages to the console when providing the `name` argument
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.debug(
            name=name,
            on_next=on_next,
            on_completed=on_completed,
            on_error=on_error,
            on_subscribe=on_subscribe,
            on_observe=on_observe,
            on_dispose=on_dispose,
            verbose=verbose,
            stack=stack,
        )

    return MultiCastOperator(op_func)
Beispiel #7
0
def flat_map(func: Callable[[MultiCastItem], MultiCastOpMixin]):
    """
    Apply a function to each item emitted by the source and flattens the result.
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.flat_map(func=func, stack=stack)

    return MultiCastOperator(op_func)
Beispiel #8
0
def flatten():
    """
    Apply a function to each item emitted by the source and flattens the result.
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.flat_map(func=lambda v: v, stack=stack)

    return MultiCastOperator(op_func)
    def test_on_error(self):
        sink = TObserver()
        observer = FirstObserver(
            observer=sink,
            stack=get_stack_lines(),
        )
        self.source.observe(init_observer_info(observer))

        self.source.on_error(self.exc)

        self.assertEqual(self.exc, sink.exception)
    def test_on_complete(self):
        sink = TObserver()
        observer = FirstObserver(
            observer=sink,
            stack=get_stack_lines(),
        )
        self.source.observe(init_observer_info(observer))

        self.source.on_completed()

        self.assertFalse(sink.is_completed)
        self.assertIsInstance(sink.exception, SequenceContainsNoElementsError)
Beispiel #11
0
def zip(*sources: Flowable) -> Flowable: #, result_selector: Callable[..., Any] = None) -> Flowable:
    """
    Create a new Flowable from zero or more Flowables by combining their item in pairs in a strict sequence.

    :param sources: zero or more Flowables whose elements are zipped together
    """

    stack = get_stack_lines()

    if len(sources) == 0:
        return empty()
    else:
        return sources[0].zip(sources[1:], stack=stack)
    def test_single_batch(self):
        sink = TObserver()
        observer = FirstObserver(
            observer=sink,
            stack=get_stack_lines(),
        )
        self.source.observe(init_observer_info(observer))

        ack = self.source.on_next_list([0, 1, 2, 3])

        self.assertEqual([0], sink.received)
        self.assertIsInstance(ack, StopAck)
        self.assertTrue(sink.is_completed)
Beispiel #13
0
def zip(*others: Flowable):
    """
    Create a new Flowable from one or more Flowables by combining their item in pairs in a strict sequence.

    :param others: :param sources: other Flowables that get zipped to this Flowable.
    """

    stack = get_stack_lines()

    def op_func(left: Flowable):
        return left.zip(others=others, stack=stack)

    return PipeOperation(op_func)
def debug_base(
        base: Any,
        name: str = None,
):
    stack = get_stack_lines()

    def op_func(source: IndexedFlowable):
        return source.debug_base(
            base=base,
            stack=stack,
            name=name,
        )

    return PipeOperation(op_func)
Beispiel #15
0
def share(func: Callable[[MultiCast], MultiCast], ):
    """
    Multi-cast the elements of the source to possibly multiple subscribers.

    This function is only valid when used inside a Multicast. Otherwise, it
    raise an exception.
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.share_func(func=func, stack=stack)

    return MultiCastOperator(op_func)
Beispiel #16
0
def filter(predicate: Callable[[Any], bool]):
    """
    Only emit those elements for which the given predicate holds.

    :param predicate: a function that returns True, if the current element passes the filter
    :return: filtered Flowable
    """

    stack = get_stack_lines()

    def op_func(left: Flowable):
        return left.filter(predicate=predicate, stack=stack)

    return PipeOperation(op_func)
Beispiel #17
0
def flat_map(func: Callable[[Any], Flowable]):
    """
    Apply a function to each item emitted by the source and flattens the result.

    The specified function must return a Flowable. The resulting Flowable
    concatenates the elements of each inner Flowables.
    The resulting Flowable concatenates the items of each inner Flowable.
    """

    stack = get_stack_lines()

    def op_func(source: Flowable):
        return source.flat_map(func=func, stack=stack)

    return PipeOperation(op_func)
Beispiel #18
0
def first(
        # raise_exception: Callable[[Callable[[], None]], None],
):
    """
    Either emits the elements of the source or a single element
    returned by `lazy_val` if the source doesn't emit any elements.

    :param lazy_val: a function that returns the single elements
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.first(stack=stack)

    return MultiCastOperator(op_func)
def match(*sources: IndexedFlowable) -> IndexedFlowable:
    """
    Merge the elements of zero or more *Flowables* into a single *Flowable*.

    :param sources: zero or more Flowables whose elements are merged
    """

    assert all(isinstance(source, IndexedFlowableMixin) for source in sources), \
        f'"{sources}" must all be of type IndexedFlowableMixin'

    stack = get_stack_lines()

    if len(sources) == 0:
        return empty()
    else:
        return sources[0].match(*sources[1:], stack=stack)
    def test_single_element(self):
        sink = TObserver()
        observer = LastObserver(
            observer=sink,
            stack=get_stack_lines(),
        )
        self.source.observe(init_observer_info(observer))

        ack = self.source.on_next_single(0)

        self.assertEqual([], sink.received)
        self.assertIsInstance(ack, ContinueAck)
        self.assertFalse(sink.is_completed)

        self.source.on_completed()

        self.assertEqual([0], sink.received)
        self.assertTrue(sink.is_completed)
def match(
        *others: IndexedFlowable,
):
    """
    Create a new Flowable from this and other Flowables by first filtering and duplicating (if necessary)
    the elements of each Flowable and zip the resulting Flowable sequences together.

    :param sources: other Flowables that get matched with this Flowable.
    """

    stack = get_stack_lines()

    def op_func(left: IndexedFlowable):
        return left.match(
            *others,
            stack=stack,
        )

    return PipeOperation(op_func)
Beispiel #22
0
def last():
    """
    Emit the last element of the Flowable sequence

    The `raise_exception` argument needs to be given as follows:

    ::

        rxbp.op.last(raise_exception=lambda f: f())

    The `raise_exception` argument is called in case there is no element.
    Like RxPY, a SequenceContainsNoElementsError is risen. But on top of that
    the place where the `last` argument is used is added to the traceback by
    providing the `raise_exception` argument.
    """

    stack = get_stack_lines()

    def op_func(source: Flowable):
        return source.last(stack=stack)

    return PipeOperation(op_func)
Beispiel #23
0
def merge_flowables(maintain_order: bool = None, ):
    """
    Create a MultiCast that emits a single element containing the reduced Flowables
    of the first element sent by the source. It is expected that the consequent
    elements emitted by the source have the same structure as the first element.

    A reduced Flowable sequences is composed by one or more (Flowable) sources.

    :param maintain_order: if True, then the reduced Flowable sequences maintain
    the order of the Flowable sources. Otherwise, the reduced Flowable
    sequence flattens the elements emitted by the sources.
    """

    stack = get_stack_lines()

    def op_func(source: MultiCast):
        return source.collect_flowables(
            stack=stack,
            maintain_order=maintain_order,
        )

    return MultiCastOperator(op_func)
Beispiel #24
0
def debug(
    name: str,
    on_next: Callable[[Any], Ack] = None,
    on_completed: Callable[[], None] = None,
    on_error: Callable[[Exception], None] = None,
    on_sync_ack: Callable[[Ack], None] = None,
    on_async_ack: Callable[[Ack], None] = None,
    on_observe: Callable[[ObserverInfo], None] = None,
    on_subscribe: Callable[[Subscriber], None] = None,
    on_raw_ack: Callable[[Ack], None] = None,
    verbose: bool = None,
):
    """
    Print debug messages to the console when providing the `name` argument

    :on_next: customize the on next debug console print
    """

    stack = get_stack_lines()

    def op_func(source: Flowable):
        return source.debug(
            name=name,
            on_next=on_next,
            on_completed=on_completed,
            on_error=on_error,
            on_observe=on_observe,
            on_subscribe=on_subscribe,
            on_sync_ack=on_sync_ack,
            on_async_ack=on_async_ack,
            on_raw_ack=on_raw_ack,
            stack=stack,
            verbose=verbose,
        )

    return PipeOperation(op_func)
    def share(self) -> 'IndexedFlowable':
        stack = get_stack_lines()

        return self._share(stack=stack)
 def test_initialize(self):
     sink = TObserver()
     FirstObserver(
         observer=sink,
         stack=get_stack_lines(),
     )
Beispiel #27
0
    def pipe(self,
             *operators: PipeOperation['SharedFlowable']) -> 'SharedFlowable':
        stack = get_stack_lines()

        return functools.reduce(lambda obs, op: op(obs), operators,
                                self)._share(stack=stack)