summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2010-06-01 14:54:29 +0200
committerMichele Simionato <michele.simionato@gmail.com>2010-06-01 14:54:29 +0200
commit8fc7947431c6e8350196dce2340cda5a544a3437 (patch)
treebbe9c5bf327d2271575d37417d0a30b85160f957
parent7ee9559aa9313824ea327111b7287b716172c286 (diff)
downloadmicheles-8fc7947431c6e8350196dce2340cda5a544a3437.tar.gz
Some cleanup and for the first time I try to use the Mercurial pre-commit hook
-rw-r--r--plac/CHANGES.txt4
-rw-r--r--plac/Makefile4
-rw-r--r--plac/doc/annotations.py1
-rw-r--r--plac/doc/article.html410
-rw-r--r--plac/doc/dbcli.py3
-rw-r--r--plac/doc/example1.py1
-rw-r--r--plac/doc/example10.py1
-rw-r--r--plac/doc/example11.py1
-rw-r--r--plac/doc/example2.py1
-rw-r--r--plac/doc/example3.py1
-rw-r--r--plac/doc/example4.py1
-rw-r--r--plac/doc/example4_.py1
-rw-r--r--plac/doc/example5.py1
-rw-r--r--plac/doc/example6.py1
-rw-r--r--plac/doc/example7.py2
-rw-r--r--plac/doc/example8.py1
-rw-r--r--plac/doc/example8_.py3
-rw-r--r--plac/doc/example9.py2
-rw-r--r--plac/doc/plac.html1036
-rw-r--r--plac/doc/plac.pdf (renamed from plac/doc/article.pdf)1707
-rw-r--r--plac/doc/plac.txt (renamed from plac/doc/article.txt)88
-rw-r--r--plac/plac.py5
22 files changed, 1991 insertions, 1284 deletions
diff --git a/plac/CHANGES.txt b/plac/CHANGES.txt
new file mode 100644
index 0000000..38a86f1
--- /dev/null
+++ b/plac/CHANGES.txt
@@ -0,0 +1,4 @@
+HISTORY
+----------
+
+0.3.0 Initial version. (2010-06-02)
diff --git a/plac/Makefile b/plac/Makefile
new file mode 100644
index 0000000..5c93cf0
--- /dev/null
+++ b/plac/Makefile
@@ -0,0 +1,4 @@
+doc/plac.pdf: doc/plac.txt
+ cd doc; rst2pdf plac.txt; rst2html plac.txt plac.html
+upload:
+ python setup.py register sdist upload
diff --git a/plac/doc/annotations.py b/plac/doc/annotations.py
index c84cc04..0de2140 100644
--- a/plac/doc/annotations.py
+++ b/plac/doc/annotations.py
@@ -1,3 +1,4 @@
+# annotations.py
class Positional(object):
def __init__(self, help='', type=None, choices=None, metavar=None):
self.help = help
diff --git a/plac/doc/article.html b/plac/doc/article.html
deleted file mode 100644
index 59feb07..0000000
--- a/plac/doc/article.html
+++ /dev/null
@@ -1,410 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
-<title></title>
-<style type="text/css">
-
-.highlight { background: #f8f8f8; }
-.highlight .c { color: #408080; font-style: italic } /* Comment */
-.highlight .err { border: 1px solid #FF0000 } /* Error */
-.highlight .k { color: #008000; font-weight: bold } /* Keyword */
-.highlight .o { color: #666666 } /* Operator */
-.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
-.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
-.highlight .gd { color: #A00000 } /* Generic.Deleted */
-.highlight .ge { font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #FF0000 } /* Generic.Error */
-.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #808080 } /* Generic.Output */
-.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0040D0 } /* Generic.Traceback */
-.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.highlight .kp { color: #008000 } /* Keyword.Pseudo */
-.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #008000; font-weight: bold } /* Keyword.Type */
-.highlight .m { color: #666666 } /* Literal.Number */
-.highlight .s { color: #BA2121 } /* Literal.String */
-.highlight .na { color: #7D9029 } /* Name.Attribute */
-.highlight .nb { color: #008000 } /* Name.Builtin */
-.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
-.highlight .no { color: #880000 } /* Name.Constant */
-.highlight .nd { color: #AA22FF } /* Name.Decorator */
-.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
-.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
-.highlight .nf { color: #0000FF } /* Name.Function */
-.highlight .nl { color: #A0A000 } /* Name.Label */
-.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
-.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
-.highlight .nv { color: #19177C } /* Name.Variable */
-.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mf { color: #666666 } /* Literal.Number.Float */
-.highlight .mh { color: #666666 } /* Literal.Number.Hex */
-.highlight .mi { color: #666666 } /* Literal.Number.Integer */
-.highlight .mo { color: #666666 } /* Literal.Number.Oct */
-.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
-.highlight .sc { color: #BA2121 } /* Literal.String.Char */
-.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
-.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
-.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
-.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
-.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
-.highlight .sx { color: #008000 } /* Literal.String.Other */
-.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
-.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
-.highlight .ss { color: #19177C } /* Literal.String.Symbol */
-.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
-.highlight .vc { color: #19177C } /* Name.Variable.Class */
-.highlight .vg { color: #19177C } /* Name.Variable.Global */
-.highlight .vi { color: #19177C } /* Name.Variable.Instance */
-.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
-
-</style>
-</head>
-<body>
-<div class="document">
-
-
-<div class="section" id="the-easiest-command-line-arguments-parser-in-the-python-world">
-<h1>The easiest command line arguments parser in the Python world</h1>
-<p>Today I want to announce to the general public the birth of my latest
-project, which aims to be the easiest command line arguments
-parser in the Python world: <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a>.</p>
-<p><a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> is designed to be <a class="reference external" href="http://www.welton.it/articles/scalable_systems">downwardly scalable</a>, i.e. to be trivially simple
-to use for trivial use cases, while being surprisingly scalable upwards
-for less trivial use cases. Still, <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> is not intended to
-be an industrial strength command line parsing module. Its
-capabilities are limited by design. If you need more power, by all means
-use the parsing modules in the standard library. Still, I have been using
-Python for 8 years and never once I had to use the full power of the
-standard library modules.</p>
-<p>Actually I am prettu much convinced that features provided by <tt class="docutils literal">plac</tt>
-aee more than enough for 99.9% of the typical use cases of a scripter
-working in a Unix-like environment. I am targetting here programmers,
-sysadmins, scientists and in general people writing throw-away scripts
-for themselves, choosing to use a command line interface because it is
-the quick and simple. Such users are not interested in features,
-they just want to be able to write a simple command line tool from a
-simple specification, not to build a command line parser by
-hand. Unfortunately, the current modules in the standard library
-forces them to go the hard way. They are designed to implement
-power user tools for programmers or system administrators, and
-they have a non-trivial learning curve.</p>
-<p>This is why, even if there is no want of command line arguments
-parsers in Python world, sometime like <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> was still lacking.</p>
-<p>The standard library alone contains three different modules for the
-parsing of command line options: <a class="reference external" href="http://docs.python.org/library/getopt.html">getopt</a> (from the stone age),
-<a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a> (from Python 2.3) and <a class="reference external" href="http://argparse.googlecode.com">argparse</a> (from Python 2.7). All of
-them are quite powerful and especially <a class="reference external" href="http://argparse.googlecode.com">argparse</a> is an industrial
-strength solution; <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> is just a nice and simple wrapper over
-<a class="reference external" href="http://argparse.googlecode.com">argparse</a>, hiding most of the complexity while retaining most of
-the power.</p>
-</div>
-<div class="section" id="the-importance-of-scaling-down">
-<h1>The importance of scaling down</h1>
-<p>An ex-coworket of mine, David Welton, once wrote a nice article about
-the importance of <a class="reference external" href="http://www.welton.it/articles/scalable_systems">scaling down</a>: most people are concerned with the
-possibility of scaling up, but we should also be concerned with the
-issue of scaling down: in other worlds, simple things should be kept
-simple. To be concrete, let me start with the simplest possible
-thing: a script that takes a single argument and does something to it.
-It cannot get more trivial than that (discarding the possibility of
-a script without command line arguments, where there is nothing to parse),
-nevertheless it is a use case <em>extremely important</em>:
-I need to write scripts like that nearly every day, I wrote hundreds
-of them in the last few years and I have never been happy. Here is
-a typical example:</p>
-<blockquote>
-<pre class="literal-block">
-def main(dsn):
- &quot;Do something with the database&quot;
- print(dsn)
-
-if __name__ == '__main__':
- import sys
- n = len(sys.argv[1:])
- if n == 0:
- sys.exit('usage: python %s dsn' % sys.argv[0])
- elif n == 1:
- main(sys.argv[1])
- else:
- sys.exit('Unrecognized arguments: %s' % ' '.join(sys.argv[2:]))
-
-</pre>
-</blockquote>
-<p>As you see the whole <tt class="docutils literal">if __name__ == '__main__'</tt> block (10 lines
-counting an empty line) is essentially boilerplate that should not exists.
-Actually I think the Python language should recognize the
-main function and perform trivial arguments parsing behind the
-scenes; unfortunaly this is unlikely to happen. Therefore I have
-been writing boilerplate like this for years, and every time
-I <em>hate</em> having to check for the <tt class="docutils literal">IndexError</tt> by hand, and I hate having
-to write always the same usage message. The purpose of using a
-scripting language is convenience and trivial things should be
-trivial. Unfortunately the standard library modules do not help
-for this use case, which may be trivial, but it is still
-incredibly common. Using <a class="reference external" href="http://docs.python.org/library/getopt.html">getopt</a> and <a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a> does not help,
-since they are intended to manage options and not positional arguments;
-the <a class="reference external" href="http://argparse.googlecode.com">argparse</a> module helps a bit and it is able to reduce the
-boilerplate from 10 lines to 7 lines:</p>
-<blockquote>
-<pre class="literal-block">
-def main(dsn):
- &quot;Do something on the database&quot;
- print(dsn)
-
-if __name__ == '__main__':
- import argparse
- p = argparse.ArgumentParser()
- p.add_argument('dsn')
- arg = p.parse_args()
- main(arg.dsn)
-
-</pre>
-</blockquote>
-<p>However saving a three lines does not justify introducing the external
-dependency (most people will not switch Python 2.7, currenctly in beta
-for many years).
-Moreover, it just feels too complex to instantiate a class and to
-define a parser by hand for such a trivial task.</p>
-<p>The <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> module works pretty well when scaling down, and it is able
-to reduce the ten lines of boiler plate to two lines. With the
-<a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> module all you need to write is</p>
-<blockquote>
-<pre class="literal-block">
-def main(dsn):
- &quot;Do something with the database&quot;
- print(dsn)
-
-if __name__ == '__main__':
- import plac; plac.call(main)
-
-</pre>
-</blockquote>
-<p>As an additional bonus she <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> module automatically recognizes the help flag:</p>
-<blockquote>
-# python example1.py -h</blockquote>
-<p>This is only the tip of the iceberg, as you will see.</p>
-</div>
-<div class="section" id="optional-arguments">
-<h1>Optional arguments</h1>
-<p>I have encountered this use case at work hundreds of times:</p>
-<blockquote>
-<pre class="literal-block">
-def main(dsn):
- &quot;Do something on the database&quot;
- print(dsn)
-
-if __name__ == '__main__':
- import argparse
- p = argparse.ArgumentParser()
- p.add_argument('dsn')
- arg = p.parse_args()
- main(arg.dsn)
-
-</pre>
-</blockquote>
-<p>9 lines of boilerplate are removed.</p>
-<p>Finally, often you want to pass a variable number of arguments to
-your command line script. Here is an example, a script which runs
-on the database a series of .sql scripts:</p>
-<blockquote>
-<pre class="literal-block">
-from datetime import datetime
-
-def main(dsn, *scripts):
- &quot;Run the given scripts on the database&quot;
- for script in scripts:
- print('executing %s' % script)
-
-if __name__ == '__main__':
- if len(sys.argv) &lt; 2:
- sys.exit('usage: python %s dsn script.sql ...' % sys.argv[0])
- main(sys.argv[1:])
-
-</pre>
-</blockquote>
-<p>Using <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a>, you can just replace the <tt class="docutils literal">__main__</tt> block with the usual
-<tt class="docutils literal">import plac; plac.call(main)</tt>. The importanting is that you get a
-much nicer usage message:</p>
-<pre class="literal-block">
-usage: example7.py [-h] dsn [scripts [scripts ...]]
-
-positional arguments:
- dsn
- scripts
-
-optional arguments:
- -h, --help show this help message and exit
-</pre>
-</div>
-<div class="section" id="options-and-flags">
-<h1>Options and flags</h1>
-<p>It is surprising how little command line scripts with options
-I have written over the years (probably less than a hundred),
-compared to the number of scripts with positional arguments
-(I certainly have written more than a thousand of them).
-Still, this use case is quite common and cannot be neglected.
-The standard library modules (all of them) are quite verbose
-when it comes to specifying the options and frankly I have
-never used them directly. Instead, I have always relied on
-an old recipe of mine, the <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> recipe, which provides a
-convenient wrapper over <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> or I have just performed the
-parsing by hand in the simplest cases.</p>
-<p><a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> is inspired to the <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> recipe, in the sense that
-it delivers the programmer from the burden of writing the
-parser for the options by hand, but is less of a hack: instead
-of extracting the parser from the docstring of the module, it
-extracts it from the signature of the <tt class="docutils literal">main</tt> function.</p>
-<p>The idea is to leverage on the <cite>function annotations</cite> concept, a new
-feature of Python 3. An example is worth a thousand words, so here
-it is:</p>
-<blockquote>
-<pre class="literal-block">
-def main(command: (&quot;SQL query&quot;, 'option-c'), dsn):
- if command:
- print('executing %s on %s' % (command, dsn))
-
-if __name__ == '__main__':
- import plac; plac.call(main)
-
-</pre>
-</blockquote>
-<p>As you see, the argument <tt class="docutils literal">command</tt> has been annotated with the
-tuple <tt class="docutils literal">(&quot;SQL query&quot;, <span class="pre">'option-c')</span></tt>: the first string is the
-help string which will appear in the usage message, whereas the
-second string tells <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> that <tt class="docutils literal">command</tt> is an option and that
-it can be abbreviated with the letter <tt class="docutils literal">c</tt>. Of course, it also
-possible to use the long option format, by prefixing the option
-with <tt class="docutils literal"><span class="pre">--command=</span></tt>. The resulting usage message is the following:</p>
-<pre class="literal-block">
-$ python3 example8.py -h
-usage: example8.py [-h] [-c COMMAND] dsn
-
-positional arguments:
- dsn
-
-optional arguments:
- -h, --help show this help message and exit
- -c COMMAND, --command COMMAND
- SQL query
-</pre>
-<p>Here are two examples of usage:</p>
-<pre class="literal-block">
-$ python3 example8.py -c&quot;select * from table&quot; dsn
-executing select * from table on dsn
-
-$ python3 example8.py --command=&quot;select * from table&quot; dsn
-executing select * from table on dsn
-</pre>
-<p>Notice that if the option is not passed, the variable <tt class="docutils literal">command</tt>
-will get the value <tt class="docutils literal">None</tt>.</p>
-<p>Even positional argument can be annotated, but it makes no sense to
-specify the &quot;option-c&quot; string, so you can skip it and write:</p>
-<pre class="literal-block">
-def main(command: (&quot;SQL query&quot;, 'option-c'), dsn: (&quot;Database dsn&quot;,)):
- ...
-</pre>
-<p>Alternatively, you can write <tt class="docutils literal">(&quot;Database dsn&quot;, None)</tt>. In both cases
-the usage message now will show a nice help string on the right hand side
-of the <tt class="docutils literal">dsn</tt> positional argument. varargs (starred-arguments) can also
-be annotated:</p>
-<pre class="literal-block">
-def main(dsn: (&quot;Database dsn&quot;,), *scripts: (&quot;SQL scripts&quot;,)):
- ...
-</pre>
-<p>is a valid signature for <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a>, which will recognize the help strings
-for both <tt class="docutils literal">dsn</tt> and <tt class="docutils literal">scripts</tt>.</p>
-<p><a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> also recognizes flags, i.e. boolean options which are
-True if they are passed to the command line and False if they are absent.
-Here is an example:</p>
-<pre class="literal-block">
-$ python3 example9.py -v dsn
-connecting to dsn
-</pre>
-<p>For consistency with the way the usage message is printed, I suggest to
-follow the FOP convention: in the <tt class="docutils literal">main</tt> function write first
-the flag arguments, then the option arguments and finally the positional
-arguments. This is a convention and you are not forced to use it, but
-it makes sense to put the position arguments at the end, since they
-may be default arguments and varargs. In this document I will always use
-the FOP convention.</p>
-</div>
-<div class="section" id="plac-is-also-for-people-not-using-python-3">
-<h1>plac is also for people not using Python 3</h1>
-<p>I do not use Python 3. At work we are just starting to think about
-migrating to Python 2.6. I think it will take years before we even
-think to migrate to Python 3. I am pretty much sure most Pythonistas
-are in the same situation. Therefore <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a> provides a way to work
-with function annotations even in Python 2.X (including Python 2.3).
-There is no magic involved; you just need to add the annotations
-by hand. For instance</p>
-<pre class="literal-block">
-def main(dsn: (&quot;Database dsn&quot;,), *scripts: (&quot;SQL scripts&quot;,)):
-</pre>
-<p>becomes:</p>
-<pre class="literal-block">
-def main(dsn, *scripts):
- ...
-main.__annotations__ = dict(
-dsn= (&quot;Database dsn&quot;,),
-scripts=(&quot;SQL scripts&quot;,))
-</pre>
-<p>One should be careful to much the keys of the annotations dictionary
-with the names of the arguments in the annotated function; for lazy
-people with Python 2.4 available the simplest way is to use the
-<tt class="docutils literal">plac.annotations</tt> decorator that performs the check for you.</p>
-<pre class="literal-block">
-&#64;annotations(
-dsn= (&quot;Database dsn&quot;,),
-scripts=(&quot;SQL scripts&quot;,))
-def main(dsn, *scripts):
- ...
-</pre>
-<p>In the rest of this article I will assume that you are using Python 2.X with
-X &gt;= 4 and I will use the <tt class="docutils literal">plac.annotations</tt> decorator.</p>
-</div>
-<div class="section" id="advanced-usage">
-<h1>Advanced usage</h1>
-<p>One of the goals of plac is to have a learning curve of <em>minutes</em>, compared
-to the learning curve of <em>hours</em> of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>. That does not mean
-that I have removed all the advanced features of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>. Actually
-a lot of <a class="reference external" href="http://argparse.googlecode.com">argparse</a> power persists in <a class="reference external" href="http://www.welton.it/articles/scalable_systems">plac</a>: in particular, the
-<tt class="docutils literal">type</tt>, <tt class="docutils literal">choices</tt> and <tt class="docutils literal">metavar</tt> concepts are there.
-Here is an example showing all of them:</p>
-<blockquote>
-<pre class="literal-block">
-import plac
-
-&#64;plac.annotations(
-operator=(&quot;The name of an operator&quot;, None, str, ['add', 'mul']),
-numbers=(&quot;A number&quot;, None, float, None, &quot;n&quot;))
-def main(operator, *numbers):
- op = getattr(float, '__%s__' % operator)
- result = dict(add=0.0, mul=1.0)[operator]
- for n in numbers:
- result = op(result, n)
- print(result)
-
-if __name__ == '__main__':
- plac.call(main)
-
-</pre>
-</blockquote>
-<p>Let me begin by discussing the <tt class="docutils literal">type</tt> feature: given any callable
-taking a string in input a returning any Python object, it is possible
-to automagically convert the parsed arguments with the callable, simply
-by listing it in the annotation</p>
-</div>
-</div>
-</body>
-</html>
diff --git a/plac/doc/dbcli.py b/plac/doc/dbcli.py
index ba6d586..04ea44b 100644
--- a/plac/doc/dbcli.py
+++ b/plac/doc/dbcli.py
@@ -1,3 +1,4 @@
+# dbcli.py
import clap
from sqlalchemy.ext.sqlsoup import SqlSoup
@@ -19,7 +20,7 @@ def main(db, header, sqlcmd, delimiter="|", *scripts):
print(delimiter.join(map(str, row)))
for script in scripts:
- db.execute(file(script).read())
+ db.bind.execute(file(script).read())
if __name__ == '__main__':
clap.call(main)
diff --git a/plac/doc/example1.py b/plac/doc/example1.py
index 59d4ef1..8d5fe7a 100644
--- a/plac/doc/example1.py
+++ b/plac/doc/example1.py
@@ -1,3 +1,4 @@
+# example1.py
def main(dsn):
"Do something with the database"
print(dsn)
diff --git a/plac/doc/example10.py b/plac/doc/example10.py
index eb45343..5da3a22 100644
--- a/plac/doc/example10.py
+++ b/plac/doc/example10.py
@@ -1,3 +1,4 @@
+# example10.py
import plac
@plac.annotations(
diff --git a/plac/doc/example11.py b/plac/doc/example11.py
index 0de8395..07fbd40 100644
--- a/plac/doc/example11.py
+++ b/plac/doc/example11.py
@@ -1,3 +1,4 @@
+# example11.py
import plac
from annotations import Positional
diff --git a/plac/doc/example2.py b/plac/doc/example2.py
index 69981ee..74a4a01 100644
--- a/plac/doc/example2.py
+++ b/plac/doc/example2.py
@@ -1,3 +1,4 @@
+# example2.py
def main(dsn):
"Do something on the database"
print(dsn)
diff --git a/plac/doc/example3.py b/plac/doc/example3.py
index 1c1a0bd..adfbed6 100644
--- a/plac/doc/example3.py
+++ b/plac/doc/example3.py
@@ -1,3 +1,4 @@
+# example3.py
def main(dsn):
"Do something with the database"
print(dsn)
diff --git a/plac/doc/example4.py b/plac/doc/example4.py
index 08a7dd2..2e76b65 100644
--- a/plac/doc/example4.py
+++ b/plac/doc/example4.py
@@ -1,3 +1,4 @@
+# example4.py
from datetime import datetime
def main(dsn, table='product', today=datetime.today()):
diff --git a/plac/doc/example4_.py b/plac/doc/example4_.py
index 2a61d47..c2c92da 100644
--- a/plac/doc/example4_.py
+++ b/plac/doc/example4_.py
@@ -1,3 +1,4 @@
+# example4_.py
from datetime import datetime
def main(dsn, table='product', today=datetime.today()):
diff --git a/plac/doc/example5.py b/plac/doc/example5.py
index d6c8c8a..1da6153 100644
--- a/plac/doc/example5.py
+++ b/plac/doc/example5.py
@@ -1,3 +1,4 @@
+# example5.py
from datetime import datetime
def main(dsn, today=datetime.today()):
diff --git a/plac/doc/example6.py b/plac/doc/example6.py
index 9c7b5fd..a68075f 100644
--- a/plac/doc/example6.py
+++ b/plac/doc/example6.py
@@ -1,3 +1,4 @@
+# example6.py
from datetime import datetime
def main(dsn, *scripts):
diff --git a/plac/doc/example7.py b/plac/doc/example7.py
index c1e6b2a..541c4ac 100644
--- a/plac/doc/example7.py
+++ b/plac/doc/example7.py
@@ -1,3 +1,5 @@
+# example7.py
+
from datetime import datetime
def main(dsn, *scripts):
diff --git a/plac/doc/example8.py b/plac/doc/example8.py
index ef5a4e7..1dad399 100644
--- a/plac/doc/example8.py
+++ b/plac/doc/example8.py
@@ -1,3 +1,4 @@
+# example8.py
def main(command: ("SQL query", 'option', 'c'), dsn):
if command:
print('executing %s on %s' % (command, dsn))
diff --git a/plac/doc/example8_.py b/plac/doc/example8_.py
index 1c14748..33ae359 100644
--- a/plac/doc/example8_.py
+++ b/plac/doc/example8_.py
@@ -1,5 +1,4 @@
-# example8_
-
+# example8_.py
def main(dsn, command: ("SQL query", 'option', 'c')='select * from table'):
print('executing %r on %s' % (command, dsn))
diff --git a/plac/doc/example9.py b/plac/doc/example9.py
index 8ab3932..8e39eff 100644
--- a/plac/doc/example9.py
+++ b/plac/doc/example9.py
@@ -1,3 +1,5 @@
+# example9.py
+
def main(verbose: ('prints more info', 'flag', 'v'), dsn: 'connection string'):
if verbose:
print('connecting to %s' % dsn)
diff --git a/plac/doc/plac.html b/plac/doc/plac.html
new file mode 100644
index 0000000..77b998a
--- /dev/null
+++ b/plac/doc/plac.html
@@ -0,0 +1,1036 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
+<title>Plac, the Easiest Command Line Arguments Parser in the World</title>
+<meta name="author" content="Michele Simionato" />
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 5196 2007-06-03 20:25:28Z wiemann $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+ border: 0 }
+
+table.borderless td, table.borderless th {
+ /* Override padding for "table.docutils td" with "! important".
+ The right padding separates the table cells. */
+ padding: 0 0.5em 0 0 ! important }
+
+.first {
+ /* Override more specific margin styles with "! important". */
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin: 0 0 0.5em 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+ul.auto-toc {
+ list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="plac-the-easiest-command-line-arguments-parser-in-the-world">
+<h1 class="title">Plac, the Easiest Command Line Arguments Parser in the World</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>Michele Simionato</td></tr>
+<tr class="field"><th class="docinfo-name">E-mail:</th><td class="field-body"><a class="reference external" href="mailto:michele.simionato&#64;gmail.com">michele.simionato&#64;gmail.com</a></td>
+</tr>
+<tr class="field"><th class="docinfo-name">Requires:</th><td class="field-body">Python 2.3+</td>
+</tr>
+<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/plac">http://pypi.python.org/pypi/plac</a></td>
+</tr>
+<tr class="field"><th class="docinfo-name">Installation:</th><td class="field-body"><tt class="docutils literal"><span class="pre">easy_install</span> <span class="pre">plac</span></tt></td>
+</tr>
+<tr class="field"><th class="docinfo-name">License:</th><td class="field-body">BSD license</td>
+</tr>
+</tbody>
+</table>
+<div class="contents topic" id="contents">
+<p class="topic-title first">Contents</p>
+<ul class="simple">
+<li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li>
+<li><a class="reference internal" href="#the-importance-of-scaling-down" id="id2">The importance of scaling down</a></li>
+<li><a class="reference internal" href="#positional-default-arguments" id="id3">Positional default arguments</a></li>
+<li><a class="reference internal" href="#options-and-flags" id="id4">Options and flags</a></li>
+<li><a class="reference internal" href="#plac-for-python-2-x-users" id="id5">plac for Python 2.X users</a></li>
+<li><a class="reference internal" href="#more-features" id="id6">More features</a></li>
+<li><a class="reference internal" href="#a-more-realistic-example" id="id7">A more realistic example</a></li>
+<li><a class="reference internal" href="#a-few-notes-on-the-underlying-implementation" id="id8">A few notes on the underlying implementation</a></li>
+<li><a class="reference internal" href="#custom-annotation-objects" id="id9">Custom annotation objects</a></li>
+<li><a class="reference internal" href="#plac-vs-argparse" id="id10">plac vs argparse</a></li>
+<li><a class="reference internal" href="#the-future" id="id11">The future</a></li>
+<li><a class="reference internal" href="#trivia-the-story-behind-the-name" id="id12">Trivia: the story behind the name</a></li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h1><a class="toc-backref" href="#id1">Introduction</a></h1>
+<p>There is no want of command line arguments parsers in the Python
+world. The standard library alone contains three different modules for
+the parsing of command line options: <a class="reference external" href="http://docs.python.org/library/getopt.html">getopt</a> (from the stone age),
+<a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a> (from Python 2.3) and <a class="reference external" href="http://argparse.googlecode.com">argparse</a> (from Python 2.7). All of
+them are quite powerful and especially <a class="reference external" href="http://argparse.googlecode.com">argparse</a> is an industrial
+strength solution; unfortunately, all of them feature a non-zero learning
+curve and a certain verbosity.</p>
+<p>Enters <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is designed to be downwardly scalable, i.e. to
+be trivially simple to use for trivial use cases, and to have a
+next-to-zero learning curve. Technically <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is just a simple
+wrapper over <a class="reference external" href="http://argparse.googlecode.com">argparse</a>, hiding most of the complexity while retaining
+most of the power. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is surprisingly scalable upwards even for
+non-trivial use cases, but it is not intended to be an industrial
+strength command line parsing module. Its capabilities are limited by
+design. If you need more power, by all means use the parsing modules
+in the standard library. Still, I have been using Python for 8 years
+and never once I had to use the full power of the standard library
+modules.</p>
+<p>Actually I am pretty much convinced that features provided by <tt class="docutils literal"><span class="pre">plac</span></tt>
+are more than enough for 99.9% of the typical use cases of a scripter.
+I am targetting here programmers, sys-admins, scientists and in
+general people writing throw-away scripts for themselves, choosing to
+use a command line interface because it is the quick and simple. Such
+users are not interested in features, they just want to be able to
+write a simple command line tool from a simple specification, not to
+build a command line parser by hand. Unfortunately, the current
+modules in the standard library forces them to go the hard way. They
+are designed to implement power user tools for programmers or system
+administrators, and they have a non-trivial learning curve.</p>
+</div>
+<div class="section" id="the-importance-of-scaling-down">
+<h1><a class="toc-backref" href="#id2">The importance of scaling down</a></h1>
+<p>An ex-coworker of mine, David Welton, once wrote a nice article about
+the import&lt;ance of <a class="reference external" href="http://www.welton.it/articles/scalable_systems">scaling down</a>: most people are concerned with the
+possibility of scaling up, but we should also be concerned with the
+issue of scaling down. In other worlds, simple things should be kept
+simple, and programs should address the common cases in an easy way,
+hopefully without loosing too much power and keeping difficult things
+possible. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> adhere as much as possible to this philosophy and it
+is designed to handle well the trivial case, while retaining the
+ability to handle complex cases relying on the underlying power of
+<a class="reference external" href="http://argparse.googlecode.com">argparse</a>.</p>
+<p>To be concrete, let me start with the simplest possible
+thing: a script that takes a single argument and does something to it.
+It cannot get more trivial than that (discarding the possibility of
+a script without command line arguments, where there is nothing to parse),
+nevertheless it is a use case <em>extremely common</em>:
+I need to write scripts like that nearly every day, I wrote hundreds
+of them in the last few years and I have never been happy. Here is
+a typical example of code I have been writing by hand for years:</p>
+<blockquote>
+<pre class="literal-block">
+# example1.py
+def main(dsn):
+ &quot;Do something with the database&quot;
+ print(dsn)
+
+if __name__ == '__main__':
+ import sys
+ n = len(sys.argv[1:])
+ if n == 0:
+ sys.exit('usage: python %s dsn' % sys.argv[0])
+ elif n == 1:
+ main(sys.argv[1])
+ else:
+ sys.exit('Unrecognized arguments: %s' % ' '.join(sys.argv[2:]))
+
+</pre>
+</blockquote>
+<p>As you see the whole <tt class="docutils literal"><span class="pre">if</span> <span class="pre">__name__</span> <span class="pre">==</span> <span class="pre">'__main__'</span></tt> block (nine lines) is
+essentially boilerplate that should not exists. Actually I think the
+Python language should recognize the main function and perform trivial
+arguments parsing behind the scenes; unfortunaly this is unlikely to
+happen. I have been writing boilerplate like this in hundreds of
+scripts for years, and every time I <em>hate</em> it. The purpose of using a
+scripting language is convenience and trivial things should be
+trivial. Unfortunately the standard library modules do not help for
+this use case, which may be trivial, but it is still incredibly
+common. Using <a class="reference external" href="http://docs.python.org/library/getopt.html">getopt</a> and <a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a> does not help, since they are
+intended to manage options and not positional arguments; the <a class="reference external" href="http://argparse.googlecode.com">argparse</a>
+module helps a bit and it is able to reduce the boilerplate from nine
+lines to six lines:</p>
+<blockquote>
+<pre class="literal-block">
+# example2.py
+def main(dsn):
+ &quot;Do something on the database&quot;
+ print(dsn)
+
+if __name__ == '__main__':
+ import argparse
+ p = argparse.ArgumentParser()
+ p.add_argument('dsn')
+ arg = p.parse_args()
+ main(arg.dsn)
+
+</pre>
+</blockquote>
+<p>However saving three lines does not justify introducing the external
+dependency: most people will not switch Python 2.7, which at the time of
+this writing is just about to be released, for many years.
+Moreover, it just feels too complex to instantiate a class and to
+define a parser by hand for such a trivial task.</p>
+<p>The <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> module is designed to manage well such use cases, and it is able
+to reduce the original nine lines of boiler plate to two lines. With the
+<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> module all you need to write is</p>
+<blockquote>
+<pre class="literal-block">
+# example3.py
+def main(dsn):
+ &quot;Do something with the database&quot;
+ print(dsn)
+
+if __name__ == '__main__':
+ import plac; plac.call(main)
+
+</pre>
+</blockquote>
+<p>The <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> module provides for free (actually the work is done by the
+underlying <a class="reference external" href="http://argparse.googlecode.com">argparse</a> module) a nice usage message:</p>
+<pre class="literal-block">
+$ python example3.py -h
+usage: example3.py [-h] dsn
+
+positional arguments:
+ dsn
+
+optional arguments:
+ -h, --help show this help message and exit
+</pre>
+<p>This is only the tip of the iceberg: <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is able to do much more than that.</p>
+</div>
+<div class="section" id="positional-default-arguments">
+<h1><a class="toc-backref" href="#id3">Positional default arguments</a></h1>
+<p>I have encountered this use case at work hundreds of times:</p>
+<blockquote>
+<pre class="literal-block">
+# example4.py
+from datetime import datetime
+
+def main(dsn, table='product', today=datetime.today()):
+ &quot;Do something on the database&quot;
+ print(dsn, table, today)
+
+if __name__ == '__main__':
+ import sys
+ args = sys.argv[1:]
+ if not args:
+ sys.exit('usage: python %s dsn' % sys.argv[0])
+ elif len(args) &gt; 2:
+ sys.exit('Unrecognized arguments: %s' % ' '.join(argv[2:]))
+ main(*args)
+
+</pre>
+</blockquote>
+<p>With <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> the entire <tt class="docutils literal"><span class="pre">__main__</span></tt> block reduces to the usual two lines:</p>
+<pre class="literal-block">
+if __name__ == '__main__':
+ import plac; plac.call(main)
+</pre>
+<p>In other words, six lines of boilerplate have been removed, and I have
+the usage message for free:</p>
+<pre class="literal-block">
+usage: example4_.py [-h] dsn [table] [today]
+
+positional arguments:
+ dsn
+ table
+ today
+
+optional arguments:
+ -h, --help show this help message and exit
+</pre>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> manages transparently even the case when you want to pass a
+variable number of arguments. Here is an example, a script running
+on a database a series of SQL scripts:</p>
+<blockquote>
+<pre class="literal-block">
+# example6.py
+from datetime import datetime
+
+def main(dsn, *scripts):
+ &quot;Run the given scripts on the database&quot;
+ for script in scripts:
+ print('executing %s' % script)
+
+if __name__ == '__main__':
+ import sys
+ if len(sys.argv) &lt; 2:
+ sys.exit('usage: python %s dsn script.sql ...' % sys.argv[0])
+ main(sys.argv[1:])
+
+</pre>
+</blockquote>
+<p>Using <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>, you can just replace the <tt class="docutils literal"><span class="pre">__main__</span></tt> block with the
+usual two lines (I have defined an Emacs keybinding for them)
+and you get the following usage message:</p>
+<pre class="literal-block">
+usage: example7.py [-h] dsn [scripts [scripts ...]]
+
+positional arguments:
+ dsn
+ scripts
+
+optional arguments:
+ -h, --help show this help message and exit
+</pre>
+<p>The examples here should have made clear that <em>plac is able to figure out
+the command line arguments parser to use from the signature of the main
+function</em>. This is the whole idea behind <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>: if my intent is clear,
+let's the machine take care of the details.</p>
+</div>
+<div class="section" id="options-and-flags">
+<h1><a class="toc-backref" href="#id4">Options and flags</a></h1>
+<p>It is surprising how few command line scripts with options I have
+written over the years (probably less than a hundred), compared to the
+number of scripts with positional arguments (I certainly have written
+more than a thousand of them). Still, this use case is quite common
+and cannot be neglected. The standard library modules (all of them)
+are quite verbose when it comes to specifying the options and frankly
+I have never used them directly. Instead, I have always relied on an
+old recipe of mine, the <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> recipe, which provides a
+convenient wrapper over <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a>. Alternatively, in the simplest
+cases, I have just performed the parsing by hand, instead of manually
+building a suitable OptionParser.</p>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is inspired to the <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> recipe, in the sense that it
+delivers the programmer from the burden of writing the parser, but is
+less of a hack: instead of extracting the parser from the docstring of
+the module, it extracts it from the signature of the <tt class="docutils literal"><span class="pre">main</span></tt>
+function.</p>
+<p>The idea comes from the <cite>function annotations</cite> concept, a new
+feature of Python 3. An example is worth a thousand words, so here
+it is:</p>
+<blockquote>
+<pre class="literal-block">
+# example8.py
+def main(command: (&quot;SQL query&quot;, 'option', 'c'), dsn):
+ if command:
+ print('executing %s on %s' % (command, dsn))
+ # ...
+
+if __name__ == '__main__':
+ import plac; plac.call(main)
+
+</pre>
+</blockquote>
+<p>As you see, the argument <tt class="docutils literal"><span class="pre">command</span></tt> has been annotated with the
+tuple <tt class="docutils literal"><span class="pre">(&quot;SQL</span> <span class="pre">query&quot;,</span> <span class="pre">'option',</span> <span class="pre">'c')</span></tt>: the first string is the
+help string which will appear in the usage message, whereas the
+second and third strings tell <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> that <tt class="docutils literal"><span class="pre">command</span></tt> is an option and that
+it can be abbreviated with the letter <tt class="docutils literal"><span class="pre">c</span></tt>. Of course, it also
+possible to use the long option format, by prefixing the option
+with <tt class="docutils literal"><span class="pre">--command=</span></tt>. The resulting usage message is the following:</p>
+<pre class="literal-block">
+$ python3 example8.py -h
+usage: example8.py [-h] [-c COMMAND] dsn
+
+positional arguments:
+ dsn
+
+optional arguments:
+ -h, --help show this help message and exit
+ -c COMMAND, --command COMMAND
+ SQL query
+</pre>
+<p>Here are two examples of usage:</p>
+<pre class="literal-block">
+$ python3 example8.py -c&quot;select * from table&quot; dsn
+executing select * from table on dsn
+
+$ python3 example8.py --command=&quot;select * from table&quot; dsn
+executing select * from table on dsn
+</pre>
+<p>Notice that if the option is not passed, the variable <tt class="docutils literal"><span class="pre">command</span></tt>
+will get the value <tt class="docutils literal"><span class="pre">None</span></tt>. It is possible to specify a non-trivial
+default for an option. Here is an example:</p>
+<blockquote>
+<pre class="literal-block">
+# example8_.py
+def main(dsn, command: (&quot;SQL query&quot;, 'option', 'c')='select * from table'):
+ print('executing %r on %s' % (command, dsn))
+
+if __name__ == '__main__':
+ import clap; clap.call(main)
+
+</pre>
+</blockquote>
+<p>Now if you do not pass the <tt class="docutils literal"><span class="pre">command</span> <span class="pre">option</span></tt>, the
+default query will be executed:</p>
+<pre class="literal-block">
+$ python article/example8_.py dsn
+executing 'select * from table' on dsn
+</pre>
+<p>Positional argument can be annotated too:</p>
+<pre class="literal-block">
+def main(command: (&quot;SQL query&quot;, 'option', 'c'),
+ dsn: (&quot;Database dsn&quot;, 'positional', None)):
+ ...
+</pre>
+<p>Of course explicit is better than implicit, an no special cases are
+special enough, but sometimes practicality beats purity, so <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is
+smart enough to convert help messages into tuples internally; in other
+words, you can just write &quot;Database dsn&quot; instead of <tt class="docutils literal"><span class="pre">(&quot;Database</span> <span class="pre">dsn&quot;,</span>
+<span class="pre">'positional',</span> <span class="pre">None)</span></tt>:</p>
+<pre class="literal-block">
+def main(command: (&quot;SQL query&quot;, 'option', 'c'), dsn: &quot;Database dsn&quot;):
+ ...
+</pre>
+<p>In both cases
+the usage message will show a nice help string on the right hand side
+of the <tt class="docutils literal"><span class="pre">dsn</span></tt> positional argument. varargs (starred-arguments) can also
+be annotated:</p>
+<pre class="literal-block">
+def main(dsn: &quot;Database dsn&quot;, *scripts: &quot;SQL scripts&quot;):
+ ...
+</pre>
+<p>is a valid signature for <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>, which will recognize the help strings
+for both <tt class="docutils literal"><span class="pre">dsn</span></tt> and <tt class="docutils literal"><span class="pre">scripts</span></tt>:</p>
+<pre class="literal-block">
+positional arguments:
+ dsn Database dsn
+ scripts SQL scripts
+</pre>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> also recognizes flags, i.e. boolean options which are
+<tt class="docutils literal"><span class="pre">True</span></tt> if they are passed to the command line and <tt class="docutils literal"><span class="pre">False</span></tt>
+if they are absent. Here is an example:</p>
+<pre class="literal-block">
+$ python3 example9.py -v dsn
+connecting to dsn
+</pre>
+<pre class="literal-block">
+$ python3 example9.py -h
+usage: example9.py [-h] [-v] dsn
+
+positional arguments:
+ dsn connection string
+
+optional arguments:
+ -h, --help show this help message and exit
+ -v, --verbose prints more info
+</pre>
+<p>Notice that it is an error trying to specify a default for flags: the
+default value for a flag is always <tt class="docutils literal"><span class="pre">False</span></tt>. If you feel the need to
+implement non-boolean flags, you should use an option with two
+choices, as explained in the &quot;more features&quot; section.</p>
+<p>For consistency with the way the usage message is printed, I suggest
+you to follow the Flag-Option-Required-Default (FORD) convention: in
+the <tt class="docutils literal"><span class="pre">main</span></tt> function write first the flag arguments, then the option
+arguments, then the required arguments and finally the default
+arguments. This is just a convention and you are not forced to use it,
+except for the default arguments (including the varargs) which must
+stay at the end since it is required by the Python syntax.</p>
+</div>
+<div class="section" id="plac-for-python-2-x-users">
+<h1><a class="toc-backref" href="#id5">plac for Python 2.X users</a></h1>
+<p>I do not use Python 3. At work we are just starting to think about
+migrating to Python 2.6. It will take years before we even
+think to migrate to Python 3. I am pretty much sure most Pythonistas
+are in the same situation. Therefore <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> provides a way to work
+with function annotations even in Python 2.X (including Python 2.3).
+There is no magic involved; you just need to add the annotations
+by hand. For instance</p>
+<pre class="literal-block">
+def main(dsn: &quot;Database dsn&quot;, *scripts: &quot;SQL scripts&quot;):
+</pre>
+<p>becomes:</p>
+<pre class="literal-block">
+def main(dsn, *scripts):
+ ...
+main.__annotations__ = dict(
+dsn=&quot;Database dsn&quot;,
+scripts=&quot;SQL scripts&quot;)
+</pre>
+<p>One should be careful to much the keys of the annotations dictionary
+with the names of the arguments in the annotated function; for lazy
+people with Python 2.4 available the simplest way is to use the
+<tt class="docutils literal"><span class="pre">plac.annotations</span></tt> decorator that performs the check for you.</p>
+<pre class="literal-block">
+&#64;annotations(
+ dsn=&quot;Database dsn&quot;,
+ scripts=&quot;SQL scripts&quot;)
+def main(dsn, *scripts):
+ ...
+</pre>
+<p>In the rest of this article I will assume that you are using Python 2.X with
+<tt class="docutils literal"><span class="pre">X</span> <span class="pre">&gt;=</span> <span class="pre">4</span></tt> and I will use the <tt class="docutils literal"><span class="pre">plac.annotations</span></tt> decorator. Notice however
+that the tests for <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> are supposed to run even with Python 2.3.</p>
+</div>
+<div class="section" id="more-features">
+<h1><a class="toc-backref" href="#id6">More features</a></h1>
+<p>One of the goals of plac is to have a learning curve of <em>minutes</em>, compared
+to the learning curve of <em>hours</em> of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>. That does not mean
+that I have removed all the features of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>. Actually
+a lot of <a class="reference external" href="http://argparse.googlecode.com">argparse</a> power persists in <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>.
+Until now, I have only showed simple annotations, but in general
+an annotation is a 5-tuple of the form</p>
+<blockquote>
+<tt class="docutils literal"><span class="pre">(help,</span> <span class="pre">kind,</span> <span class="pre">abbrev,</span> <span class="pre">type,</span> <span class="pre">choices,</span> <span class="pre">metavar)</span></tt></blockquote>
+<p>where <tt class="docutils literal"><span class="pre">help</span></tt> is the help message, <tt class="docutils literal"><span class="pre">kind</span></tt> is one of {&quot;flag&quot;,
+&quot;option &quot;, &quot;positional&quot;}, <tt class="docutils literal"><span class="pre">abbrev</span></tt> is a one-character string,
+<tt class="docutils literal"><span class="pre">type</span></tt> is callable taking a string in input, choices is a sequence
+of values and <tt class="docutils literal"><span class="pre">metavar</span></tt> is a string.</p>
+<p><tt class="docutils literal"><span class="pre">type</span></tt> is used to automagically convert the arguments from string
+to any Python type; by default there is no convertion i.e. <tt class="docutils literal"><span class="pre">type=None</span></tt>.</p>
+<p><tt class="docutils literal"><span class="pre">choices</span></tt> is used to restrict the number of the valid
+options; by default there is no restriction i.e. <tt class="docutils literal"><span class="pre">choices=None</span></tt>.</p>
+<p><tt class="docutils literal"><span class="pre">metavar</span></tt> is used to change the argument name in the usage message
+(and only there); by default the metavar is equal to the name of the
+argument, unless the argument has a default and in such a case is
+equal to the stringified form of the default.</p>
+<p>Here is an example showing many of the features (shamelessly stolen
+from the <a class="reference external" href="http://argparse.googlecode.com">argparse</a> documentation):</p>
+<blockquote>
+<pre class="literal-block">
+# example10.py
+import plac
+
+&#64;plac.annotations(
+operator=(&quot;The name of an operator&quot;, 'positional', None, str, ['add', 'mul']),
+numbers=(&quot;A number&quot;, 'positional', None, float, None, &quot;n&quot;))
+def main(operator, *numbers):
+ &quot;A script to add and multiply numbers&quot;
+ op = getattr(float, '__%s__' % operator)
+ result = dict(add=0.0, mul=1.0)[operator]
+ for n in numbers:
+ result = op(result, n)
+ print(result)
+
+if __name__ == '__main__':
+ plac.call(main)
+
+</pre>
+</blockquote>
+<p>Here is the usage for the script:</p>
+<pre class="literal-block">
+usage: example10.py [-h] {add,mul} [n [n ...]]
+
+A script to add and multiply numbers
+
+positional arguments:
+ {add,mul} The name of an operator
+ n A number
+
+optional arguments:
+ -h, --help show this help message and exit
+</pre>
+<p>Notice that the docstring of the <tt class="docutils literal"><span class="pre">main</span></tt> function has been automatically added
+to the usage message. Here are a couple of examples of use:</p>
+<pre class="literal-block">
+$ python example10.py add 1 2 3 4
+10.0
+$ python example10.py mul 1 2 3 4
+24.0
+$ python example10.py ad 1 2 3 4 # a mispelling error
+usage: example10.py [-h] {add,mul} [n [n ...]]
+example10.py: error: argument operator: invalid choice: 'ad' (choose from 'add', 'mul')
+</pre>
+</div>
+<div class="section" id="a-more-realistic-example">
+<h1><a class="toc-backref" href="#id7">A more realistic example</a></h1>
+<p>Here is a more realistic script using most of the features of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> to
+run SQL queries on a database by relying on <a class="reference external" href="http://www.sqlalchemy.org/">SQLAlchemy</a>. Notice the usage
+of the <tt class="docutils literal"><span class="pre">type</span></tt> feature to automagically convert a SQLAlchemy connection
+string into a <a class="reference external" href="http://www.sqlalchemy.org/docs/reference/ext/sqlsoup.html">SqlSoup</a> object:</p>
+<blockquote>
+<pre class="literal-block">
+# dbcli.py
+import clap
+from sqlalchemy.ext.sqlsoup import SqlSoup
+
+&#64;clap.annotations(
+ db=(&quot;Connection string&quot;, 'positional', None, SqlSoup),
+ header=(&quot;Header&quot;, 'flag', 'H'),
+ sqlcmd=(&quot;SQL command&quot;, 'option', 'c', str, None, &quot;SQL&quot;),
+ delimiter=(&quot;Column separator&quot;, 'option', 'd'),
+ scripts=&quot;SQL scripts&quot;,
+ )
+def main(db, header, sqlcmd, delimiter=&quot;|&quot;, *scripts):
+ &quot;A script to run queries and SQL scripts on a database&quot;
+ print('Working on %s' % db.bind.url)
+ if sqlcmd:
+ result = db.bind.execute(sqlcmd)
+ if header: # print the header
+ print(delimiter.join(result.keys()))
+ for row in result: # print the rows
+ print(delimiter.join(map(str, row)))
+
+ for script in scripts:
+ db.bind.execute(file(script).read())
+
+if __name__ == '__main__':
+ clap.call(main)
+
+</pre>
+</blockquote>
+<p>Here is the usage message:</p>
+<pre class="literal-block">
+$ python article/dbcli.py -h
+usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]
+
+A script to run queries and SQL scripts on a database
+
+positional arguments:
+ db Connection string
+ scripts SQL scripts
+
+optional arguments:
+ -h, --help show this help message and exit
+ -H, --header Header
+ -c SQL, --sqlcmd SQL SQL command
+ -d |, --delimiter | Column separator
+</pre>
+</div>
+<div class="section" id="a-few-notes-on-the-underlying-implementation">
+<h1><a class="toc-backref" href="#id8">A few notes on the underlying implementation</a></h1>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> relies on a <a class="reference external" href="http://argparse.googlecode.com">argparse</a> for all of the heavy lifting work and it is
+possible to leverage on <a class="reference external" href="http://argparse.googlecode.com">argparse</a> features directly or indirectly.</p>
+<p>For instance, you can make invisible an argument in the usage message
+simply by using <tt class="docutils literal"><span class="pre">'==SUPPRESS==`'`</span> <span class="pre">as</span> <span class="pre">help</span> <span class="pre">string</span> <span class="pre">(or</span>
+<span class="pre">``argparse.SUPPRESS</span></tt>). Similarly, you can use <a class="reference external" href="http://argparse.googlecode.com/svn/tags/r11/doc/other-utilities.html?highlight=filetype#FileType">argparse.FileType</a>
+directly.</p>
+<p>It is also possible to pass options to the underlying
+<tt class="docutils literal"><span class="pre">argparse.ArgumentParser</span></tt> object (currently it accepts the default
+arguments <tt class="docutils literal"><span class="pre">description</span></tt>, <tt class="docutils literal"><span class="pre">epilog</span></tt>, <tt class="docutils literal"><span class="pre">prog</span></tt>, <tt class="docutils literal"><span class="pre">usage</span></tt>,
+<tt class="docutils literal"><span class="pre">add_help</span></tt>, <tt class="docutils literal"><span class="pre">argument_default</span></tt>, <tt class="docutils literal"><span class="pre">parents</span></tt>, <tt class="docutils literal"><span class="pre">prefix_chars</span></tt>,
+<tt class="docutils literal"><span class="pre">fromfile_prefix_chars</span></tt>, <tt class="docutils literal"><span class="pre">conflict_handler</span></tt>, <tt class="docutils literal"><span class="pre">formatter_class</span></tt>).
+It is enough to set such attributes on the <tt class="docutils literal"><span class="pre">main</span></tt> function. For
+instance</p>
+<pre class="literal-block">
+def main(...):
+ pass
+
+main.add_help = False
+</pre>
+<p>disable the recognition of the help flag <tt class="docutils literal"><span class="pre">-h,</span> <span class="pre">--help</span></tt>. This is not
+particularly elegant, but I assume the typical user of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> will be
+happy with the default message and would not want to go at this level
+of detail; still it is possible if she wants to. For instance, by
+setting the <tt class="docutils literal"><span class="pre">description</span></tt> attribute, it is possible to add a comment to the
+usage message (by default the docstring of the <tt class="docutils literal"><span class="pre">main</span></tt> function is
+used as description). It is also possible to change the option prefix;
+for instance if your script must run under Windows and you want to use
+&quot;/&quot; as option prefix you can add the lines:</p>
+<pre class="literal-block">
+main.prefix_chars='-/'
+main.short_prefix = '/'
+</pre>
+<p>The recognition of the <tt class="docutils literal"><span class="pre">short_prefix</span></tt> attribute is a <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>
+extension; there is also a companion <tt class="docutils literal"><span class="pre">long_prefix</span></tt> attribute with
+default value of <tt class="docutils literal"><span class="pre">--</span></tt>. <tt class="docutils literal"><span class="pre">prefix_chars</span></tt> is an <a class="reference external" href="http://argparse.googlecode.com">argparse</a> feature.
+Interested readers should read the documentation of <a class="reference external" href="http://argparse.googlecode.com">argparse</a> to
+understand the meaning of the other options. If there is a set of
+options that you use very often, you may consider writing a decorator
+adding such options to the <tt class="docutils literal"><span class="pre">main</span></tt> function for you. For simplicity,
+<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not perform any magic of that kind.</p>
+<p>It is possible to access directly the underlying <a class="reference external" href="http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html">ArgumentParser</a> object, by
+invoking the <tt class="docutils literal"><span class="pre">plac.parser_from</span></tt> utility function:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; import plac
+&gt;&gt;&gt; def main(arg):
+... pass
+...
+&gt;&gt;&gt; print plac.parser_from(main)
+ArgumentParser(prog='', usage=None, description=None, version=None,
+formatter_class=&lt;class 'argparse.HelpFormatter'&gt;, conflict_handler='error',
+add_help=True)
+</pre>
+<p>I use <tt class="docutils literal"><span class="pre">plac.parser_from</span></tt> in the unit tests of the module, but regular
+users should never need to use it.</p>
+</div>
+<div class="section" id="custom-annotation-objects">
+<h1><a class="toc-backref" href="#id9">Custom annotation objects</a></h1>
+<p>Internally <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> uses an <tt class="docutils literal"><span class="pre">Annotation</span></tt> class to convert the tuples
+in the function signature into annotation objects, i.e. objects with
+six attributes <tt class="docutils literal"><span class="pre">help,</span> <span class="pre">kind,</span> <span class="pre">short,</span> <span class="pre">type,</span> <span class="pre">choices,</span> <span class="pre">metavar</span></tt>.</p>
+<p>Advanced users can implement their own annotation objects.
+For instance, here is an example of how you could implement annotations for
+positional arguments:</p>
+<blockquote>
+<pre class="literal-block">
+# annotations.py
+class Positional(object):
+ def __init__(self, help='', type=None, choices=None, metavar=None):
+ self.help = help
+ self.kind = 'positional'
+ self.abbrev = None
+ self.type = type
+ self.choices = choices
+ self.metavar = metavar
+
+</pre>
+</blockquote>
+<p>You can use such annotations objects as follows:</p>
+<blockquote>
+<pre class="literal-block">
+# example11.py
+import plac
+from annotations import Positional
+
+&#64;plac.annotations(
+ i=Positional(&quot;This is an int&quot;, int),
+ n=Positional(&quot;This is a float&quot;, float),
+ rest=Positional(&quot;Other arguments&quot;))
+def main(i, n, *rest):
+ print(i, n, rest)
+
+if __name__ == '__main__':
+ import plac; plac.call(main)
+
+</pre>
+</blockquote>
+<p>Here is the usage message you get:</p>
+<pre class="literal-block">
+usage: example11.py [-h] i n [rest [rest ...]]
+
+positional arguments:
+ i This is an int
+ n This is a float
+ rest Other arguments
+
+optional arguments:
+ -h, --help show this help message and exit
+</pre>
+<p>You can go on and define <tt class="docutils literal"><span class="pre">Option</span></tt> and <tt class="docutils literal"><span class="pre">Flag</span></tt> classes, if you like.
+Using custom annotation objects you could do advanced things like extracting the
+annotations from a configuration file or from a database, but I expect such
+use cases to be quite rare: the default mechanism should work
+pretty well for most users.</p>
+</div>
+<div class="section" id="plac-vs-argparse">
+<h1><a class="toc-backref" href="#id10">plac vs argparse</a></h1>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is opinionated and by design it does not try to make available
+all of the features of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>. In particular you should be aware
+of the following limitations/differences.</p>
+<ul class="simple">
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> automatically defines both a long and short form for each options,
+just like <a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a>. <a class="reference external" href="http://argparse.googlecode.com">argparse</a> allows you to define only a long form,
+or only a short form, if you like. However, since I have always been
+happy with the behavior of <a class="reference external" href="http://docs.python.org/library/optparse.html">optparse</a>, which I feel is pretty much
+consistent, I have decided not to support this feature.</li>
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not support &quot;required options&quot;. As the <a class="reference external" href="http://argparse.googlecode.com">argparse</a>
+documentation puts it: <em>Required options are generally considered bad
+form - normal users expect options to be optional. You should avoid
+the use of required options whenever possible.</em></li>
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> supports only regular boolean flags. <a class="reference external" href="http://argparse.googlecode.com">argparse</a> has the ability to
+define generalized two-value flags with values different from <tt class="docutils literal"><span class="pre">True</span></tt>
+and <tt class="docutils literal"><span class="pre">False</span></tt>. An earlier version of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> had this feature too, but
+since you can use options with two choices instead, and in any case
+the conversion from <tt class="docutils literal"><span class="pre">{True,</span> <span class="pre">False}</span></tt> to any couple of values
+can be trivially implemented with a ternary operator
+(<tt class="docutils literal"><span class="pre">value1</span> <span class="pre">if</span> <span class="pre">flag</span> <span class="pre">else</span> <span class="pre">value2</span></tt>), I have removed it (KISS rules!).</li>
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not support <tt class="docutils literal"><span class="pre">nargs</span></tt> options directly (it uses them internally,
+though, to implement flag recognition). The reason it that all the use
+cases of interest to me are covered by <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> and did not feel the need
+to increase the learning curve by adding direct support to <tt class="docutils literal"><span class="pre">nargs</span></tt>.</li>
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not support subparsers directly. For the moment, this
+looks like a feature too advanced for the goals of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>.</li>
+<li><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not support actions directly. This also
+looks like a feature too advanced for the goals of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>. Notice however
+that the ability to define your own annotation objects may mitigate the
+need for custom actions.</li>
+</ul>
+<p>I should stress again that if you want to access all of the <a class="reference external" href="http://argparse.googlecode.com">argparse</a> features
+from <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> you can use <tt class="docutils literal"><span class="pre">plac.parser_from</span></tt> and you will get
+the underlying <a class="reference external" href="http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html">ArgumentParser</a> object. The the full power of <a class="reference external" href="http://argparse.googlecode.com">argparse</a>
+is then available to you: you can use <tt class="docutils literal"><span class="pre">add_argument</span></tt>, <tt class="docutils literal"><span class="pre">add_subparsers()</span></tt>,
+etc. In other words, while some features are not supported directly,
+<em>all</em> features are supported indirectly.</p>
+</div>
+<div class="section" id="the-future">
+<h1><a class="toc-backref" href="#id11">The future</a></h1>
+<p>Currently plac is below 100 lines of code, not counting blanks, comments
+and docstrings. I do not plan to extend it much in the future. The idea is
+to keep the module short: it is and it should remain a little wrapper over
+<a class="reference external" href="http://argparse.googlecode.com">argparse</a>. Actually I have thought about contributing the code back to
+<a class="reference external" href="http://argparse.googlecode.com">argparse</a> if <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> becomes successfull and gains a reasonable number of
+users. For the moment it should be considered experimental: after all
+I wrote it in three days, including the tests, the documentation and the
+time to learn <a class="reference external" href="http://argparse.googlecode.com">argparse</a>.</p>
+</div>
+<div class="section" id="trivia-the-story-behind-the-name">
+<h1><a class="toc-backref" href="#id12">Trivia: the story behind the name</a></h1>
+<p>The <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> project started very humble: I just wanted to make
+easy_installable my old <a class="reference external" href="http://code.activestate.com/recipes/278844-parsing-the-command-line/">optionparse</a> recipe, and to publish it on PyPI.
+The original name of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> was optionparser and the idea behind it was
+to build an <a class="reference external" href="http://docs.python.org/library/optparse.html?highlight=optionparser#optparse.OptionParser">OptionParser</a> object from the docstring of the module.
+However, before doing that, I decided to check out the <a class="reference external" href="http://argparse.googlecode.com">argparse</a> module,
+since I knew it was going into Python 2.7 and Python 2.7 was coming out.
+Soon enough I realized two things:</p>
+<ol class="arabic simple">
+<li>the single greatest idea of <a class="reference external" href="http://argparse.googlecode.com">argparse</a> was unifying the positional arguments
+and the options in a single namespace object;</li>
+<li>parsing the docstring was so old-fashioned, considering the existence
+of functions annotations in Python 3.</li>
+</ol>
+<p>Putting together these two observations with the original idea of inferring the
+parser I decided to build an <a class="reference external" href="http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html">ArgumentParser</a> object from function
+annotations. The <tt class="docutils literal"><span class="pre">optionparser</span></tt> name was ruled out, since I was
+using <a class="reference external" href="http://argparse.googlecode.com">argparse</a>; a name like <tt class="docutils literal"><span class="pre">argparse_plus</span></tt> was also ruled out,
+since the typical usage was completely different from the <a class="reference external" href="http://argparse.googlecode.com">argparse</a> usage.</p>
+<p>I made a research on PyPI and the name clap (Command Line Arguments Parser)
+was not taken, so I renamed everything to clap. After two days
+a <a class="reference external" href="http://pypi.python.org/pypi/Clap/0.7">Clap</a> module appeared on PyPI! &lt;expletives deleted&gt;</p>
+<p>Having little fantasy, I decided to rename everything again to plac, as
+an anagram of clap: since it is a non-existing English name, I hope nobody
+will steal it from me!</p>
+</div>
+</div>
+</body>
+</html>
diff --git a/plac/doc/article.pdf b/plac/doc/plac.pdf
index e3cf4d7..45cc4f1 100644
--- a/plac/doc/article.pdf
+++ b/plac/doc/plac.pdf
@@ -156,7 +156,7 @@ endobj
/Dest [ 56 0 R
/XYZ
62.69291
- 470.6236
+ 458.6236
0 ]
/Rect [ 62.69291
518.5936
@@ -174,7 +174,7 @@ endobj
/Dest [ 56 0 R
/XYZ
62.69291
- 470.6236
+ 458.6236
0 ]
/Rect [ 527.0227
518.5936
@@ -192,7 +192,7 @@ endobj
/Dest [ 64 0 R
/XYZ
62.69291
- 305.4236
+ 269.4236
0 ]
/Rect [ 62.69291
500.5936
@@ -210,7 +210,7 @@ endobj
/Dest [ 64 0 R
/XYZ
62.69291
- 305.4236
+ 269.4236
0 ]
/Rect [ 527.0227
500.5936
@@ -297,14 +297,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 83 0 R
+ /Dest [ 82 0 R
/XYZ
62.69291
- 407.2849
+ 395.2849
0 ]
/Rect [ 62.69291
446.5936
- 282.1729
+ 180.5229
458.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -315,10 +315,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 83 0 R
+ /Dest [ 82 0 R
/XYZ
62.69291
- 407.2849
+ 395.2849
0 ]
/Rect [ 527.0227
446.5936
@@ -333,14 +333,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 90 0 R
+ /Dest [ 88 0 R
/XYZ
62.69291
- 480.6236
+ 448.6236
0 ]
/Rect [ 62.69291
428.5936
- 191.5929
+ 282.1729
440.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -351,10 +351,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 90 0 R
+ /Dest [ 88 0 R
/XYZ
62.69291
- 480.6236
+ 448.6236
0 ]
/Rect [ 527.0227
428.5936
@@ -369,14 +369,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 113 0 R
+ /Dest [ 95 0 R
/XYZ
62.69291
- 587.8236
+ 525.8236
0 ]
/Rect [ 62.69291
410.5936
- 141.6229
+ 191.5929
422.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -387,10 +387,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 113 0 R
+ /Dest [ 95 0 R
/XYZ
62.69291
- 587.8236
+ 525.8236
0 ]
/Rect [ 521.4627
410.5936
@@ -405,14 +405,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 113 0 R
+ /Dest [ 121 0 R
/XYZ
62.69291
- 188.8236
+ 587.8236
0 ]
/Rect [ 62.69291
392.5936
- 136.0529
+ 141.6229
404.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -423,10 +423,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 113 0 R
+ /Dest [ 121 0 R
/XYZ
62.69291
- 188.8236
+ 587.8236
0 ]
/Rect [ 521.4627
392.5936
@@ -441,10 +441,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 118 0 R
+ /Dest [ 121 0 R
/XYZ
62.69291
- 256.6236
+ 188.8236
0 ]
/Rect [ 62.69291
374.5936
@@ -459,10 +459,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 118 0 R
+ /Dest [ 121 0 R
/XYZ
62.69291
- 256.6236
+ 188.8236
0 ]
/Rect [ 521.4627
374.5936
@@ -477,7 +477,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 129 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
765.0236
@@ -495,7 +495,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 129 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
765.0236
@@ -515,9 +515,9 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 361.1228
+ /Rect [ 403.6414
290.5936
- 392.9767
+ 435.6067
302.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -530,10 +530,10 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 493.6727
- 290.5936
- 531.3087
- 302.5936 ]
+ /Rect [ 62.69291
+ 278.5936
+ 104.8841
+ 290.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -545,9 +545,9 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 164.0504
+ /Rect [ 206.3791
278.5936
- 206.7572
+ 249.1203
290.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -560,10 +560,10 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 493.1227
- 278.5936
- 532.1158
- 290.5936 ]
+ /Rect [ 62.69291
+ 266.5936
+ 105.1329
+ 278.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -680,12 +680,12 @@ endobj
38 0 R
39 0 R
40 0 R ]
- /Contents 146 0 R
+ /Contents 149 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -759,9 +759,9 @@ endobj
0
0 ]
/Rect [ 504.7827
- 314.3936
+ 302.3936
532.1006
- 326.3936 ]
+ 314.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -774,9 +774,9 @@ endobj
0
0 ]
/Rect [ 82.40665
- 302.3936
+ 290.3936
124.3504
- 314.3936 ]
+ 302.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -789,9 +789,9 @@ endobj
0
0 ]
/Rect [ 62.69291
- 290.3936
+ 278.3936
104.9329
- 302.3936 ]
+ 290.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -804,12 +804,12 @@ endobj
46 0 R
47 0 R
48 0 R ]
- /Contents 147 0 R
+ /Contents 150 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -859,9 +859,9 @@ endobj
0
0 ]
/Rect [ 83.6329
- 635.3936
+ 623.3936
105.6829
- 647.3936 ]
+ 635.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -874,9 +874,9 @@ endobj
0
0 ]
/Rect [ 421.9727
- 635.3936
+ 623.3936
465.1427
- 647.3936 ]
+ 635.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -889,9 +889,9 @@ endobj
0
0 ]
/Rect [ 211.6529
- 486.1936
+ 474.1936
232.7729
- 498.1936 ]
+ 486.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -904,9 +904,9 @@ endobj
0
0 ]
/Rect [ 85.47291
- 229.9936
+ 205.9936
106.5929
- 241.9936 ]
+ 217.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -919,12 +919,12 @@ endobj
53 0 R
54 0 R
55 0 R ]
- /Contents 148 0 R
+ /Contents 151 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -944,9 +944,9 @@ endobj
0
0 ]
/Rect [ 62.69291
- 687.3936
+ 663.3936
84.20915
- 699.3936 ]
+ 675.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -959,9 +959,9 @@ endobj
0
0 ]
/Rect [ 91.59679
- 494.1936
+ 458.1936
109.9368
- 506.1936 ]
+ 470.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -974,9 +974,9 @@ endobj
0
0 ]
/Rect [ 446.6187
- 332.9936
+ 296.9936
464.9587
- 344.9936 ]
+ 308.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -989,9 +989,9 @@ endobj
0
0 ]
/Rect [ 446.8103
- 221.9936
+ 185.9936
502.5727
- 233.9936 ]
+ 197.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1004,9 +1004,9 @@ endobj
0
0 ]
/Rect [ 260.18
- 209.9936
+ 173.9936
312.43
- 221.9936 ]
+ 185.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1019,9 +1019,9 @@ endobj
0
0 ]
/Rect [ 62.69291
- 179.9936
+ 143.9936
84.28901
- 191.9936 ]
+ 155.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1034,9 +1034,9 @@ endobj
0
0 ]
/Rect [ 161.7834
- 179.9936
+ 143.9936
217.2895
- 191.9936 ]
+ 155.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1050,12 +1050,12 @@ endobj
61 0 R
62 0 R
63 0 R ]
- /Contents 149 0 R
+ /Contents 152 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1075,9 +1075,9 @@ endobj
0
0 ]
/Rect [ 133.1479
- 629.3936
+ 617.3936
154.4129
- 641.3936 ]
+ 629.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1085,12 +1085,12 @@ endobj
66 0 obj
% Page dictionary
<< /Annots [ 65 0 R ]
- /Contents 150 0 R
+ /Contents 153 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1168,12 +1168,12 @@ endobj
68 0 R
69 0 R
70 0 R ]
- /Contents 151 0 R
+ /Contents 154 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1283,12 +1283,12 @@ endobj
75 0 R
76 0 R
77 0 R ]
- /Contents 152 0 R
+ /Contents 155 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1307,10 +1307,10 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 62.69291
- 371.8549
- 83.9079
- 383.8549 ]
+ /Rect [ 338.1568
+ 359.8549
+ 360.5113
+ 371.8549 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -1318,19 +1318,86 @@ endobj
80 0 obj
<< /A << /S /URI
/Type /Action
+ /URI (http://www.sqlalchemy.org/) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 110.6843
+ 347.8549
+ 169.0343
+ 359.8549 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER68': class PDFDictionary
+81 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://www.sqlalchemy.org/docs/reference/ext/sqlsoup.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 168.3029
+ 335.8549
+ 208.8829
+ 347.8549 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page8': class PDFPage
+82 0 obj
+% Page dictionary
+<< /Annots [ 79 0 R
+ 80 0 R
+ 81 0 R ]
+ /Contents 156 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 148 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER69': class PDFDictionary
+83 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 413.1936
+ 83.9079
+ 425.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER70': class PDFDictionary
+84 0 obj
+<< /A << /S /URI
+ /Type /Action
/URI (http://argparse.googlecode.com) >>
/Border [ 0
0
0 ]
/Rect [ 133.1029
- 371.8549
+ 413.1936
175.4379
- 383.8549 ]
+ 425.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER68': class PDFDictionary
-81 0 obj
+% 'Annot.NUMBER71': class PDFDictionary
+85 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1338,14 +1405,29 @@ endobj
0
0 ]
/Rect [ 454.1177
- 371.8549
+ 413.1936
496.4527
- 383.8549 ]
+ 425.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER69': class PDFDictionary
-82 0 obj
+% 'Annot.NUMBER72': class PDFDictionary
+86 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://argparse.googlecode.com/svn/tags/r11/doc/other-utilities.html?highlight=filetype#FileType) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 359.1936
+ 146.0529
+ 371.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER73': class PDFDictionary
+87 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1353,25 +1435,26 @@ endobj
0
0 ]
/Rect [ 127.9872
- 162.6549
+ 203.9936
149.3819
- 174.6549 ]
+ 215.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page8': class PDFPage
-83 0 obj
+% 'Page9': class PDFPage
+88 0 obj
% Page dictionary
-<< /Annots [ 79 0 R
- 80 0 R
- 81 0 R
- 82 0 R ]
- /Contents 153 0 R
+<< /Annots [ 83 0 R
+ 84 0 R
+ 85 0 R
+ 86 0 R
+ 87 0 R ]
+ /Contents 157 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1382,8 +1465,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER70': class PDFDictionary
-84 0 obj
+% 'Annot.NUMBER74': class PDFDictionary
+89 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1391,14 +1474,14 @@ endobj
0
0 ]
/Rect [ 326.9971
- 711.3936
+ 756.5936
351.8113
- 723.3936 ]
+ 768.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER71': class PDFDictionary
-85 0 obj
+% 'Annot.NUMBER75': class PDFDictionary
+90 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1406,14 +1489,14 @@ endobj
0
0 ]
/Rect [ 407.706
- 699.3936
+ 744.5936
452.2944
- 711.3936 ]
+ 756.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER72': class PDFDictionary
-86 0 obj
+% 'Annot.NUMBER76': class PDFDictionary
+91 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1421,14 +1504,14 @@ endobj
0
0 ]
/Rect [ 259.0928
- 687.3936
+ 732.5936
302.7528
- 699.3936 ]
+ 744.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER73': class PDFDictionary
-87 0 obj
+% 'Annot.NUMBER77': class PDFDictionary
+92 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1436,14 +1519,14 @@ endobj
0
0 ]
/Rect [ 258.3129
- 663.3936
+ 708.5936
279.4329
- 675.3936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER74': class PDFDictionary
-88 0 obj
+% 'Annot.NUMBER78': class PDFDictionary
+93 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html) >>
@@ -1451,14 +1534,14 @@ endobj
0
0 ]
/Rect [ 327.2261
- 645.3936
+ 690.5936
410.5152
- 657.3936 ]
+ 702.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER75': class PDFDictionary
-89 0 obj
+% 'Annot.NUMBER79': class PDFDictionary
+94 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1466,27 +1549,27 @@ endobj
0
0 ]
/Rect [ 106.6216
- 445.1936
+ 490.3936
128.3202
- 457.1936 ]
+ 502.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page9': class PDFPage
-90 0 obj
+% 'Page10': class PDFPage
+95 0 obj
% Page dictionary
-<< /Annots [ 84 0 R
- 85 0 R
- 86 0 R
- 87 0 R
- 88 0 R
- 89 0 R ]
- /Contents 154 0 R
+<< /Annots [ 89 0 R
+ 90 0 R
+ 91 0 R
+ 92 0 R
+ 93 0 R
+ 94 0 R ]
+ /Contents 158 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1497,8 +1580,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER76': class PDFDictionary
-91 0 obj
+% 'Annot.NUMBER80': class PDFDictionary
+96 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1512,8 +1595,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER77': class PDFDictionary
-92 0 obj
+% 'Annot.NUMBER81': class PDFDictionary
+97 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1527,8 +1610,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER78': class PDFDictionary
-93 0 obj
+% 'Annot.NUMBER82': class PDFDictionary
+98 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1542,8 +1625,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER79': class PDFDictionary
-94 0 obj
+% 'Annot.NUMBER83': class PDFDictionary
+99 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html) >>
@@ -1557,8 +1640,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER80': class PDFDictionary
-95 0 obj
+% 'Annot.NUMBER84': class PDFDictionary
+100 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1572,8 +1655,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER81': class PDFDictionary
-96 0 obj
+% 'Annot.NUMBER85': class PDFDictionary
+101 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html) >>
@@ -1587,8 +1670,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER82': class PDFDictionary
-97 0 obj
+% 'Annot.NUMBER86': class PDFDictionary
+102 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1602,8 +1685,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER83': class PDFDictionary
-98 0 obj
+% 'Annot.NUMBER87': class PDFDictionary
+103 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1617,8 +1700,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER84': class PDFDictionary
-99 0 obj
+% 'Annot.NUMBER88': class PDFDictionary
+104 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1632,8 +1715,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER85': class PDFDictionary
-100 0 obj
+% 'Annot.NUMBER89': class PDFDictionary
+105 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1647,8 +1730,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER86': class PDFDictionary
-101 0 obj
+% 'Annot.NUMBER90': class PDFDictionary
+106 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1662,8 +1745,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER87': class PDFDictionary
-102 0 obj
+% 'Annot.NUMBER91': class PDFDictionary
+107 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1677,8 +1760,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER88': class PDFDictionary
-103 0 obj
+% 'Annot.NUMBER92': class PDFDictionary
+108 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1692,8 +1775,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER89': class PDFDictionary
-104 0 obj
+% 'Annot.NUMBER93': class PDFDictionary
+109 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1707,8 +1790,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER90': class PDFDictionary
-105 0 obj
+% 'Annot.NUMBER94': class PDFDictionary
+110 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1722,8 +1805,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER91': class PDFDictionary
-106 0 obj
+% 'Annot.NUMBER95': class PDFDictionary
+111 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1737,8 +1820,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER92': class PDFDictionary
-107 0 obj
+% 'Annot.NUMBER96': class PDFDictionary
+112 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1752,8 +1835,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER93': class PDFDictionary
-108 0 obj
+% 'Annot.NUMBER97': class PDFDictionary
+113 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1767,8 +1850,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER94': class PDFDictionary
-109 0 obj
+% 'Annot.NUMBER98': class PDFDictionary
+114 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1782,8 +1865,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER95': class PDFDictionary
-110 0 obj
+% 'Annot.NUMBER99': class PDFDictionary
+115 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html) >>
@@ -1797,8 +1880,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER96': class PDFDictionary
-111 0 obj
+% 'Annot.NUMBER100': class PDFDictionary
+116 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1812,64 +1895,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER97': class PDFDictionary
-112 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 314.0328
- 153.3936
- 335.3494
- 165.3936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Page10': class PDFPage
-113 0 obj
-% Page dictionary
-<< /Annots [ 91 0 R
- 92 0 R
- 93 0 R
- 94 0 R
- 95 0 R
- 96 0 R
- 97 0 R
- 98 0 R
- 99 0 R
- 100 0 R
- 101 0 R
- 102 0 R
- 103 0 R
- 104 0 R
- 105 0 R
- 106 0 R
- 107 0 R
- 108 0 R
- 109 0 R
- 110 0 R
- 111 0 R
- 112 0 R ]
- /Contents 155 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 145 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER98': class PDFDictionary
-114 0 obj
+% 'Annot.NUMBER101': class PDFDictionary
+117 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1877,14 +1904,14 @@ endobj
0
0 ]
/Rect [ 86.82623
- 197.1936
+ 129.3936
126.2862
- 209.1936 ]
+ 141.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER99': class PDFDictionary
-115 0 obj
+% 'Annot.NUMBER102': class PDFDictionary
+118 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1892,14 +1919,14 @@ endobj
0
0 ]
/Rect [ 415.1627
- 197.1936
+ 129.3936
459.306
- 209.1936 ]
+ 141.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER100': class PDFDictionary
-116 0 obj
+% 'Annot.NUMBER103': class PDFDictionary
+119 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1907,14 +1934,14 @@ endobj
0
0 ]
/Rect [ 468.9894
- 197.1936
+ 129.3936
492.0127
- 209.1936 ]
+ 141.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER101': class PDFDictionary
-117 0 obj
+% 'Annot.NUMBER104': class PDFDictionary
+120 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1922,25 +1949,46 @@ endobj
0
0 ]
/Rect [ 62.69291
- 161.1936
+ 93.39362
102.1529
- 173.1936 ]
+ 105.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page11': class PDFPage
-118 0 obj
+121 0 obj
% Page dictionary
-<< /Annots [ 114 0 R
+<< /Annots [ 96 0 R
+ 97 0 R
+ 98 0 R
+ 99 0 R
+ 100 0 R
+ 101 0 R
+ 102 0 R
+ 103 0 R
+ 104 0 R
+ 105 0 R
+ 106 0 R
+ 107 0 R
+ 108 0 R
+ 109 0 R
+ 110 0 R
+ 111 0 R
+ 112 0 R
+ 113 0 R
+ 114 0 R
115 0 R
116 0 R
- 117 0 R ]
- /Contents 156 0 R
+ 117 0 R
+ 118 0 R
+ 119 0 R
+ 120 0 R ]
+ /Contents 159 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1951,8 +1999,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER102': class PDFDictionary
-119 0 obj
+% 'Annot.NUMBER105': class PDFDictionary
+122 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1966,8 +2014,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER103': class PDFDictionary
-120 0 obj
+% 'Annot.NUMBER106': class PDFDictionary
+123 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://code.activestate.com/recipes/278844-parsing-the-command-line/) >>
@@ -1981,8 +2029,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER104': class PDFDictionary
-121 0 obj
+% 'Annot.NUMBER107': class PDFDictionary
+124 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1996,8 +2044,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER105': class PDFDictionary
-122 0 obj
+% 'Annot.NUMBER108': class PDFDictionary
+125 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html?highlight=optionparser#optparse.OptionParser) >>
@@ -2011,23 +2059,23 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER106': class PDFDictionary
-123 0 obj
+% 'Annot.NUMBER109': class PDFDictionary
+126 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
/Border [ 0
0
0 ]
- /Rect [ 97.06763
+ /Rect [ 96.54131
693.5936
- 139.815
+ 139.0255
705.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER107': class PDFDictionary
-124 0 obj
+% 'Annot.NUMBER110': class PDFDictionary
+127 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2041,8 +2089,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER108': class PDFDictionary
-125 0 obj
+% 'Annot.NUMBER111': class PDFDictionary
+128 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html) >>
@@ -2056,8 +2104,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER109': class PDFDictionary
-126 0 obj
+% 'Annot.NUMBER112': class PDFDictionary
+129 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2071,8 +2119,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER110': class PDFDictionary
-127 0 obj
+% 'Annot.NUMBER113': class PDFDictionary
+130 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2086,8 +2134,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER111': class PDFDictionary
-128 0 obj
+% 'Annot.NUMBER114': class PDFDictionary
+131 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/Clap/0.7) >>
@@ -2102,24 +2150,24 @@ endobj
/Type /Annot >>
endobj
% 'Page12': class PDFPage
-129 0 obj
+132 0 obj
% Page dictionary
-<< /Annots [ 119 0 R
- 120 0 R
- 121 0 R
- 122 0 R
+<< /Annots [ 122 0 R
123 0 R
124 0 R
125 0 R
126 0 R
127 0 R
- 128 0 R ]
- /Contents 157 0 R
+ 128 0 R
+ 129 0 R
+ 130 0 R
+ 131 0 R ]
+ /Contents 160 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 145 0 R
+ /Parent 148 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2130,175 +2178,175 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'R130': class PDFCatalog
-130 0 obj
+% 'R133': class PDFCatalog
+133 0 obj
% Document Root
-<< /Outlines 132 0 R
- /PageLabels 158 0 R
+<< /Outlines 135 0 R
+ /PageLabels 161 0 R
/PageMode /UseNone
- /Pages 145 0 R
+ /Pages 148 0 R
/Type /Catalog >>
endobj
-% 'R131': class PDFInfo
-131 0 obj
+% 'R134': class PDFInfo
+134 0 obj
<< /Author (Michele Simionato)
- /CreationDate (D:20100601131016-01'00')
+ /CreationDate (D:20100601145350-01'00')
/Keywords ()
/Producer (ReportLab http://www.reportlab.com)
/Subject (\(unspecified\))
/Title (Plac, the Easiest Command Line Arguments Parser in the World) >>
endobj
-% 'R132': class PDFOutlines
-132 0 obj
+% 'R135': class PDFOutlines
+135 0 obj
<< /Count 12
- /First 133 0 R
- /Last 144 0 R
+ /First 136 0 R
+ /Last 147 0 R
/Type /Outlines >>
endobj
% 'Outline.0': class OutlineEntryObject
-133 0 obj
+136 0 obj
<< /Dest [ 41 0 R
/XYZ
62.69291
338.0236
0 ]
- /Next 134 0 R
- /Parent 132 0 R
+ /Next 137 0 R
+ /Parent 135 0 R
/Title (Introduction) >>
endobj
% 'Outline.1': class OutlineEntryObject
-134 0 obj
+137 0 obj
<< /Dest [ 49 0 R
/XYZ
62.69291
729.0236
0 ]
- /Next 135 0 R
- /Parent 132 0 R
- /Prev 133 0 R
+ /Next 138 0 R
+ /Parent 135 0 R
+ /Prev 136 0 R
/Title (The importance of scaling down) >>
endobj
% 'Outline.2': class OutlineEntryObject
-135 0 obj
+138 0 obj
<< /Dest [ 56 0 R
/XYZ
62.69291
- 470.6236
+ 458.6236
0 ]
- /Next 136 0 R
- /Parent 132 0 R
- /Prev 134 0 R
+ /Next 139 0 R
+ /Parent 135 0 R
+ /Prev 137 0 R
/Title (Positional default arguments) >>
endobj
% 'Outline.3': class OutlineEntryObject
-136 0 obj
+139 0 obj
<< /Dest [ 64 0 R
/XYZ
62.69291
- 305.4236
+ 269.4236
0 ]
- /Next 137 0 R
- /Parent 132 0 R
- /Prev 135 0 R
+ /Next 140 0 R
+ /Parent 135 0 R
+ /Prev 138 0 R
/Title (Options and flags) >>
endobj
% 'Outline.4': class OutlineEntryObject
-137 0 obj
+140 0 obj
<< /Dest [ 71 0 R
/XYZ
62.69291
201.0236
0 ]
- /Next 138 0 R
- /Parent 132 0 R
- /Prev 136 0 R
+ /Next 141 0 R
+ /Parent 135 0 R
+ /Prev 139 0 R
/Title (plac for Python 2.X users) >>
endobj
% 'Outline.5': class OutlineEntryObject
-138 0 obj
+141 0 obj
<< /Dest [ 78 0 R
/XYZ
62.69291
490.6236
0 ]
- /Next 139 0 R
- /Parent 132 0 R
- /Prev 137 0 R
+ /Next 142 0 R
+ /Parent 135 0 R
+ /Prev 140 0 R
/Title (More features) >>
endobj
% 'Outline.6': class OutlineEntryObject
-139 0 obj
-<< /Dest [ 83 0 R
+142 0 obj
+<< /Dest [ 82 0 R
/XYZ
62.69291
- 407.2849
+ 395.2849
0 ]
- /Next 140 0 R
- /Parent 132 0 R
- /Prev 138 0 R
- /Title (A few notes on the underlying implementation) >>
+ /Next 143 0 R
+ /Parent 135 0 R
+ /Prev 141 0 R
+ /Title (A more realistic example) >>
endobj
% 'Outline.7': class OutlineEntryObject
-140 0 obj
-<< /Dest [ 90 0 R
+143 0 obj
+<< /Dest [ 88 0 R
/XYZ
62.69291
- 480.6236
+ 448.6236
0 ]
- /Next 141 0 R
- /Parent 132 0 R
- /Prev 139 0 R
- /Title (Custom annotation objects) >>
+ /Next 144 0 R
+ /Parent 135 0 R
+ /Prev 142 0 R
+ /Title (A few notes on the underlying implementation) >>
endobj
% 'Outline.8': class OutlineEntryObject
-141 0 obj
-<< /Dest [ 113 0 R
+144 0 obj
+<< /Dest [ 95 0 R
/XYZ
62.69291
- 587.8236
+ 525.8236
0 ]
- /Next 142 0 R
- /Parent 132 0 R
- /Prev 140 0 R
- /Title (plac vs argparse) >>
+ /Next 145 0 R
+ /Parent 135 0 R
+ /Prev 143 0 R
+ /Title (Custom annotation objects) >>
endobj
% 'Outline.9': class OutlineEntryObject
-142 0 obj
-<< /Dest [ 113 0 R
+145 0 obj
+<< /Dest [ 121 0 R
/XYZ
62.69291
- 188.8236
+ 587.8236
0 ]
- /Next 143 0 R
- /Parent 132 0 R
- /Prev 141 0 R
- /Title (A final example) >>
+ /Next 146 0 R
+ /Parent 135 0 R
+ /Prev 144 0 R
+ /Title (plac vs argparse) >>
endobj
% 'Outline.10': class OutlineEntryObject
-143 0 obj
-<< /Dest [ 118 0 R
+146 0 obj
+<< /Dest [ 121 0 R
/XYZ
62.69291
- 256.6236
+ 188.8236
0 ]
- /Next 144 0 R
- /Parent 132 0 R
- /Prev 142 0 R
+ /Next 147 0 R
+ /Parent 135 0 R
+ /Prev 145 0 R
/Title (The future) >>
endobj
% 'Outline.11': class OutlineEntryObject
-144 0 obj
-<< /Dest [ 129 0 R
+147 0 obj
+<< /Dest [ 132 0 R
/XYZ
62.69291
765.0236
0 ]
- /Parent 132 0 R
- /Prev 143 0 R
+ /Parent 135 0 R
+ /Prev 146 0 R
/Title (Trivia: the story behind the name) >>
endobj
-% 'R145': class PDFPages
-145 0 obj
+% 'R148': class PDFPages
+148 0 obj
% page tree
<< /Count 12
/Kids [ 41 0 R
@@ -2308,17 +2356,17 @@ endobj
66 0 R
71 0 R
78 0 R
- 83 0 R
- 90 0 R
- 113 0 R
- 118 0 R
- 129 0 R ]
+ 82 0 R
+ 88 0 R
+ 95 0 R
+ 121 0 R
+ 132 0 R ]
/Type /Pages >>
endobj
-% 'R146': class PDFStream
-146 0 obj
+% 'R149': class PDFStream
+149 0 obj
% page stream
-<< /Length 8388 >>
+<< /Length 8404 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2552,7 +2600,7 @@ Q
q
1 0 0 1 0 93 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A few notes on the underlying implementation) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A more realistic example) Tj T* ET
Q
Q
q
@@ -2566,7 +2614,7 @@ Q
q
1 0 0 1 0 75 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Custom annotation objects) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A few notes on the underlying implementation) Tj T* ET
Q
Q
q
@@ -2580,7 +2628,7 @@ Q
q
1 0 0 1 0 57 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (plac vs argparse) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Custom annotation objects) Tj T* ET
Q
Q
q
@@ -2594,7 +2642,7 @@ Q
q
1 0 0 1 0 39 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A final example) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (plac vs argparse) Tj T* ET
Q
Q
q
@@ -2602,7 +2650,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (10) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (11) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -2645,7 +2693,7 @@ Q
q
1 0 0 1 62.69291 251.0236 cm
q
-BT 1 0 0 1 0 52.82 Tm .05061 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is no want of command line arguments parsers in Python world. The standard library alone contains) Tj T* 0 Tw 1.273984 Tw (three different modules for the parsing of command line options: ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (\(from the stone age\), ) Tj 0 0 .501961 rg (optparse) Tj T* 0 Tw .46686 Tw 0 0 0 rg (\(from Python 2.3\) and ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (\(from Python 2.7\). All of them are quite powerful and especially ) Tj 0 0 .501961 rg (argparse) Tj T* 0 Tw .25686 Tw 0 0 0 rg (is an industrial strength solution; unfortunately, all of them feature a non-zero learning curve and a certain) Tj T* 0 Tw (verbosity.) Tj T* ET
+BT 1 0 0 1 0 52.82 Tm 1.50936 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is no want of command line arguments parsers in the Python world. The standard library alone) Tj T* 0 Tw 1.385318 Tw (contains three different modules for the parsing of command line options: ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (\(from the stone age\),) Tj T* 0 Tw .501235 Tw 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (\(from Python 2.3\) and ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (\(from Python 2.7\). All of them are quite powerful and especially) Tj T* 0 Tw .199984 Tw 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (is an industrial strength solution; unfortunately, all of them feature a non-zero learning curve and) Tj T* 0 Tw (a certain verbosity.) Tj T* ET
Q
Q
q
@@ -2664,10 +2712,10 @@ Q
endstream
endobj
-% 'R147': class PDFStream
-147 0 obj
+% 'R150': class PDFStream
+150 0 obj
% page stream
-<< /Length 5433 >>
+<< /Length 5477 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2698,7 +2746,7 @@ q
1 0 0 1 62.69291 558.0236 cm
Q
q
-1 0 0 1 62.69291 388.8236 cm
+1 0 0 1 62.69291 376.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -2713,11 +2761,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 168 re B*
+n -6 -6 448.6898 180 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 149.71 Tm /F4 10 Tf 12 TL (def main\(dsn\):) Tj T* ( "Do something with the database") Tj T* ( print\(dsn\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( n = len\(sys.argv[1:]\)) Tj T* ( if n == 0:) Tj T* ( sys.exit\('usage: python %s dsn' % sys.argv[0]\)) Tj T* ( elif n == 1:) Tj T* ( main\(sys.argv[1]\)) Tj T* ( else:) Tj T* ( sys.exit\('Unrecognized arguments: %s' % ' '.join\(sys.argv[2:]\)\)) Tj T* ET
+BT 1 0 0 1 0 161.71 Tm /F4 10 Tf 12 TL (# example1.py) Tj T* (def main\(dsn\):) Tj T* ( "Do something with the database") Tj T* ( print\(dsn\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( n = len\(sys.argv[1:]\)) Tj T* ( if n == 0:) Tj T* ( sys.exit\('usage: python %s dsn' % sys.argv[0]\)) Tj T* ( elif n == 1:) Tj T* ( main\(sys.argv[1]\)) Tj T* ( else:) Tj T* ( sys.exit\('Unrecognized arguments: %s' % ' '.join\(sys.argv[2:]\)\)) Tj T* ET
Q
Q
Q
@@ -2727,19 +2775,19 @@ q
Q
Q
q
-1 0 0 1 62.69291 388.8236 cm
+1 0 0 1 62.69291 376.8236 cm
Q
q
-1 0 0 1 62.69291 286.8236 cm
+1 0 0 1 62.69291 274.8236 cm
q
BT 1 0 0 1 0 88.82 Tm .880651 Tw 12 TL /F1 10 Tf 0 0 0 rg (As you see the whole ) Tj /F4 10 Tf (if __name__ == '__main__' ) Tj /F1 10 Tf (block \(nine lines\) is essentially boilerplate that) Tj T* 0 Tw 1.125318 Tw (should not exists. Actually I think the Python language should recognize the main function and perform) Tj T* 0 Tw 1.385984 Tw (trivial arguments parsing behind the scenes; unfortunaly this is unlikely to happen. I have been writing) Tj T* 0 Tw 1.767356 Tw (boilerplate like this in hundreds of scripts for years, and every time I ) Tj /F5 10 Tf (hate ) Tj /F1 10 Tf (it. The purpose of using a) Tj T* 0 Tw 1.47229 Tw (scripting language is convenience and trivial things should be trivial. Unfortunately the standard library) Tj T* 0 Tw .482093 Tw (modules do not help for this use case, which may be trivial, but it is still incredibly common. Using ) Tj 0 0 .501961 rg (getopt) Tj T* 0 Tw .253735 Tw 0 0 0 rg (and ) Tj 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (does not help, since they are intended to manage options and not positional arguments; the) Tj T* 0 Tw 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module helps a bit and it is able to reduce the boilerplate from nine lines to six lines:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 280.8236 cm
+1 0 0 1 62.69291 268.8236 cm
Q
q
-1 0 0 1 62.69291 147.6236 cm
+1 0 0 1 62.69291 123.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -2754,11 +2802,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 132 re B*
+n -6 -6 448.6898 144 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 113.71 Tm /F4 10 Tf 12 TL (def main\(dsn\):) Tj T* ( "Do something on the database") Tj T* ( print\(dsn\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import argparse) Tj T* ( p = argparse.ArgumentParser\(\)) Tj T* ( p.add_argument\('dsn'\)) Tj T* ( arg = p.parse_args\(\)) Tj T* ( main\(arg.dsn\)) Tj T* ET
+BT 1 0 0 1 0 125.71 Tm /F4 10 Tf 12 TL (# example2.py) Tj T* (def main\(dsn\):) Tj T* ( "Do something on the database") Tj T* ( print\(dsn\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import argparse) Tj T* ( p = argparse.ArgumentParser\(\)) Tj T* ( p.add_argument\('dsn'\)) Tj T* ( arg = p.parse_args\(\)) Tj T* ( main\(arg.dsn\)) Tj T* ET
Q
Q
Q
@@ -2768,10 +2816,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 147.6236 cm
+1 0 0 1 62.69291 123.6236 cm
Q
q
-1 0 0 1 62.69291 105.6236 cm
+1 0 0 1 62.69291 81.62362 cm
q
0 0 0 rg
BT 1 0 0 1 0 28.82 Tm /F1 10 Tf 12 TL 1.644269 Tw (However saving three lines does not justify introducing the external dependency: most people will not) Tj T* 0 Tw .276303 Tw (switch Python 2.7, which at the time of this writing is just about to be released, for many years. Moreover,) Tj T* 0 Tw (it just feels too complex to instantiate a class and to define a parser by hand for such a trivial task.) Tj T* ET
@@ -2781,10 +2829,10 @@ Q
endstream
endobj
-% 'R148': class PDFStream
-148 0 obj
+% 'R151': class PDFStream
+151 0 obj
% page stream
-<< /Length 4329 >>
+<< /Length 4343 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2797,7 +2845,7 @@ q
1 0 0 1 62.69291 735.0236 cm
Q
q
-1 0 0 1 62.69291 649.8236 cm
+1 0 0 1 62.69291 637.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -2812,11 +2860,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 84 re B*
+n -6 -6 448.6898 96 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL (def main\(dsn\):) Tj T* ( "Do something with the database") Tj T* ( print\(dsn\)) Tj T* ( ) Tj T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL (# example3.py) Tj T* (def main\(dsn\):) Tj T* ( "Do something with the database") Tj T* ( print\(dsn\)) Tj T* ( ) Tj T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
@@ -2826,16 +2874,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 649.8236 cm
+1 0 0 1 62.69291 637.8236 cm
Q
q
-1 0 0 1 62.69291 619.8236 cm
+1 0 0 1 62.69291 607.8236 cm
q
BT 1 0 0 1 0 16.82 Tm .929986 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (module provides for free \(actually the work is done by the underlying ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module\) a nice) Tj T* 0 Tw (usage message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 502.6236 cm
+1 0 0 1 62.69291 490.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2856,29 +2904,29 @@ Q
Q
Q
q
-1 0 0 1 62.69291 482.6236 cm
+1 0 0 1 62.69291 470.6236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (This is only the tip of the iceberg: ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to do much more than that.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 449.6236 cm
+1 0 0 1 62.69291 437.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Positional default arguments) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 431.6236 cm
+1 0 0 1 62.69291 419.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (I have encountered this use case at work hundreds of times:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 425.6236 cm
+1 0 0 1 62.69291 413.6236 cm
Q
q
-1 0 0 1 62.69291 244.4236 cm
+1 0 0 1 62.69291 220.4236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -2893,10 +2941,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 180 re B*
+n -6 -6 448.6898 192 re B*
Q
q
-BT 1 0 0 1 0 161.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (from datetime import datetime) Tj T* T* (def main\(dsn, table='product', today=datetime.today\(\)\):) Tj T* ( "Do something on the database") Tj T* ( print\(dsn, table, today\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( args = sys.argv[1:]) Tj T* ( if not args:) Tj T* ( sys.exit\('usage: python %s dsn' % sys.argv[0]\)) Tj T* ( elif len\(args\) ) Tj (>) Tj ( 2:) Tj T* ( sys.exit\('Unrecognized arguments: %s' % ' '.join\(argv[2:]\)\)) Tj T* ( main\(*args\)) Tj T* ET
+BT 1 0 0 1 0 173.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (# example4.py) Tj T* (from datetime import datetime) Tj T* T* (def main\(dsn, table='product', today=datetime.today\(\)\):) Tj T* ( "Do something on the database") Tj T* ( print\(dsn, table, today\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( args = sys.argv[1:]) Tj T* ( if not args:) Tj T* ( sys.exit\('usage: python %s dsn' % sys.argv[0]\)) Tj T* ( elif len\(args\) ) Tj (>) Tj ( 2:) Tj T* ( sys.exit\('Unrecognized arguments: %s' % ' '.join\(argv[2:]\)\)) Tj T* ( main\(*args\)) Tj T* ET
Q
Q
Q
@@ -2906,16 +2954,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 244.4236 cm
+1 0 0 1 62.69291 220.4236 cm
Q
q
-1 0 0 1 62.69291 226.4236 cm
+1 0 0 1 62.69291 202.4236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (With ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (the entire ) Tj /F4 10 Tf (__main__ ) Tj /F1 10 Tf (block reduces to the usual two lines:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 181.2236 cm
+1 0 0 1 62.69291 157.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2936,7 +2984,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 161.2236 cm
+1 0 0 1 62.69291 137.2236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (In other words, six lines of boilerplate have been removed, and I have the usage message for free:) Tj T* ET
@@ -2953,11 +3001,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 72 re B*
+n -6 -6 468.6898 48 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (usage: example4_.py [-h] dsn [table] [today]) Tj T* T* (positional arguments:) Tj T* ( dsn) Tj T* ( table) Tj T* ET
+BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL (usage: example4_.py [-h] dsn [table] [today]) Tj T* T* (positional arguments:) Tj T* ET
Q
Q
Q
@@ -2967,14 +3015,14 @@ Q
endstream
endobj
-% 'R149': class PDFStream
-149 0 obj
+% 'R152': class PDFStream
+152 0 obj
% page stream
-<< /Length 4867 >>
+<< /Length 4886 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 703.8236 cm
+1 0 0 1 62.69291 679.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2984,27 +3032,27 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 60 re B*
+n -6 -6 468.6898 84 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ( today) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ET
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL ( dsn) Tj T* ( table) Tj T* ( today) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 671.8236 cm
+1 0 0 1 62.69291 647.8236 cm
q
-BT 1 0 0 1 0 16.82 Tm .396235 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (manages transparently even the case when you want to pass a variable number of arguments. Here) Tj T* 0 Tw (is an example, a script running on a database a series of ) Tj /F4 10 Tf (.sql ) Tj /F1 10 Tf (scripts:) Tj T* ET
+BT 1 0 0 1 0 16.82 Tm .396235 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (manages transparently even the case when you want to pass a variable number of arguments. Here) Tj T* 0 Tw (is an example, a script running on a database a series of SQL scripts:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 665.8236 cm
+1 0 0 1 62.69291 641.8236 cm
Q
q
-1 0 0 1 62.69291 508.6236 cm
+1 0 0 1 62.69291 472.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3019,10 +3067,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 442.6898 156 re B*
+n -6 -6 442.6898 168 re B*
Q
q
-BT 1 0 0 1 0 137.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (from datetime import datetime) Tj T* T* (def main\(dsn, *scripts\):) Tj T* ( "Run the given scripts on the database") Tj T* ( for script in scripts:) Tj T* ( print\('executing %s' % script\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( if len\(sys.argv\) ) Tj (<) Tj ( 2:) Tj T* ( sys.exit\('usage: python %s dsn script.sql ...' % sys.argv[0]\)) Tj T* ( main\(sys.argv[1:]\)) Tj T* ET
+BT 1 0 0 1 0 149.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (# example6.py) Tj T* (from datetime import datetime) Tj T* T* (def main\(dsn, *scripts\):) Tj T* ( "Run the given scripts on the database") Tj T* ( for script in scripts:) Tj T* ( print\('executing %s' % script\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import sys) Tj T* ( if len\(sys.argv\) ) Tj (<) Tj ( 2:) Tj T* ( sys.exit\('usage: python %s dsn script.sql ...' % sys.argv[0]\)) Tj T* ( main\(sys.argv[1:]\)) Tj T* ET
Q
Q
Q
@@ -3032,16 +3080,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 508.6236 cm
+1 0 0 1 62.69291 472.6236 cm
Q
q
-1 0 0 1 62.69291 478.6236 cm
+1 0 0 1 62.69291 442.6236 cm
q
BT 1 0 0 1 0 16.82 Tm .563876 Tw 12 TL /F1 10 Tf 0 0 0 rg (Using ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (, you can just replace the ) Tj /F4 10 Tf (__main__ ) Tj /F1 10 Tf (block with the usual two lines \(I have defined an Emacs) Tj T* 0 Tw (keybinding for them\) and you get the following usage message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 361.4236 cm
+1 0 0 1 62.69291 325.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3062,50 +3110,50 @@ Q
Q
Q
q
-1 0 0 1 62.69291 317.4236 cm
+1 0 0 1 62.69291 281.4236 cm
q
BT 1 0 0 1 0 28.82 Tm .92881 Tw 12 TL /F1 10 Tf 0 0 0 rg (The examples here should have made clear that ) Tj /F5 10 Tf (plac is able to figure out the command line arguments) Tj T* 0 Tw .928488 Tw (parser to use from the signature of the main function) Tj /F1 10 Tf (. This is the whole idea behind ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (: if my intent is) Tj T* 0 Tw (clear, let's the machine take care of the details.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 284.4236 cm
+1 0 0 1 62.69291 248.4236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Options and flags) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 194.4236 cm
+1 0 0 1 62.69291 158.4236 cm
q
BT 1 0 0 1 0 76.82 Tm .046098 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is surprising how few command line scripts with options I have written over the years \(probably less than) Tj T* 0 Tw 1.165984 Tw (a hundred\), compared to the number of scripts with positional arguments \(I certainly have written more) Tj T* 0 Tw 1.221163 Tw (than a thousand of them\). Still, this use case is quite common and cannot be neglected. The standard) Tj T* 0 Tw .446098 Tw (library modules \(all of them\) are quite verbose when it comes to specifying the options and frankly I have) Tj T* 0 Tw .732339 Tw (never used them directly. Instead, I have always relied on an old recipe of mine, the ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe,) Tj T* 0 Tw 1.32784 Tw (which provides a convenient wrapper over ) Tj 0 0 .501961 rg (optionparse) Tj 0 0 0 rg (. Alternatively, in the simplest cases, I have just) Tj T* 0 Tw (performed the parsing by hand, instead of manually building a suitable OptionParser.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 152.4236 cm
+1 0 0 1 62.69291 116.4236 cm
q
BT 1 0 0 1 0 28.82 Tm .476098 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is inspired to the ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe, in the sense that it delivers the programmer from the burden of) Tj T* 0 Tw .011488 Tw (writing the parser, but is less of a hack: instead of extracting the parser from the docstring of the module, it) Tj T* 0 Tw (extracts it from the signature of the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 122.4236 cm
+1 0 0 1 62.69291 86.42362 cm
q
BT 1 0 0 1 0 16.82 Tm .319987 Tw 12 TL /F1 10 Tf 0 0 0 rg (The idea comes from the ) Tj /F5 10 Tf (function annotations ) Tj /F1 10 Tf (concept, a new feature of Python 3. An example is worth a) Tj T* 0 Tw (thousand words, so here it is:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 116.4236 cm
+1 0 0 1 62.69291 80.42362 cm
Q
endstream
endobj
-% 'R150': class PDFStream
-150 0 obj
+% 'R153': class PDFStream
+153 0 obj
% page stream
-<< /Length 4749 >>
+<< /Length 4772 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 667.8236 cm
+1 0 0 1 62.69291 655.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3120,11 +3168,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 442.6898 96 re B*
+n -6 -6 442.6898 108 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL (def main\(command: \("SQL query", 'option', 'c'\), dsn\):) Tj T* ( if command:) Tj T* ( print\('executing %s on %s' % \(command, dsn\)\)) Tj T* ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL (# example8.py) Tj T* (def main\(command: \("SQL query", 'option', 'c'\), dsn\):) Tj T* ( if command:) Tj T* ( print\('executing %s on %s' % \(command, dsn\)\)) Tj T* ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
@@ -3134,16 +3182,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 667.8236 cm
+1 0 0 1 62.69291 655.8236 cm
Q
q
-1 0 0 1 62.69291 601.8236 cm
+1 0 0 1 62.69291 589.8236 cm
q
BT 1 0 0 1 0 52.82 Tm .789983 Tw 12 TL /F1 10 Tf 0 0 0 rg (As you see, the argument ) Tj /F4 10 Tf (command ) Tj /F1 10 Tf (has been annotated with the tuple ) Tj /F4 10 Tf (\("SQL query", 'option',) Tj T* 0 Tw .593876 Tw ('c'\)) Tj /F1 10 Tf (: the first string is the help string which will appear in the usage message, whereas the second and) Tj T* 0 Tw .144988 Tw (third strings tell ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (that ) Tj /F4 10 Tf (command ) Tj /F1 10 Tf (is an option and that it can be abbreviated with the letter ) Tj /F4 10 Tf (c) Tj /F1 10 Tf (. Of course,) Tj T* 0 Tw 1.543735 Tw (it also possible to use the long option format, by prefixing the option with ) Tj /F4 10 Tf (--command=) Tj /F1 10 Tf (. The resulting) Tj T* 0 Tw (usage message is the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 460.6236 cm
+1 0 0 1 62.69291 448.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3164,14 +3212,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 440.6236 cm
+1 0 0 1 62.69291 428.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here are two examples of usage:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 359.4236 cm
+1 0 0 1 62.69291 347.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3192,16 +3240,16 @@ Q
Q
Q
q
-1 0 0 1 62.69291 327.4236 cm
+1 0 0 1 62.69291 315.4236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.34104 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that if the option is not passed, the variable ) Tj /F4 10 Tf (command ) Tj /F1 10 Tf (will get the value ) Tj /F4 10 Tf (None) Tj /F1 10 Tf (. It is possible to) Tj T* 0 Tw (specify a non-trivial default for an option. Here is an example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 321.4236 cm
+1 0 0 1 62.69291 309.4236 cm
Q
q
-1 0 0 1 62.6378 227.0167 cm
+1 0 0 1 62.6378 226.6719 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3216,11 +3264,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 462 96 re B*
+n -6 -6 462 84 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL (# example8_) Tj T* T* (def main\(dsn, command: \("SQL query", 'option', 'c'\)='select * from table'\):) Tj T* ( print\('executing %r on %s' % \(command, dsn\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import clap; clap.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL (# example8_.py) Tj T* (def main\(dsn, command: \("SQL query", 'option', 'c'\)='select * from table'\):) Tj T* ( print\('executing %r on %s' % \(command, dsn\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import clap; clap.call\(main\)) Tj T* ET
Q
Q
Q
@@ -3230,16 +3278,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 227.0167 cm
+1 0 0 1 62.69291 226.6719 cm
Q
q
-1 0 0 1 62.69291 209.0167 cm
+1 0 0 1 62.69291 208.6719 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Now if you do not pass the ) Tj /F4 10 Tf (command option) Tj /F1 10 Tf (, the default query will be executed:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 163.8167 cm
+1 0 0 1 62.69291 163.4719 cm
q
q
1 0 0 1 0 0 cm
@@ -3260,14 +3308,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 143.8167 cm
+1 0 0 1 62.69291 143.4719 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Positional argument can be annotated too:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 86.6167 cm
+1 0 0 1 62.69291 86.27188 cm
q
q
1 0 0 1 0 0 cm
@@ -3291,8 +3339,8 @@ Q
endstream
endobj
-% 'R151': class PDFStream
-151 0 obj
+% 'R154': class PDFStream
+154 0 obj
% page stream
<< /Length 5617 >>
stream
@@ -3475,10 +3523,10 @@ Q
endstream
endobj
-% 'R152': class PDFStream
-152 0 obj
+% 'R155': class PDFStream
+155 0 obj
% page stream
-<< /Length 5596 >>
+<< /Length 5578 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -3628,7 +3676,7 @@ n -6 -6 480 144 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 125.71 Tm /F4 10 Tf 12 TL (import plac) Tj T* T* (@plac.annotations\() Tj T* (operator=\("The name of an operator", 'positional', None, str, ['add', 'mul']\),) Tj T* (numbers=\("A number", 'positional', None, float, None, "n"\)\)) Tj T* (def main\(operator, *numbers\):) Tj T* ( "A script to add and multiply numbers") Tj T* ( op = getattr\(float, '__%s__' % operator\)) Tj T* ( result = dict\(add=0.0, mul=1.0\)[operator]) Tj T* ( for n in numbers:) Tj T* ( result = op\(result, n\)) Tj T* ET
+BT 1 0 0 1 0 125.71 Tm /F4 10 Tf 12 TL (# example10.py) Tj T* (import plac) Tj T* T* (@plac.annotations\() Tj T* (operator=\("The name of an operator", 'positional', None, str, ['add', 'mul']\),) Tj T* (numbers=\("A number", 'positional', None, float, None, "n"\)\)) Tj T* (def main\(operator, *numbers\):) Tj T* ( "A script to add and multiply numbers") Tj T* ( op = getattr\(float, '__%s__' % operator\)) Tj T* ( result = dict\(add=0.0, mul=1.0\)[operator]) Tj T* ( for n in numbers:) Tj T* ET
Q
Q
Q
@@ -3641,14 +3689,14 @@ Q
endstream
endobj
-% 'R153': class PDFStream
-153 0 obj
+% 'R156': class PDFStream
+156 0 obj
% page stream
-<< /Length 5160 >>
+<< /Length 3966 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 703.8236 cm
+1 0 0 1 62.69291 691.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3663,11 +3711,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 442.6898 60 re B*
+n -6 -6 442.6898 72 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ( print\(result\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL ( result = op\(result, n\)) Tj T* ( print\(result\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.call\(main\)) Tj T* ET
Q
Q
Q
@@ -3677,17 +3725,17 @@ q
Q
Q
q
-1 0 0 1 62.69291 703.8236 cm
+1 0 0 1 62.69291 691.8236 cm
Q
q
-1 0 0 1 62.69291 685.8236 cm
+1 0 0 1 62.69291 673.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage for the script:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 544.6236 cm
+1 0 0 1 62.69291 532.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3708,13 +3756,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 512.6236 cm
+1 0 0 1 62.69291 500.6236 cm
q
BT 1 0 0 1 0 16.82 Tm .15186 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that the docstring of the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function has been automatically added to the usage message. Here) Tj T* 0 Tw (are a couple of examples of use:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 419.2849 cm
+1 0 0 1 62.69291 407.2849 cm
q
q
.87797 0 0 .87797 0 0 cm
@@ -3735,31 +3783,145 @@ Q
Q
Q
q
-1 0 0 1 62.69291 386.2849 cm
+1 0 0 1 62.69291 374.2849 cm
+q
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A more realistic example) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 332.2849 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.234488 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here is a more realistic script using most of the features of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (to run SQL queries on a database by) Tj T* 0 Tw .930697 Tw (relying on ) Tj 0 0 .501961 rg (SQLAlchemy) Tj 0 0 0 rg (. Notice the usage of the ) Tj /F4 10 Tf (type ) Tj /F1 10 Tf (feature to automagically convert a SQLAlchemy) Tj T* 0 Tw (connection string into a ) Tj 0 0 .501961 rg (SqlSoup ) Tj 0 0 0 rg (object:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 326.2849 cm
+Q
+q
+1 0 0 1 62.69291 76.86614 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+BT 1 0 0 1 0 2 Tm T* ET
+q
+1 0 0 1 20 0 cm
+q
+q
+1 0 0 1 0 0 cm
+q
+1 0 0 1 6.6 6.6 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 442.6898 240 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 221.71 Tm /F4 10 Tf 12 TL (# dbcli.py) Tj T* (import clap) Tj T* (from sqlalchemy.ext.sqlsoup import SqlSoup) Tj T* T* (@clap.annotations\() Tj T* ( db=\("Connection string", 'positional', None, SqlSoup\),) Tj T* ( header=\("Header", 'flag', 'H'\),) Tj T* ( sqlcmd=\("SQL command", 'option', 'c', str, None, "SQL"\),) Tj T* ( delimiter=\("Column separator", 'option', 'd'\),) Tj T* ( scripts="SQL scripts",) Tj T* ( \)) Tj T* (def main\(db, header, sqlcmd, delimiter="|", *scripts\):) Tj T* ( "A script to run queries and SQL scripts on a database") Tj T* ( print\('Working on %s' % db.bind.url\)) Tj T* ( if sqlcmd:) Tj T* ( result = db.bind.execute\(sqlcmd\)) Tj T* ( if header: # print the header) Tj T* ( print\(delimiter.join\(result.keys\(\)\)\)) Tj T* ( for row in result: # print the rows) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+Q
+Q
+
+endstream
+
+endobj
+% 'R157': class PDFStream
+157 0 obj
+% page stream
+<< /Length 4959 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 667.8236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+BT 1 0 0 1 0 2 Tm T* ET
+q
+1 0 0 1 20 0 cm
+q
+q
+1 0 0 1 0 0 cm
+q
+1 0 0 1 6.6 6.6 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 442.6898 96 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL ( print\(delimiter.join\(map\(str, row\)\)\)) Tj T* T* ( for script in scripts:) Tj T* ( db.bind.execute\(file\(script\).read\(\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( clap.call\(main\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 667.8236 cm
+Q
+q
+1 0 0 1 62.69291 649.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage message:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 460.6236 cm
+q
+q
+1 0 0 1 0 0 cm
+q
+1 0 0 1 6.6 6.6 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 468.6898 180 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 161.71 Tm /F4 10 Tf 12 TL ($ python article/dbcli.py -h) Tj T* (usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]) Tj T* T* (A script to run queries and SQL scripts on a database) Tj T* T* (positional arguments:) Tj T* ( db Connection string) Tj T* ( scripts SQL scripts) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -H, --header Header) Tj T* ( -c SQL, --sqlcmd SQL SQL command) Tj T* ( -d |, --delimiter | Column separator) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 427.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A few notes on the underlying implementation) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 356.2849 cm
+1 0 0 1 62.69291 397.6236 cm
q
BT 1 0 0 1 0 16.82 Tm .094988 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (relies on a ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (for all of the heavy lifting work and it is possible to leverage on ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (features) Tj T* 0 Tw (directly or indirectly.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 314.2849 cm
+1 0 0 1 62.69291 355.6236 cm
q
-BT 1 0 0 1 0 28.82 Tm 5.575697 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, you can make invisible an argument in the usage message simply by using) Tj T* 0 Tw 11.11997 Tw ('==SUPPRESS==' as help string \(or ) Tj /F4 10 Tf (argparse.SUPPRESS) Tj /F1 10 Tf (\). Similarly, you can use) Tj T* 0 Tw /F4 10 Tf (argparse.FileType ) Tj /F1 10 Tf (directly.) Tj T* ET
+BT 1 0 0 1 0 28.82 Tm 5.575697 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, you can make invisible an argument in the usage message simply by using) Tj T* 0 Tw 4.107752 Tw /F4 10 Tf ('==SUPPRESS==`'` as help string \(or ``argparse.SUPPRESS) Tj /F1 10 Tf (\). Similarly, you can use) Tj T* 0 Tw 0 0 .501961 rg (argparse.FileType ) Tj 0 0 0 rg (directly.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 260.2849 cm
+1 0 0 1 62.69291 301.6236 cm
q
BT 1 0 0 1 0 40.82 Tm 1.639213 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is also possible to pass options to the underlying ) Tj /F4 10 Tf (argparse.ArgumentParser ) Tj /F1 10 Tf (object \(currently it) Tj T* 0 Tw .285529 Tw (accepts the default arguments ) Tj /F4 10 Tf (description) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (epilog) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (prog) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (usage) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (add_help) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (argument_default) Tj /F1 10 Tf (,) Tj T* 0 Tw 1.439953 Tw /F4 10 Tf (parents) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (prefix_chars) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (fromfile_prefix_chars) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (conflict_handler) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (formatter_class) Tj /F1 10 Tf (\). It) Tj T* 0 Tw (is enough to set such attributes on the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function. For instance) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 191.0849 cm
+1 0 0 1 62.69291 232.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3780,23 +3942,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 111.0849 cm
+1 0 0 1 62.69291 152.4236 cm
q
BT 1 0 0 1 0 64.82 Tm 1.256457 Tw 12 TL /F1 10 Tf 0 0 0 rg (disable the recognition of the help flag ) Tj /F4 10 Tf (-h, --help) Tj /F1 10 Tf (. This is not particularly elegant, but I assume the) Tj T* 0 Tw .274751 Tw (typical user of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (will be happy with the default message and would not want to go at this level of detail;) Tj T* 0 Tw .230514 Tw (still it is possible if she wants to. For instance, by setting the ) Tj /F4 10 Tf (description ) Tj /F1 10 Tf (attribute, it is possible to add) Tj T* 0 Tw .04332 Tw (a comment to the usage message \(by default the docstring of the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function is used as description\). It) Tj T* 0 Tw .877765 Tw (is also possible to change the option prefix; for instance if your script must run under Windows and you) Tj T* 0 Tw (want to use "/" as option prefix you can add the lines:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R154': class PDFStream
-154 0 obj
-% page stream
-<< /Length 5176 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 727.8236 cm
+1 0 0 1 62.69291 107.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3816,20 +3968,30 @@ Q
Q
Q
Q
+
+endstream
+
+endobj
+% 'R158': class PDFStream
+158 0 obj
+% page stream
+<< /Length 4919 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 659.8236 cm
+1 0 0 1 62.69291 705.0236 cm
q
BT 1 0 0 1 0 52.82 Tm 3.694269 Tw 12 TL /F1 10 Tf 0 0 0 rg (The recognition of the ) Tj /F4 10 Tf (short_prefix ) Tj /F1 10 Tf (attribute is a ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (extension; there is also a companion) Tj T* 0 Tw 2.348314 Tw /F4 10 Tf (long_prefix ) Tj /F1 10 Tf (attribute with default value of ) Tj /F4 10 Tf (--) Tj /F1 10 Tf (. ) Tj /F4 10 Tf (prefix_chars ) Tj /F1 10 Tf (is an ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (feature. Interested) Tj T* 0 Tw 1.419984 Tw (readers should read the documentation of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (to understand the meaning of the other options. If) Tj T* 0 Tw .098935 Tw (there is a set of options that you use very often, you may consider writing a decorator adding such options) Tj T* 0 Tw (to the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function for you. For simplicity, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (does not perform any magic of that kind.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 629.8236 cm
+1 0 0 1 62.69291 675.0236 cm
q
BT 1 0 0 1 0 16.82 Tm 7.709147 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is possible to access directly the underlying ) Tj 0 0 .501961 rg (ArgumentParser ) Tj 0 0 0 rg (object, by invoking the) Tj T* 0 Tw /F4 10 Tf (plac.parser_from ) Tj /F1 10 Tf (utility function:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 512.6236 cm
+1 0 0 1 62.69291 557.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3849,35 +4011,35 @@ Q
Q
Q
q
-1 0 0 1 62.69291 492.6236 cm
+1 0 0 1 62.69291 537.8236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (I use ) Tj /F4 10 Tf (plac.parser_from ) Tj /F1 10 Tf (in the unit tests of the module, but regular users should never need to use it.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 459.6236 cm
+1 0 0 1 62.69291 504.8236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Custom annotation objects) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 429.6236 cm
+1 0 0 1 62.69291 474.8236 cm
q
BT 1 0 0 1 0 16.82 Tm .578651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (uses an ) Tj /F4 10 Tf (Annotation ) Tj /F1 10 Tf (class to convert the tuples in the function signature into annotation) Tj T* 0 Tw (objects, i.e. objects with six attributes ) Tj /F4 10 Tf (help, kind, short, type, choices, metavar) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 399.6236 cm
+1 0 0 1 62.69291 444.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .083735 Tw (Advanced users can implement their own annotation objects. For instance, here is an example of how you) Tj T* 0 Tw (could implement annotations for positional arguments:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 393.6236 cm
+1 0 0 1 62.69291 438.8236 cm
Q
q
-1 0 0 1 62.69291 284.4236 cm
+1 0 0 1 62.69291 317.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3892,11 +4054,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 108 re B*
+n -6 -6 448.6898 120 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL (class Positional\(object\):) Tj T* ( def __init__\(self, help='', type=None, choices=None, metavar=None\):) Tj T* ( self.help = help) Tj T* ( self.kind = 'positional') Tj T* ( self.abbrev = None) Tj T* ( self.type = type) Tj T* ( self.choices = choices) Tj T* ( self.metavar = metavar) Tj T* ET
+BT 1 0 0 1 0 101.71 Tm /F4 10 Tf 12 TL (# annotations.py) Tj T* (class Positional\(object\):) Tj T* ( def __init__\(self, help='', type=None, choices=None, metavar=None\):) Tj T* ( self.help = help) Tj T* ( self.kind = 'positional') Tj T* ( self.abbrev = None) Tj T* ( self.type = type) Tj T* ( self.choices = choices) Tj T* ( self.metavar = metavar) Tj T* ET
Q
Q
Q
@@ -3906,20 +4068,20 @@ q
Q
Q
q
-1 0 0 1 62.69291 284.4236 cm
+1 0 0 1 62.69291 317.6236 cm
Q
q
-1 0 0 1 62.69291 266.4236 cm
+1 0 0 1 62.69291 299.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (You can use such annotations objects as follows:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 260.4236 cm
+1 0 0 1 62.69291 293.6236 cm
Q
q
-1 0 0 1 62.69291 103.2236 cm
+1 0 0 1 62.69291 124.4236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3934,11 +4096,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 448.6898 156 re B*
+n -6 -6 448.6898 168 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 137.71 Tm /F4 10 Tf 12 TL (import plac) Tj T* (from annotations import Positional) Tj T* T* (@plac.annotations\() Tj T* ( i=Positional\("This is an int", int\),) Tj T* ( n=Positional\("This is a float", float\),) Tj T* ( rest=Positional\("Other arguments"\)\)) Tj T* (def main\(i, n, *rest\):) Tj T* ( print\(i, n, rest\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 149.71 Tm /F4 10 Tf 12 TL (# example11.py) Tj T* (import plac) Tj T* (from annotations import Positional) Tj T* T* (@plac.annotations\() Tj T* ( i=Positional\("This is an int", int\),) Tj T* ( n=Positional\("This is a float", float\),) Tj T* ( rest=Positional\("Other arguments"\)\)) Tj T* (def main\(i, n, *rest\):) Tj T* ( print\(i, n, rest\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
@@ -3948,10 +4110,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 103.2236 cm
+1 0 0 1 62.69291 124.4236 cm
Q
q
-1 0 0 1 62.69291 85.22362 cm
+1 0 0 1 62.69291 106.4236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage message you get:) Tj T* ET
@@ -3961,10 +4123,10 @@ Q
endstream
endobj
-% 'R155': class PDFStream
-155 0 obj
+% 'R159': class PDFStream
+159 0 obj
% page stream
-<< /Length 8028 >>
+<< /Length 8190 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -4177,125 +4339,11 @@ Q
q
1 0 0 1 62.69291 167.8236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A final example) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 137.8236 cm
-q
-BT 1 0 0 1 0 16.82 Tm .196655 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here is a more realistic script using all of the features of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (to run SQL queries on a database by relying) Tj T* 0 Tw (on SQLAlchemy.) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 131.8236 cm
-Q
-q
-1 0 0 1 62.69291 76.86614 cm
-0 0 0 rg
-BT /F3 10 Tf 12 TL ET
-BT 1 0 0 1 0 2 Tm T* ET
-q
-1 0 0 1 20 0 cm
-q
-q
-1 0 0 1 0 0 cm
-q
-1 0 0 1 6.6 6.6 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 442.6898 36 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL (import clap) Tj T* (from sqlalchemy.ext.sqlsoup import SqlSoup) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-Q
-Q
-
-endstream
-
-endobj
-% 'R156': class PDFStream
-156 0 obj
-% page stream
-<< /Length 3299 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 475.8236 cm
-0 0 0 rg
-BT /F3 10 Tf 12 TL ET
-BT 1 0 0 1 0 2 Tm T* ET
-q
-1 0 0 1 20 0 cm
-q
-q
-1 0 0 1 0 0 cm
-q
-1 0 0 1 6.6 6.6 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 442.6898 288 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 269.71 Tm /F4 10 Tf 12 TL T* (@clap.annotations\() Tj T* ( db=\("Connection string", 'positional', None, SqlSoup\),) Tj T* ( header=\("Header", 'flag', 'H'\),) Tj T* ( sqlcmd=\("SQL command", 'option', 'c', str, None, "SQL"\),) Tj T* ( delimiter=\("Column separator", 'option', 'd'\),) Tj T* ( scripts="SQL scripts",) Tj T* ( \)) Tj T* (def main\(db, header, sqlcmd, delimiter="|", *scripts\):) Tj T* ( "A script to run queries and SQL scripts on a database") Tj T* ( print\('Working on %s' % db.bind.url\)) Tj T* ( if sqlcmd:) Tj T* ( result = db.bind.execute\(sqlcmd\)) Tj T* ( if header: # print the header) Tj T* ( print\(delimiter.join\(result.keys\(\)\)\)) Tj T* ( for row in result: # print the rows) Tj T* ( print\(delimiter.join\(map\(str, row\)\)\)) Tj T* T* ( for script in scripts:) Tj T* ( db.execute\(file\(script\).read\(\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( clap.call\(main\)) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-Q
-Q
-q
-1 0 0 1 62.69291 475.8236 cm
-Q
-q
-1 0 0 1 62.69291 457.8236 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage message:) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 268.6236 cm
-q
-q
-1 0 0 1 0 0 cm
-q
-1 0 0 1 6.6 6.6 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 468.6898 180 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 161.71 Tm /F4 10 Tf 12 TL ($ python article/dbcli.py -h) Tj T* (usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]) Tj T* T* (A script to run queries and SQL scripts on a database) Tj T* T* (positional arguments:) Tj T* ( db Connection string) Tj T* ( scripts SQL scripts) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -H, --header Header) Tj T* ( -c SQL, --sqlcmd SQL SQL command) Tj T* ( -d |, --delimiter | Column separator) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-1 0 0 1 62.69291 235.6236 cm
-q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The future) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 157.6236 cm
+1 0 0 1 62.69291 89.82362 cm
q
BT 1 0 0 1 0 64.82 Tm .444431 Tw 12 TL /F1 10 Tf 0 0 0 rg (Currently plac is below 100 lines of code, not counting blanks, comments and docstrings. I do not plan to) Tj T* 0 Tw .035444 Tw (extend it much in the future. The idea is to keep the module short: it is and it should remain a little wrapper) Tj T* 0 Tw 1.903318 Tw (over ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. Actually I have thought about contributing the code back to ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (if ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (becomes) Tj T* 0 Tw 4.105697 Tw (successfull and gains a reasonable number of users. For the moment it should be considered) Tj T* 0 Tw .351654 Tw (experimental: after all I wrote it in three days, including the tests, the documentation and the time to learn) Tj T* 0 Tw 0 0 .501961 rg (argparse) Tj 0 0 0 rg (.) Tj T* ET
Q
@@ -4304,10 +4352,10 @@ Q
endstream
endobj
-% 'R157': class PDFStream
-157 0 obj
+% 'R160': class PDFStream
+160 0 obj
% page stream
-<< /Length 3429 >>
+<< /Length 3431 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -4319,7 +4367,7 @@ Q
q
1 0 0 1 62.69291 678.0236 cm
q
-BT 1 0 0 1 0 52.82 Tm .942651 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (project started very humble: I just wanted to make easy_installable my old ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe,) Tj T* 0 Tw .565988 Tw (and to publish it on PyPI. The original name of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (was optionparser and the idea behind it was to build) Tj T* 0 Tw .603735 Tw (an ) Tj 0 0 .501961 rg (OptionParser ) Tj 0 0 0 rg (object from the docstring of the module. However, before doing that, I decided to check) Tj T* 0 Tw .507356 Tw (out the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module, since I new it was going into Python 2.7 and Python 2.7 was coming out. Soon) Tj T* 0 Tw (enough I realized two things:) Tj T* ET
+BT 1 0 0 1 0 52.82 Tm .942651 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (project started very humble: I just wanted to make easy_installable my old ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe,) Tj T* 0 Tw .565988 Tw (and to publish it on PyPI. The original name of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (was optionparser and the idea behind it was to build) Tj T* 0 Tw .603735 Tw (an ) Tj 0 0 .501961 rg (OptionParser ) Tj 0 0 0 rg (object from the docstring of the module. However, before doing that, I decided to check) Tj T* 0 Tw .244198 Tw (out the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module, since I knew it was going into Python 2.7 and Python 2.7 was coming out. Soon) Tj T* 0 Tw (enough I realized two things:) Tj T* ET
Q
Q
q
@@ -4390,122 +4438,122 @@ Q
q
1 0 0 1 62.69291 528.0236 cm
q
-BT 1 0 0 1 0 16.82 Tm 1.093876 Tw 12 TL /F1 10 Tf 0 0 0 rg (I made a research on PyPI and the name clap \(Command Line Arguments Parser\) was not taken, so I) Tj T* 0 Tw (renamed everything to clap. After two days a ) Tj 0 0 .501961 rg (Clap ) Tj 0 0 0 rg (module appeared on PyPI! <) Tj (expletive deleted) Tj (>) Tj T* ET
+BT 1 0 0 1 0 16.82 Tm 1.093876 Tw 12 TL /F1 10 Tf 0 0 0 rg (I made a research on PyPI and the name clap \(Command Line Arguments Parser\) was not taken, so I) Tj T* 0 Tw (renamed everything to clap. After two days a ) Tj 0 0 .501961 rg (Clap ) Tj 0 0 0 rg (module appeared on PyPI! <) Tj (expletives deleted) Tj (>) Tj T* ET
Q
Q
q
1 0 0 1 62.69291 498.0236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 1.123145 Tw (Having little fantasy, I decided to rename everything again to plac, as an anagram of clap: since it is a) Tj T* 0 Tw (non-existing English name, I hope nobody will stole it from me!) Tj T* ET
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 1.123145 Tw (Having little fantasy, I decided to rename everything again to plac, as an anagram of clap: since it is a) Tj T* 0 Tw (non-existing English name, I hope nobody will steal it from me!) Tj T* ET
Q
Q
endstream
endobj
-% 'R158': class PDFPageLabels
-158 0 obj
+% 'R161': class PDFPageLabels
+161 0 obj
% Document Root
<< /Nums [ 0
- 159 0 R
+ 162 0 R
1
- 160 0 R
+ 163 0 R
2
- 161 0 R
+ 164 0 R
3
- 162 0 R
+ 165 0 R
4
- 163 0 R
+ 166 0 R
5
- 164 0 R
+ 167 0 R
6
- 165 0 R
+ 168 0 R
7
- 166 0 R
+ 169 0 R
8
- 167 0 R
+ 170 0 R
9
- 168 0 R
+ 171 0 R
10
- 169 0 R
+ 172 0 R
11
- 170 0 R ] >>
+ 173 0 R ] >>
endobj
-% 'R159': class PDFPageLabel
-159 0 obj
+% 'R162': class PDFPageLabel
+162 0 obj
% None
<< /S /D
/St 1 >>
endobj
-% 'R160': class PDFPageLabel
-160 0 obj
+% 'R163': class PDFPageLabel
+163 0 obj
% None
<< /S /D
/St 2 >>
endobj
-% 'R161': class PDFPageLabel
-161 0 obj
+% 'R164': class PDFPageLabel
+164 0 obj
% None
<< /S /D
/St 3 >>
endobj
-% 'R162': class PDFPageLabel
-162 0 obj
+% 'R165': class PDFPageLabel
+165 0 obj
% None
<< /S /D
/St 4 >>
endobj
-% 'R163': class PDFPageLabel
-163 0 obj
+% 'R166': class PDFPageLabel
+166 0 obj
% None
<< /S /D
/St 5 >>
endobj
-% 'R164': class PDFPageLabel
-164 0 obj
+% 'R167': class PDFPageLabel
+167 0 obj
% None
<< /S /D
/St 6 >>
endobj
-% 'R165': class PDFPageLabel
-165 0 obj
+% 'R168': class PDFPageLabel
+168 0 obj
% None
<< /S /D
/St 7 >>
endobj
-% 'R166': class PDFPageLabel
-166 0 obj
+% 'R169': class PDFPageLabel
+169 0 obj
% None
<< /S /D
/St 8 >>
endobj
-% 'R167': class PDFPageLabel
-167 0 obj
+% 'R170': class PDFPageLabel
+170 0 obj
% None
<< /S /D
/St 9 >>
endobj
-% 'R168': class PDFPageLabel
-168 0 obj
+% 'R171': class PDFPageLabel
+171 0 obj
% None
<< /S /D
/St 10 >>
endobj
-% 'R169': class PDFPageLabel
-169 0 obj
+% 'R172': class PDFPageLabel
+172 0 obj
% None
<< /S /D
/St 11 >>
endobj
-% 'R170': class PDFPageLabel
-170 0 obj
+% 'R173': class PDFPageLabel
+173 0 obj
% None
<< /S /D
/St 12 >>
endobj
xref
-0 171
+0 174
0000000000 65535 f
0000000113 00000 n
0000000258 00000 n
@@ -4531,160 +4579,163 @@ xref
0000004837 00000 n
0000005080 00000 n
0000005323 00000 n
-0000005567 00000 n
-0000005811 00000 n
-0000006055 00000 n
-0000006299 00000 n
-0000006543 00000 n
-0000006787 00000 n
-0000007031 00000 n
-0000007274 00000 n
-0000007536 00000 n
-0000007800 00000 n
-0000008050 00000 n
-0000008300 00000 n
-0000008552 00000 n
-0000008804 00000 n
-0000009056 00000 n
-0000009306 00000 n
-0000009543 00000 n
-0000010163 00000 n
-0000010429 00000 n
-0000010680 00000 n
-0000010917 00000 n
-0000011112 00000 n
-0000011374 00000 n
-0000011638 00000 n
-0000011873 00000 n
-0000012236 00000 n
-0000012488 00000 n
-0000012740 00000 n
-0000012991 00000 n
-0000013241 00000 n
-0000013493 00000 n
-0000013730 00000 n
-0000014093 00000 n
-0000014345 00000 n
-0000014597 00000 n
-0000014849 00000 n
-0000015137 00000 n
-0000015421 00000 n
-0000015673 00000 n
-0000015946 00000 n
-0000016318 00000 n
-0000016555 00000 n
-0000016873 00000 n
-0000017124 00000 n
-0000017376 00000 n
-0000017628 00000 n
-0000017865 00000 n
-0000018210 00000 n
-0000018462 00000 n
-0000018712 00000 n
-0000018962 00000 n
-0000019212 00000 n
-0000019464 00000 n
-0000019699 00000 n
-0000020062 00000 n
-0000020313 00000 n
-0000020563 00000 n
-0000020813 00000 n
-0000021050 00000 n
-0000021395 00000 n
-0000021647 00000 n
-0000021896 00000 n
-0000022146 00000 n
-0000022398 00000 n
-0000022685 00000 n
-0000022922 00000 n
-0000023285 00000 n
-0000023536 00000 n
-0000023786 00000 n
-0000024038 00000 n
-0000024302 00000 n
-0000024552 00000 n
-0000024816 00000 n
-0000025068 00000 n
-0000025318 00000 n
-0000025570 00000 n
-0000025821 00000 n
-0000026074 00000 n
-0000026325 00000 n
-0000026577 00000 n
-0000026830 00000 n
-0000027083 00000 n
-0000027336 00000 n
-0000027589 00000 n
-0000027840 00000 n
-0000028092 00000 n
-0000028380 00000 n
-0000028631 00000 n
-0000028870 00000 n
-0000029391 00000 n
-0000029642 00000 n
-0000029893 00000 n
-0000030147 00000 n
-0000030384 00000 n
-0000030735 00000 n
-0000030989 00000 n
-0000031276 00000 n
-0000031530 00000 n
-0000031841 00000 n
-0000032092 00000 n
-0000032344 00000 n
-0000032633 00000 n
-0000032885 00000 n
-0000033137 00000 n
-0000033380 00000 n
-0000033777 00000 n
-0000033941 00000 n
-0000034232 00000 n
-0000034361 00000 n
-0000034537 00000 n
-0000034747 00000 n
-0000034955 00000 n
-0000035152 00000 n
-0000035357 00000 n
-0000035550 00000 n
-0000035774 00000 n
-0000035979 00000 n
-0000036176 00000 n
-0000036373 00000 n
-0000036565 00000 n
-0000036748 00000 n
-0000036961 00000 n
-0000045452 00000 n
-0000050988 00000 n
-0000055420 00000 n
-0000060390 00000 n
-0000065242 00000 n
-0000070962 00000 n
-0000076661 00000 n
-0000081924 00000 n
-0000087203 00000 n
-0000095334 00000 n
-0000098736 00000 n
-0000102272 00000 n
-0000102524 00000 n
-0000102603 00000 n
-0000102682 00000 n
-0000102761 00000 n
-0000102840 00000 n
-0000102919 00000 n
-0000102998 00000 n
-0000103077 00000 n
-0000103156 00000 n
-0000103235 00000 n
-0000103315 00000 n
-0000103395 00000 n
+0000005566 00000 n
+0000005809 00000 n
+0000006053 00000 n
+0000006297 00000 n
+0000006541 00000 n
+0000006785 00000 n
+0000007029 00000 n
+0000007272 00000 n
+0000007534 00000 n
+0000007798 00000 n
+0000008048 00000 n
+0000008298 00000 n
+0000008550 00000 n
+0000008802 00000 n
+0000009054 00000 n
+0000009304 00000 n
+0000009541 00000 n
+0000010161 00000 n
+0000010427 00000 n
+0000010678 00000 n
+0000010915 00000 n
+0000011110 00000 n
+0000011372 00000 n
+0000011636 00000 n
+0000011871 00000 n
+0000012234 00000 n
+0000012486 00000 n
+0000012738 00000 n
+0000012989 00000 n
+0000013239 00000 n
+0000013491 00000 n
+0000013728 00000 n
+0000014091 00000 n
+0000014343 00000 n
+0000014595 00000 n
+0000014847 00000 n
+0000015135 00000 n
+0000015419 00000 n
+0000015671 00000 n
+0000015944 00000 n
+0000016316 00000 n
+0000016553 00000 n
+0000016871 00000 n
+0000017122 00000 n
+0000017374 00000 n
+0000017626 00000 n
+0000017863 00000 n
+0000018208 00000 n
+0000018460 00000 n
+0000018710 00000 n
+0000018960 00000 n
+0000019210 00000 n
+0000019462 00000 n
+0000019697 00000 n
+0000020060 00000 n
+0000020312 00000 n
+0000020558 00000 n
+0000020820 00000 n
+0000021156 00000 n
+0000021407 00000 n
+0000021657 00000 n
+0000021907 00000 n
+0000022223 00000 n
+0000022460 00000 n
+0000022814 00000 n
+0000023066 00000 n
+0000023315 00000 n
+0000023565 00000 n
+0000023817 00000 n
+0000024104 00000 n
+0000024342 00000 n
+0000024705 00000 n
+0000024956 00000 n
+0000025206 00000 n
+0000025458 00000 n
+0000025722 00000 n
+0000025973 00000 n
+0000026238 00000 n
+0000026491 00000 n
+0000026742 00000 n
+0000026995 00000 n
+0000027246 00000 n
+0000027499 00000 n
+0000027750 00000 n
+0000028002 00000 n
+0000028255 00000 n
+0000028508 00000 n
+0000028761 00000 n
+0000029014 00000 n
+0000029265 00000 n
+0000029517 00000 n
+0000029806 00000 n
+0000030058 00000 n
+0000030310 00000 n
+0000030561 00000 n
+0000030815 00000 n
+0000031052 00000 n
+0000031609 00000 n
+0000031863 00000 n
+0000032150 00000 n
+0000032404 00000 n
+0000032715 00000 n
+0000032967 00000 n
+0000033219 00000 n
+0000033508 00000 n
+0000033760 00000 n
+0000034012 00000 n
+0000034255 00000 n
+0000034652 00000 n
+0000034816 00000 n
+0000035107 00000 n
+0000035236 00000 n
+0000035412 00000 n
+0000035622 00000 n
+0000035830 00000 n
+0000036027 00000 n
+0000036232 00000 n
+0000036425 00000 n
+0000036629 00000 n
+0000036853 00000 n
+0000037058 00000 n
+0000037256 00000 n
+0000037448 00000 n
+0000037631 00000 n
+0000037843 00000 n
+0000046350 00000 n
+0000051930 00000 n
+0000056376 00000 n
+0000061365 00000 n
+0000066240 00000 n
+0000071960 00000 n
+0000077641 00000 n
+0000081710 00000 n
+0000086772 00000 n
+0000091794 00000 n
+0000100087 00000 n
+0000103625 00000 n
+0000103877 00000 n
+0000103956 00000 n
+0000104035 00000 n
+0000104114 00000 n
+0000104193 00000 n
+0000104272 00000 n
+0000104351 00000 n
+0000104430 00000 n
+0000104509 00000 n
+0000104588 00000 n
+0000104668 00000 n
+0000104748 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(\277\245\225\024\025\215\375JE\232\372/B\334iX) (\277\245\225\024\025\215\375JE\232\372/B\334iX)]
+ [(\235G:\345\242\327\277\256\202.\210\323e\200\340K) (\235G:\345\242\327\277\256\202.\210\323e\200\340K)]
- /Info 131 0 R
- /Root 130 0 R
- /Size 171 >>
+ /Info 134 0 R
+ /Root 133 0 R
+ /Size 174 >>
startxref
-103444
+104797
%%EOF
diff --git a/plac/doc/article.txt b/plac/doc/plac.txt
index 7acd5c8..3432f1d 100644
--- a/plac/doc/article.txt
+++ b/plac/doc/plac.txt
@@ -13,7 +13,7 @@ Plac, the Easiest Command Line Arguments Parser in the World
Introduction
------------------------------------------------
-There is no want of command line arguments parsers in Python
+There is no want of command line arguments parsers in the Python
world. The standard library alone contains three different modules for
the parsing of command line options: getopt_ (from the stone age),
optparse_ (from Python 2.3) and argparse_ (from Python 2.7). All of
@@ -143,7 +143,7 @@ the usage message for free::
plac_ manages transparently even the case when you want to pass a
variable number of arguments. Here is an example, a script running
-on a database a series of ``.sql`` scripts:
+on a database a series of SQL scripts:
.. include:: example6.py
:literal:
@@ -394,15 +394,44 @@ to the usage message. Here are a couple of examples of use::
usage: example10.py [-h] {add,mul} [n [n ...]]
example10.py: error: argument operator: invalid choice: 'ad' (choose from 'add', 'mul')
+A more realistic example
+---------------------------------------
+
+Here is a more realistic script using most of the features of plac_ to
+run SQL queries on a database by relying on SQLAlchemy_. Notice the usage
+of the ``type`` feature to automagically convert a SQLAlchemy connection
+string into a SqlSoup_ object:
+
+ .. include:: dbcli.py
+ :literal:
+
+Here is the usage message::
+
+ $ python article/dbcli.py -h
+ usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]
+
+ A script to run queries and SQL scripts on a database
+
+ positional arguments:
+ db Connection string
+ scripts SQL scripts
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -H, --header Header
+ -c SQL, --sqlcmd SQL SQL command
+ -d |, --delimiter | Column separator
+
A few notes on the underlying implementation
----------------------------------------------------
plac_ relies on a argparse_ for all of the heavy lifting work and it is
possible to leverage on argparse_ features directly or indirectly.
-For instance, you can make invisible an argument in the usage message simply by
-using '==SUPPRESS==' as help string (or ``argparse.SUPPRESS``). Similarly, you can
-use ``argparse.FileType`` directly.
+For instance, you can make invisible an argument in the usage message
+simply by using ``'==SUPPRESS==`'` as help string (or
+``argparse.SUPPRESS``). Similarly, you can use argparse.FileType_
+directly.
It is also possible to pass options to the underlying
``argparse.ArgumentParser`` object (currently it accepts the default
@@ -433,13 +462,13 @@ for instance if your script must run under Windows and you want to use
main.short_prefix = '/'
The recognition of the ``short_prefix`` attribute is a plac_
-extension; there is also a companion ``long_prefix``
-attribute with default value of ``--``. ``prefix_chars`` is an argparse_ feature.
-Interested readers should read the documentation of argparse_ to understand the
-meaning of the other options. If there is a set of options that you
-use very often, you may consider writing a decorator adding such
-options to the ``main`` function for you. For simplicity, plac_ does
-not perform any magic of that kind.
+extension; there is also a companion ``long_prefix`` attribute with
+default value of ``--``. ``prefix_chars`` is an argparse_ feature.
+Interested readers should read the documentation of argparse_ to
+understand the meaning of the other options. If there is a set of
+options that you use very often, you may consider writing a decorator
+adding such options to the ``main`` function for you. For simplicity,
+plac_ does not perform any magic of that kind.
It is possible to access directly the underlying ArgumentParser_ object, by
invoking the ``plac.parser_from`` utility function:
@@ -539,32 +568,6 @@ is then available to you: you can use ``add_argument``, ``add_subparsers()``,
etc. In other words, while some features are not supported directly,
*all* features are supported indirectly.
-A final example
----------------------------------------
-
-Here is a more realistic script using all of the features of plac_ to run SQL queries
-on a database by relying on SQLAlchemy.
-
- .. include:: dbcli.py
- :literal:
-
-Here is the usage message::
-
- $ python article/dbcli.py -h
- usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]
-
- A script to run queries and SQL scripts on a database
-
- positional arguments:
- db Connection string
- scripts SQL scripts
-
- optional arguments:
- -h, --help show this help message and exit
- -H, --header Header
- -c SQL, --sqlcmd SQL SQL command
- -d |, --delimiter | Column separator
-
The future
-------------------------------
@@ -585,7 +588,7 @@ easy_installable my old optionparse_ recipe, and to publish it on PyPI.
The original name of plac_ was optionparser and the idea behind it was
to build an OptionParser_ object from the docstring of the module.
However, before doing that, I decided to check out the argparse_ module,
-since I new it was going into Python 2.7 and Python 2.7 was coming out.
+since I knew it was going into Python 2.7 and Python 2.7 was coming out.
Soon enough I realized two things:
1. the single greatest idea of argparse_ was unifying the positional arguments
@@ -601,11 +604,11 @@ since the typical usage was completely different from the argparse_ usage.
I made a research on PyPI and the name clap (Command Line Arguments Parser)
was not taken, so I renamed everything to clap. After two days
-a Clap_ module appeared on PyPI! <expletive deleted>
+a Clap_ module appeared on PyPI! <expletives deleted>
Having little fantasy, I decided to rename everything again to plac, as
an anagram of clap: since it is a non-existing English name, I hope nobody
-will stole it from me!
+will steal it from me!
.. _argparse: http://argparse.googlecode.com
.. _optparse: http://docs.python.org/library/optparse.html
@@ -614,5 +617,8 @@ will stole it from me!
.. _plac: http://pypi.python.org/pypi/plac
.. _scaling down: http://www.welton.it/articles/scalable_systems
.. _ArgumentParser: http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html
+.. _argparse.FileType: http://argparse.googlecode.com/svn/tags/r11/doc/other-utilities.html?highlight=filetype#FileType
.. _Clap: http://pypi.python.org/pypi/Clap/0.7
.. _OptionParser: http://docs.python.org/library/optparse.html?highlight=optionparser#optparse.OptionParser
+.. _SQLAlchemy: http://www.sqlalchemy.org/
+.. _SqlSoup: http://www.sqlalchemy.org/docs/reference/ext/sqlsoup.html
diff --git a/plac/plac.py b/plac/plac.py
index fdde35f..ef0bf75 100644
--- a/plac/plac.py
+++ b/plac/plac.py
@@ -29,7 +29,7 @@ See plac/doc.html for the documentation.
"""
# this module should be kept Python 2.3 compatible
-__version__ = '0.2.0'
+__version__ = '0.3.0'
import re, sys, inspect, argparse
@@ -73,9 +73,10 @@ def is_annotation(obj):
class Annotation(object):
def __init__(self, help="", kind="positional", abbrev=None, type=str,
choices=None, metavar=None):
+ assert kind in ('positional', 'option', 'flag'), kind
if kind == "positional":
assert abbrev is None, abbrev
- else:
+ else: # option, flag
assert isinstance(abbrev, str) and len(abbrev) == 1, abbrev
self.help = help
self.kind = kind