dhellmann / CommandLineApp (http://doughellmann.com/projects/CommandLineApp/)
The CommandLineApp class makes creating command line applications in Python as simple as defining callbacks to handle options when they appear in 'sys.argv'.
Clone this repository (size: 120.8 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/dhellmann/commandlineapp/
| commit 31: | f63602f347f5 |
| parent 30: | 8dff32e529f3 |
| branch: | default |
start cleaning up old option handler references
Changed (Δ1.4 KB):
raw changeset »
.hgignore (1 lines added, 0 lines removed)
docs/source/PyMagArticle/Listing2.py (4 lines added, 2 lines removed)
docs/source/PyMagArticle/index.rst (86 lines added, 18 lines removed)
pavement.py (11 lines added, 11 lines removed)
Up to file-list docs/source/PyMagArticle/Listing2.py:
| … | … | @@ -9,6 +9,8 @@ import commandlineapp |
9 |
9 |
class csvcat(commandlineapp.CommandLineApp): |
10 |
10 |
"""Concatenate comma separated value files. |
11 |
11 |
""" |
12 |
||
13 |
_app_name = 'csvcat' |
|
12 |
14 |
|
13 |
15 |
EXAMPLES_DESCRIPTION = ''' |
14 |
16 |
To concatenate 2 files, including all columns and headers: |
| … | … | @@ -49,7 +51,7 @@ To concatenate 2 files, including only t |
49 |
51 |
""" |
50 |
52 |
self.dialect = name |
51 |
53 |
return |
52 |
option |
|
54 |
option_handler_d = option_handler_dialect |
|
53 |
55 |
|
54 |
56 |
columns = [] |
55 |
57 |
def option_handler_columns(self, *col): |
| … | … | @@ -58,7 +60,7 @@ To concatenate 2 files, including only t |
58 |
60 |
""" |
59 |
61 |
self.columns.extend([int(c) for c in col]) |
60 |
62 |
return |
61 |
option |
|
63 |
option_handler_c = option_handler_columns |
|
62 |
64 |
|
63 |
65 |
def getPrintableColumns(self, row): |
64 |
66 |
"""Return only the part of the row which should be printed. |
Up to file-list docs/source/PyMagArticle/index.rst:
| … | … | @@ -41,11 +41,79 @@ Listing 1 |
41 |
41 |
|
42 |
42 |
:: |
43 |
43 |
|
44 |
$ python Listing2.py --help |
|
45 |
Traceback (most recent call last): |
|
46 |
File "Listing2.py", line 7, in <module> |
|
47 |
import commandlineapp |
|
48 |
|
|
44 |
$ python docs/source/PyMagArticle/Listing2.py --help |
|
45 |
Concatenate comma separated value files. |
|
46 |
||
47 |
||
48 |
SYNTAX: |
|
49 |
||
50 |
csvcat [<options>] filename [filename...] |
|
51 |
||
52 |
-c col[,col...], --columns=col[,col...] |
|
53 |
-d name, --dialect=name |
|
54 |
--debug |
|
55 |
-h |
|
56 |
--help |
|
57 |
--quiet |
|
58 |
--skip-headers |
|
59 |
-v |
|
60 |
--verbose=level |
|
61 |
||
62 |
||
63 |
ARGUMENTS: |
|
64 |
||
65 |
The names of comma separated value files, such as might be |
|
66 |
exported from a spreadsheet or database program. |
|
67 |
||
68 |
||
69 |
OPTIONS: |
|
70 |
||
71 |
-c col[,col...], --columns=col[,col...] |
|
72 |
Limit the output to the specified columns. Columns are |
|
73 |
identified by number, starting with 0. |
|
74 |
||
75 |
-d name, --dialect=name |
|
76 |
Specify the output dialect name. Defaults to "excel". |
|
77 |
||
78 |
--debug |
|
79 |
Set debug mode to see tracebacks. |
|
80 |
||
81 |
-h |
|
82 |
Displays abbreviated help message. |
|
83 |
||
84 |
--help |
|
85 |
Displays verbose help message. |
|
86 |
||
87 |
--quiet |
|
88 |
Turn on quiet mode. |
|
89 |
||
90 |
--skip-headers |
|
91 |
Treat the first line of each file as a header, and only |
|
92 |
include one copy in the output. |
|
93 |
||
94 |
-v |
|
95 |
Increment the verbose level. |
|
96 |
||
97 |
Higher levels are more verbose. The default is 1. |
|
98 |
||
99 |
--verbose=level |
|
100 |
Set the verbose level. |
|
101 |
||
102 |
EXAMPLES: |
|
103 |
||
104 |
||
105 |
To concatenate 2 files, including all columns and headers: |
|
106 |
||
107 |
$ csvcat file1.csv file2.csv |
|
108 |
||
109 |
To concatenate 2 files, skipping the headers in the second file: |
|
110 |
||
111 |
$ csvcat --skip-headers file1.csv file2.csv |
|
112 |
||
113 |
To concatenate 2 files, including only the first and third columns: |
|
114 |
||
115 |
$ csvcat --col 0,2 file1.csv file2.csv |
|
116 |
||
49 |
117 |
|
50 |
118 |
.. [[[end]]] |
51 |
119 |
|
| … | … | @@ -57,7 +125,7 @@ Listing 2 |
57 |
125 |
|
58 |
126 |
The program description is taken from the docstring of the **csvcat** class. Before it is printed, the text is split into paragraphs and reformatted using **textwrap**, to ensure that it is no wider than 80 columns of text. |
59 |
127 |
|
60 |
The program description is followed by a syntax summary for the program. The options listed in the syntax section correspond to methods with names that begin with ``option |
|
128 |
The program description is followed by a syntax summary for the program. The options listed in the syntax section correspond to methods with names that begin with ``option_handler_``. For example, ``option_handler_skip_headers()`` indicates that **csvcat** should accept a ``--skip-headers`` option on the command line. |
|
61 |
129 |
|
62 |
130 |
The names of any non-optional arguments to the program appear in the syntax summary. In this case, **csvcat** needs the names of the files containing the input data. At least one file name is necessary, and multiple names can be given, as indicated by the fact that the ``filename`` argument to ``main()`` (line 78) uses the variable argument notation: ``*filename``. A longer description of the arguments, taken from the docstring of the ``main()`` method (lines 79-82), follows the syntax summary. As with the general program summary, the description of the arguments is reformatted with **textwrap** to fit the screen. |
63 |
131 |
|
| … | … | @@ -66,15 +134,15 @@ Options and Their Arguments |
66 |
134 |
|
67 |
135 |
Following the argument description is a detailed explanation of all of the options to the program. **CommandLineApp** examines each option handler method to build the option description, including the name of the option, alternative names for the same option, and the name and description of any arguments the option accepts. There are three variations of option handlers, based on the arguments used by the option. |
68 |
136 |
|
69 |
The simplest kind of option does not take an argument at all, and is used as a "switch" to turn a feature on or off. The method ``option |
|
137 |
The simplest kind of option does not take an argument at all, and is used as a "switch" to turn a feature on or off. The method ``option_handler_skip_headers`` (lines 38-43) is an example of such a switch. The method takes no argument, so **CommandLineApp** recognizes that the option being defined does not take an argument either. To create the option name, the prefix is stripped from the method name, and the underscore is converted to a dash (``-``); ``option_handler_skip_headers`` becomes ``--skip-headers``. |
|
70 |
138 |
|
71 |
Other options accept a single argument. For example, the ``--dialect`` option requires the name of the CSV output dialect. The method ``option |
|
139 |
Other options accept a single argument. For example, the ``--dialect`` option requires the name of the CSV output dialect. The method ``option_handler_dialect`` (lines 46-51) takes one argument, called ``name``. The suggested syntax for the option, as seen in Listing 1, is ``--dialect=name``. The name of the method's argument is used as the name of the argument to the option in the help text. |
|
72 |
140 |
|
73 |
The ``-d`` option has the same meaning as ``--dialect``, because ``option |
|
141 |
The ``-d`` option has the same meaning as ``--dialect``, because ``option_handler_d`` is an alias for ``option_handler_dialect`` (line 52). **CommandLineApp** recognizes aliases, and combines the forms in the documentation so the alternative forms ``-d name`` and ``--dialect=name`` are described together. |
|
74 |
142 |
|
75 |
143 |
It is often useful for an option to take multiple arguments, as with ``--columns``. The user could repeat the option on the command line, but it is more compact to allow them to list multiple values in one argument list. When **CommandLineApp** sees an option handler method that takes a variable argument list, it treats the corresponding option as accepting a list of arguments. When the option appears on the command line, the string argument is split on any commas and the resulting list of strings is passed to the option handler method. |
76 |
144 |
|
77 |
For example, ``option |
|
145 |
For example, ``option_handler_columns`` (lines 55-60) takes a variable length argument named ``col``. The option ``--columns`` can be followed by several column numbers, separated by commas. The option handler is called with the list of values pre-parsed. In the syntax description, the argument is shown repeating: ``--columns=col[,col...]``. |
|
78 |
146 |
|
79 |
147 |
For all cases, the docstring from the option handler method serves as the help text for the option. The text of the docstring is reformatted using **textwrap** so both the code and help output are easy to read without extra effort on the part of the developer. |
80 |
148 |
|
| … | … | @@ -197,43 +265,43 @@ Option Definitions |
197 |
265 |
|
198 |
266 |
The standard library module **inspect** provides functions for performing introspection operations on classes and objects at runtime. The API supports basic querying and type checking so it is possible, for example, to get a list of the methods of a class, including all inherited methods. |
199 |
267 |
|
200 |
``CommandLineApp.scanForOptions()`` uses **inspect** to scan an application class for option handler methods (lines 251-260). All of the methods of the class are retrieved with ``inspect.getmembers()``, and those whose name starts with ``option |
|
268 |
``CommandLineApp.scanForOptions()`` uses **inspect** to scan an application class for option handler methods (lines 251-260). All of the methods of the class are retrieved with ``inspect.getmembers()``, and those whose name starts with ``option_handler_`` are added to the list of supported options. Since most command line options use dashes instead of underscores, but method names cannot contain dashes, the underscores in the option handler method names are converted to dashes when creating the option name. |
|
201 |
269 |
|
202 |
270 |
The ``__init__()`` method of the **OptionDef** class (lines 440-469) does all of the work of determining the command line switch name and what type of arguments the switch takes. The option handler method is examined with ``inspect.getargspec()``, and the result is used to initialize the **OptionDef**. |
203 |
271 |
|
204 |
272 |
An "argspec" for a function is a tuple made up of four values: a list of the names of all regular arguments to the function, including ``self`` if the function is a method; the name of the argument to receive the variable argument values, if any; the name of the argument to receive the keyword arguments, if any; and a list of the default values for the arguments, in they order they appear in the list of option names. |
205 |
273 |
|
206 |
The argspecs for the option handlers in **csvcat** illustrate the variations of interest to **OptionDef**. First, ``option |
|
274 |
The argspecs for the option handlers in **csvcat** illustrate the variations of interest to **OptionDef**. First, ``option_handler_skip_headers``: |
|
207 |
275 |
|
208 |
276 |
:: |
209 |
277 |
|
210 |
278 |
>>> import Listing2 |
211 |
279 |
>>> import inspect |
212 |
280 |
>>> print inspect.getargspec( |
213 |
... Listing2.csvcat.option |
|
281 |
... Listing2.csvcat.option_handler_skip_headers) |
|
214 |
282 |
(['self'], None, None, None) |
215 |
283 |
|
216 |
284 |
Since the only positional argument to the method is ``self``, and there is no variable argument name given, the option handler is treated as a simple command line switch without any arguments. |
217 |
285 |
|
218 |
The ``option |
|
286 |
The ``option_handler_dialect``, on the other hand, does include an additional argument: |
|
219 |
287 |
|
220 |
288 |
:: |
221 |
289 |
|
222 |
290 |
>>> print inspect.getargspec( |
223 |
... Listing2.csvcat.option |
|
291 |
... Listing2.csvcat.option_handler_dialect) |
|
224 |
292 |
(['self', 'name'], None, None, None) |
225 |
293 |
|
226 |
294 |
The ``name`` argument is listed in the argspec as a single regular argument. The result, when a program is run, is that while the options are being processed by **CommandLineApp** and **OptionDef**, the value for ``name`` is passed directly to the option handler method (line 497). |
227 |
295 |
|
228 |
The ``option |
|
296 |
The ``option_handler_columns`` method illustrates variable argument handling: |
|
229 |
297 |
|
230 |
298 |
:: |
231 |
299 |
|
232 |
300 |
>>> print inspect.getargspec( |
233 |
... Listing2.csvcat.option |
|
301 |
... Listing2.csvcat.option_handler_columns) |
|
234 |
302 |
(['self'], 'col', None, None) |
235 |
303 |
|
236 |
The ``col`` argument from ``option |
|
304 |
The ``col`` argument from ``option_handler_columns`` is named in the argspec as the variable argument identifier. Since ``option_handler_columns`` accepts variable arguments, the **OptionDef** splits the argument value into a list of strings, and the list is passed to the option handler method (lines 494-495) using the variable argument syntax. |
|
237 |
305 |
|
238 |
306 |
The other variable argument configuration, using unidentified keyword arguments, does not make sense for an option handler. The user of the command line program has no standard way to specify named arguments to options, so they are not supported by **OptionDef**. |
239 |
307 |
| … | … | @@ -118,12 +118,19 @@ def run_script(input_file, script_name, |
118 |
118 |
If False, the output is passed to rstrip() then one newline is added. If |
119 |
119 |
True, newlines are added to the output until it ends in 2. |
120 |
120 |
""" |
121 |
# rundir = path(input_file).dirname() |
|
122 |
# if interpreter: |
|
123 |
# cmd = '%(interpreter)s %(script_name)s' % vars() |
|
124 |
# else: |
|
125 |
# cmd = script_name |
|
126 |
# real_cmd = 'cd %(rundir)s; %(cmd)s 2>&1' % vars() |
|
121 |
127 |
rundir = path(input_file).dirname() |
128 |
full_script_name = rundir / script_name |
|
122 |
129 |
if interpreter: |
123 |
cmd = '%(interpreter)s %( |
|
130 |
cmd = '%(interpreter)s %(full_script_name)s' % vars() |
|
124 |
131 |
else: |
125 |
cmd = script_name |
|
126 |
real_cmd = 'cd %(rundir)s; %(cmd)s 2>&1' % vars() |
|
132 |
cmd = full_script_name |
|
133 |
real_cmd = cmd |
|
127 |
134 |
try: |
128 |
135 |
output_text = sh(real_cmd, capture=True, ignore_error=ignore_error) |
129 |
136 |
except Exception, err: |
| … | … | @@ -163,14 +170,7 @@ def sdist(): |
163 |
170 |
pass |
164 |
171 |
|
165 |
172 |
@task |
166 |
def copy_src_to_listing(options): |
|
167 |
#destdir=path(options.sphinx.docroot) / options.sphinx.sourcedir / 'PyMagArticle' |
|
168 |
destdir='docs/source/PyMagArticle' |
|
169 |
sh('cp commandlineapp.py %s' % destdir) |
|
170 |
return |
|
171 |
||
172 |
@task |
|
173 |
@needs(['copy_src_to_listing', 'cog', 'paver.doctools.html']) |
|
173 |
@needs(['cog', 'paver.doctools.html']) |
|
174 |
174 |
def html(options): |
175 |
175 |
"""Run sphinx to produce the documentation. |
176 |
176 |
""" |
