Package: broqer
Initial focus on embedded systemsBroqercan be used wherever continuous streams of data have to be processed - and they are everywhere. Watch out!SynopsisPure python implementation without dependenciesUnder MIT license (2018 Günther Jena)Source is hosted onGitHub.comDocumentation is hosted onReadTheDocs.comTested on Python 3.7. 3.8, 3.9, 3.10 and 3.11Unit tested withpytest, coding style checked withFlake8, static type checked withmypy, static code checked withPylint, documented withSphinxOperators known fromReactiveXand other streaming frameworks (likeMap,CombineLatest, …)Centralised object to keep track of publishers and subscribersStarting point to build applications with a microservice architectureShowcaseIn other frameworks aPublisheris sometimes calledOberservable. ASubscriberis able to observe changes the publisher is emitting. With these basics you’re
able to use the observer pattern - let’s see!Observer patternSubscribing to a publisher is done via the .subscribe() method.
A simple subscriber isSinkwhich is calling a function with optional positional
and keyword arguments.>>>frombroqerimportPublisher,Sink>>>a=Publisher(5)# create a publisher with state `5`>>>s=Sink(print,'Change:')# create a subscriber>>>disposable=a.subscribe(s)# subscribe subscriber to publisherChange:5>>>a.notify(3)# change the stateChange:3>>>disposable.dispose()# unsubscribeCombine publishers with arithmetic operatorsYou’re able to create publishers on the fly by combining two publishers with
the common operators (like+,>,<<, …).>>>a=Publisher(1)>>>b=Publisher(3)>>>c=a*3>b# create a new publisher via operator overloading>>>disposable=c.subscribe(Sink(print,'c:'))c:False>>>a.notify(2)c:True>>>b.notify(10)c:FalseAlso fancy stuff like getting item by index or key is possible:>>>i=Publisher('a')>>>d=Publisher({'a':100,'b':200,'c':300})>>>disposable=d[i].subscribe(Sink(print,'r:'))r:100>>>i.notify('c')r:300>>>d.notify({'c':123})r:123Some python built in functions can’t return Publishers (e.g.len()needs to
return an integer). For these cases special functions are defined in broqer:Str,Int,Float,LenandIn(forx in y). Also other functions
for convenience are available:All,Any,BitwiseAndandBitwiseOr.Attribute access on a publisher is building a publisher where the actual attribute
access is done on emitting values. A publisher has to know, which type it should
mimic - this is done via.inherit_type(type).>>>i=Publisher('Attribute access made REACTIVE')>>>i.inherit_type(str)>>>disposable=i.lower().split(sep=' ').subscribe(Sink(print))['attribute','access','made','reactive']>>>i.notify('Reactive and pythonic')['reactive','and','pythonic']Function decoratorsMake your own operators on the fly with function decorators. Decorators are
available forAccumulate,CombineLatest,Filter,Map,MapAsync,MapThreaded,ReduceandSink.>>>frombroqerimportop>>>@op.build_map...defcount_vowels(s):...returnsum([s.count(v)forvin'aeiou'])>>>msg=Publisher('Hello World!')>>>disposable=(msg|count_vowels).subscribe(Sink(print,'Number of vowels:'))Numberofvowels:3>>>msg.notify('Wahuuu')Numberofvowels:4You can even make configurableMaps andFilters:>>>importre>>>@op.build_filter_factory...deffilter_pattern(pattern,s):...returnre.search(pattern,s)isnotNone>>>msg=Publisher('Cars passed: 135!')>>>disposable=(msg|filter_pattern('[0-9]+')).subscribe(Sink(print))Carspassed:135!>>>msg.notify('No cars have passed')>>>msg.notify('Only 1 car has passed')Only1carhaspassedInstallpipinstallbroqerCreditsBroqer was inspired by:RxPY: Reactive Extension for Python (by Børge Lanes and Dag Brattli)aioreactive: Async/Await reactive tools for Python (by Dag Brattli)streamz: build pipelines to manage continuous streams of data (by Matthew Rocklin)MQTT: M2M connectivity protocolFlorian Feurstein: spending hours of discussion, coming up with great ideas and help me understand the concepts!APIPublishersAPublisheris the source for messages.Publisher()Basic publisherOperatorsCombineLatest(*publishers)Combine the latest emit of multiple publishers and emit the combinationFilter(predicate, …)Filters values based on apredicatefunctionMap(map_func, *args, **kwargs)Applymap_func(*args,value, **kwargs)to each emitted valueMapAsync(coro, mode, …)Applycoro(*args,value, **kwargs)to each emitted valueThrottle (duration)Limit the number of emits per durationSubscribersASubscriberis the sink for messages.Sink(func, *args, **kwargs)Applyfunc(*args,value, **kwargs)to each emitted valueSinkAsync(coro, …)Applycoro(*args,value, **kwargs)to each emitted valueOnEmitFuture(timeout=None)Build a future able to await forTrace(d)Debug output for publishersValuesValue(*init)Publisher and Subscriber