Package: conz
This module contains a lightweight library for creating command line programs,
conz.conz has following features:Simplifies working with pipesProvides methods for handling typical interactive scenariosSupports output colorizationProvides tools for working with long-running tasksControls output in interactive and non-interactive scenariosManages signals (SIGINT and SIGPIPE)ContentsInstallingQuick tourFormatting conventionsUsageWorking with outputColorizingWorking with inputAdvanced interactive inputRVPLYes/No inputMenuWorking with progressQuittingSignal handlingReporting bugsInstallingYou can install conz from PyPI using pip or easy_install:pip install conz

easy_install conzQuick tourA quick tour example can be found inexamples/quicktour.py:import conz

someval = True

cn = conz.Console(verbose=True)

cn.pstd('This goes to STDOUT')
cn.perr('This goes to STDERR')
cn.pverr(someval, 'This message is related to somevar')

cn.pstd(cn.color.green('This message is green'))

with cn.progress('Some long operation'):
    import time
    time.sleep(2)

data = cn.read('Type something in:')
cn.pstd('You typed in {}'.format(cn.color.yellow(data, style='italic')))Formatting conventionsBecause this library deals with terminal output a lot, we have to somehow tell
when something is terminal output and when it is code. Because of this, we use
lines to delimit console output. For example:----------------------------------------------
I'm a sample output
----------------------------------------------When output is to the STDERR, ‘E’ will be shown in the right corner.:---------------------------------------------E
I'm a sample error
----------------------------------------------When user enters data, the Entered data will be followed by<Enter>and the
right corner will include the ‘I’ character (for ‘interactive session’):---------------------------------------------I
Prompt: some data<Enter>
----------------------------------------------When value is returned from user input, the value is printed right below the
output preceeded by==>:---------------------------------------------I
Prompt: some data<Enter>
----------------------------------------------
==> 'some data'UsageTheconzpackage includes a classConsolewhich is the only class you
will even need to work with. Simply import and instantiate it at the top of
your program.import conz
cn = conz.Console()Working with outputTheConsole()class is, for the most part, a wrapper around theprint()function (not print statement, so not compatible with versions of Python that
do not support this). It controls howprint()is invoked and takes care of
some of the edge cases where it may malfunction.Theprint()method on aConsoleobject is a very simple wrapper around
Python’sprint()whic does nothing except pass it’s positional and keywrod
arguments to theprint()function. We will never use it directly, though,
as there are shortcuts for doing specific things withprint().To output to STDOUT, we use thepstd()method. It takes the same arguments
asprint()function, with the exception offilekeyword argument which
is set by this method and cannot be overridden.cn.pstd('This always goes to STDOUT', end='...')
----------------------------------------------
This always goes to STDOUT
----------------------------------------------To output to STDERR, we use theperr()method. As withpstd(), it
overrides thefileargument for us.cn.perr('Mayday, mayday!')
---------------------------------------------E
Mayday, mayday!
----------------------------------------------The main difference between regularprint()andpstd()/perr()methods is that the latter will flush the STDOUT/STDERR after writing to it.
This can prvent weird issues in some edge cases.There is a variant ofperr()which prints a more structured message to
STDERR. Thepverr()method takes a value and a message, and prints then inVALUE: Messageformat.path = '/foo/bar/baz.txt'
cn.verr(path, 'not found')
---------------------------------------------E
/foo/bar/baz.txt: not found
----------------------------------------------A variant ofpstd()ispverb(). It is exactly the same aspstd(),
except that it only outputs whenverboseflag on theConsoleobject isTrue. This is useful for programs that need to differentiate between
interactive and non-interactive use (e.g., using in pipe vs invoking directly)
or wish to have a--verboseswitch, etc.cn.verbose = True
cn.pverb("I'm a talkative program")
----------------------------------------------
I'm a talkative program
----------------------------------------------

cn.verbose = False
cn.pverb("I'm a talkative program")
----------------------------------------------

----------------------------------------------Theverboseflag can be set either as an argument during instantiation, or
simply by setting the attribute as in the previous example.TheConsoleobject also provides aouttermproperty which isFalsewhen program is outputting to a pipe rather than the terminal:if cn.outterm:
    # give full output to the user
else:
    # give a short output that can be parsed by a machine, etcColorizingBefore we start, note that this implementation isnot cross-platform. If
you need something with a bit more punch, you should look atcolorama.To colorize the output, both theconzmodule andConsoleclass have acolorattribute, which provides methods for output colorization. Each piece
of text can have the following attributes:foreground colorstylebackground colorForeground and background colors can be:blackredgreenyellowbluepurple (magenta)cyanwhiteStyles can be:bolditalicunderlineblinkreverse (inverts foreground and background colors)Each of these colors have a method on thecolorattribute. Each color
method takesstyleandbgkeyword arguments which set the style and
background color respectively. Thecolor()method can be used to specify
colors dynamically. Here are some examples:cn.color.red('This is red text')
cn.color.color('This is red text', color='red')
cn.color.blue('This is blue underlined text', style='underline')
cn.color.color('This is green on yellow', color='green', bg='yellow')You can find an example script inexamples/colors.pywhich prings all
possible combinations of various colors, styles, and backgrounds.Working with inputThere are two types of input you can work with: interactive user input, and
pipes.To read the user input, useread()method. This method takes two optional
arguments. One is thepromptargument, which we use to set the prompt. It
is an empty string by default. The other argument is a data-cleaning function.
When you pass thecleanargument, user input is passed through the function
before it is retuned. For example:cn.read('Exit? [y/N] ', clean=lambda x: x.lower()[:1] == 'y')
---------------------------------------------I
Exit? [y/N] y<Enter>
----------------------------------------------
==> TrueNote that this method usesraw_input()on Python 2.7.x andinput()on
Python 3.x.To work with pipes, we use thereadpipe()method. This method reads from
the STDIN pipe one line at a time and returns an iterator that allows us to
iterate over the lines.for l in cn.readpipe():
    l = l.strip()
    cn.pstd('Received: {}'.format())Note that line-feed characters are not stripped from the output so it is up to
us to strip it away.When working with a large number of lines coming down the pipe, we may
sometimes need to work in batches, rather than one line at a time. Thechunkargument can be set to an integer value that specifies the number of
lines we want buffered before they are returned to us. When using chunks, the
lines are returned as a list of strings, rather than strings. The following
example will return pipe input in groups of 500:for lines in cn.readpipe(500):
    # do something with 500 linesIf we need to know whether input will come from a pipe or not, we can use theintermproperty.if cn.interm:
    # possibly interactive version
else:
    # we are on the receiving end of a pipeAdvanced interactive inputSo far we have looked at simpe user input. However in most cases, input is not
the only thing we want. We normally also need to show notes, validate the
input, construct menus, etc. TheConsoleclass provides three methods that
are useful for different scenarios.You will find examples of code discussed here inexamples/user_input.pyandexamples/menu.py.RVPLRVPL (pead validate print loop) is a loop in which some data is read from the
user, validated, and error message printed. This loop continues as long as data
is invalid. Thervpl()method is used to start such a loop.At bare minimum,rvpl()is called with a prompt that should be shown to the
user.cn.rvpl('Please enter your name:')
---------------------------------------------I
Please enter your name: My name<enter>
----------------------------------------------
==> 'My name'Likeread(),rvpl()also takes acleanargument, which is used to
control how the value is cleaned. In addition, it takesvalidatorargument,
which is a function that validates the cleaned data. The default validator
simply makes sure the input is not an empty string.For invalid input, error message is displayed:cn.rvpl('Please enter your name:')
---------------------------------------------I
Please enter your name: <Enter>
Entered value is invalid
Please enter your name: Mike<Enter>
----------------------------------------------
==> 'Mike'Error message can be customized using theerrorargument. Iferrorargument is is a callable, it will be called with entered value and it must
return the message to be shown.valid_input = ('a', 'b', 'c')
error = lambda x: '{} is not one of the {}'.format(
    x, ', '.join(valid_input))
validator = lambda x: x in valid_input
cn.rvpl('Type one of the first 3 characters of English alphabet:')
---------------------------------------------I
Type one of the first 3 characters of English alphabet: e<Enter>
e is not one of the a, b, c
Type one of the first 3 characters of English alphabet: b<Enter>
----------------------------------------------
==> 'b'An intro message can be passed which is shown above the prompt. Unlinke the
prompt itself, intro message is not repeated in the loop.cn.rvpl('>', intro='Please enter your name:')
---------------------------------------------I
Please enter your name:
> <Enter>
Entered value is invalid
> Mike<Enter>
----------------------------------------------
==> 'Mike'When requesting optional input, the strict validation can be turned off using
thestrictargument. When this argument isFalse, then the loop exists
even when validation fails. The value returned when validation fails is
controlled bydefaultargument, which defaults toNone.cn.rvpl('Please enter your name:', strict=False, default='Bob')
---------------------------------------------I
Please enter your name: <Enter>
----------------------------------------------
==> 'Bob'Yes/No inputTheyesno()method provides a specialized version the RVPL limited to yes
and no answer, and returninTrueorFalse.cn.yesno('Are you all right?')
---------------------------------------------I
Are you all right? (y/n): y<Enter>
----------------------------------------------
==> TrueThe prompt passed toyesno()is automatically appended the ‘(y/n):’ string.
The appearance of this string depends on the default value discussed further
below.Since it is a wrapper aroundrvpl()it takes the sameerrorandintroarguments which behave the same way.Although it takes thedefaultargument likervpl(), the behavior is
different. WhendefaultisNoneit automatically turns on strict
validation. The argument can also be eitherTrueorFalse, in which
case the default value is respectively ‘yes’ and ‘no’.cn.yesno('Are you all right?', default=True)
---------------------------------------------I
Are you all right? (Y/n): <Enter>
----------------------------------------------
==> True

cn.yesno('Are you all right?', default=False
---------------------------------------------I
Are you all right? (y/N): <Enter>
----------------------------------------------
==> FalseMenuMenu is another specialization of the RVPL, used for displaying menus. This is
facilitated by themenu()method.This method has only one required argument, which is an iterable of menu
choices. Each member of the iterable must be a two-tuple which holds the actual
value as first member and the value’s label as second. For example:choices = (('f', 'foo'), ('b', 'bar'))
cn.menu(choices)
---------------------------------------------I
  1) foo
  2) bar
Please choose from the provided options: 1<Enter>
----------------------------------------------
==> 'f'Almost all aspects of the menu can be customized. Theprompt,error,intro,strictanddefaultbehave the same way as in regular RVPL so
we will not discuss them in detail here.Display of the menu items themselves is controlled by two arguments:formatterandnumerator.numeratorargument controls how the enumeration of the menu items is done.
It takes the number of menu items as its only argument, and must return a list
of strings to be used as options. For example:choices = (('f', 'foo'), ('b', 'bar'))
numer = lambda n: ('abcd'[i] for i in range(n), numerator=numer)
cn.menu(choices)
---------------------------------------------I
  a) foo
  b) bar
Please choose from the provided options: a<Enter>
----------------------------------------------
==> 'f'formattertakes the number of the item and item’s label and must return a
formatted menu item. For example:choices = (('f', 'foo'), ('b', 'bar'))
fmt = lambda n, lbl: '{} ({})'.format(lbl, n)
cn.menu(choices, formatter=fmt)
---------------------------------------------I
foo (1)
bar (2)
Please choose from the provided options: 1<Enter>
----------------------------------------------
==> 'f'Working with progressProgress is a more complex construct that we use to notify user of some
activity that may take a while. Each progress has a start banner, which is
printed before we begin, and two end banners, one for success and one for
failure.Before we can use the progress context manager, we must enable verbose mode.cn.verbose = TrueA progress is started using theprogress()method, which is a context
manager.with cn.progress("Let's get this show on the road"):
    # do somethingThis is the simplest form. When an exception of any kind is triggered inside
the context, it is trapped, the failure banner is printed, and theconz.ProgressAbrtexception is raised. (This exception is also available as
an attribute onConsoleobjects for convenience.) If everything goes well,
then the success banner will be printed. With the previous code snippet, sucess
output may look like this:----------------------------------------------
Let's get this show on the road...DONE
----------------------------------------------And failure would look like this:----------------------------------------------
Let's get this show on the road...FAIL
----------------------------------------------The end banners can be customized by using theendandabrtarguments:with cn.progress('Almost there', end='finally!', abrt='awww, bummer'):
    # do somethingThe outputs would look like this:----------------------------------------------
Almost there...finally!
----------------------------------------------or:----------------------------------------------
Almost there...awww, bummer
----------------------------------------------The elipsis (three dots) can be customized using thesepargument:with cn.progress('File check', sep=': '):
    # do somethingThis results in:----------------------------------------------
File check: DONE
----------------------------------------------or:----------------------------------------------
File check: FAIL
----------------------------------------------By default, the progress context manager will trap any exception. This may or
may not make sense for a particular situation. This behavior can therefore be
customized using theexcsargument, which takes a tuple of exception
classes that we are expecting. Passing exceptions explicitly like this allows
the context manager to propagate unhandled exceptions and reval subtle flaws in
our logic.We can also specify a callback that runs each time an exception (other thanProgressAbrtandProgressOKare raised inside the context. This
callback is specified usingonerrorargument, and defaults to an error
handler that prints ‘Program error: ERROR MESSAGE’ to STDERR. For convenience,
theConsoleobject has aerror()method which creates such handlers.By default, the tracebacks raised during progress is suppressed. To see the
full traceback,Consoleconstructor takes adebugargument, which can
be set toTrueto prevent traceback suppression.To create a handler, we call theerror()method like so:handler = cn.error('Ouch!', exit=1)
with cn.progress('Ouch progress', onerror=handler):
    raise RuntimeError()The above results in:----------------------------------------------
Outch progress...FAIL
Ouch!
----------------------------------------------The message may have a{err}placeholder, which gets replaced by the string
representation of the exception that was raised in the block.To completely suppress the error handler, simply pass it a function that does
nothing.with cn.progress('No ouch', onerror: lambda exc: None):
    raise RuntimeError()
----------------------------------------------
No ouch...FAIL
----------------------------------------------NoteNote that passingNoneasonerrorvalue simply causes the default
error handler to be used instead.The progress context manager returns aProgressobject, which provides
methods for explicitly terminating the progress, and printing the progress
indicator. This object hasend()andabrt()methods, which are called
to terminate with success and error status respectively. For example:with cn.progress('Something') as prg:
    if not success:
        prg.abrt()
    prg.end()Theend()andabrt()methods raiseProgressOKandProgressAbrtexceptions repsectively. We can suppress raising of the exceptions usingnoraiseargument and setting it toTrue. Both of the methods will use
the default end banners. We can also use any banner we want by passing it as
the first positional argument. This can be useful in cases where the end banner
should indicate different outcomes.NoteDefault banners are colorized (green for success, red for failure). Any
custom banners passed directly toend()andabrt()will not be
colorized, though.TheProgressOKexception is not meant to be
handled by us in any way, and it’s simply there to facilitate flow control.ProgressAbrtis, by default, reraised so that code outside the context
manager can handle it. Therefore, we normally wrap the context block in a
try-except:try:
    with cn.progress('Something'):
        # do something
except cn.ProgressAbrt:
    # something went wrongThis reraising of theProgressAbrtexception can be suppressed by using thereraiseargument which can beTrueorFalse. Setting this flag toFalsesilences theProgressAbrtexception. At that point, we are still
able to do error handling using theonerrorcallback.You can find a script inexamples/progress.pywhich demonstrates a few
typical cases.QuittingTo quit the program, we call thequit()method on theConsoleobject.
This method works the same way assys.exit()(except that it takes one lessimportto use it).Signal handlingThe default implementation ofConsoleclass automatically takes care ofSIGINT(keyboard interrupt) andSIGPIPE(broken pipe) signals. You can
customize the way those are handled by overloading theonint()andonpipe()methods. You can also customize the registration of signals
themselves by overloading theregister_signals()method.Reporting bugsPlease report any bugs or feature requests to theissue tracker.