File: index.rst

package info (click to toggle)
python-cliapp 1.20120630-1
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 308 kB
  • sloc: python: 2,297; makefile: 86
file content (182 lines) | stat: -rw-r--r-- 6,386 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
Welcome to cliapp's documentation!
==================================

``cliapp`` is a Python framework for Unix-like command line programs,
which typically have the following characteristics:

* non-interactive
* the programs read input files named on the command line, 
  or the standard input
* each line of input is processed individually
* output is to the standard output
* there are various options to modify how the program works
* certain options are common to all: ``--help``, ``--version``

Programs like the above are often used as filters in a pipeline.
The scaffoling to set up a command line parser, open each input
file, read each line of input, etc, is the same in each program.
Only the logic of what to do with each line differs.

``cliapp`` is not restricted to line-based filters, but is a more
general framework. It provides ways for its users to override
most behavior. For example:

* you can treat command line arguments as URLs, or record identfiers
  in a database, or whatever you like
* you can read input files in whatever chunks you like, or not at all,
  rather than forcing a line-based paradigm

Despite all the flexibility, writing simple line-based filters
remains very straightforward. The point is to get the framework to
do all the usual things, and avoid repeating code across users of the
framework.


Example
-------

::

    class ExampleApp(cliapp.Application):

        def add_settings(self):
            self.settings.string_list(['pattern', 'e'], 
                                      'search for regular expression PATTERN',
                                      metavar='REGEXP')
    
        # We override process_inputs to be able to do something after the last
        # input line.
        def process_inputs(self, args):
            self.matches = 0
            cliapp.Application.process_inputs(self, args)
            self.output.write('There were %s matches.\\n' % self.matches)
    
        def process_input_line(self, name, line):
            for pattern in self.settings['pattern']:
                if pattern in line:
                    self.output.write('%s:%s: %s' % (name, self.lineno, line))
                    self.matches += 1
                    logging.debug('Match: %s line %d' % (name, self.lineno))


    if __name__ == '__main__':
        ExampleApp().run()


Walkthrough
-----------

Every application should be a class that subclasses ``cliapp.Application``.
The subclass should provide specific methods. Read the documentation
for the ``cliapp.Application`` class to see all methods, but a rough
summary is here:

* the ``settings`` attribute is the ``cliapp.Settings`` instance used by
  the application
* override ``add_settings`` to add new settings for the application
* override ``process_*`` methods to override various stages in how
  arguments and input files are processed
* override ``process_args`` to decide how each argument is processed;
  by default, this called ``process_inputs`` or handles subcommands
* ``process_inputs`` calls ``process_input`` (note singular) for each 
  argument, or on ``-`` to process standard input if no files are named
  on the command line
* ``process_input`` calls ``open_input`` to open each file, then calls
  ``process_input_line`` for each input line
* ``process_input_line`` does nothing, by default

This cascade of overrideable methods is started by the `run`
method, which also sets up logging, loads configuration files,
parses the command line, and handles reporting of exceptions.
It can also run the rest of the code under the Python profiler,
if the appropriate environment variable is set.


Logging
-------

Logging support: by default, no log file is written, it must be
requested explicitly by the user. The default log level is info.
    
Subcommands
-----------

Sometimes a command line tool needs to support subcommands.
For example, version control tools often do this:
``git commit``, ``git clone``, etc. To do this with ``cliapp``,
you need to add methods with names like ``cmd_commit`` and
``cmd_clone``::

    class VersionControlTool(cliapp.Application):
    
        def cmd_commit(self, args):
            '''commit command description'''
            pass
        def cmd_clone(self, args):
            '''clone command description'''
            pass
            
If any such methods exist, ``cliapp`` automatically supports
subcommands. The name of the method, without the ``cmd_`` prefix,
forms the name of the subcommand. Any underscores in the method
name get converted to dashes in the command line. Case is
preserved.

Subcommands may also be added using the ``add_subcommand`` method.

All options are global, not specific to the subcommand.
All non-option arguments are passed to the method in its only
argument.

Subcommands are implemented by the ``process_args`` method.
If you override that method, you need to support subcommands
yourself (perhaps by calling the ``cliapp`` implementation).


Manual pages
------------

``cliapp`` provides a way to fill in a manual page template, in
**troff** format, with information about all options. This
allows you to write the rest of the manual page without having
to remember to update all options. This is a compromise between
ease-of-development and manual page quality.

A high quality manual page probably needs to be written from
scratch. For example, the description of each option in a manual
page should usually be longer than what is suitable for
``--help`` output. However, it is tedious to write option
descriptions many times.

To use this, use the ``--generate-manpage=TEMPLATE`` option,
where ``TEMPLATE`` is the name of the template file. See
``example.1`` in the ``cliapp`` source tree for an example.


Profiling support
-----------------
    
If ``sys.argv[0]`` is ``foo``, and the environment
variable ``FOO_PROFILE`` is set, then the execution of the 
application (the ``run`` method) is profiled, using ``cProfile``, and
the profile written to the file named in the environment variable.



Reference manual
================

.. automodule:: cliapp
   :members:
   :undoc-members:
   :exclude-members: add_boolean_setting, add_bytesize_setting,
        add_choice_setting, add_integer_setting, add_string_list_setting,
        add_string_setting, config_files

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`