def test_adapt_call_underlying_error(self): err_msg = "We should see the original traceback." def throws(a): raise TypeError(err_msg) with self.assertRaises(TypeError) as e: adapt_call(throws)(None) self.assertEqual(err_msg, str(e.exception))
def test_adapt_call_adaptation_error(self): def not_adaptable(a, b, c): pass err_msg = "Couldn't adapt function {}".format(not_adaptable.__name__) with self.assertRaises(TypeError) as e1: adapt_call(not_adaptable)(None) with self.assertRaises(TypeError) as e2: adapt_call(not_adaptable)(None, None) for e in (e1, e2): self.assertEqual(err_msg, str(e.exception))
def select(self, selector): """Projects each element of an observable sequence into a new form by incorporating the element's index. 1 - source.map(lambda value: value * value) 2 - source.map(lambda value, index: value * value + index) Keyword arguments: :param Callable[[Any, Any], Any] selector: A transform function to apply to each source element; the second parameter of the function represents the index of the source element. :rtype: Observable Returns an observable sequence whose elements are the result of invoking the transform function on each element of source. """ selector = adapt_call(selector) def subscribe(observer): count = [0] def on_next(value): try: result = selector(value, count[0]) except Exception as err: observer.on_error(err) else: count[0] += 1 observer.on_next(result) return self.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def test_adapt_call_stcmethod1(self): func = adapt_call(C(42).stcmethod1) value = func(42) assert value == 4200 value = func(42, 43) assert value == 4200 value = func(42, 43, 44) assert value == 4200
def select_many(self, selector, result_selector=None): """One of the Following: Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence. 1 - source.select_many(lambda x: Observable.range(0, x)) Or: Projects each element of an observable sequence to an observable sequence, invokes the result selector for the source element and each of the corresponding inner sequence's elements, and merges the results into one observable sequence. 1 - source.select_many(lambda x: Observable.range(0, x), lambda x, y: x + y) Or: Projects each element of the source observable sequence to the other observable sequence and merges the resulting observable sequences into one observable sequence. 1 - source.select_many(Observable.from_([1,2,3])) Keyword arguments: selector -- A transform function to apply to each element or an observable sequence to project each element from the source sequence onto. result_selector -- [Optional] A transform function to apply to each element of the intermediate sequence. Returns an observable sequence whose elements are the result of invoking the one-to-many transform function collectionSelector on each element of the input sequence and then mapping each of those sequence elements and their corresponding source element to a result element. """ if result_selector: def projection(x, i): selector_result = selector(x, i) if isinstance(selector_result, collections.Iterable): result = Observable.from_(selector_result) else: result = Observable.from_future(selector_result) return result.map(lambda y, i: result_selector(x, y, i)) return self.flat_map(projection) if callable(selector): selector = adapt_call(selector) ret = _flat_map(self, selector) else: ret = _flat_map(self, lambda _, __: selector) return ret
def select_many(self, selector, result_selector=None): """One of the Following: Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence. 1 - source.select_many(lambda x: Observable.range(0, x)) Or: Projects each element of an observable sequence to an observable sequence, invokes the result selector for the source element and each of the corresponding inner sequence's elements, and merges the results into one observable sequence. 1 - source.select_many(lambda x: Observable.range(0, x), lambda x, y: x + y) Or: Projects each element of the source observable sequence to the other observable sequence and merges the resulting observable sequences into one observable sequence. 1 - source.select_many(Observable.from_([1,2,3])) Keyword arguments: selector -- A transform function to apply to each element or an observable sequence to project each element from the source sequence onto. result_selector -- [Optional] A transform function to apply to each element of the intermediate sequence. Returns an observable sequence whose elements are the result of invoking the one-to-many transform function collectionSelector on each element of the input sequence and then mapping each of those sequence elements and their corresponding source element to a result element. """ if result_selector: def projection(x, i): selector_result = selector(x, i) if isinstance(selector_result, collections.Iterable): result = Observable.from_(selector_result) else: result = Observable.from_future(selector_result) return result.map(lambda y: result_selector(x, y, i)) return self.flat_map(projection) if callable(selector): selector = adapt_call(selector) ret = _flat_map(self, selector) else: ret = _flat_map(self, lambda _,__: selector) return ret
def for_each(self, action): """Invokes a method on each item emitted by this BlockingObservable and blocks until the Observable completes. Note: This will block even if the underlying Observable is asynchronous. This is similar to Observable#subscribe(subscriber), but it blocks. Because it blocks it does not need the Subscriber#on_completed() or Subscriber#on_error(Throwable) methods. If the underlying Observable terminates with an error, rather than calling `onError`, this method will throw an exception. Keyword arguments: :param types.FunctionType action: the action to invoke for each item emitted by the `BlockingObservable`. :raises Exception: if an error occurs :returns: None :rtype: None """ action = adapt_call(action) latch = threading.Event() exception = [None] count = [0] def on_next(value): with self.lock: i = count[0] count[0] += 1 action(value, i) def on_error(err): # If we receive an on_error event we set the reference on the # outer thread so we can git it and throw after the latch.wait() # # We do this instead of throwing directly since this may be on # a different thread and the latch is still waiting. exception[0] = err latch.set() def on_completed(): latch.set() self.observable.subscribe(on_next, on_error, on_completed) # Block until the subscription completes and then return latch.wait() if exception[0] is not None: raise Exception(exception[0])
def for_each(self, action): """Invokes a method on each item emitted by this BlockingObservable and blocks until the Observable completes. Note: This will block even if the underlying Observable is asynchronous. This is similar to Observable#subscribe(subscriber), but it blocks. Because it blocks it does not need the Subscriber#on_completed() or Subscriber#on_error(Throwable) methods. If the underlying Observable terminates with an error, rather than calling `onError`, this method will throw an exception. Keyword arguments: :param types.FunctionType action: the action to invoke for each item emitted by the `BlockingObservable`. :raises Exception: if an error occurs :returns: None :rtype: None """ action = adapt_call(action) latch = config["concurrency"].Event() exception = [None] count = [0] def on_next(value): with self.lock: i = count[0] count[0] += 1 action(value, i) def on_error(err): # If we receive an on_error event we set the reference on the # outer thread so we can git it and throw after the latch.wait() # # We do this instead of throwing directly since this may be on # a different thread and the latch is still waiting. exception[0] = err latch.set() def on_completed(): latch.set() self.observable.subscribe(on_next, on_error, on_completed) # Block until the subscription completes and then return latch.wait() if exception[0] is not None: raise Exception(exception[0])
def take_while(self, predicate): """Returns elements from an observable sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function. 1 - source.take_while(lambda value: value < 10) 2 - source.take_while(lambda value, index: value < 10 or index < 10) Keyword arguments: predicate -- A function to test each element for a condition; the second parameter of the function represents the index of the source element. Returns an observable sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. """ predicate = adapt_call(predicate) observable = self def subscribe(observer): running, i = [True], [0] def on_next(value): with self.lock: if not running[0]: return try: running[0] = predicate(value, i[0]) except Exception as exn: observer.on_error(exn) return else: i[0] += 1 if running[0]: observer.on_next(value) else: observer.on_completed() return observable.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def where(self, predicate): """Filters the elements of an observable sequence based on a predicate by incorporating the element's index. Examples:: source.filter(lambda value: value < 10) source.filter(lambda value, index: value < 10 or index < 10) Arguments: self (Observable): Observable sequence to filter. predicate: A function to test each source element for a condition; the second parameter of the function represents the index of the source element. Returns: Observable: An observable sequence that contains elements from the input sequence that satisfy the condition. """ predicate = adapt_call(predicate) parent = self def subscribe(observer): count = [0] def on_next(value): try: should_run = predicate(value, count[0]) except Exception as ex: observer.on_error(ex) return else: count[0] += 1 if should_run: observer.on_next(value) return parent.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def skip_while(self, predicate): """Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements. The element's index is used in the logic of the predicate function. 1 - source.skip_while(lambda value: value < 10) 2 - source.skip_while(lambda value, index: value < 10 or index < 10) predicate -- A function to test each element for a condition; the second parameter of the function represents the index of the source element. Returns an observable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate. """ predicate = adapt_call(predicate) source = self def subscribe(observer): i, running = [0], [False] def on_next(value): if not running[0]: try: running[0] = not predicate(value, i[0]) except Exception as exn: observer.on_error(exn) return else: i[0] += 1 if running[0]: observer.on_next(value) return source.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def where(self, predicate): """Filters the elements of an observable sequence based on a predicate by incorporating the element's index. 1 - source.filter(lambda value: value < 10) 2 - source.filter(lambda value, index: value < 10 or index < 10) Keyword arguments: :param Observable self: Observable sequence to filter. :param (T, <int>) -> bool predicate: A function to test each source element for a condition; the second parameter of the function represents the index of the source element. :returns: An observable sequence that contains elements from the input sequence that satisfy the condition. :rtype: Observable """ predicate = adapt_call(predicate) parent = self def subscribe(observer): count = [0] def on_next(value): try: should_run = predicate(value, count[0]) except Exception as ex: observer.on_error(ex) return else: count[0] += 1 if should_run: observer.on_next(value) return parent.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def partition(self, predicate): """Returns two observables which partition the observations of the source by the given function. The first will trigger observations for those values for which the predicate returns true. The second will trigger observations for those values where the predicate returns false. The predicate is executed once for each subscribed observer. Both also propagate all error observations arising from the source and each completes when the source completes. Keyword arguments: predicate -- The function to determine which output Observable will trigger a particular observation. Returns a list of observables. The first triggers when the predicate returns True, and the second triggers when the predicate returns False. """ published = self.publish().ref_count() return [ published.where(predicate), # where does adapt_call itself published.where(lambda x, i: not adapt_call(predicate)(x, i)) ]
def test_adapt_call_call_object(self): func = adapt_call(C(42)) value = func(2) assert value == 44
def test_adapt_call_method1(self): func = adapt_call(C(42).method1) value = func(2, 4) assert value == 44