The command-line echo example

The command-line echo application simply outputs the arguments passed on the command-line to the console. This subpart details its functional and reactive implementation with Cyclotron.

First, more imports than previously are needed:

from collections import namedtuple
from rx import Observable
from cyclotron import Component
from cyclotron.rx import run

import cyclotron_std.sys.stdout as stdout
import cyclotron_std.sys.argv as argv

In addition to Observable of the rx module, namedtuple as well as several cyclotron modules are used. The Component constructor and the run function are the minimal requirements to start an application. Then two drivers of cyclotron-std are used. The stdout driver is a sink-only driver that outputs received items on the standard output, and the argv driver is a source-only driver that exposes the arguments provided in the command-line.

After these imports, three named tuples are declared. There is one for Drivers used by the application, one for the entry point Source object, and one for the entry point Sink object:

Drivers = namedtuple('Drivers', ['stdout', 'argv'])
Source = namedtuple('Source', ['argv'])
Sink = namedtuple('Sink', ['stdout'])

The stdout and argv drivers are used. The objects in the Drivers tuple fields are the Component objects that implement the corresponding driver. They are initialized later. The source of the entry point is just the source of the argv driver. The Sink of the entry point contains only the Sink of the stdout driver. Once these definitions are available, Source and Sink can be used in the entry point of the application:

def echo(sources):
console = sources.argv.argv.skip(1).map(lambda i: i + ' ')
return Sink(
stdout=stdout.Sink(data=console)
)

The echo function is a component. The sources input argument is a named tuple of type source. This component returns a Sink named tuple. The console observable takes all arguments except the first one, and appends a new line after each of them. The sources.argv object is a named tuple of type argv.Source. This named tuple has only one field named argv. It is an observable emitting one item per command-line argument. The skip operator used here allows us to skip some items from an observable. In this case one item is removed. This first item corresponds to the name of the binary being used. This first item is skipped so that only the arguments are printed.

The echo component returns a Sink object, and sets the stdout field with an object of type stdout.Sink. This named tuple has one field named data. This field must contain an observable emitting the items to write on the standard output.

Finally, the application can be initialized and started:

if __name__ == '__main__':
dispose = run(
entry_point=Component(call=echo, input=Source),
drivers=Drivers(
stdout=stdout.make_driver(),
argv=argv.make_driver(),
)
)
dispose()

The run function is called with two parameters as input: the component that is the entry point of the application, and the drivers that are being used. A Component object is created by using the Component constructor with two parameters: the entry point function of the component and the type being used as an input parameter. Each field of the Drivers object is a driver Component object. Both drivers used here provide a factory method to create them; this factory method is called make_driver. This is a very common way to expose drivers factories.

These four snippets put together are a complete implementation of the command-line echo example. The whole code is available at the GitHub repository (https://github.com/PacktPublishing/Hands-On-Reactive-Programming-with-Python) for this book, in the cyclotron_echo_argv.py script. In a very simple application, like this one, this design adds some overhead, but it becomes negligible very quickly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.235.62