def partition(source: Observable) -> List[Observable]: """The partially applied `partition` operator. 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. Args: source: Source obserable to partition. Returns: A list of observables. The first triggers when the predicate returns True, and the second triggers when the predicate returns False. """ published = source.pipe( ops.publish(), ops.ref_count() ) return [ published.pipe(ops.filter(predicate)), published.pipe(ops.filter(lambda x: not predicate(x))) ]
def create(): def mapper(x_yy): x, yy = x_yy return yy.pipe(ops.map(lambda y: '{}{}'.format(x.value, y.value))) return xs.pipe( ops.group_join( ys, lambda x: rx.timer(x.interval).pipe(ops.filter(lambda _: False)), lambda y: rx.timer(y.interval).pipe(ops.filter(lambda _: False)), ), ops.flat_map(mapper), )
def create(): def mapper(xy): x, y = xy return "{}{}".format(x.value, y.value) return xs.pipe( ops.join( ys, lambda x: rx.timer(x.interval).pipe(ops.filter(lambda _: False)), lambda y: rx.timer(y.interval).pipe(ops.filter(lambda _: False)), ), ops.map(mapper), )
def _first_or_default(predicate: Predicate = None, default_value: Any = None) -> Callable[[Observable], Observable]: """Returns the first element of an observable sequence that satisfies the condition in the predicate, or a default value if no such element exists. Examples: >>> res = source.first_or_default() >>> res = source.first_or_default(lambda x: x > 3) >>> res = source.first_or_default(lambda x: x > 3, 0) >>> res = source.first_or_default(None, 0) Args: source -- Observable sequence. predicate -- [optional] A predicate function to evaluate for elements in the source sequence. default_value -- [Optional] The default value if no such element exists. If not specified, defaults to None. Returns: A function that takes an observable source and reutrn an observable sequence containing the first element in the observable sequence that satisfies the condition in the predicate, or a default value if no such element exists. """ if predicate: return pipe( ops.filter(predicate), ops.first_or_default(None, default_value) ) return _first_or_default_async(True, default_value)
def _single_or_default(predicate: Predicate = None, default_value: Any = None) -> Observable: """Returns the only element of an observable sequence that matches the predicate, or a default value if no such element exists this method reports an exception if there is more than one element in the observable sequence. Examples: >>> res = single_or_default() >>> res = single_or_default(lambda x: x == 42) >>> res = single_or_default(lambda x: x == 42, 0) >>> res = single_or_default(None, 0) Args: predicate -- [Optional] A predicate function to evaluate for elements in the source sequence. default_value -- [Optional] The default value if the index is outside the bounds of the source sequence. Returns: An observable Sequence containing the single element in the observable sequence that satisfies the condition in the predicate, or a default value if no such element exists. """ if predicate: return pipe(ops.filter(predicate), ops.single_or_default(None, default_value)) else: return _single_or_default_async(True, default_value)
def open(self): scheduler = AsyncIOScheduler() print("WebSocket opened") # A Subject is both an observable and observer, so we can both subscribe # to it and also feed (send) it with new values self.subject = Subject() # Get all distinct key up events from the input and only fire if long enough and distinct searcher = self.subject.pipe( ops.map(lambda x: x["term"]), ops.filter(lambda text: len(text) > 2), # Only if the text is longer than 2 characters ops.debounce(0.750), # Pause for 750ms ops.distinct_until_changed(), # Only if the value has changed ops.flat_map_latest(search_wikipedia) ) def send_response(x): self.write_message(x.body) def on_error(ex): print(ex) searcher.subscribe(send_response, on_error, scheduler=scheduler)
def last(source: Observable) -> Observable: """Partially applied last operator. Returns the last element of an observable sequence that satisfies the condition in the predicate if specified, else the last element. Examples: >>> res = last(source) Args: source: Source observable to get last item from. Returns: An observable sequence containing the last element in the observable sequence that satisfies the condition in the predicate. """ if predicate: return source.pipe( operators.filter(predicate), operators.last() ) return last_or_default_async(source, False)
def some(source: Observable) -> Observable: """Partially applied operator. Determines whether some element of an observable sequence satisfies a condition if present, else if some items are in the sequence. Example: >>> obs = some(source) Args: predicate -- A function to test each element for a condition. Returns: An observable sequence containing a single element determining whether some elements in the source sequence pass the test in the specified predicate if given, else if some items are in the sequence. """ def subscribe(observer, scheduler=None): def on_next(_): observer.on_next(True) observer.on_completed() def on_error(): observer.on_next(False) observer.on_completed() return source.subscribe_(on_next, observer.on_error, on_error, scheduler) if predicate: return source.pipe( ops.filter(predicate), _some(), ) return Observable(subscribe)
def _contains(value: Any, comparer=None) -> Callable[[Observable], Observable]: comparer_ = comparer or default_comparer filtering = ops.filter(lambda v: comparer_(v, value)) something = ops.some() return pipe(filtering, something)
def create(): def predicate(x): invoked[0] += 1 if x > 5: raise Exception(ex) return is_prime(x) return xs.pipe(filter(predicate))
def _count(predicate: Optional[Predicate] = None) -> Callable[[Observable], Observable]: if predicate: filtering = ops.filter(predicate) return pipe(filtering, ops.count()) counter = ops.reduce(lambda n, _: n + 1, seed=0) return pipe(counter)
def action(scheduler, state): def predicate(x): invoked[0] += 1 if x == 8: d.dispose() return is_prime(x) ys[0] = xs.pipe(filter(predicate)) return ys[0]
def _all(predicate: Predicate) -> Callable[[Observable], Observable]: filtering = ops.filter(lambda v: not predicate(v)) mapping = ops.map(lambda b: not b) some = ops.some() return pipe( filtering, some, mapping )
def buffer_with_count(source: Observable) -> Observable: nonlocal skip if skip is None: skip = count def mapper(value): return value.pipe(ops.to_iterable(), ops.map(list)) def predicate(value): return len(value) > 0 return source.pipe(ops.window_with_count(count, skip), ops.flat_map(mapper), ops.filter(predicate))
def open(self): print("WebSocket opened") # A Subject is both an observable and observer, so we can both subscribe # to it and also feed (on_next) it with new values self.subject = Subject() # Now we take on our magic glasses and project the stream of bytes into # a ... query = self.subject.pipe( # 1. stream of keycodes ops.map(lambda obj: obj["keycode"]), # 2. stream of windows (10 ints long) ops.window_with_count(10, 1), # 3. stream of booleans, True or False ops.flat_map(lambda win: win.pipe(ops.sequence_equal(codes))), # 4. stream of Trues ops.filter(lambda equal: equal) ) # 4. we then subscribe to the Trues, and signal Konami! if we see any query.subscribe(lambda x: self.write_message("Konami!"))
def last_or_default(source: Observable) -> Observable: """Return last or default element. Examples: >>> res = _last_or_default(source) Args: source: Observable sequence to get the last item from. Returns: Observable sequence containing the last element in the observable sequence. """ if predicate: return source.pipe( ops.filter(predicate), ops.last_or_default(None, default_value), ) return last_or_default_async(source, True, default_value)
def _single(predicate: Predicate = None) -> Callable[[Observable], Observable]: """Returns the only element of an observable sequence that satisfies the condition in the optional predicate, and reports an exception if there is not exactly one element in the observable sequence. Example: >>> res = single() >>> res = single(lambda x: x == 42) Args: predicate -- [Optional] A predicate function to evaluate for elements in the source sequence. Returns: An observable sequence containing the single element in the observable sequence that satisfies the condition in the predicate. """ if predicate: return pipe(ops.filter(predicate), ops.single()) else: return ops.single_or_default_async(False)
def _first(predicate=None) -> Callable[[Observable], Observable]: """Returns the first element of an observable sequence that satisfies the condition in the predicate if present else the first item in the sequence. Examples: >>> res = res = first()(source) >>> res = res = first(lambda x: x > 3)(source) Args: predicate -- [Optional] A predicate function to evaluate for elements in the source sequence. Returns: A function that takes an observable source and returns an observable sequence containing the first element in the observable sequence that satisfies the condition in the predicate if provided, else the first item in the sequence. """ if predicate: return pipe(ops.filter(predicate), ops.first()) return _first_or_default_async(False)
def demo3(): '''先入优先队列,在t序列到达出队''' #数据源要是热的,保证每个队列 source_stream = Subject() #优先队列 pq = PriorityQueue() push_to_pq = lambda item: pq.put((item['ts'], item)) audio_stream = source_stream.pipe( op.filter(lambda i: i['type'] == 'a') #过滤出a ) audio_stream.subscribe(push_to_pq) img_stream = source_stream.pipe( op.filter(lambda i: i['type'] == 'v'), #过滤出v op.map(v2i), #得到i ) img_stream.subscribe(push_to_pq) target_stream = img_stream.pipe( op.map(i2t), #得到t ) #根据最慢的target_stream组装同步后的最终结果 composed_stream = Subject() def send_all_until(item_t): '''把t前后时段的全部东西汇总,然后按timestamp排序,再输出 但是不work ''' ts_end = item_t['ts'] #从优先队列中取出全部优先级小于等于ts_end的记录,拿出来的顺序就是最终输出的顺序 print(ts_end) res = [] while True: #优先队列中拿出来的顺序是ts从小到大的顺序 ts, item = pq.get() if ts <= ts_end: res.append(item) else: #如果拿多了,要塞回去, 且停止继续拿 pq.put((ts, item)) break #如果拿完了,也退出 if pq.qsize() == 0: break #最后补上最慢的target res.append(item_t) #print(f'时刻 {ts_end}, 队列中样本 {res}') # for item in res: composed_stream.on_next(item) target_stream.subscribe(send_all_until) composed_stream.subscribe( lambda value: print("Received {0}".format(value))) #-------------stream的管道完全连接完毕---------------------------- #最后才开始推送数据 for item in [ { 'ts': 0, 'type': 'v', 'data': 'v1' }, { 'ts': 1, 'type': 'a', 'data': 'a1' }, { 'ts': 2, 'type': 'a', 'data': 'a2' }, { 'ts': 3, 'type': 'v', 'data': 'v2' }, { 'ts': 4, 'type': 'a', 'data': 'a3' }, { 'ts': 5, 'type': 'a', 'data': 'a4' }, { 'ts': 6, 'type': 'v', 'data': 'v3' }, ]: source_stream.on_next(item)
import rx from rx import operators as ops import os def recursive_files_in_directory(folder): def emit_files_recursively(observer, scheduler): for root, directories, filenames in os.walk(folder): for directory in directories: observer.on_next(os.path.join(root, directory)) for filename in filenames: observer.on_next(os.path.join(root, filename)) observer.on_completed() return rx.create(emit_files_recursively) recursive_files_in_directory('../').pipe( # ops.filter(lambda f: f.endswith('.txt')) ops.filter(lambda f: f.endswith('.py'))).subscribe( on_next=lambda l: print(l), on_error=lambda e: print(e), on_completed=lambda: print('done'))
def delete_file_with_path(credentials, path: str, retries: int = 5): return _files_in_path(credentials, path, retries).pipe( last(), filter(lambda file: file), flat_map(lambda file: delete_file(credentials, file, retries=retries)) )
def audio_encoder(sources): # Parse configuration parser = create_arg_parser() read_request, read_response = sources.argv.argv.pipe( ops.skip(1), argparse.parse(parser), ops.filter(lambda i: i.key == 'config'), ops.map(lambda i: file.Read(id='config', path=i.value)), file.read(sources.file.response), ) config = read_response.pipe( ops.filter(lambda i: i.id == "config"), ops.flat_map(lambda i: i.data), parse_config, ) # Transcode request handling encode_init = config.pipe( ops.map( lambda i: encoder.Initialize(storage_path=i.encode.storage_path))) encode_request = sources.httpd.route.pipe( ops.filter(lambda i: i.id == 'flac_transcode'), ops.flat_map(lambda i: i.request), ops.do_action(lambda i: print("[{}]http req: {}".format( datetime.datetime.now(), threading.get_ident()))), #.observe_on(encode_scheduler) ops.flat_map(lambda i: Observable.just(i, encode_scheduler)), ops.do_action(lambda i: print("[{}]encode req: {}".format( datetime.datetime.now(), threading.get_ident()))), ops.map(lambda i: encoder.EncodeMp3( id=i.context, data=i.data, key=i.match_info['key'])), ) encoder_request = rx.merge(encode_init, encode_request) # store encoded file store_requests = sources.encoder.response.pipe( ops.do_action(lambda i: print("[{}]encode res: {}".format( datetime.datetime.now(), threading.get_ident()))), ops.observe_on(s3_scheduler), ops.do_action(lambda i: print("[{}]s3 req: {}".format( datetime.datetime.now(), threading.get_ident()))), ops.map(lambda i: s3.UploadObject( key=i.key + '.flac', data=i.data, id=i.id, )), ) # acknowledge http request http_response = sources.s3.response.pipe( ops.do_action(lambda i: print("[{}]s3 res: {}".format( datetime.datetime.now(), threading.get_ident()))), ops.do_action( lambda i: print("httpd res: {}".format(threading.get_ident()))), ops.map(lambda i: httpd.Response( data='ok'.encode('utf-8'), context=i.id, )), ) # http server http_init = config.pipe( ops.flat_map(lambda i: rx.from_([ httpd.Initialize(request_max_size=0), httpd.AddRoute( methods=['POST'], path='/api/transcode/v1/flac/{key:[a-zA-Z0-9-\._]*}', id='flac_transcode', ), httpd.StartServer(host=i.server.http.host, port=i.server.http.port ), ]))) http = rx.merge(http_init, http_response) # s3 database s3_init = config.pipe( ops.map(lambda i: s3.Configure( access_key=i.s3.access_key, secret_key=i.s3.secret_key, bucket=i.s3.bucket, endpoint_url=i.s3.endpoint_url, region_name=i.s3.region_name, ))) # merge sink requests file_requests = read_request s3_requests = rx.merge(s3_init, store_requests) return Sink( encoder=encoder.Sink(request=encoder_request), s3=s3.Sink(request=s3_requests), file=file.Sink(request=file_requests), httpd=httpd.Sink(control=http), )
def model_events(cls): return cls._subject.pipe(filter(lambda event: event['instance'].__class__ == cls))
def _load(source): return source.pipe( ops.skip(skip), ops.map(parse_line), ops.filter(lambda i: i is not None), )
consumer_key = os.environ.get("consumer_key") consumer_secret = os.environ.get("consumer_secret") def tweets_for(topics): def observe_tweets(observer, scheduler): class TweetListener(StreamListener): def on_data(self, data): observer.on_next(data) return True def on_error(self, status): observer.on_error(status) # This handles Twitter authentification and the connection to Twitter Streaming API l = TweetListener() auth = OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) stream = Stream(auth, l) stream.filter(track=topics) return create(observe_tweets) topics = sys.argv[1:] if len(topics) < 1: topics = ['SpaceX', 'Covid-19'] tweets_for(topics).pipe( ops.map(lambda d: json.loads(d)), ops.filter(lambda map: "text" in map), ops.map(lambda map: map["text"].strip())).subscribe(lambda s: print(s))
import sys from rx import Observable from rx import of, create, operators as op def leer_archivo(observer, schedule): archivo = open("ods_1_2.csv", "r") lineas = archivo.readlines() for l in lineas: observer.on_next(l) observer.on_completed() suscribe = create(leer_archivo) composed = suscribe.pipe(op.map(lambda s: s), op.filter(lambda i: len(i) > 2)) composed.subscribe(lambda i: print("Received {0}".format(i))) print("done")
import rx from rx import operators as ops rx.from_(["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]).pipe(ops.filter(lambda s: len(s) >= 5), ops.take(2)).subscribe( on_next=lambda s: print('R: ' + s), on_error=lambda e: print('on_error' + e), on_completed=lambda: print('Done!!'), )
from rx import range, operators as op test = range(1, 11) sub1 = test.pipe( op.filter(lambda s: s % 2 == 0), # next x -> 2, 4, 6, 8, 10 op.reduce(lambda acc, x: acc + x, 3) # acc: 3, x: 2 -> 5 # acc: 5, x: 4 -> 9 # acc: 9, x: 6 -> 15 # acc: 15, x: 8 -> 23 # acc: 23, x: 10 -> 33 ) sub1.subscribe(lambda x: print("This value {}".format(x)))
def create(): return self.test_obs.pipe(pairwise_buffer, ops.filter(lambda x: x[0] != x[1]))
save_one_item, conn.get_database("planning").get_collection("graphs2")) save_edges_in_db = partial( save_many_items, conn.get_database("planning").get_collection("edges2")) save_nodes_in_db = partial( save_many_items, conn.get_database("planning").get_collection("nodes2")) graph_type_map = {"source": "edge", "node_name": "node", "name": "graph"} get_dict_type = partial(get_obj_type_from_type_map, graph_type_map) edge_subject, node_subject, graph_subject = Subject(), Subject(), Subject() processed_edges = edge_subject.pipe( op.filter(lambda edge_dic: not exists(edge_dic)), op.group_by(lambda dic: "".join( [str(v) for k, v in dic.items() if k not in ['level', 'type']])), op.map(lambda o: general_edge_grouper(o)), op.merge_all(), op.buffer_with_count(1000), op.map(lambda dict_list: save_edges_in_db(dict_list)), op.buffer_with_count(5), op.map(lambda futures: perform_futures(futures)), op.map(lambda results: [r.inserted_ids for r in results])).subscribe(dumb) processed_nodes = node_subject.pipe( op.filter(lambda node_dic: not exists(node_dic)), op.group_by(lambda dic: "".join( [str(v) for k, v in dic.items() if k not in ['level']])), op.map(lambda o: general_node_grouper(o)), op.merge_all(), op.buffer_with_count(5000), op.map(lambda dict_list: save_nodes_in_db(dict_list)),
import rx import rx.operators as ops numbers = rx.from_([1, 2, 3, 4, 5]).pipe(ops.filter(lambda i: 1 < i < 4)) numbers.subscribe(on_next=lambda i: print("on_next {}".format(i)), on_error=lambda e: print("on_error: {}".format(e)), on_completed=lambda: print("on_completed"))
from rx import Observable, from_, operators as ops from csv import DictReader # from_(DictReader(open('python-study/reactive-python/src/file/datafile.csv', 'r')) # ).subscribe( # lambda row: print("{0:4}\t{1:<35}".format(row['iata'], row['airport'][:35])) # ) # from_(open("python-study/reactive-python/src/file/rxtest.txt")).pipe( # ops.distinct(), # ops.map(lambda l: l.strip()), # ops.filter(lambda l: l != "") # ).subscribe(print) from_( DictReader( open( 'python-study/reactive-python/src/file/mth_six_record.csv', 'r', encoding='utf-8'))).pipe( ops.filter(lambda row: row['channel_id'] == "BOSS")).subscribe( lambda row: print(row))
def length_more_than_5(): return rx.pipe( op.map(lambda s: len(s)), op.filter(lambda i: i >= 5), )
def eventFilter(event_type): return rx.pipe(rxops.filter(lambda event: event.get('eventType', None) == event_type))
def on_completed(self) -> None: super().on_completed() def publish(self, event: TEventDatum) -> None: try: self.on_next(event) except Exception as exception: self.logger.warning( f"Failed to publish event '{event}' - {exception}") def dispose(self) -> None: super().dispose() if __name__ == "__main__": rx.from_([1, 2, 3, 4, 5]).subscribe(PrintingObserverSubscriber(False)) rx.from_([1, 2, 3, 4, 5]).pipe(ops.filter(lambda item: (item % 2) == 0), ).subscribe( PrintingObserverSubscriber(False)) collector = CollectingObserverSubscriber() rx.from_(["a", "b", "c"]).subscribe(collector) print(collector.collected) rx.from_([1, 2, 3, 4, 5]).pipe( ops.map(debug_print_item("Before even check:")), ops.filter(lambda item: (item % 2) == 0), ops.map(debug_print_item("After even check:")), ).subscribe(PrintingObserverSubscriber(True))
import rx from rx import operators as ops import multiprocessing import rx.scheduler as scheduler thread_count = multiprocessing.cpu_count() thread_pool_scheduler = scheduler.ThreadPoolScheduler(thread_count) rx.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( ops.filter(lambda i: i % 2 == 0), ops.subscribe_on(thread_pool_scheduler)).subscribe(lambda i: print(1)) rx.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( ops.filter(lambda i: i % 2 == 0), ops.subscribe_on(thread_pool_scheduler)).subscribe(lambda i: print(2)) rx.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( ops.filter(lambda i: i % 2 == 0), ops.subscribe_on(thread_pool_scheduler)).subscribe(lambda i: print(3)) rx.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( ops.filter(lambda i: i % 2 == 0), ops.subscribe_on(thread_pool_scheduler)).subscribe(lambda i: print(4)) print("AAAAA")
import rx from rx import operators as ops source = rx.of("Alpha", "Beta", "Gamma", "Delta", "Epsilon") composed = source.pipe( ops.map(lambda s: len(s)), ops.filter(lambda i: i >= 5) ) composed.subscribe(lambda value: print("Received {0}".format(value)))
def observe(self, name, *args, **kwargs): return self._subject.pipe(rxops.filter(lambda item: item[1] == name)).subscribe(*args, **kwargs)
def delete_file_with_path(credentials, path: str): return _files_in_path(credentials, path).pipe( last(), filter(lambda file: file), flat_map(lambda file: delete_file(credentials, file)))
def observe(self, prop, listener): self._subject.pipe(rxops.filter( lambda item: item[1] == prop)).subscribe(listener)
def filterOperator(self): source = of(1,2,3,4,5,6,7,8,9).pipe( op.filter(lambda item: item > 4) ) source.subscribe(lambda item: print('"Subscribe Filter" output: {}'.format(item)))
import rx from rx import operators as ops rx.from_(["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]).pipe(ops.filter(lambda s: len(s) != 5), ops.count()).subscribe(lambda i: print(i))
def _path_elements(path): return from_list(path.split('/')).pipe( filter(lambda name: name and name.strip()) # Allow for double // and trailing / in path )
def create(): def predicate(x): invoked[0] += 1 return is_prime(x) return xs.pipe(filter(predicate))
import rx from rx import operators as ops source = rx.of("Alpha", "Beta", "Gamma", "Delta", "Epsilon") composed = source.pipe(ops.map(lambda s: len(s)), ops.filter(lambda i: i >= 5)) composed.subscribe(lambda value: print("Received {0}".format(value)))
def create(): def predicate(x): invoked[0] += 1 return True return xs.pipe(filter(predicate))
# Find the sum of all the multiples of 3 or 5 below 1000. from rx import from_list, operators as op max_number = 1000 # Legacy method multiples = [] for number in range(max_number): if (number % 3 == 0 or number % 5 == 0): multiples.append(number) print(sum(multiples)) # With reactive programming from_list(range(max_number)).pipe( op.filter(lambda n: n % 3 == 0 or n % 5 == 0), op.sum()).subscribe(lambda s: print(s))
def add_responder(self, event_type, responder): unregister = self.subject.pipe( op.filter(lambda e: isinstance(e, event_type))).subscribe( responder) self._disposables.append(unregister)
#-----保存录像---------- def fname_record1(): #f'{datetime.now().isoformat()}' dt_str = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') return f'{id_vehicle}_{dt_str}' #订阅 # ----------保存---------- recorder = Recorder(fname_record1, event_need_record) video_subject.subscribe(lambda args: recorder.on_frame(*args)) #----------播放----------- video_subject.pipe( #处理:过滤出图像 ops.filter(lambda args: args[0] == 'h264') #过滤出frame部分 , ops.map(lambda args: args[1])).subscribe(show_frame264) async def client_mock(): '''模拟客户操作,直播开始30秒后开始录像 30秒后停止录像''' print('客户操作') await asyncio.sleep(20) print('模拟玩家开始录像') event_need_record._loop.call_soon_threadsafe(event_need_record.set) await asyncio.sleep(30) print('模拟玩家停止图像') event_need_record._loop.call_soon_threadsafe(event_need_record.clear) await asyncio.sleep(10) print('模拟玩家停止直播')
def demo_chains_op(): of("Alpha", "Beta", "Gamma", "Delta", "Epsilon").pipe(op.map(lambda s: len(s)), op.filter(lambda i: i >= 5)).subscribe( lambda value: print("Received {0}".format(value)))