Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Use friendlier names in doc examples

  • Loading branch information...
commit eda31958c8d79d2c6064e9fbb68d98ac91d6c0cf 1 parent 46b72fe
Oscar Benjamin authored
163 docs/positional.rst
Source Rendered
@@ -31,26 +31,27 @@ Before considering how Opster handles positional arguments it is instructive
31 31 to look at a simple example of a script that does not use opster. Opster works
32 32 by turning a function into a script. The simplest way to construct a script
33 33 that receives some positional command line arguments and sends them to a
34   -function looks something like `pos1.py`:
  34 +function looks something like `basic.py`:
35 35
36   -.. literalinclude:: scripts/pos1.py
  36 +.. literalinclude:: scripts/basic.py
37 37
38 38 This script has one required argument, ``arg1``, and one optional argument,
39 39 ``arg2``, (defaulting to ``None``). With valid arguments everything is fine::
40 40
41   - $ python pos1.py one
42   - arg1: one
  41 + $ python basic.py spam
  42 + arg1: spam
43 43 arg2: None
44 44
45   - $ python pos1.py one two
46   - arg1: one
47   - arg2: two
  45 + $ python basic.py spam ham
  46 + arg1: spam
  47 + arg2: ham
48 48
49   -However `pos1.py` bombs when given too many or too few input arguments::
  49 +However `basic.py` does not fail gracefully when given too many or too few
  50 +input arguments::
50 51
51   - $ python pos1.py one two three
  52 + $ python basic.py spam ham eggs
52 53 Traceback (most recent call last):
53   - File "pos1.py", line 13, in <module>
  54 + File "basic.py", line 13, in <module>
54 55 main(*sys.argv[1:])
55 56 TypeError: main() takes at most 2 arguments (3 given)
56 57 [1]
@@ -58,36 +59,37 @@ However `pos1.py` bombs when given too many or too few input arguments::
58 59 Using opster
59 60 ============
60 61
61   -Using Opster we can make a friendlier script, `pos2.py`, with only a handful
  62 +Using Opster we can make a friendlier script, `better.py`, with only a handful
62 63 of changes:
63 64
64   -.. literalinclude:: scripts/pos2.py
  65 +.. literalinclude:: scripts/better.py
65 66 :emphasize-lines: 5, 7, 9, 14
66 67
67 68 Let us briefly consider the changes highlighted above:
68 69
69 70 #. We need to import opster's ``command`` decorator.
70 71 #. ``command()`` is used to decorate the ``main`` function.
71   -#. The doc-string for ``main`` is changed to a message suitable for output in
72   - a command-line environment.
  72 +#. The doc-string for ``main`` is changed to a message suitable for a
  73 + command-line user.
73 74 #. Instead of calling ``main`` directly we call its ``.command`` attribute
74 75 which was added by the ``command`` decorator.
75 76
76   -For valid arguments nothing changes::
  77 +So what happens when we run this script from the command line? For valid
  78 +arguments nothing changes::
77 79
78   - $ python pos2.py one
79   - arg1: one
  80 + $ python better.py spam
  81 + arg1: spam
80 82 arg2: None
81 83
82   - $ python pos2.py one two
83   - arg1: one
84   - arg2: two
  84 + $ python better.py spam ham
  85 + arg1: spam
  86 + arg2: ham
85 87
86   -However `pos2.py` can now print helpful output when run ``-h`` or
  88 +However `better.py` can now print helpful output when run ``-h`` or
87 89 ``--help``::
88 90
89   - $ python pos2.py --help
90   - pos2.py ARG1 [ARG2]
  91 + $ python better.py --help
  92 + better.py ARG1 [ARG2]
91 93
92 94 Display the values of ARG1 and ARG2
93 95
@@ -95,14 +97,14 @@ However `pos2.py` can now print helpful output when run ``-h`` or
95 97
96 98 -h --help display help
97 99
98   -If `pos2.py` is given the wrong number of arguments it will say so and then
  100 +If `better.py` is given the wrong number of arguments it will say so and then
99 101 print out its help message. This is the more typical behaviour that users
100 102 expect when they type the wrong arguments to a command line program::
101 103
102   - $ python pos2.py one two three
103   - pos2.py: invalid arguments
  104 + $ python better.py spam ham eggs
  105 + better.py: invalid arguments
104 106
105   - pos2.py ARG1 [ARG2]
  107 + better.py ARG1 [ARG2]
106 108
107 109 Display the values of ARG1 and ARG2
108 110
@@ -115,21 +117,21 @@ How it works
115 117
116 118 The idea of Opster is to quickly turn a python function into a full-featured
117 119 command line script. Opster decides how to do this by looking at the arguments
118   -of the function that is wrapped with ``opster.command`` decorator. Let us
119   -consider a slightly more complicated example `pos3.py`:
  120 +of the function that is wrapped with ``command`` decorator. Let us consider a
  121 +slightly more complicated example `complete.py`:
120 122
121   -.. literalinclude:: scripts/pos3.py
  123 +.. literalinclude:: scripts/complete.py
122 124
123   -The ``main`` function in `pos3.py` has two required arguments and four
  125 +The ``main`` function in `complete.py` has two required arguments and four
124 126 optional arguments. Opster interprets the two required arguments to ``main``
125 127 as required positional arguments for the the script. For each optional
126 128 argument to ``main`` Opster checks the type of the default value: if it is a
127 129 `tuple` it is assumed to be the definition of an `option`. Otherwise the
128   -optional arguments to ``main`` are taken to be optional arguments to the
129   -script. We can check the help output from this script::
  130 +optional arguments to ``main`` are taken to be optional `positional` arguments
  131 +to the script. We can check the help output from this script::
130 132
131   - $ python pos3.py --help
132   - pos3.py [OPTIONS] INFILE OUTFILE [PATTERN] [EXCLUDE]
  133 + $ python complete.py --help
  134 + complete.py [OPTIONS] INFILE OUTFILE [PATTERN] [EXCLUDE]
133 135
134 136 Write lines from INFILE to OUTFILE.
135 137
@@ -153,24 +155,24 @@ The above help message is generated by combining three things:
153 155 #. The list of option arguments that the script takes (The ``help`` option was
154 156 added automatically by Opster).
155 157
156   -Since `pos3.py` has two required arguments (``INFILE`` and ``OUTFILE``) and
  158 +Since `complete.py` has two required arguments (``INFILE`` and ``OUTFILE``) and
157 159 two optional positional arguments (``PATTERN`` and ``EXCLUDE``) it can take
158 160 between two and four positional arguments and will give an error message
159 161 otherwise. If either of the optional positional arguments is not given, the
160 162 corresponding argument to ``main`` will be set to its default value as given
161 163 in the definition of ``main``::
162 164
163   - $ python pos3.py input.txt output.txt
164   - infile: input.txt
165   - outfile: output.txt
  165 + $ python complete.py bar.txt foo.txt
  166 + infile: bar.txt
  167 + outfile: foo.txt
166 168 pattern: .*
167 169 exclude: None
168 170
169   - $ python pos3.py input.txt output.txt str1 str2
170   - infile: input.txt
171   - outfile: output.txt
172   - pattern: str1
173   - exclude: str2
  171 + $ python complete.py bar.txt foo.txt messiah "naughty boy"
  172 + infile: bar.txt
  173 + outfile: foo.txt
  174 + pattern: messiah
  175 + exclude: naughty boy
174 176
175 177 The ``command`` decorator wraps the ``main`` function, but ensures that it can
176 178 still be called as a function from within python. This is useful if you want
@@ -178,10 +180,10 @@ to import the function in another module and use it there:
178 180
179 181 .. doctest::
180 182
181   - >>> from scripts import pos3
182   - >>> pos3.main('input.txt', 'output.txt')
183   - infile: input.txt
184   - outfile: output.txt
  183 + >>> from scripts import complete
  184 + >>> complete.main('bar.txt', 'foo.txt')
  185 + infile: bar.txt
  186 + outfile: foo.txt
185 187 pattern: .*
186 188 exclude: None
187 189
@@ -193,35 +195,36 @@ that are explicitly `keyword-only` in the function signature. This enables a
193 195 clear separation between `positional` arguments and `option` arguments that
194 196 the ``command`` decorator can use when inspecting a function. Scripts that are
195 197 only intended to run under Python 3 should use keyword-only arguments to
196   -define options as shown in `pos4.py`:
  198 +define options as shown in `kwonly.py`:
197 199
198   -.. literalinclude:: scripts/pos4.py
  200 +.. literalinclude:: scripts/kwonly.py
199 201 :language: python3
  202 + :emphasize-lines: 10
200 203
201 204 This script would be a syntax error on Python 2 but works as you would expect
202 205 on Python 3::
203 206
204   - $ python3 pos4.py --help
205   - pos4.py [OPTIONS] ARG1 [ARG2]
  207 + $ python3 kwonly.py --help
  208 + kwonly.py [OPTIONS] ARG1 [ARG2]
206 209
207   - Do important things
  210 + spam the ham
208 211
209 212 options:
210 213
211   - -o --option an arbitrary option
212   - -h --help display help
  214 + -e --eggs use eggs
  215 + -h --help display help
213 216
214 217 If ``main`` has any keyword-only arguments then the ``command`` decorator will
215 218 assume that all `keyword-only` arguments are `option` definitions and that all
216 219 positional arguments to ``main`` are positional arguments to the script. This
217 220 means that Opster will not check the type of the default value to see if it is
218 221 a tuple and it is possible to have a positional argument whose default value
219   -is a tuple, such as ``arg2`` in `pos4.py`::
  222 +is a tuple, such as ``arg2`` in `kwonly.py`::
220 223
221   - $ python3 pos4.py val1
222   - arg1: val1
  224 + $ python3 kwonly.py foo
  225 + arg1: foo
223 226 arg2: ()
224   - option: False
  227 + eggs: False
225 228
226 229 While Opster supports Python 2.6 and 2.7 it will need to support the syntax
227 230 that does not use `keyword-only` arguments to define options. It is
@@ -235,44 +238,44 @@ Many command line applications can accept an unlimited number of command line
235 238 arguments. Opster provides support for this using Python's `varargs` syntax.
236 239 If we can use `keyword-only` arguments for option definitions, then we can
237 240 simply place the `varargs` paramerer at the end of the list of positional
238   -arguments like in `pos5.py`:
  241 +arguments like in `varargs.py`:
239 242
240   -.. literalinclude:: scripts/pos5.py
  243 +.. literalinclude:: scripts/varargs.py
241 244 :language: python3
242 245
243 246 The usage string illustrates the fact that many values can be provided with an
244   -ellipsis ``...`` after ``FILES``::
  247 +ellipsis ``...`` after ``CHEESES``::
245 248
246   - $ python3 pos5.py --help
247   - pos5.py [OPTIONS] PATTERN [FILES ...]
  249 + $ python3 varargs.py --help
  250 + varargs.py [OPTIONS] SHOP [CHEESES ...]
248 251
249   - Do important things
  252 + Buy cheese
250 253
251 254 options:
252 255
253   - -o --option an arbitrary option
254   - -h --help display help
  256 + -m --music provide musical accompaniment
  257 + -h --help display help
255 258
256   -The parameter ``files`` will receive a tuple of any arguments supplied after
257   -the required ``PATTERN`` argument::
  259 +The parameter ``cheeses`` will receive a tuple of any command line arguments
  260 +supplied after the required ``SHOP`` argument::
258 261
259   - $ python3 pos5.py foo file1.txt file2.txt file3.txt
260   - pattern: foo
261   - files: ('file1.txt', 'file2.txt', 'file3.txt')
  262 + $ python3 varargs.py wensleydale cheddar ilchester camembert
  263 + shop: wensleydale
  264 + cheeses: ('cheddar', 'ilchester', 'camembert')
262 265
263 266 Because the `keyword-only` syntax is unavailable on Python 2.x, Opster
264 267 provides an alternative syntax for specifying that a script should accept a
265 268 variable number of arguments, which is to place the `varargs` parameter
266 269 at the end of the argument list `after` the option definitions as shown in
267   -``pos6.py``:
  270 +``varargs_py2.py``:
268 271
269   -.. literalinclude:: scripts/pos6.py
  272 +.. literalinclude:: scripts/varargs_py2.py
270 273
271   -Opster will take care of ensuring that the ``main`` function in `pos6.py`
272   -still receives the positional arguments to the script the same way as the
273   -``main`` in `pos5.py`::
  274 +Opster will take care of ensuring that the ``cheeses`` parameter in the
  275 +``main`` function of `varargs_py2.py` still receives the positional command
  276 +line arguments the same way as in `varargs.py`::
274 277
275   - $ python pos6.py foo file1.txt file2.txt file3.txt
276   - pattern: foo
277   - files: ('file1.txt', 'file2.txt', 'file3.txt')
  278 + $ python varargs_py2.py wensleydale cheddar ilchester camembert
  279 + shop: wensleydale
  280 + cheeses: ('cheddar', 'ilchester', 'camembert')
278 281
2  docs/scripts/pos1.py → docs/scripts/basic.py
... ... @@ -1,4 +1,4 @@
1   -# pos1.py
  1 +# basic.py
2 2
3 3 from __future__ import print_function
4 4
2  docs/scripts/pos2.py → docs/scripts/better.py
... ... @@ -1,4 +1,4 @@
1   -# pos2.py
  1 +# better.py
2 2
3 3 from __future__ import print_function
4 4
2  docs/scripts/pos3.py → docs/scripts/complete.py
... ... @@ -1,4 +1,4 @@
1   -# pos3.py
  1 +# complete.py
2 2
3 3 from __future__ import print_function
4 4
8 docs/scripts/pos4.py → docs/scripts/kwonly.py
... ... @@ -1,4 +1,4 @@
1   -# pos4.py
  1 +# kwonly.py
2 2
3 3 from __future__ import print_function
4 4
@@ -8,11 +8,11 @@
8 8 def main(arg1,
9 9 arg2=(),
10 10 *, # <-- separates option definitions
11   - option=('o', False, 'an arbitrary option')):
12   - '''Do important things'''
  11 + eggs=('e', False, 'use eggs')):
  12 + '''spam the ham'''
13 13 print('arg1:', arg1)
14 14 print('arg2:', arg2)
15   - print('option:', option)
  15 + print('eggs:', eggs)
16 16
17 17 if __name__ == "__main__":
18 18 main.command()
16 docs/scripts/pos5.py
... ... @@ -1,16 +0,0 @@
1   -# pos5.py
2   -
3   -from __future__ import print_function
4   -
5   -from opster import command
6   -
7   -@command()
8   -def main(pattern,
9   - *files,
10   - option=('o', False, 'an arbitrary option')):
11   - '''Do important things'''
12   - print('pattern:', pattern)
13   - print('files:', files)
14   -
15   -if __name__ == "__main__":
16   - main.command()
16 docs/scripts/pos6.py
... ... @@ -1,16 +0,0 @@
1   -# pos6.py
2   -
3   -from __future__ import print_function
4   -
5   -from opster import command
6   -
7   -@command()
8   -def main(pattern,
9   - option=('o', False, 'an arbitrary option'),
10   - *files):
11   - '''Do important things'''
12   - print('pattern:', pattern)
13   - print('files:', files)
14   -
15   -if __name__ == "__main__":
16   - main.command()
16 docs/scripts/varargs.py
... ... @@ -0,0 +1,16 @@
  1 +# varargs.py
  2 +
  3 +from __future__ import print_function
  4 +
  5 +from opster import command
  6 +
  7 +@command()
  8 +def main(shop,
  9 + *cheeses,
  10 + music=('m', False, 'provide musical accompaniment')):
  11 + '''Buy cheese'''
  12 + print('shop:', shop)
  13 + print('cheeses:', cheeses)
  14 +
  15 +if __name__ == "__main__":
  16 + main.command()
16 docs/scripts/varargs_py2.py
... ... @@ -0,0 +1,16 @@
  1 +# varargs_py2.py
  2 +
  3 +from __future__ import print_function
  4 +
  5 +from opster import command
  6 +
  7 +@command()
  8 +def main(shop,
  9 + music=('m', False, 'provide musical accompaniment'),
  10 + *cheeses):
  11 + '''Buy cheese'''
  12 + print('shop:', shop)
  13 + print('cheeses:', cheeses)
  14 +
  15 +if __name__ == "__main__":
  16 + main.command()

0 comments on commit eda3195

Please sign in to comment.
Something went wrong with that request. Please try again.