summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2010-08-11 08:02:09 +0200
committerMichele Simionato <michele.simionato@gmail.com>2010-08-11 08:02:09 +0200
commit5d4b85b1ad7072125b3768890bb13c3c62a44b39 (patch)
tree2e62010153f25e507aeae0acafd4b426c6713a5d
parent4d370234721062eb9191f91a2ea22cb03230891e (diff)
downloadmicheles-5d4b85b1ad7072125b3768890bb13c3c62a44b39.tar.gz
Bug fixed plac.Interpreter.call and simplified import_main to work with factories
-rw-r--r--plac/CHANGES.txt1
-rw-r--r--plac/doc/plac.html1658
-rw-r--r--plac/doc/plac.pdf12709
-rw-r--r--plac/doc/plac_core.txt (renamed from plac/doc/plac.txt)0
-rw-r--r--plac/plac.py2
-rw-r--r--plac/plac_core.py16
-rw-r--r--plac/plac_ext.py63
7 files changed, 12442 insertions, 2007 deletions
diff --git a/plac/CHANGES.txt b/plac/CHANGES.txt
index fb7fa04..257bbc8 100644
--- a/plac/CHANGES.txt
+++ b/plac/CHANGES.txt
@@ -1,6 +1,7 @@
HISTORY
----------
+0.7.1 A few bug fixes (2010-08-11)
0.7.0 Improved and documented the support for parallel programming;
added an asynchronous server; added plac.Interpreter.call (2010-08-07)
0.6.1 Fixed the history file location; added the ability to pass a split
diff --git a/plac/doc/plac.html b/plac/doc/plac.html
index a634480..354af7a 100644
--- a/plac/doc/plac.html
+++ b/plac/doc/plac.html
@@ -4,9 +4,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
-<title>Plac: Parsing the Command Line the Easy Way</title>
-<meta name="author" content="Michele Simionato" />
-<meta name="date" content="July 2010" />
+<title></title>
<style type="text/css">
.first {
@@ -413,51 +411,79 @@ h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
</style>
</head>
<body>
-<div class="document" id="plac-parsing-the-command-line-the-easy-way">
-<h1 class="title">Plac: Parsing the Command Line the Easy Way</h1>
-<table class="docinfo" frame="void" rules="none">
-<col class="docinfo-name" />
-<col class="docinfo-content" />
+<div class="document">
+
+
+<div class="section" id="plac-parsing-the-command-line-the-easy-way">
+<h1><a class="toc-backref" href="#id53">Plac: Parsing the Command Line the Easy Way</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
<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 class="field"><th class="field-name">Author:</th><td class="field-body">Michele Simionato</td>
+</tr>
+<tr class="field"><th class="field-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><th class="docinfo-name">Date:</th>
-<td>July 2010</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 class="field"><th class="field-name">Date:</th><td class="field-body">July 2010</td>
</tr>
-<tr class="field"><th class="docinfo-name">Project page:</th><td class="field-body"><a class="reference external" href="http://micheles.googlecode.com/hg/plac/doc/plac.html">http://micheles.googlecode.com/hg/plac/doc/plac.html</a></td>
+<tr class="field"><th class="field-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">Requires:</th><td class="field-body">Python 2.3+</td>
+<tr class="field"><th class="field-name">Project page:</th><td class="field-body"><a class="reference external" href="http://micheles.googlecode.com/hg/plac/doc/plac.html">http://micheles.googlecode.com/hg/plac/doc/plac.html</a></td>
</tr>
-<tr class="field"><th class="docinfo-name">Installation:</th><td class="field-body"><tt class="docutils literal">easy_install <span class="pre">-U</span> plac</tt></td>
+<tr class="field"><th class="field-name">Requires:</th><td class="field-body">Python 2.3+</td>
</tr>
-<tr class="field"><th class="docinfo-name">License:</th><td class="field-body">BSD license</td>
+<tr class="field"><th class="field-name">Installation:</th><td class="field-body"><tt class="docutils literal">easy_install <span class="pre">-U</span> plac</tt></td>
+</tr>
+<tr class="field"><th class="field-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="#the-importance-of-scaling-down" id="id1">The importance of scaling down</a></li>
-<li><a class="reference internal" href="#scripts-with-required-arguments" id="id2">Scripts with required arguments</a></li>
-<li><a class="reference internal" href="#scripts-with-default-arguments" id="id3">Scripts with default arguments</a></li>
-<li><a class="reference internal" href="#scripts-with-options-and-smart-options" id="id4">Scripts with options (and smart options)</a></li>
-<li><a class="reference internal" href="#scripts-with-flags" id="id5">Scripts with flags</a></li>
-<li><a class="reference internal" href="#plac-for-python-2-x-users" id="id6">plac for Python 2.X users</a></li>
-<li><a class="reference internal" href="#more-features" id="id7">More features</a></li>
-<li><a class="reference internal" href="#a-realistic-example" id="id8">A realistic example</a></li>
-<li><a class="reference internal" href="#keyword-arguments" id="id9">Keyword arguments</a></li>
-<li><a class="reference internal" href="#final-example-a-shelve-interface" id="id10">Final example: a shelve interface</a></li>
-<li><a class="reference internal" href="#plac-vs-argparse" id="id11">plac vs argparse</a></li>
-<li><a class="reference internal" href="#plac-vs-the-rest-of-the-world" id="id12">plac vs the rest of the world</a></li>
-<li><a class="reference internal" href="#the-future" id="id13">The future</a></li>
-<li><a class="reference internal" href="#trivia-the-story-behind-the-name" id="id14">Trivia: the story behind the name</a></li>
+<li><a class="reference internal" href="#plac-parsing-the-command-line-the-easy-way" id="id18">Plac: Parsing the Command Line the Easy Way</a><ul>
+<li><a class="reference internal" href="#the-importance-of-scaling-down" id="id19">The importance of scaling down</a></li>
+<li><a class="reference internal" href="#scripts-with-required-arguments" id="id20">Scripts with required arguments</a></li>
+<li><a class="reference internal" href="#scripts-with-default-arguments" id="id21">Scripts with default arguments</a></li>
+<li><a class="reference internal" href="#scripts-with-options-and-smart-options" id="id22">Scripts with options (and smart options)</a></li>
+<li><a class="reference internal" href="#scripts-with-flags" id="id23">Scripts with flags</a></li>
+<li><a class="reference internal" href="#plac-for-python-2-x-users" id="id24">plac for Python 2.X users</a></li>
+<li><a class="reference internal" href="#more-features" id="id25">More features</a></li>
+<li><a class="reference internal" href="#a-realistic-example" id="id26">A realistic example</a></li>
+<li><a class="reference internal" href="#keyword-arguments" id="id27">Keyword arguments</a></li>
+<li><a class="reference internal" href="#final-example-a-shelve-interface" id="id28">Final example: a shelve interface</a></li>
+<li><a class="reference internal" href="#plac-vs-argparse" id="id29">plac vs argparse</a></li>
+<li><a class="reference internal" href="#plac-vs-the-rest-of-the-world" id="id30">plac vs the rest of the world</a></li>
+<li><a class="reference internal" href="#the-future" id="id31">The future</a></li>
+<li><a class="reference internal" href="#trivia-the-story-behind-the-name" id="id32">Trivia: the story behind the name</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#advanced-usages-of-plac" id="id33">Advanced usages of plac</a><ul>
+<li><a class="reference internal" href="#introduction" id="id34">Introduction</a></li>
+<li><a class="reference internal" href="#from-scripts-to-interactive-applications" id="id35">From scripts to interactive applications</a></li>
+<li><a class="reference internal" href="#testing-a-plac-application" id="id36">Testing a plac application</a></li>
+<li><a class="reference internal" href="#plac-easy-tests" id="id37">Plac easy tests</a></li>
+<li><a class="reference internal" href="#plac-batch-scripts" id="id38">Plac batch scripts</a></li>
+<li><a class="reference internal" href="#implementing-subcommands" id="id39">Implementing subcommands</a></li>
+<li><a class="reference internal" href="#plac-interpreter-call" id="id40">plac.Interpreter.call</a></li>
+<li><a class="reference internal" href="#readline-support" id="id41">Readline support</a></li>
+<li><a class="reference internal" href="#the-plac-runner" id="id42">The plac runner</a></li>
+<li><a class="reference internal" href="#a-non-class-based-example" id="id43">A non class-based example</a></li>
+<li><a class="reference internal" href="#writing-your-own-plac-runner" id="id44">Writing your own plac runner</a></li>
+<li><a class="reference internal" href="#long-running-commands" id="id45">Long running commands</a></li>
+<li><a class="reference internal" href="#threaded-commands" id="id46">Threaded commands</a></li>
+<li><a class="reference internal" href="#running-commands-as-external-processes" id="id47">Running commands as external processes</a></li>
+<li><a class="reference internal" href="#managing-the-output-of-concurrent-commands" id="id48">Managing the output of concurrent commands</a></li>
+<li><a class="reference internal" href="#parallel-computing-with-plac" id="id49">Parallel computing with plac</a></li>
+<li><a class="reference internal" href="#the-plac-server" id="id50">The plac server</a></li>
+<li><a class="reference internal" href="#summary" id="id51">Summary</a></li>
+<li><a class="reference internal" href="#appendix-custom-annotation-objects" id="id52">Appendix: custom annotation objects</a></li>
+</ul>
+</li>
</ul>
</div>
<div class="section" id="the-importance-of-scaling-down">
-<h1><a class="toc-backref" href="#id1">The importance of scaling down</a></h1>
+<h2><a class="toc-backref" href="#id54">The importance of scaling down</a></h2>
<p>There is no want of command line arguments parsers in the Python
world. The standard library alone contains three different modules:
<a class="reference external" href="http://docs.python.org/library/getopt.html">getopt</a> (from the stone age),
@@ -498,7 +524,7 @@ is designed to be simple to use and extremely concise, as the examples
below will show.</p>
</div>
<div class="section" id="scripts-with-required-arguments">
-<h1><a class="toc-backref" href="#id2">Scripts with required arguments</a></h1>
+<h2><a class="toc-backref" href="#id55">Scripts with required arguments</a></h2>
<p>Let me start with the simplest possible thing: a script that takes a
single argument and does something to it. It cannot get simpler
than that, unless you consider a script without command-line
@@ -592,7 +618,7 @@ optional arguments:
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="scripts-with-default-arguments">
-<h1><a class="toc-backref" href="#id3">Scripts with default arguments</a></h1>
+<h2><a class="toc-backref" href="#id56">Scripts with default arguments</a></h2>
<p>The need to have suitable defaults for command-line scripts is quite
common. For instance I have encountered this use case at work hundreds
of times:</p>
@@ -717,7 +743,7 @@ optional arguments:
I will show in the next paragraphs.</p>
</div>
<div class="section" id="scripts-with-options-and-smart-options">
-<h1><a class="toc-backref" href="#id4">Scripts with options (and smart options)</a></h1>
+<h2><a class="toc-backref" href="#id57">Scripts with options (and smart options)</a></h2>
<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 wrote (certainly more
@@ -841,7 +867,7 @@ executing 'select * from table' on dsn
</pre>
</div>
<div class="section" id="scripts-with-flags">
-<h1><a class="toc-backref" href="#id5">Scripts with flags</a></h1>
+<h2><a class="toc-backref" href="#id58">Scripts with flags</a></h2>
<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is able to recognize flags, i.e. boolean options which are
<tt class="docutils literal">True</tt> if they are passed to the command line and <tt class="docutils literal">False</tt>
if they are absent. Here is an example:</p>
@@ -890,7 +916,7 @@ the one-character abbreviation for options, since it does not make sense
to compose them.</p>
</div>
<div class="section" id="plac-for-python-2-x-users">
-<h1><a class="toc-backref" href="#id6">plac for Python 2.X users</a></h1>
+<h2><a class="toc-backref" href="#id59">plac for Python 2.X users</a></h2>
<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
think to migrate to Python 3. I am pretty much sure most Pythonistas
@@ -926,7 +952,7 @@ X &gt;= 4 and I will use the <tt class="docutils literal">plac.annotations</tt>
that the core features of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> run even on Python 2.3.</p>
</div>
<div class="section" id="more-features">
-<h1><a class="toc-backref" href="#id7">More features</a></h1>
+<h2><a class="toc-backref" href="#id60">More features</a></h2>
<p>One of the goals of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is to have a learning curve of <em>minutes</em> for
its core features, compared to the learning curve of <em>hours</em> of
<a class="reference external" href="http://argparse.googlecode.com">argparse</a>. In order to reach this goal, I have <em>not</em> sacrificed all
@@ -1041,7 +1067,7 @@ line as soon as available, whereas the default behaviour is to print
all the lines together and the end of the computation.</p>
</div>
<div class="section" id="a-realistic-example">
-<h1><a class="toc-backref" href="#id8">A realistic example</a></h1>
+<h2><a class="toc-backref" href="#id61">A realistic example</a></h2>
<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">type</tt> feature to automagically convert a SQLAlchemy connection
@@ -1105,7 +1131,7 @@ optional arguments:
<p>You can check for yourself that the script works.</p>
</div>
<div class="section" id="keyword-arguments">
-<h1><a class="toc-backref" href="#id9">Keyword arguments</a></h1>
+<h2><a class="toc-backref" href="#id62">Keyword arguments</a></h2>
<p>Starting from release 0.4, <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> supports keyword arguments. In
practice that means that if your main function has keyword arguments,
<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> treats specially arguments of the form <tt class="docutils literal">&quot;name=value&quot;</tt> in the
@@ -1165,7 +1191,7 @@ is a consequence of the way the argument names are managed in function calls
by the Python language.</p>
</div>
<div class="section" id="final-example-a-shelve-interface">
-<h1><a class="toc-backref" href="#id10">Final example: a shelve interface</a></h1>
+<h2><a class="toc-backref" href="#id63">Final example: a shelve interface</a></h2>
<p>Here is a less trivial example for the keyword arguments feature.
The use case is the following: suppose we have stored the
configuration parameters of a given application into a Python shelve
@@ -1287,7 +1313,7 @@ ishelve.py: error: unrecognized arguments: .cler
</pre>
</div>
<div class="section" id="plac-vs-argparse">
-<h1><a class="toc-backref" href="#id11">plac vs argparse</a></h1>
+<h2><a class="toc-backref" href="#id64">plac vs argparse</a></h2>
<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 an easy way. In particular you
should be aware of the following limitations/differences (the
@@ -1385,7 +1411,7 @@ adding such options to the <tt class="docutils literal">main</tt> function for y
attribute.</p>
</div>
<div class="section" id="plac-vs-the-rest-of-the-world">
-<h1><a class="toc-backref" href="#id12">plac vs the rest of the world</a></h1>
+<h2><a class="toc-backref" href="#id65">plac vs the rest of the world</a></h2>
<p>Originally <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> boasted about being &quot;the easiest command-line
arguments parser in the world&quot;. Since then, people started pointing
out to me various projects which are based on the same idea
@@ -1408,7 +1434,7 @@ Catherine Devlin. However, this is completely coincidental, since I became
aware of the <a class="reference external" href="http://packages.python.org/cmd2/">cmd2</a> module only after writing <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>.</p>
</div>
<div class="section" id="the-future">
-<h1><a class="toc-backref" href="#id13">The future</a></h1>
+<h2><a class="toc-backref" href="#id66">The future</a></h2>
<p>Currently the core of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is around 200 lines of code, not counting blanks,
comments and docstrings. I do not plan to extend the core much in the
future. The idea is to keep the module short: it is and it should
@@ -1429,7 +1455,7 @@ they require Python 2.5 to work, whereas <tt class="docutils literal">plac_core.
Python 2.3.</p>
</div>
<div class="section" id="trivia-the-story-behind-the-name">
-<h1><a class="toc-backref" href="#id14">Trivia: the story behind the name</a></h1>
+<h2><a class="toc-backref" href="#id67">Trivia: the story behind the name</a></h2>
<p>The <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> project started very humbly: 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
@@ -1457,5 +1483,1545 @@ will steal it from me!</p>
<p>That's all, I hope you will enjoy working with <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>!</p>
</div>
</div>
+<div class="section" id="advanced-usages-of-plac">
+<h1><a class="toc-backref" href="#id68">Advanced usages of plac</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Author:</th><td class="field-body">Michele Simionato</td>
+</tr>
+<tr class="field"><th class="field-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="field-name">Date:</th><td class="field-body">August 2010</td>
+</tr>
+<tr class="field"><th class="field-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="field-name">Project page:</th><td class="field-body"><a class="reference external" href="http://micheles.googlecode.com/hg/plac/doc/plac.html">http://micheles.googlecode.com/hg/plac/doc/plac.html</a></td>
+</tr>
+<tr class="field"><th class="field-name">Installation:</th><td class="field-body"><tt class="docutils literal">easy_install <span class="pre">-U</span> plac</tt></td>
+</tr>
+<tr class="field"><th class="field-name">License:</th><td class="field-body">BSD license</td>
+</tr>
+<tr class="field"><th class="field-name">Requires:</th><td class="field-body">Python 2.5+</td>
+</tr>
+</tbody>
+</table>
+<p><em>The present document discusses a few of the advanced use
+cases for plac. It shows how to write interactive and non-interactive
+interpreters with plac, and how to use plac for testing and scripting a generic
+application. It assumes you have already read an understood the
+basic documentation.</em></p>
+<div class="contents topic" id="id1">
+<p class="topic-title first">Contents</p>
+<ul class="simple">
+<li><a class="reference internal" href="#plac-parsing-the-command-line-the-easy-way" id="id53">Plac: Parsing the Command Line the Easy Way</a><ul>
+<li><a class="reference internal" href="#the-importance-of-scaling-down" id="id54">The importance of scaling down</a></li>
+<li><a class="reference internal" href="#scripts-with-required-arguments" id="id55">Scripts with required arguments</a></li>
+<li><a class="reference internal" href="#scripts-with-default-arguments" id="id56">Scripts with default arguments</a></li>
+<li><a class="reference internal" href="#scripts-with-options-and-smart-options" id="id57">Scripts with options (and smart options)</a></li>
+<li><a class="reference internal" href="#scripts-with-flags" id="id58">Scripts with flags</a></li>
+<li><a class="reference internal" href="#plac-for-python-2-x-users" id="id59">plac for Python 2.X users</a></li>
+<li><a class="reference internal" href="#more-features" id="id60">More features</a></li>
+<li><a class="reference internal" href="#a-realistic-example" id="id61">A realistic example</a></li>
+<li><a class="reference internal" href="#keyword-arguments" id="id62">Keyword arguments</a></li>
+<li><a class="reference internal" href="#final-example-a-shelve-interface" id="id63">Final example: a shelve interface</a></li>
+<li><a class="reference internal" href="#plac-vs-argparse" id="id64">plac vs argparse</a></li>
+<li><a class="reference internal" href="#plac-vs-the-rest-of-the-world" id="id65">plac vs the rest of the world</a></li>
+<li><a class="reference internal" href="#the-future" id="id66">The future</a></li>
+<li><a class="reference internal" href="#trivia-the-story-behind-the-name" id="id67">Trivia: the story behind the name</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#advanced-usages-of-plac" id="id68">Advanced usages of plac</a><ul>
+<li><a class="reference internal" href="#introduction" id="id69">Introduction</a></li>
+<li><a class="reference internal" href="#from-scripts-to-interactive-applications" id="id70">From scripts to interactive applications</a></li>
+<li><a class="reference internal" href="#testing-a-plac-application" id="id71">Testing a plac application</a></li>
+<li><a class="reference internal" href="#plac-easy-tests" id="id72">Plac easy tests</a></li>
+<li><a class="reference internal" href="#plac-batch-scripts" id="id73">Plac batch scripts</a></li>
+<li><a class="reference internal" href="#implementing-subcommands" id="id74">Implementing subcommands</a></li>
+<li><a class="reference internal" href="#plac-interpreter-call" id="id75">plac.Interpreter.call</a></li>
+<li><a class="reference internal" href="#readline-support" id="id76">Readline support</a></li>
+<li><a class="reference internal" href="#the-plac-runner" id="id77">The plac runner</a></li>
+<li><a class="reference internal" href="#a-non-class-based-example" id="id78">A non class-based example</a></li>
+<li><a class="reference internal" href="#writing-your-own-plac-runner" id="id79">Writing your own plac runner</a></li>
+<li><a class="reference internal" href="#long-running-commands" id="id80">Long running commands</a></li>
+<li><a class="reference internal" href="#threaded-commands" id="id81">Threaded commands</a></li>
+<li><a class="reference internal" href="#running-commands-as-external-processes" id="id82">Running commands as external processes</a></li>
+<li><a class="reference internal" href="#managing-the-output-of-concurrent-commands" id="id83">Managing the output of concurrent commands</a></li>
+<li><a class="reference internal" href="#parallel-computing-with-plac" id="id84">Parallel computing with plac</a></li>
+<li><a class="reference internal" href="#the-plac-server" id="id85">The plac server</a></li>
+<li><a class="reference internal" href="#summary" id="id86">Summary</a></li>
+<li><a class="reference internal" href="#appendix-custom-annotation-objects" id="id87">Appendix: custom annotation objects</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h2><a class="toc-backref" href="#id69">Introduction</a></h2>
+<p>One of the design goals of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is to make it dead easy to write a
+scriptable and testable interface for an application. You can use
+<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> whenever you have an API with strings in input and strings in
+output, and that includes a <em>huge</em> domain of applications.</p>
+<p>A string-oriented interface is a scriptable interface by
+construction. That means that you can define a command language for
+your application and that it is possible to write scripts which are
+interpretable by <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> and can be run as batch scripts.</p>
+<p>Actually, at the most general level, you can see <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> as a generic tool to
+write domain specific languages (DSL). With <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> you
+can test your application interactively as well as with batch
+scripts, and even with the analogous of Python doctests for your
+defined language.</p>
+<p>You can easily replace the <tt class="docutils literal">cmd</tt> module of the standard library and
+you could easily write an application like <a class="reference external" href="http://twill.idyll.org/">twill</a> with <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>. Or you
+could use it to script your building procedure. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> also supports
+parallel execution of multiple commands and can be used as
+task manager and monitor. It is also quite easy to build a GUI
+or a Web application on top of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>. When speaking of things
+you can do with <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>, your imagination is the only limit!</p>
+</div>
+<div class="section" id="from-scripts-to-interactive-applications">
+<h2><a class="toc-backref" href="#id70">From scripts to interactive applications</a></h2>
+<p>Command-line scripts have many advantages, but they are no substitute
+for interactive applications.
+In particular, if you have a script with a large startup time which must be run
+multiple times, it is best to turn it into an interactive application,
+so that the startup is performed only once. <tt class="docutils literal">plac</tt> provides an
+<tt class="docutils literal">Interpreter</tt> class just for this purpose.</p>
+<p>The <tt class="docutils literal">Interpreter</tt> class wraps the main function of a script and
+provides an <tt class="docutils literal">.interact</tt> method to start an interactive interpreter
+reading commands from the console.</p>
+<p>For instance, you can define an interactive interpreter on top of the
+<tt class="docutils literal">ishelve</tt> script introduced in the <a class="reference external" href="http://micheles.googlecode.com/hg/plac/doc/plac.html">basic documentation</a> as
+follows:</p>
+<pre class="literal-block">
+# shelve_interpreter.py
+import plac, ishelve
+
+&#64;plac.annotations(
+ interactive=('start interactive interface', 'flag'),
+ subcommands='the commands of the underlying ishelve interpreter')
+def main(interactive, *subcommands):
+ &quot;&quot;&quot;
+ This script works both interactively and non-interactively.
+ Use .help to see the internal commands.
+ &quot;&quot;&quot;
+ if interactive:
+ plac.Interpreter(ishelve.main).interact()
+ else:
+ for out in plac.call(ishelve.main, subcommands):
+ print(out)
+
+if __name__ == '__main__':
+ plac.call(main)
+
+</pre>
+<p>A trick has been used here: the ishelve command-line interface has been
+hidden inside an external interface. They are distinct: for instance
+the external interface recognizes the <tt class="docutils literal"><span class="pre">-h/--help</span></tt> flag whereas the
+internal interface only recognizes the <tt class="docutils literal">.help</tt> command:</p>
+<pre class="literal-block">
+$ python shelve_interpreter.py -h
+</pre>
+<pre class="literal-block">
+usage: shelve_interpreter.py [-h] [-interactive]
+ [subcommands [subcommands ...]]
+
+ This script works both interactively and non-interactively.
+ Use .help to see the internal commands.
+
+
+positional arguments:
+ subcommands the commands of the underlying ishelve interpreter
+
+optional arguments:
+ -h, --help show this help message and exit
+ -interactive start interactive interface
+
+</pre>
+<p>Thanks to this ingenuous trick, the script can be run both interactively
+and non-interactively:</p>
+<pre class="literal-block">
+$ python shelve_interpreter.py .clear # non-interactive use
+cleared the shelve
+</pre>
+<p>Here is an usage session:</p>
+<pre class="literal-block">
+$ python shelve_interpreter.py -i # interactive use
+A simple interface to a shelve. Use .help to see the available commands.
+i&gt; .help
+Commands: .help, .showall, .clear, .delete
+&lt;param&gt; ...
+&lt;param=value&gt; ...
+i&gt; a=1
+setting a=1
+i&gt; a
+1
+i&gt; b=2
+setting b=2
+i&gt; a b
+1
+2
+i&gt; .del a
+deleted a
+i&gt; a
+a: not found
+i&gt; .show
+b=2
+i&gt; [CTRL-D]
+</pre>
+<p>The <tt class="docutils literal">.interact</tt> method
+reads commands from the console and send them to the
+underlying interpreter, until the user send a CTRL-D
+command (CTRL-Z in Windows). There is a default
+argument <tt class="docutils literal"><span class="pre">prompt='i&gt;</span> '</tt> which
+can be used to change the prompt. The text displayed at the beginning
+of the interactive session is the docstring of the main function.
+<tt class="docutils literal">plac</tt> also understands command abbreviations: in this example
+<tt class="docutils literal">del</tt> is an abbreviation for <tt class="docutils literal">delete</tt>. In case of ambiguous
+abbreviations <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> raises a <tt class="docutils literal">NameError</tt>.</p>
+<p>Finally I must notice that the <tt class="docutils literal">plac.Interpreter</tt> is available only if you
+are using a recent version of Python (&gt;= 2.5), because it is a context
+manager object which uses extended generators internally.</p>
+</div>
+<div class="section" id="testing-a-plac-application">
+<h2><a class="toc-backref" href="#id71">Testing a plac application</a></h2>
+<p>You can conveniently test your application in interactive mode.
+However manual testing is a poor substitute for automatic testing.</p>
+<p>In principle, one could write automatic tests for the
+<tt class="docutils literal">ishelve</tt> application by using <tt class="docutils literal">plac.call</tt> directly:</p>
+<pre class="literal-block">
+# test_ishelve.py
+import plac, ishelve
+
+def test():
+ assert plac.call(ishelve.main, ['.clear']) == ['cleared the shelve']
+ assert plac.call(ishelve.main, ['a=1']) == ['setting a=1']
+ assert plac.call(ishelve.main, ['a']) == ['1']
+ assert plac.call(ishelve.main, ['.delete=a']) == ['deleted a']
+ assert plac.call(ishelve.main, ['a']) == ['a: not found']
+
+if __name__ == '__main__':
+ test()
+
+</pre>
+<p>However, using <tt class="docutils literal">plac.call</tt> is not especially nice. The big
+issue is that <tt class="docutils literal">plac.call</tt> responds to invalid input by printing an
+error message on stderr and by raising a <tt class="docutils literal">SystemExit</tt>: this is
+certainly not a nice thing to do in a test.</p>
+<p>As a consequence of this behavior it is impossible to test for invalid
+commands, unless you wrap the <tt class="docutils literal">SystemExit</tt> exception by
+hand each time (a possibly you do something with the error message in
+stderr too). Luckily, <tt class="docutils literal">plac</tt> offers a better testing support through
+the <tt class="docutils literal">check</tt> method of <tt class="docutils literal">Interpreter</tt> objects:</p>
+<pre class="literal-block">
+# test_ishelve_more.py
+from __future__ import with_statement
+import plac, ishelve
+
+def test():
+ with plac.Interpreter(ishelve.main) as i:
+ i.check('.clear', 'cleared the shelve')
+ i.check('a=1', 'setting a=1')
+ i.check('a', '1')
+ i.check('.delete=a', 'deleted a')
+ i.check('a', 'a: not found')
+
+</pre>
+<p>The method <tt class="docutils literal">.check(given_input, expected_output)</tt> works on strings
+and raises an <tt class="docutils literal">AssertionError</tt> if the output produced by the
+interpreter is different from the expected output for the given input.
+Notice that <tt class="docutils literal">AssertionError</tt> is catched by tools like <tt class="docutils literal">py.test</tt> and
+<tt class="docutils literal">nosetests</tt> and actually <tt class="docutils literal">plac</tt> tests are intended to be run with
+such tools.</p>
+<p>Interpreters offer a minor syntactic advantage with respect to calling
+<tt class="docutils literal">plac.call</tt> directly, but they offer a <em>major</em> semantic advantage when things
+go wrong (read exceptions): an <tt class="docutils literal">Interpreter</tt> object internally invokes
+something like <tt class="docutils literal">plac.call</tt>, but it wraps all exceptions, so that <tt class="docutils literal">i.check</tt>
+is guaranteed not to raise any exception except <tt class="docutils literal">AssertionError</tt>.</p>
+<p>Even the <tt class="docutils literal">SystemExit</tt> exception is captured and you can write your test as</p>
+<blockquote>
+<tt class="docutils literal"><span class="pre">i.check('-cler',</span> 'SystemExit: unrecognized arguments: <span class="pre">-cler')</span></tt></blockquote>
+<p>without risk of exiting from the Python interpreter.</p>
+<p>There is a second advantage of interpreters: if the main function contains some
+initialization code and finalization code
+(<tt class="docutils literal">__enter__</tt> and <tt class="docutils literal">__exit__</tt> functions) they will be run only
+once at the beginning and at the end of the interpreter loop.
+<tt class="docutils literal">plac.call</tt> instead ignores the initialization/finalization code.</p>
+</div>
+<div class="section" id="plac-easy-tests">
+<h2><a class="toc-backref" href="#id72">Plac easy tests</a></h2>
+<p>Writing your tests in terms of <tt class="docutils literal">Interpreter.check</tt> is certainly an
+improvement over writing them in terms of <tt class="docutils literal">plac.call</tt>, but they
+are still too low-level for my taste. The <tt class="docutils literal">Interpreter</tt> class provides
+support for doctest-style tests, a.k.a. <em>plac easy tests</em>.</p>
+<p>By using plac easy tests you can cut and paste your interactive session and
+turn it into a runnable automatics test.
+Consider for instance the following file <tt class="docutils literal">ishelve.placet</tt> (the <tt class="docutils literal">.placet</tt>
+extension is a mnemonic for plac easy tests):</p>
+<pre class="literal-block">
+#!ishelve.py
+i&gt; .clear # start from a clean state
+cleared the shelve
+i&gt; a=1
+setting a=1
+i&gt; a
+1
+i&gt; .del a
+deleted a
+i&gt; a
+a: not found
+i&gt; .cler # spelling error
+.cler: not found
+
+</pre>
+<p>Notice the precence of the shebang line containing the name of the
+<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> tool to test (a <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> tool is just a Python module with a
+function called <tt class="docutils literal">main</tt>). The shebang is ignored by the interpreter
+(it looks like a comment to it) but it is there so that external
+tools (say a test runner) can infer the plac interpreter
+to use to test the file.</p>
+<p>You can test <tt class="docutils literal">ishelve.placet</tt> file by calling the
+<tt class="docutils literal">.doctest</tt> method of the interpreter, as in this example:</p>
+<pre class="literal-block">
+$ python -c&quot;import plac, ishelve
+plac.Interpreter(ishelve.main).doctest(open('ishelve.placet'), verbose=True)&quot;
+</pre>
+<p>Internally <tt class="docutils literal">Interpreter.doctests</tt> invokes something like <tt class="docutils literal">Interpreter.check</tt>
+multiple times inside the same context and compare the output with the
+expected output: if even a check fails, the whole test fail.</p>
+<p>You should realize tha the easy tests supported by <tt class="docutils literal">plac</tt> are <em>not</em>
+unittests: they are functional tests. They model then user interaction and the
+order of the operations generally matters. The single subtests in a
+<tt class="docutils literal">.placet</tt> file are not independent and it makes sense to exit
+immediately at the first failure.</p>
+<p>The support for doctests in <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> comes nearly for free, thanks to the
+<a class="reference external" href="http://docs.python.org/library/shlex.html">shlex</a> module in the standard library, which is able to parse simple
+languages as the ones you can implement with <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>. In particular,
+thanks to <a class="reference external" href="http://docs.python.org/library/shlex.html">shlex</a>, <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is able to recognize comments (the default
+comment character is <tt class="docutils literal">#</tt>), escape sequences and more. Look at the
+<a class="reference external" href="http://docs.python.org/library/shlex.html">shlex</a> documentation if you need to customize how the language is
+interpreted. For more flexibility, it is even possible to pass to the
+interpreter a custom split function with signature <tt class="docutils literal">split(line,
+commentchar)</tt>.</p>
+<p>In addition, I have implemented from scratch some support for line number
+recognition, so that if a test fail you get the line number of the
+failing command. This is especially useful if your tests are
+stored in external files, even if plac easy tests does not need to be in
+a file: you can just pass to the <tt class="docutils literal">.doctest</tt> method a list of
+strings corresponding to the lines of the file.</p>
+<p>At the present <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not use any code from the doctest
+module, but the situation may change in the future (it would be nice
+if <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> could reuse doctests directives like ELLIPSIS).</p>
+<p>It is straighforward to integrate your <tt class="docutils literal">.placet</tt> tests with standard
+testing tools. For instance, you can integrate your doctests with <tt class="docutils literal">nose</tt>
+or <tt class="docutils literal">py.test</tt> as follow:</p>
+<pre class="literal-block">
+import os, shlex, plac
+
+def test_doct():
+ &quot;&quot;&quot;
+ Find all the doctests in the current directory and run them with the
+ corresponding plac interpreter (the shebang rules!)
+ &quot;&quot;&quot;
+ placets = [f for f in os.listdir('.') if f.endswith('.placet')]
+ for placet in placets:
+ lines = list(open(placet))
+ assert lines[0].startswith('#!'), 'Missing or incorrect shebang line!'
+ firstline = lines[0][2:] # strip the shebang
+ main = plac.import_main(*shlex.split(firstline))
+ yield plac.Interpreter(main).doctest, lines[1:]
+</pre>
+<p>Here you should notice that usage of <tt class="docutils literal">plac.import_main</tt>, an utility
+which is able to import the main function of the script specified in
+the shebang line. You can use both the full path name of the
+tool, or a relative path name. In this case the runner look at the
+environment variable <tt class="docutils literal">PLACPATH</tt> and it searches
+the plac tool in the directories specified there (<tt class="docutils literal">PLACPATH</tt> is just
+a string containing directory names separated by colons). If the variable
+<tt class="docutils literal">PLACPATH</tt> is not defined, it just looks in the current directory.
+If the plac tool is not found, an <tt class="docutils literal">ImportError</tt> is raised.</p>
+</div>
+<div class="section" id="plac-batch-scripts">
+<h2><a class="toc-backref" href="#id73">Plac batch scripts</a></h2>
+<p>It is pretty easy to realize that an interactive interpreter can
+also be used to run batch scripts: instead of reading the commands from
+the console, it is enough to read the commands from a file.
+<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> interpreters provide an <tt class="docutils literal">.execute</tt> method to perform just that.</p>
+<p>There is just a subtle point to notice: whereas in an interactive loop
+one wants to manage all exceptions, a batch script should not in the
+background in case of unexpected errors. The implementation of
+<tt class="docutils literal">Interpreter.execute</tt> makes sure that any error raised by
+<tt class="docutils literal">plac.call</tt> internally is re-raised. In other words, <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>
+interpreters <em>wrap the errors, but does not eat them</em>: the errors are
+always accessible and can be re-raised on demand.</p>
+<p>The exception is the case of invalid commands, which are skipped.
+Consider for instance the following batch file, which contains a
+mispelled command (<tt class="docutils literal">.dl</tt> instead of <tt class="docutils literal">.del</tt>):</p>
+<pre class="literal-block">
+#!ishelve.py
+.clear
+a=1 b=2
+.show
+.del a
+.dl b
+.show
+
+</pre>
+<p>If you execute the batch file, the interpreter will print a <tt class="docutils literal">.dl: not found</tt>
+at the <tt class="docutils literal">.dl</tt> line and will continue:</p>
+<pre class="literal-block">
+$ python -c &quot;import plac, ishelve
+plac.Interpreter(ishelve.main).execute(open('ishelve.plac'), verbose=True)&quot;
+i&gt; .clear
+cleared the shelve
+i&gt; a=1 b=2
+setting a=1
+setting b=2
+i&gt; .show
+b=2
+a=1
+i&gt; .del a
+deleted a
+i&gt; .dl b
+2
+.dl: not found
+i&gt; .show
+b=2
+</pre>
+<p>The <tt class="docutils literal">verbose</tt> flag is there to show the lines which are being interpreted
+(prefixed by <tt class="docutils literal">i&gt;</tt>). This is done on purpose, so that you can cut and paste
+the output of the batch script and turn it into a <tt class="docutils literal">.placet</tt> test
+(cool, isn't it?).</p>
+</div>
+<div class="section" id="implementing-subcommands">
+<h2><a class="toc-backref" href="#id74">Implementing subcommands</a></h2>
+<p>When I discussed the <tt class="docutils literal">ishelve</tt> implementation in the <a class="reference external" href="http://micheles.googlecode.com/hg/plac/doc/plac.html">basic
+documentation</a>, I said that it looked like a poor man implementation
+of an object system as a chain of elifs; I also said that <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> was
+able to do much better than that. Here I will substantiate my claim.</p>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is actually able to infer a set of subparsers from a
+generic container of commands. This is useful if you want to
+implement <em>subcommands</em> (a familiar example of a command-line
+application featuring subcommands is subversion).</p>
+<p>Technically a container of commands is any object with a <tt class="docutils literal">.commands</tt> attribute
+listing a set of functions or methods which are valid commands. A command
+container may have initialization/finalization hooks (<tt class="docutils literal">__enter__/__exit__</tt>)
+and dispatch hooks (<tt class="docutils literal">__missing__</tt>, invoked for invalid command names).
+Moreover, only when using command containers <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is able to provide
+automatic autocompletion of commands.</p>
+<p>The shelve interface can be rewritten in an object-oriented way as follows:</p>
+<pre class="literal-block">
+# ishelve2.py
+import shelve, os, sys, plac
+
+class ShelveInterface(object):
+ &quot;A minimal interface over a shelve object.&quot;
+ commands = 'set', 'show', 'showall', 'delete'
+ &#64;plac.annotations(
+ configfile=('path name of the shelve', 'option'))
+ def __init__(self, configfile):
+ self.configfile = configfile or '~/conf.shelve'
+ self.fname = os.path.expanduser(self.configfile)
+ self.__doc__ += '\nOperating on %s.\n.help to see '\
+ 'the available commands.\n' % self.fname
+ def __enter__(self):
+ self.sh = shelve.open(self.fname)
+ return self
+ def __exit__(self, etype, exc, tb):
+ self.sh.close()
+ def set(self, name, value):
+ &quot;set name value&quot;
+ yield 'setting %s=%s' % (name, value)
+ self.sh[name] = value
+ def show(self, *names):
+ &quot;show given parameters&quot;
+ for name in names:
+ yield '%s = %s' % (name, self.sh[name]) # no error checking
+ def showall(self):
+ &quot;show all parameters&quot;
+ for name in self.sh:
+ yield '%s = %s' % (name, self.sh[name])
+ def delete(self, name=None):
+ &quot;delete given parameter (or everything)&quot;
+ if name is None:
+ yield 'deleting everything'
+ self.sh.clear()
+ else:
+ yield 'deleting %s' % name
+ del self.sh[name] # no error checking
+
+main = ShelveInterface # useful for the tests
+
+if __name__ == '__main__':
+ plac.Interpreter(plac.call(ShelveInterface)).interact()
+
+</pre>
+<p><tt class="docutils literal">plac.Interpreter</tt> objects wrap context manager objects
+consistently. In other words, if you wrap an object with
+<tt class="docutils literal">__enter__</tt> and <tt class="docutils literal">__exit__</tt> methods, they are invoked in the right
+order (<tt class="docutils literal">__enter__</tt> before the interpreter loop starts and
+<tt class="docutils literal">__exit__</tt> after the interpreter loop ends, both in the regular and
+in the exceptional case). In our example, the methods <tt class="docutils literal">__enter__</tt>
+and <tt class="docutils literal">__exit__</tt> make sure the the shelve is opened and closed
+correctly even in the case of exceptions. Notice that I have not
+implemented any error checking in the <tt class="docutils literal">show</tt> and <tt class="docutils literal">delete</tt> methods
+on purpose, to verify that <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> works correctly in the presence of
+exceptions.</p>
+<p>When working with command containers, <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> automatically adds two
+special commands to the set of provided commands: <tt class="docutils literal">.help</tt>
+and <tt class="docutils literal">.last_tb</tt>. The <tt class="docutils literal">.help</tt> command is the easier to understand:
+when invoked without arguments it displays the list of available commands
+with the same formatting of the <a class="reference external" href="http://docs.python.org/library/cmd.html">cmd</a> module; when invoked with the name of
+a command it displays the usage message for that command.
+The <tt class="docutils literal">.last_tb</tt> command is useful when debugging: in case of errors,
+it allows you to display the traceback of the last executed command.</p>
+<p>Here is a session of usage on an Unix-like operating system:</p>
+<pre class="literal-block">
+$ python ishelve2.py
+A minimal interface over a shelve object.
+Operating on /home/micheles/conf.shelve.
+.help to see the available commands.
+i&gt; .help
+
+special commands
+================
+.help .last_tb
+
+custom commands
+===============
+delete set show showall
+
+i&gt; delete
+deleting everything
+i&gt; set a pippo
+setting a=pippo
+i&gt; set b lippo
+setting b=lippo
+i&gt; showall
+b = lippo
+a = pippo
+i&gt; show a b
+a = pippo
+b = lippo
+i&gt; del a
+deleting a
+i&gt; showall
+b = lippo
+i&gt; delete a
+deleting a
+KeyError: 'a'
+i&gt; .last_tb
+ File &quot;/usr/local/lib/python2.6/dist-packages/plac-0.6.0-py2.6.egg/plac_ext.py&quot;, line 190, in _wrap
+ for value in genobj:
+ File &quot;./ishelve2.py&quot;, line 37, in delete
+ del self.sh[name] # no error checking
+ File &quot;/usr/lib/python2.6/shelve.py&quot;, line 136, in __delitem__
+ del self.dict[key]
+i&gt;
+</pre>
+<p>Notice that in interactive mode the traceback is hidden, unless
+you pass the <tt class="docutils literal">verbose</tt> flag to the <tt class="docutils literal">Interpreter.interact</tt> method.</p>
+</div>
+<div class="section" id="plac-interpreter-call">
+<h2><a class="toc-backref" href="#id75">plac.Interpreter.call</a></h2>
+<p>At the core of <tt class="docutils literal">plac</tt> there is the <tt class="docutils literal">call</tt> function which invokes
+a callable with the list of the arguments passed at the command-line
+(<tt class="docutils literal">sys.argv[1:]</tt>). Thanks to <tt class="docutils literal">plac.call</tt> you can launch your module
+by simply adding the lines:</p>
+<pre class="literal-block">
+if __name__ == '__main__':
+ plac.call(main)
+</pre>
+<p>Everything works fine if <tt class="docutils literal">main</tt> is a simple callable performing some
+action; however, in many cases, one has a <tt class="docutils literal">main</tt> &quot;function&quot; which
+is a actually a factory returning a command container object. For
+instance, in my second shelve example the main function is the class
+<tt class="docutils literal">ShelveInterface</tt>, and the two lines needed to run the module are
+a bit ugly:</p>
+<pre class="literal-block">
+if __name__ == '__main__':
+ plac.Interpreter(plac.call(ShelveInterface)).interact()
+</pre>
+<p>Moreover, now the program runs, but only in interactive mode, i.e.
+it is not possible to run it as a script. It would be nice instead
+to be able to specify the command to execute on the command-line
+and have the interpreter start, execute the command and finish
+properly (I mean by calling <tt class="docutils literal">__enter__</tt> and <tt class="docutils literal">__exit__</tt>)
+without needing user input. The the script could be called from
+a batch shell script working in the background.
+In order to provide such functionality <tt class="docutils literal">plac.Interpreter</tt> provides
+a classmethod named <tt class="docutils literal">.call</tt> which takes the factory, instantiates
+it with the arguments read from the command line, wraps the resulting
+container object as an interpreter and runs it with the rest arguments
+found in the command line. Here is the code to turn the <tt class="docutils literal">ShelveInterface</tt>
+into a script</p>
+<pre class="literal-block">
+# ishelve3.py
+from ishelve2 import ShelveInterface as main
+
+if __name__ == '__main__':
+ import plac; plac.Interpreter.call(main)
+
+</pre>
+<p>and here are a few examples of usage:</p>
+<pre class="literal-block">
+$ python ishelve3.py -h
+</pre>
+<pre class="literal-block">
+usage: ishelve3.py [-h] [-configfile CONFIGFILE]
+
+A minimal interface over a shelve object.
+
+optional arguments:
+ -h, --help show this help message and exit
+ -configfile CONFIGFILE
+ path name of the shelve
+
+</pre>
+<pre class="literal-block">
+$ python ishelve3.py set a 1
+setting a=1
+$ python ishelve3.py show a
+a = 1
+</pre>
+<p>If you do not pass enough arguments in the command line, then the
+script will automatically enter in interactive mode and ask the user
+for the command to execute:</p>
+<pre class="literal-block">
+$ python ishelve3.py
+A minimal interface over a shelve object.
+Operating on /home/micheles/conf.shelve.
+.help to see the available commands.
+
+i&gt;
+</pre>
+<p>In a sense, I have closed the circle: at the beginning of this
+document I discussed how to turn a script into an interactive
+application (the <tt class="docutils literal">shelve_interpreter.py</tt> example), whereas here I
+have show how to turn an interactive application into a script.</p>
+<p>The complete signature of <tt class="docutils literal">plac.Interpreter.call</tt> is the following:</p>
+<pre class="literal-block">
+call(factory, arglist=sys.argv[1:],
+ commentchar='#', split=shlex.split,
+ stdin=sys.stdin, prompt='i&gt; ', verbose=False)
+</pre>
+<p>The factory must have a fixed number of positional arguments (no
+default arguments, no varargs, no kwargs), otherwise a <tt class="docutils literal">TypeError</tt>
+is raised: the reason is that we want to be able to distinguish the
+command-line arguments needed to instantiate the factory from the rest
+arguments that must be sent to the corresponding interpreter object.
+It is also possible to specify a list of arguments different from
+<tt class="docutils literal">sys.argv[1:]</tt> (useful in tests), the character to be recognized as
+a comment, the splitting function, the input source and the prompt to
+use while in interactive mode, and a verbose flag.</p>
+</div>
+<div class="section" id="readline-support">
+<h2><a class="toc-backref" href="#id76">Readline support</a></h2>
+<p>Starting from release 0.6 <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> offers full readline support. That
+means that if your Python was compiled with readline support you get
+autocompletion and persistent command history for free. By default
+all commands are autocomplete in a case sensitive way. If you want to
+add new words to the autocompletion set, or you want to change the
+location of the <tt class="docutils literal">.history</tt> file, or to change the case sensitivity,
+the way to go is to pass a <tt class="docutils literal">plac.ReadlineInput</tt> object to the
+interpreter. Here is an example, assuming you want to build a
+database interface understanding SQL commands:</p>
+<pre class="literal-block">
+import os, plac
+from sqlalchemy.ext.sqlsoup import SqlSoup
+
+SQLKEYWORDS = set(['select', 'from', 'inner', 'join', 'outer', 'left', 'right']
+ ) # and many others
+DBTABLES = set(['table1', 'table2']) # you can read them from the db schema
+
+COMPLETIONS = SQLKEYWORDS | DBTABLES
+
+class SqlInterface(object):
+ commands = ['SELECT']
+ def __init__(self, dsn):
+ self.soup = SqlSoup(dsn)
+ def SELECT(self, argstring):
+ sql = 'SELECT ' + argstring
+ for row in self.soup.bind.execute(sql):
+ yield str(row) # the formatting can be much improved
+
+rl_input = plac.ReadlineInput(
+ COMPLETIONS, histfile=os.path.expanduser('~/.sql_interface.history'),
+ case_sensitive=False)
+
+def split_on_first_space(line, commentchar):
+ return line.strip().split(' ', 1) # ignoring comments
+
+if __name__ == '__main__':
+ plac.Interpreter.call(SqlInterface, split=split_on_first_space,
+ stdin=rl_input, prompt='sql&gt; ')
+
+</pre>
+<p>Here is an example of usage:</p>
+<pre class="literal-block">
+$ python sql_interface.py &lt;some dsn&gt;
+sql&gt; SELECT a.* FROM TABLE1 AS a INNER JOIN TABLE2 AS b ON a.id = b.id
+...
+</pre>
+<p>You can check that entering just <tt class="docutils literal">sel</tt> and pressing TAB the readline library
+completes the <tt class="docutils literal">SELECT</tt> keyword for you and makes it upper case; idem for
+<tt class="docutils literal">FROM</tt>, <tt class="docutils literal">INNER</tt>, <tt class="docutils literal">JOIN</tt> and even for the names of the tables. An
+obvious improvement is to read the names of the tables by introspecting
+the database: actually you can even read the names of the views and of
+the columns, and have full autocompletion. All the entered commands
+and recorded and saved in the file <tt class="docutils literal"><span class="pre">~/.sql_interface.history</span></tt> when
+exiting from the command-line interface.</p>
+<p>If the readline library is not available, my suggestion is to use the
+<a class="reference external" href="http://freshmeat.net/projects/rlwrap/">rlwrap</a> tool which provides similar features, at least on Unix-like
+platforms. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> should also work fine on Windows with the <a class="reference external" href="http://ipython.scipy.org/moin/PyReadline/Intro">pyreadline</a>
+library (I do not use Windows, so this part is very little tested: I
+tried it only once and it worked, but your mileage may vary).
+For people worried about licenses, I will notice that <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> uses the
+readline library only if available, it does not include it and it does
+not rely on it in any fundamental way, so that the <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> licence does
+not need to be the GPL (actually it is a BSD
+do-whatever-you-want-with-it licence).</p>
+<p>The interactive mode of <tt class="docutils literal">plac</tt> can be used as a replacement of the
+<a class="reference external" href="http://docs.python.org/library/cmd.html">cmd</a> module in the standard library. It is actually better than <a class="reference external" href="http://docs.python.org/library/cmd.html">cmd</a>:
+for instance, the <tt class="docutils literal">.help</tt> command is more powerful, since it
+provides information about the arguments accepted by the given command:</p>
+<pre class="literal-block">
+i&gt; .help set
+usage: set name value
+
+set name value
+
+positional arguments:
+ name
+ value
+
+i&gt; .help delete
+usage: delete [name]
+
+delete given parameter (or everything)
+
+positional arguments:
+ name
+
+i&gt; .help show
+usage: show [names [names ...]]
+
+show given parameters
+
+positional arguments:
+ names
+</pre>
+<p>As you can imagine, the help message is provided by the underlying <a class="reference external" href="http://argparse.googlecode.com">argparse</a>
+subparser (there is a subparser for each command). <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> commands accept
+options, flags, varargs, keyword arguments, arguments with defaults,
+arguments with a fixed number of choices, type conversion and all the
+features provided of <a class="reference external" href="http://argparse.googlecode.com">argparse</a> which should be reimplemented from scratch
+using <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>.</p>
+<p>Moreover at the moment <tt class="docutils literal">plac</tt> also understands command abbreviations.
+However, this feature may disappear in
+future releases. It was meaningful in the past, when <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> did not support
+readline.</p>
+<p>Notice that if an abbreviation is ambiguous, <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> warns you:</p>
+<pre class="literal-block">
+i&gt; sh
+NameError: Ambiguous command 'sh': matching ['showall', 'show']
+</pre>
+</div>
+<div class="section" id="the-plac-runner">
+<h2><a class="toc-backref" href="#id77">The plac runner</a></h2>
+<p>The distribution of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> includes a runner script named <tt class="docutils literal">plac_runner.py</tt>,
+which will be installed in a suitable directory in your system by <a class="reference external" href="http://docs.python.org/distutils/">distutils</a>
+(say in <tt class="docutils literal">\usr\local\bin\plac_runner.py</tt> in a Unix-like operative system).
+The runner provides many facilities to run <tt class="docutils literal">.plac</tt> scripts and
+<tt class="docutils literal">.placet</tt> files, as well as Python modules containg a <tt class="docutils literal">main</tt>
+object, which can be a function, a command container object or
+even a command container class.</p>
+<p>For instance, suppose you want to execute a script containing commands
+defined in the <tt class="docutils literal">ishelve2</tt> module like the following one:</p>
+<pre class="literal-block">
+#!ishelve2.py:ShelveInterface -c ~/conf.shelve
+set a 1
+del a
+del a # intentional error
+
+</pre>
+<p>The first line of the <tt class="docutils literal">.plac</tt> script contains the name of the
+python module containing the plac interpreter and the arguments
+which must be passed to its main function in order to be able
+to instantiate an interpreter object. In this case I appended
+<tt class="docutils literal">:ShelveInterface</tt> to the name of the module to specify the
+object that must be imported: if not specified, by default the
+object named 'main' is imported.
+The other lines contains commands.
+You can run the script as follows:</p>
+<pre class="literal-block">
+$ plac_runner.py --batch ishelve2.plac
+setting a=1
+deleting a
+Traceback (most recent call last):
+ ...
+_bsddb.DBNotFoundError: (-30988, 'DB_NOTFOUND: No matching key/data pair found')
+</pre>
+<p>The last command intentionally contained an error, to show that the
+plac runner does not eat the traceback.</p>
+<p>The runner can also be used to run Python modules in interactive
+mode and non-interactive mode. If you put this alias in your bashrc</p>
+<blockquote>
+<tt class="docutils literal">alias <span class="pre">plac=&quot;plac_runner.py&quot;</span></tt></blockquote>
+<p>(or you define a suitable <tt class="docutils literal">plac.bat</tt> script in Windows) you can
+run the <tt class="docutils literal">ishelve2.py</tt> script in interactive mode as
+follows:</p>
+<pre class="literal-block">
+$ plac -i ishelve2.py
+A minimal interface over a shelve object.
+Operating on /home/micheles/conf.shelve.
+.help to see the available commands.
+
+i&gt; del
+deleting everything
+i&gt; set a 1
+setting a=1
+i&gt; set b 2
+setting b=2
+i&gt; show b
+b = 2
+</pre>
+<p>Now you can cut and paste the interactive session an turns into into
+a <tt class="docutils literal">.placet</tt> file like the following:</p>
+<pre class="literal-block">
+#!ishelve2.py:ShelveInterface -configfile=~/test.shelve
+i&gt; del
+deleting everything
+i&gt; set a 1
+setting a=1
+i&gt; set b 2
+setting b=2
+i&gt; show a
+a = 1
+
+</pre>
+<p>Notice that the first line specifies a test database
+<tt class="docutils literal">~/test.shelve</tt>, to avoid clobbering your default shelve. If you
+mispell the arguments in the first line plac will give you an
+<a class="reference external" href="http://argparse.googlecode.com">argparse</a> error message (just try).</p>
+<p>You can run placets following the shebang convention directly with
+the plac runner:</p>
+<pre class="literal-block">
+$ plac --test ishelve2.placet
+run 1 plac test(s)
+</pre>
+<p>If you want to see the output of the tests, pass the <tt class="docutils literal"><span class="pre">-v/--verbose</span></tt> flag.
+Notice that he runner ignore the extension, so you can actually use any
+extension your like, but <em>it relies on the first line of the file to invoke
+the corresponding plac tool with the given arguments</em>.</p>
+<p>The plac runner does not provide any test discovery facility,
+but you can use standard Unix tools to help. For instance, you can
+run all the <tt class="docutils literal">.placet</tt> files into a directory and its subdirectories
+as follows:</p>
+<pre class="literal-block">
+$ find . -name \*.placet | xargs plac_runner.py -t
+</pre>
+<p>The plac runner expects the main function of your script to
+return a plac tool, i.e. a function or an object with a <tt class="docutils literal">.commands</tt>
+attribute. It this is not the case the runner gracefully exits.</p>
+<p>It also works in non-interactive mode, if you call it as</p>
+<blockquote>
+<tt class="docutils literal">$ plac module.py args ...</tt></blockquote>
+<p>Here is an example:</p>
+<pre class="literal-block">
+$ plac ishelve.py a=1
+setting a=1
+$ plac ishelve.py .show
+a=1
+</pre>
+<p>Notice that in non-interactive mode the runner just invokes <tt class="docutils literal">plac.call</tt>
+on the <tt class="docutils literal">main</tt> object of the Python module.</p>
+</div>
+<div class="section" id="a-non-class-based-example">
+<h2><a class="toc-backref" href="#id78">A non class-based example</a></h2>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> does not force you to use classes to define command containers.
+Even a simple function can be a valid command container, it is
+enough to add to it a <tt class="docutils literal">.commands</tt> attribute and possibly
+<tt class="docutils literal">__enter__</tt> and/or <tt class="docutils literal">__exit__</tt> attributes.</p>
+<p>In particular, a Python module is a perfect container of commands. As an
+example, consider the following module implementing a fake Version
+Control System:</p>
+<pre class="literal-block">
+&quot;A Fake Version Control System&quot;
+
+import plac
+
+commands = 'checkout', 'commit', 'status'
+
+&#64;plac.annotations(url='url of the source code')
+def checkout(url):
+ &quot;A fake checkout command&quot;
+ return ('checkout ', url)
+
+&#64;plac.annotations(message=('commit message', 'option'))
+def commit(message):
+ &quot;A fake commit command&quot;
+ return ('commit ', message)
+
+&#64;plac.annotations(quiet=('summary information', 'flag', 'q'))
+def status(quiet):
+ &quot;A fake status command&quot;
+ return ('status ', quiet)
+
+def __missing__(name):
+ return 'Command %r does not exist' % name
+
+def __exit__(etype, exc, tb):
+ &quot;Will be called automatically at the end of the call/cmdloop&quot;
+ if etype in (None, GeneratorExit): # success
+ print('ok')
+
+main = __import__(__name__) # the module imports itself!
+
+</pre>
+<p>Notice that I have defined both an <tt class="docutils literal">__exit__</tt> hook and a <tt class="docutils literal">__missing__</tt>
+hook, invoked for non-existing commands.
+The real trick here is the line <tt class="docutils literal">main = __import__(__name__)</tt>, which
+define <tt class="docutils literal">main</tt> to be an alias for the current module.</p>
+<p>The <tt class="docutils literal">vcs</tt> module does not contain an <tt class="docutils literal">if __name__ == '__main__'</tt>
+block, but you can still run it through the plac runner
+(try <tt class="docutils literal">plac vcs.py <span class="pre">-h</span></tt>):</p>
+<pre class="literal-block">
+usage: plac_runner.py vcs.py [-h] {status,commit,checkout} ...
+
+A Fake Version Control System
+
+optional arguments:
+ -h, --help show this help message and exit
+
+subcommands:
+ {status,commit,checkout}
+ -h to get additional help
+
+</pre>
+<p>You can get help for the subcommands by postponing <tt class="docutils literal"><span class="pre">-h</span></tt> after the
+name of the command:</p>
+<pre class="literal-block">
+$ plac vcs.py status -h
+usage: vcs.py status [-h] [-q]
+
+A fake status command
+
+optional arguments:
+ -h, --help show this help message and exit
+ -q, --quiet summary information
+</pre>
+<p>Notice how the docstring of the command is automatically shown in
+usage message, as well as the documentation for the sub flag <tt class="docutils literal"><span class="pre">-q</span></tt>.</p>
+<p>Here is an example of a non-interactive session:</p>
+<pre class="literal-block">
+$ plac vcs.py check url
+checkout
+url
+$ plac vcs.py st -q
+status
+True
+$ plac vcs.py co
+commit
+None
+</pre>
+<p>and here is an interactive session:</p>
+<pre class="literal-block">
+$ plac -i vcs.py
+usage: plac_runner.py vcs.py [-h] {status,commit,checkout} ...
+i&gt; check url
+checkout
+url
+i&gt; st -q
+status
+True
+i&gt; co
+commit
+None
+i&gt; sto
+Command 'sto' does not exist
+i&gt; [CTRL-D]
+ok
+</pre>
+<p>Notice the invocation of the <tt class="docutils literal">__missing__</tt> hook for non-existing commands.
+Notice also that the <tt class="docutils literal">__exit__</tt> hook gets called only in interactive
+mode.</p>
+<p>If the commands are completely independent, a module is a good fit for
+a method container. In other situations, it is best to use a custom
+class.</p>
+</div>
+<div class="section" id="writing-your-own-plac-runner">
+<h2><a class="toc-backref" href="#id79">Writing your own plac runner</a></h2>
+<p>The runner included in the <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> distribution is intentionally kept
+small (around 50 lines of code) so that you can study it and write
+your own runner if want to. If you need to go to such level
+of detail, you should know that the most important method of
+the <tt class="docutils literal">Interpreter</tt> class is the <tt class="docutils literal">.send</tt> method, which takes
+strings in input and returns a four-tuple with attributes
+<tt class="docutils literal">.str</tt>, <tt class="docutils literal">.etype</tt>, <tt class="docutils literal">.exc</tt> and <tt class="docutils literal">.tb</tt>:</p>
+<ul class="simple">
+<li><tt class="docutils literal">.str</tt> is the output of the command, if successful (a string);</li>
+<li><tt class="docutils literal">.etype</tt> is the class of the exception, if the command fail;</li>
+<li><tt class="docutils literal">.exc</tt> is the exception instance;</li>
+<li><tt class="docutils literal">.tb</tt> is the traceback.</li>
+</ul>
+<p>Moreover the <tt class="docutils literal">__str__</tt> representation of the output object is redefined
+to return the output string if the command was successful or the error
+message if the command failed (actually it returns the error message
+preceded by the name of the exception class).</p>
+<p>For instance, if you send a mispelled option to
+the interpreter a <tt class="docutils literal">SystemExit</tt> will be trapped:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; import plac
+&gt;&gt;&gt; from ishelve import ishelve
+&gt;&gt;&gt; with plac.Interpreter(ishelve) as i:
+... print(i.send('.cler'))
+...
+SystemExit: unrecognized arguments: .cler
+</pre>
+<p>It is important to invoke the <tt class="docutils literal">.send</tt> method inside the context manager,
+otherwise you will get a <tt class="docutils literal">RuntimeError</tt>.</p>
+<p>For instance, suppose you want to implement a graphical runner for a
+plac-based interpreter with two text widgets: one to enter the commands
+and one to display the results. Suppose you want to display the errors
+with tracebacks in red. You will need to code something like that
+(pseudocode follows):</p>
+<pre class="literal-block">
+input_widget = WidgetReadingInput()
+output_widget = WidgetDisplayingOutput()
+
+def send(interpreter, line):
+ out = interpreter.send(line)
+ if out.tb: # there was an error
+ output_widget.display(out.tb, color='red')
+ else:
+ output_widget.display(out.str)
+
+main = plac.import_main(tool_path) # get the main object
+
+with plac.Interpreter(main) as i:
+ def callback(event):
+ if event.user_pressed_ENTER():
+ send(i, input_widget.last_line)
+ input_widget.addcallback(callback)
+ gui_mainloop.start()
+</pre>
+<p>You can adapt the pseudocode to your GUI toolkit of choice and you can
+also change the file associations in such a way that clicking on a
+plac tool file the graphical user interface starts.</p>
+<p>An example of GUI program built on top of <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is given later on, in the
+paragraph <em>Managing the output of concurrent commands</em> (using Tkinter
+for simplicity and portability).</p>
+<p>There is a final <em>caveat</em>: since the plac interpreter loop is
+implemented via extended generators, plac interpreters are single threaded: you
+will get an error if you <tt class="docutils literal">.send</tt> commands from separated threads.
+You can circumvent the problem by using a queue. If EXIT is a sentinel
+value to signal exiting from the interpreter look, you can write code
+like this:</p>
+<pre class="literal-block">
+with interpreter:
+ for input_value in iter(input_queue.get, EXIT):
+ output_queue.put(interpreter.send(input_value))
+</pre>
+<p>The same trick also work for processes; you could run the interpreter
+loop in a separate process and send commands to it via the Queue
+class provided by the <a class="reference external" href="http://docs.python.org/library/multiprocessing.html">multiprocessing</a> module.</p>
+</div>
+<div class="section" id="long-running-commands">
+<h2><a class="toc-backref" href="#id80">Long running commands</a></h2>
+<p>As we saw, by default a <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> interpreter blocks until
+the command terminates. This is an issue, in the sense that it makes
+the interactive experience quite painful for long running commands. An
+example is better than a thousand words, so consider the following
+fake importer:</p>
+<pre class="literal-block">
+import time
+import plac
+
+class FakeImporter(object):
+ &quot;A fake importer with an import_file command&quot;
+ commands = ['import_file']
+ def __init__(self, dsn):
+ self.dsn = dsn
+ def import_file(self, fname):
+ &quot;Import a file into the database&quot;
+ try:
+ for n in range(10000):
+ time.sleep(.01)
+ if n % 100 == 99:
+ yield 'Imported %d lines' % (n+1)
+ finally:
+ print('closing the file')
+
+if __name__ == '__main__':
+ plac.Interpreter.call(FakeImporter)
+
+</pre>
+<p>If you run the <tt class="docutils literal">import_file</tt> command, you will have to wait for 200 seconds
+before entering a new command:</p>
+<pre class="literal-block">
+$ python importer1.py dsn
+A fake importer with an import_file command
+i&gt; import_file file1
+... &lt;wait 3+ minutes&gt;
+Imported 100 lines
+Imported 200 lines
+Imported 300 lines
+...
+Imported 10000 lines
+closing the file
+</pre>
+<p>Being unable to enter any other command is quite annoying: in such situation one
+would like to run the long running commands in the background, to keep
+the interface responsive. <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> provides two ways to reach this goal: threads
+and processes.</p>
+</div>
+<div class="section" id="threaded-commands">
+<h2><a class="toc-backref" href="#id81">Threaded commands</a></h2>
+<p>The most familiar way to execute a task in the background (even if not
+necessarily the best way) is to run it into a separated thread. In our
+example it is sufficient to replace the line</p>
+<blockquote>
+<tt class="docutils literal">commands = ['import_file']</tt></blockquote>
+<p>with</p>
+<blockquote>
+<tt class="docutils literal">thcommands = ['import_file']</tt></blockquote>
+<p>to tell to the <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> interpreter that the command <tt class="docutils literal">import_file</tt> should be
+run into a separated thread. Here is an example session:</p>
+<pre class="literal-block">
+i&gt; import_file file1
+&lt;ThreadedTask 1 [import_file file1] RUNNING&gt;
+</pre>
+<p>The import task started in a separated thread. You can see the
+progress of the task by using the special command <tt class="docutils literal">.output</tt>:</p>
+<pre class="literal-block">
+i&gt; .output 1
+&lt;ThreadedTask 1 [import_file file1] RUNNING&gt;
+Imported 100 lines
+Imported 200 lines
+</pre>
+<p>If you look after a while, you will get more lines of output:</p>
+<pre class="literal-block">
+i&gt; .output 1
+&lt;ThreadedTask 1 [import_file file1] RUNNING&gt;
+Imported 100 lines
+Imported 200 lines
+Imported 300 lines
+Imported 400 lines
+</pre>
+<p>If you look after a time long enough, the task will be finished:</p>
+<pre class="literal-block">
+i&gt; .output 1
+&lt;ThreadedTask 1 [import_file file1] FINISHED&gt;
+</pre>
+<p>You can even skip the number argument: then <tt class="docutils literal">.output</tt> will the return
+the output of the last launched command (the special commands like .output
+do not count).</p>
+<p>You can launch many tasks one after the other:</p>
+<pre class="literal-block">
+i&gt; import_file file2
+&lt;ThreadedTask 5 [import_file file2] RUNNING&gt;
+i&gt; import_file file3
+&lt;ThreadedTask 6 [import_file file3] RUNNING&gt;
+</pre>
+<p>The <tt class="docutils literal">.list</tt> command displays all the running tasks:</p>
+<pre class="literal-block">
+i&gt; .list
+&lt;ThreadedTask 5 [import_file file2] RUNNING&gt;
+&lt;ThreadedTask 6 [import_file file3] RUNNING&gt;
+</pre>
+<p>It is even possible to kill a task:</p>
+<pre class="literal-block">
+i&gt; .kill 5
+&lt;ThreadedTask 5 [import_file file2] TOBEKILLED&gt;
+# wait a bit ...
+closing the file
+i&gt; .output 5
+&lt;ThreadedTask 5 [import_file file2] KILLED&gt;
+</pre>
+<p>You should notice that since at the Python level it is impossible to kill
+a thread, the <tt class="docutils literal">.kill</tt> commands works by setting the status of the task to
+<tt class="docutils literal">TOBEKILLED</tt>. Internally the generator corresponding to the command
+is executed in the thread and the status is checked at each iteration:
+when the status become <tt class="docutils literal">TOBEKILLED</tt> a <tt class="docutils literal">GeneratorExit</tt> exception is
+raised and the thread terminates (softly, so that the <tt class="docutils literal">finally</tt> clause
+is honored). In our example the generator is yielding
+back control once every 100 iterations, i.e. every two seconds (not much).
+In order to get a responsive interface it is a good idea to yield more
+often, for instance every 10 iterations (i.e. 5 times per second),
+as in the following code:</p>
+<pre class="literal-block">
+import time
+import plac
+
+class FakeImporter(object):
+ &quot;A fake importer with an import_file command&quot;
+ thcommands = ['import_file']
+ def __init__(self, dsn):
+ self.dsn = dsn
+ def import_file(self, fname):
+ &quot;Import a file into the database&quot;
+ try:
+ for n in range(10000):
+ time.sleep(.02)
+ if n % 100 == 99: # every two seconds
+ yield 'Imported %d lines' % (n+1)
+ if n % 10 == 9: # every 0.2 seconds
+ yield # go back and check the TOBEKILLED status
+ finally:
+ print('closing the file')
+
+if __name__ == '__main__':
+ plac.Interpreter.call(FakeImporter)
+
+</pre>
+</div>
+<div class="section" id="running-commands-as-external-processes">
+<h2><a class="toc-backref" href="#id82">Running commands as external processes</a></h2>
+<p>Threads are not loved much in the Python world and actually most people
+prefer to use processes instead. For this reason <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> provides the
+option to execute long running commands as external processes. Unfortunately
+the current implementation only works in Unix-like operating systems
+(including Mac OS X) because it relies on fork via the <a class="reference external" href="http://docs.python.org/library/multiprocessing.html">multiprocessing</a>
+module.</p>
+<p>In our example, to enable the feature it is sufficient to replace the line</p>
+<blockquote>
+<tt class="docutils literal">thcommands = ['import_file']</tt></blockquote>
+<p>with</p>
+<blockquote>
+<tt class="docutils literal">mpcommands = ['import_file']</tt>.</blockquote>
+<p>The user experience is exactly the same as with threads and you will not see any
+difference at the user interface level:</p>
+<pre class="literal-block">
+i&gt; import_file file3
+&lt;MPTask 1 [import_file file3] SUBMITTED&gt;
+i&gt; .kill 1
+&lt;MPTask 1 [import_file file3] RUNNING&gt;
+closing the file
+i&gt; .o 1
+&lt;MPTask 1 [import_file file3] KILLED&gt;
+Imported 100 lines
+Imported 200 lines
+i&gt;
+</pre>
+<p>Still, using processes is quite different than using threads: in
+particular, when using processes you can only yield pickleable values
+and you cannot re-raise an exception first raised in a different
+process, because traceback objects are not pickleable. Moreover,
+you cannot rely on automatic sharing of your objects.</p>
+<p>On the plus side, when using processes you do not need to worry about
+killing a command: they are killed immediately using a SIGTERM signal,
+and there is not a <tt class="docutils literal">TOBEKILLED</tt> mechanism. Moreover, the killing is
+guaranteed to be soft: internally a command receiving a SIGTERM raises
+a <tt class="docutils literal">TerminatedProcess</tt> exception which is trapped in the generator
+loop, so that the command is closed properly.</p>
+<p>Using processes allows to take full advantage of multicore machines
+and it is safer than using threads, so it is the recommended approach
+unless you are working on Windows.</p>
+</div>
+<div class="section" id="managing-the-output-of-concurrent-commands">
+<h2><a class="toc-backref" href="#id83">Managing the output of concurrent commands</a></h2>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> acts as a command-line task launcher and can be used as the base
+to build a GUI-based task launcher and task monitor. To this aim the
+interpreter class provides a <tt class="docutils literal">.submit</tt> method which returns a task
+object and a <tt class="docutils literal">.tasks</tt> method returning the list of all the tasks
+submitted to the interpreter. The <tt class="docutils literal">submit</tt> method does not start the task
+and thus it is nonblocking.
+Each task has an <tt class="docutils literal">.outlist</tt> attribute which is a list
+storing the value yielded by the generator underlying the task (the
+<tt class="docutils literal">None</tt> values are skipped though): the <tt class="docutils literal">.outlist</tt> grows as the
+task runs and more values are yielded. Accessing the <tt class="docutils literal">.outlist</tt> is
+nonblocking and can be done freely.
+Finally there is a <tt class="docutils literal">.result</tt>
+property which waits for the task to finish and returns the last yielded
+value or raises an exception.</p>
+<p>Here is some example code to visualize the output of the FakeImporter
+in Tkinter (I chose Tkinter because it is easy to use and it is
+in the standard library, but you can use any GUI):</p>
+<pre class="literal-block">
+from Tkinter import *
+from importer3 import FakeImporter
+
+def taskwidget(root, task, tick=500):
+ &quot;A Label widget showing the output of a task every 500 ms&quot;
+ sv = StringVar(root)
+ lb = Label(root, textvariable=sv)
+ def show_outlist():
+ try:
+ out = task.outlist[-1]
+ except IndexError: # no output yet
+ out = ''
+ sv.set('%s %s' % (task, out))
+ root.after(tick, show_outlist)
+ root.after(0, show_outlist)
+ return lb
+
+def monitor(tasks):
+ root = Tk()
+ for task in tasks:
+ task.run()
+ taskwidget(root, task).pack()
+ root.mainloop()
+
+if __name__ == '__main__':
+ import plac
+ with plac.Interpreter(plac.call(FakeImporter)) as i:
+ tasks = [i.submit('import_file f1'), i.submit('import_file f2')]
+ monitor(tasks)
+
+</pre>
+</div>
+<div class="section" id="parallel-computing-with-plac">
+<h2><a class="toc-backref" href="#id84">Parallel computing with plac</a></h2>
+<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is certainly not intended as a tool for parallel computing, but
+still you can use it to launch a set of commands and to collect the
+results, similarly to the MapReduce pattern recently popularized by
+Google. In order to give an example, I will consider the &quot;Hello
+World&quot; of parallel computing, i.e. the computation of pi with
+independent processes. There is a huge number of algorithms to
+compute pi; here I will describe a trivial one chosen for simplicity,
+not per efficienty. The trick is to consider the first quadrant of a
+circle with radius 1 and to extract a number of points <tt class="docutils literal">(x, y)</tt> with
+<tt class="docutils literal">x</tt> and <tt class="docutils literal">y</tt> random variables in the interval <tt class="docutils literal">[0,1]</tt>. The
+probability of extracting a number inside the quadrant (i.e. with
+<tt class="docutils literal">x^2 + y^2 &lt; 1</tt>) is proportional to the area of the quadrant
+(i.e. <tt class="docutils literal">pi/4</tt>). The value of <tt class="docutils literal">pi</tt> therefore can be extracted by
+multiplying by 4 the ratio between the number of points in the
+quadrant versus the total number of points <tt class="docutils literal">N</tt>, for <tt class="docutils literal">N</tt> large:</p>
+<pre class="literal-block">
+def calc_pi(N):
+ inside = 0
+ for j in xrange(N):
+ x, y = random(), random()
+ if x*x + y*y &lt; 1:
+ inside += 1
+ return (4.0 * inside) / N
+</pre>
+<p>The algorithm is trivially parallelizable: if you have n CPUs, you can
+compute pi n times with N/n iterations, sum the results and divide the total
+by n. I have a Macbook with two cores, therefore I would expect a speedup
+factor of 2 with respect to a sequential computation. Moreover, I would
+expect a threaded computation to be even slower than a sequential
+computation, due to the GIL and the scheduling overhead.</p>
+<p>Here is a script implementing the algorithm and working in three different
+modes (parallel mode, threaded mode and sequential mode) depending on a
+<tt class="docutils literal">mode</tt> option:</p>
+<pre class="literal-block">
+from __future__ import with_statement
+from random import random
+import multiprocessing
+import plac
+
+class PiCalculator(object):
+ &quot;&quot;&quot;Compute pi in parallel with threads or processes&quot;&quot;&quot;
+
+ &#64;plac.annotations(
+ npoints=('number of integration points', 'positional', None, int),
+ mode=('sequential|parallel|threaded', 'option', 'm', str, 'SPT'))
+ def __init__(self, npoints, mode='S'):
+ self.npoints = npoints
+ if mode == 'P':
+ self.mpcommands = ['calc_pi']
+ elif mode == 'T':
+ self.thcommands = ['calc_pi']
+ elif mode == 'S':
+ self.commands = ['calc_pi']
+ self.n_cpu = multiprocessing.cpu_count()
+
+ def submit_tasks(self):
+ self.i = plac.Interpreter(self).__enter__()
+ return [self.i.submit('calc_pi %d' % (self.npoints / self.n_cpu))
+ for _ in range(self.n_cpu)]
+
+ def close(self):
+ self.i.close()
+
+ &#64;plac.annotations(
+ npoints=('npoints', 'positional', None, int))
+ def calc_pi(self, npoints):
+ counts = 0
+ for j in xrange(npoints):
+ n, r = divmod(j, 1000000)
+ if r == 0:
+ yield '%dM iterations' % n
+ x, y = random(), random()
+ if x*x + y*y &lt; 1:
+ counts += 1
+ yield (4.0 * counts)/npoints
+
+ def run(self):
+ tasks = self.i.tasks()
+ for t in tasks:
+ t.run()
+ try:
+ total = 0
+ for task in tasks:
+ total += task.result
+ except: # the task was killed
+ print tasks
+ return
+ return total / self.n_cpu
+
+if __name__ == '__main__':
+ pc = plac.call(PiCalculator)
+ pc.submit_tasks()
+ try:
+ import time; t0 = time.time()
+ print '%f in %f seconds ' % (pc.run(), time.time() - t0)
+ finally:
+ pc.close()
+
+</pre>
+<p>Notice the <tt class="docutils literal">submit_tasks</tt> method, which instantiates and initializes a
+<tt class="docutils literal">plac.Interpreter</tt> object and submits a number of commands corresponding
+to the number of available CPUs. The <tt class="docutils literal">calc_pi</tt> command yield a log
+message every million of interactions, just to monitor the progress of
+the computation. The <tt class="docutils literal">run</tt> method starts all the submitted commands
+in parallel and sums the results. It returns the average value of <tt class="docutils literal">pi</tt>
+after the slowest CPU has finished its job (if the CPUs are equal and
+equally busy they should finish more or less at the same time).</p>
+<p>Here are the results on my old Macbook with Ubuntu 10.04 and Python 2.6,
+for 10 million of iterations:</p>
+<pre class="literal-block">
+$ python picalculator.py -mP 10000000
+3.141904 in 5.744545 seconds
+$ python picalculator.py -mT 10000000
+3.141272 in 13.875645 seconds
+$ python picalculator.py -mS 10000000
+3.141586 in 11.353841 seconds
+</pre>
+<p>As you see using processes one gets a 2x speedup indeed, where the threaded
+mode is some 20% slower than the sequential mode.</p>
+</div>
+<div class="section" id="the-plac-server">
+<h2><a class="toc-backref" href="#id85">The plac server</a></h2>
+<p>A command-line oriented interface can be easily converted into a
+socket-based interface. Starting from release 0.7 plac features
+a builtin server which is able to accept commands from multiple
+clients and to execute them. The server works by instantiating
+a separate interpreter for each client, so that if a client interpreter
+dies for any reason the other interpreters keep working.
+To avoid external dependencies the server is based on the <tt class="docutils literal">asynchat</tt>
+module in the standard library, but it would not be difficult to
+replace the server with a different one (for instance, a Twisted server).
+Since <tt class="docutils literal">asynchat</tt>-based servers are asynchronous, any blocking command
+in the interpreter should be run in a separated process or thread.
+The default port for the <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> server is 2199, and the command to
+signal end-of-connection is EOF.
+For instance, here is how you could manage remote import on a database
+(say a SQLite db):</p>
+<pre class="literal-block">
+import plac
+from importer2 import FakeImporter
+
+def main(port=2199):
+ main = FakeImporter('dsn')
+ plac.Interpreter(main).start_server(port)
+
+if __name__ == '__main__':
+ plac.call(main)
+
+</pre>
+<p>You can connect to the server with <tt class="docutils literal">telnet</tt> on port 2199, as follows:</p>
+<pre class="literal-block">
+$ telnet localhost 2199
+Trying ::1...
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+i&gt; import_file f1
+i&gt; .list
+&lt;ThreadedTask 1 [import_file f1] RUNNING&gt;
+i&gt; .out
+Imported 100 lines
+Imported 200 lines
+i&gt; EOF
+Connection closed by foreign host.
+</pre>
+</div>
+<div class="section" id="summary">
+<h2><a class="toc-backref" href="#id86">Summary</a></h2>
+<p>Once <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> claimed to be the easiest command-line arguments parser
+in the world. Having read this document you may think that it is not
+so easy after all. But it is a false impression. Actually the
+rules are quite simple:</p>
+<ol class="arabic simple">
+<li>if you want to implement a command-line script, use <tt class="docutils literal">plac.call</tt>;</li>
+<li>if you want to implement a command interpreter, use <tt class="docutils literal">plac.Interpreter</tt>:<ul>
+<li>for an interactive interpreter, call the <tt class="docutils literal">.interact</tt> method;</li>
+<li>for an batch interpreter, call the <tt class="docutils literal">.execute</tt> method;</li>
+</ul>
+</li>
+<li>for testing call the <tt class="docutils literal">Interpreter.check</tt> method in the appropriate context
+or use the <tt class="docutils literal">Interpreter.doctest</tt> feature;</li>
+<li>if you need to go at a lower level, you may need to call the
+<tt class="docutils literal">Interpreter.send</tt> method which returns a (finished) <tt class="docutils literal">Task</tt> object.</li>
+<li>long running command can be executed in the background as threads or
+processes: just declare them in the lists <tt class="docutils literal">thcommands</tt> and <tt class="docutils literal">mpcommands</tt>
+respectively.</li>
+<li>the <tt class="docutils literal">.start_server</tt> method starts an asynchronous server on the
+given port number (default 2199)</li>
+</ol>
+<p>Moreover, remember that <tt class="docutils literal">plac_runner.py</tt> is your friend.</p>
+</div>
+<hr class="docutils" />
+<div class="section" id="appendix-custom-annotation-objects">
+<h2><a class="toc-backref" href="#id87">Appendix: custom annotation objects</a></h2>
+<p>Internally <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> uses an <tt class="docutils literal">Annotation</tt> class to convert the tuples
+in the function signature into annotation objects, i.e. objects with
+six attributes <tt class="docutils literal">help, kind, short, type, choices, metavar</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>
+<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>
+<p>You can use such annotations objects as follows:</p>
+<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>
+<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">Option</tt> and <tt class="docutils literal">Flag</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>
+</div>
</body>
</html>
diff --git a/plac/doc/plac.pdf b/plac/doc/plac.pdf
index 5a6c78c..0a6f91d 100644
--- a/plac/doc/plac.pdf
+++ b/plac/doc/plac.pdf
@@ -7,7 +7,7 @@
/F2 3 0 R
/F3 4 0 R
/F4 8 0 R
- /F5 52 0 R >>
+ /F5 95 0 R >>
endobj
% 'F1': class PDFType1Font
2 0 obj
@@ -45,9 +45,9 @@ endobj
0
0 ]
/Rect [ 153.7323
- 707.5936
+ 708.5936
526.5827
- 719.5936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -60,9 +60,9 @@ endobj
0
0 ]
/Rect [ 153.7323
- 677.5936
+ 678.5936
526.5827
- 689.5936 ]
+ 690.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -75,9 +75,9 @@ endobj
0
0 ]
/Rect [ 153.7323
- 650.5936
+ 651.5936
526.5827
- 662.5936 ]
+ 663.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
@@ -90,512 +90,1379 @@ endobj
/Subtype /Type1
/Type /Font >>
endobj
-% 'Annot.NUMBER4': class LinkAnnotation
+% 'Page1': class PDFPage
9 0 obj
+% Page dictionary
+<< /Annots [ 5 0 R
+ 6 0 R
+ 7 0 R ]
+ /Contents 412 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER4': class LinkAnnotation
+10 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 9 0 R
/XYZ
62.69291
- 296.0236
+ 765.0236
0 ]
/Rect [ 62.69291
- 548.5936
- 215.5029
- 560.5936 ]
+ 726.5936
+ 286.0929
+ 738.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER5': class LinkAnnotation
-10 0 obj
+11 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 9 0 R
/XYZ
62.69291
- 296.0236
+ 765.0236
0 ]
/Rect [ 527.0227
- 548.5936
+ 726.5936
532.5827
- 560.5936 ]
+ 738.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER6': class LinkAnnotation
-11 0 obj
+12 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 56 0 R
+ /Dest [ 96 0 R
/XYZ
62.69291
- 615.0236
+ 765.0236
0 ]
- /Rect [ 62.69291
- 530.5936
- 216.0629
- 542.5936 ]
+ /Rect [ 82.69291
+ 708.5936
+ 223.8629
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER7': class LinkAnnotation
-12 0 obj
+13 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 56 0 R
+ /Dest [ 96 0 R
/XYZ
62.69291
- 615.0236
+ 765.0236
0 ]
/Rect [ 527.0227
- 530.5936
+ 708.5936
532.5827
- 542.5936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER8': class LinkAnnotation
-13 0 obj
+14 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 63 0 R
+ /Dest [ 96 0 R
/XYZ
62.69291
- 274.2236
+ 411.0236
0 ]
- /Rect [ 62.69291
- 512.5936
- 208.8329
- 524.5936 ]
+ /Rect [ 82.69291
+ 690.5936
+ 223.2929
+ 702.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER9': class LinkAnnotation
-14 0 obj
+15 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 63 0 R
+ /Dest [ 96 0 R
/XYZ
62.69291
- 274.2236
+ 411.0236
0 ]
/Rect [ 527.0227
- 512.5936
+ 690.5936
532.5827
- 524.5936 ]
+ 702.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER10': class LinkAnnotation
-15 0 obj
+16 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 75 0 R
+ /Dest [ 110 0 R
/XYZ
62.69291
- 229.4236
+ 765.0236
0 ]
- /Rect [ 62.69291
- 494.5936
- 254.3829
- 506.5936 ]
+ /Rect [ 82.69291
+ 672.5936
+ 216.6329
+ 684.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER11': class LinkAnnotation
-16 0 obj
+17 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 75 0 R
+ /Dest [ 110 0 R
/XYZ
62.69291
- 229.4236
+ 765.0236
0 ]
/Rect [ 527.0227
- 494.5936
+ 672.5936
532.5827
- 506.5936 ]
+ 684.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER12': class LinkAnnotation
-17 0 obj
+18 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 79 0 R
+ /Dest [ 120 0 R
/XYZ
62.69291
- 231.0236
+ 741.0236
0 ]
- /Rect [ 62.69291
- 476.5936
- 145.4929
- 488.5936 ]
+ /Rect [ 82.69291
+ 654.5936
+ 257.7529
+ 666.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER13': class LinkAnnotation
-18 0 obj
+19 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 79 0 R
+ /Dest [ 120 0 R
/XYZ
62.69291
- 231.0236
+ 741.0236
0 ]
/Rect [ 527.0227
- 476.5936
+ 654.5936
532.5827
- 488.5936 ]
+ 666.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER14': class LinkAnnotation
-19 0 obj
+20 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 81 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 377.4236
+ 765.0236
0 ]
- /Rect [ 62.69291
- 458.5936
- 182.7329
- 470.5936 ]
+ /Rect [ 82.69291
+ 636.5936
+ 157.7129
+ 648.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER15': class LinkAnnotation
-20 0 obj
+21 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 81 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 377.4236
+ 765.0236
0 ]
/Rect [ 527.0227
- 458.5936
+ 636.5936
532.5827
- 470.5936 ]
+ 648.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER16': class LinkAnnotation
-21 0 obj
+22 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 89 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 647.8236
+ 265.7299
0 ]
- /Rect [ 62.69291
- 440.5936
- 128.2629
- 452.5936 ]
+ /Rect [ 82.69291
+ 618.5936
+ 194.4129
+ 630.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER17': class LinkAnnotation
-22 0 obj
+23 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 89 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 647.8236
+ 265.7299
0 ]
/Rect [ 527.0227
- 440.5936
+ 618.5936
532.5827
- 452.5936 ]
+ 630.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER18': class LinkAnnotation
-23 0 obj
+24 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 94 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 683.8236
+ 522.6236
0 ]
- /Rect [ 62.69291
- 422.5936
- 153.2929
- 434.5936 ]
+ /Rect [ 82.69291
+ 600.5936
+ 144.3829
+ 612.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER19': class LinkAnnotation
-24 0 obj
+25 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 94 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 683.8236
+ 522.6236
0 ]
/Rect [ 521.4627
- 422.5936
+ 600.5936
532.5827
- 434.5936 ]
+ 612.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER20': class LinkAnnotation
-25 0 obj
+26 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 97 0 R
+ /Dest [ 137 0 R
/XYZ
62.69291
- 623.8236
+ 552.6236
0 ]
- /Rect [ 62.69291
- 404.5936
- 158.8229
- 416.5936 ]
+ /Rect [ 82.69291
+ 582.5936
+ 166.6029
+ 594.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER21': class LinkAnnotation
-26 0 obj
+27 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 97 0 R
+ /Dest [ 137 0 R
/XYZ
62.69291
- 623.8236
+ 552.6236
0 ]
/Rect [ 521.4627
- 404.5936
+ 582.5936
532.5827
- 416.5936 ]
+ 594.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER22': class LinkAnnotation
-27 0 obj
+28 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 99 0 R
+ /Dest [ 140 0 R
/XYZ
62.69291
- 594.6236
+ 513.8236
0 ]
- /Rect [ 62.69291
- 386.5936
- 218.8729
- 398.5936 ]
+ /Rect [ 82.69291
+ 564.5936
+ 171.6129
+ 576.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER23': class LinkAnnotation
-28 0 obj
+29 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 99 0 R
+ /Dest [ 140 0 R
/XYZ
62.69291
- 594.6236
+ 513.8236
0 ]
/Rect [ 521.4627
- 386.5936
+ 564.5936
532.5827
- 398.5936 ]
+ 576.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER24': class LinkAnnotation
-29 0 obj
+30 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 124 0 R
+ /Dest [ 142 0 R
/XYZ
62.69291
- 511.8236
+ 493.4236
0 ]
- /Rect [ 62.69291
- 368.5936
- 141.6229
- 380.5936 ]
+ /Rect [ 82.69291
+ 546.5936
+ 228.8629
+ 558.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER25': class LinkAnnotation
-30 0 obj
+31 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 124 0 R
+ /Dest [ 142 0 R
/XYZ
62.69291
- 511.8236
+ 493.4236
0 ]
/Rect [ 521.4627
- 368.5936
+ 546.5936
532.5827
- 380.5936 ]
+ 558.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER26': class LinkAnnotation
-31 0 obj
+32 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 133 0 R
+ /Dest [ 159 0 R
/XYZ
62.69291
- 161.4236
+ 422.6236
0 ]
- /Rect [ 62.69291
- 350.5936
- 194.9529
- 362.5936 ]
+ /Rect [ 82.69291
+ 528.5936
+ 156.0529
+ 540.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER27': class LinkAnnotation
-32 0 obj
+33 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 133 0 R
+ /Dest [ 159 0 R
/XYZ
62.69291
- 161.4236
+ 422.6236
0 ]
/Rect [ 521.4627
- 350.5936
+ 528.5936
532.5827
- 362.5936 ]
+ 540.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER28': class LinkAnnotation
-33 0 obj
+34 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 167 0 R
+ /Dest [ 208 0 R
/XYZ
62.69291
- 603.0236
+ 741.0236
0 ]
- /Rect [ 62.69291
- 332.5936
- 111.5829
- 344.5936 ]
+ /Rect [ 82.69291
+ 510.5936
+ 204.4129
+ 522.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER29': class LinkAnnotation
-34 0 obj
+35 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 167 0 R
+ /Dest [ 208 0 R
/XYZ
62.69291
- 603.0236
+ 741.0236
0 ]
/Rect [ 521.4627
- 332.5936
+ 510.5936
532.5827
- 344.5936 ]
+ 522.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER30': class LinkAnnotation
-35 0 obj
+36 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 167 0 R
+ /Dest [ 208 0 R
/XYZ
62.69291
- 396.0236
+ 513.0236
0 ]
- /Rect [ 62.69291
- 314.5936
- 219.9529
- 326.5936 ]
+ /Rect [ 82.69291
+ 492.5936
+ 128.2729
+ 504.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Annot.NUMBER31': class LinkAnnotation
-36 0 obj
+37 0 obj
<< /Border [ 0
0
0 ]
/Contents ()
- /Dest [ 167 0 R
+ /Dest [ 208 0 R
/XYZ
62.69291
- 396.0236
+ 513.0236
0 ]
/Rect [ 521.4627
- 314.5936
+ 492.5936
532.5827
- 326.5936 ]
+ 504.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER32': class PDFDictionary
-37 0 obj
+% 'Annot.NUMBER32': class LinkAnnotation
+38 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 309.0236
+ 0 ]
+ /Rect [ 82.69291
+ 474.5936
+ 228.3129
+ 486.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER33': class LinkAnnotation
+39 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 309.0236
+ 0 ]
+ /Rect [ 521.4627
+ 474.5936
+ 532.5827
+ 486.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER34': class LinkAnnotation
+40 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 214 0 R
+ /XYZ
+ 62.69291
+ 681.0236
+ 0 ]
+ /Rect [ 62.69291
+ 456.5936
+ 182.7329
+ 468.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER35': class LinkAnnotation
+41 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 214 0 R
+ /XYZ
+ 62.69291
+ 681.0236
+ 0 ]
+ /Rect [ 521.4627
+ 456.5936
+ 532.5827
+ 468.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER36': class LinkAnnotation
+42 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 438.5936
+ 134.9429
+ 450.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER37': class LinkAnnotation
+43 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 438.5936
+ 532.5827
+ 450.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER38': class LinkAnnotation
+44 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 543.0236
+ 0 ]
+ /Rect [ 82.69291
+ 420.5936
+ 252.7429
+ 432.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER39': class LinkAnnotation
+45 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 543.0236
+ 0 ]
+ /Rect [ 521.4627
+ 420.5936
+ 532.5827
+ 432.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER40': class LinkAnnotation
+46 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 300 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 402.5936
+ 195.5229
+ 414.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER41': class LinkAnnotation
+47 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 300 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 402.5936
+ 532.5827
+ 414.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER42': class LinkAnnotation
+48 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 309 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 82.69291
+ 384.5936
+ 149.9429
+ 396.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER43': class LinkAnnotation
+49 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 309 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 521.4627
+ 384.5936
+ 532.5827
+ 396.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER44': class LinkAnnotation
+50 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 314 0 R
+ /XYZ
+ 62.69291
+ 431.8485
+ 0 ]
+ /Rect [ 82.69291
+ 366.5936
+ 161.0529
+ 378.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER45': class LinkAnnotation
+51 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 314 0 R
+ /XYZ
+ 62.69291
+ 431.8485
+ 0 ]
+ /Rect [ 521.4627
+ 366.5936
+ 532.5827
+ 378.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER46': class LinkAnnotation
+52 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 319 0 R
+ /XYZ
+ 62.69291
+ 515.8236
+ 0 ]
+ /Rect [ 82.69291
+ 348.5936
+ 210.5129
+ 360.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER47': class LinkAnnotation
+53 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 319 0 R
+ /XYZ
+ 62.69291
+ 515.8236
+ 0 ]
+ /Rect [ 521.4627
+ 348.5936
+ 532.5827
+ 360.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER48': class LinkAnnotation
+54 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 324 0 R
+ /XYZ
+ 62.69291
+ 441.5042
+ 0 ]
+ /Rect [ 82.69291
+ 330.5936
+ 167.7229
+ 342.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER49': class LinkAnnotation
+55 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 324 0 R
+ /XYZ
+ 62.69291
+ 441.5042
+ 0 ]
+ /Rect [ 521.4627
+ 330.5936
+ 532.5827
+ 342.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER50': class LinkAnnotation
+56 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 332 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 312.5936
+ 158.2829
+ 324.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER51': class LinkAnnotation
+57 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 332 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 312.5936
+ 532.5827
+ 324.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER52': class LinkAnnotation
+58 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 343 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 82.69291
+ 294.5936
+ 152.7229
+ 306.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER53': class LinkAnnotation
+59 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 343 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 521.4627
+ 294.5936
+ 532.5827
+ 306.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER54': class LinkAnnotation
+60 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 347 0 R
+ /XYZ
+ 62.69291
+ 401.4236
+ 0 ]
+ /Rect [ 82.69291
+ 276.5936
+ 205.5229
+ 288.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER55': class LinkAnnotation
+61 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 347 0 R
+ /XYZ
+ 62.69291
+ 401.4236
+ 0 ]
+ /Rect [ 521.4627
+ 276.5936
+ 532.5827
+ 288.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER56': class LinkAnnotation
+62 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 350 0 R
+ /XYZ
+ 62.69291
+ 408.6236
+ 0 ]
+ /Rect [ 82.69291
+ 258.5936
+ 209.9529
+ 270.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER57': class LinkAnnotation
+63 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 350 0 R
+ /XYZ
+ 62.69291
+ 408.6236
+ 0 ]
+ /Rect [ 521.4627
+ 258.5936
+ 532.5827
+ 270.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER58': class LinkAnnotation
+64 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 354 0 R
+ /XYZ
+ 62.69291
+ 244.6236
+ 0 ]
+ /Rect [ 82.69291
+ 240.5936
+ 192.7429
+ 252.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER59': class LinkAnnotation
+65 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 354 0 R
+ /XYZ
+ 62.69291
+ 244.6236
+ 0 ]
+ /Rect [ 521.4627
+ 240.5936
+ 532.5827
+ 252.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER60': class LinkAnnotation
+66 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 357 0 R
+ /XYZ
+ 62.69291
+ 354.6236
+ 0 ]
+ /Rect [ 82.69291
+ 222.5936
+ 177.1729
+ 234.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER61': class LinkAnnotation
+67 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 357 0 R
+ /XYZ
+ 62.69291
+ 354.6236
+ 0 ]
+ /Rect [ 521.4627
+ 222.5936
+ 532.5827
+ 234.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER62': class LinkAnnotation
+68 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 361 0 R
+ /XYZ
+ 62.69291
+ 511.8236
+ 0 ]
+ /Rect [ 82.69291
+ 204.5936
+ 271.6529
+ 216.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER63': class LinkAnnotation
+69 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 361 0 R
+ /XYZ
+ 62.69291
+ 511.8236
+ 0 ]
+ /Rect [ 521.4627
+ 204.5936
+ 532.5827
+ 216.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER64': class LinkAnnotation
+70 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 363 0 R
+ /XYZ
+ 62.69291
+ 711.0236
+ 0 ]
+ /Rect [ 82.69291
+ 186.5936
+ 286.6829
+ 198.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER65': class LinkAnnotation
+71 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 363 0 R
+ /XYZ
+ 62.69291
+ 711.0236
+ 0 ]
+ /Rect [ 521.4627
+ 186.5936
+ 532.5827
+ 198.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER66': class LinkAnnotation
+72 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 365 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 168.5936
+ 206.6229
+ 180.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER67': class LinkAnnotation
+73 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 365 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 168.5936
+ 532.5827
+ 180.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER68': class LinkAnnotation
+74 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 729.0236
+ 0 ]
+ /Rect [ 82.69291
+ 150.5936
+ 151.6029
+ 162.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER69': class LinkAnnotation
+75 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 729.0236
+ 0 ]
+ /Rect [ 521.4627
+ 150.5936
+ 532.5827
+ 162.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER70': class LinkAnnotation
+76 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 82.69291
+ 132.5936
+ 125.4729
+ 144.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER71': class LinkAnnotation
+77 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 521.4627
+ 132.5936
+ 532.5827
+ 144.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER72': class LinkAnnotation
+78 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 371 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 82.69291
+ 114.5936
+ 246.1129
+ 126.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER73': class LinkAnnotation
+79 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 371 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 521.4627
+ 114.5936
+ 532.5827
+ 126.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page2': class PDFPage
+80 0 obj
+% Page dictionary
+<< /Annots [ 10 0 R
+ 11 0 R
+ 12 0 R
+ 13 0 R
+ 14 0 R
+ 15 0 R
+ 16 0 R
+ 17 0 R
+ 18 0 R
+ 19 0 R
+ 20 0 R
+ 21 0 R
+ 22 0 R
+ 23 0 R
+ 24 0 R
+ 25 0 R
+ 26 0 R
+ 27 0 R
+ 28 0 R
+ 29 0 R
+ 30 0 R
+ 31 0 R
+ 32 0 R
+ 33 0 R
+ 34 0 R
+ 35 0 R
+ 36 0 R
+ 37 0 R
+ 38 0 R
+ 39 0 R
+ 40 0 R
+ 41 0 R
+ 42 0 R
+ 43 0 R
+ 44 0 R
+ 45 0 R
+ 46 0 R
+ 47 0 R
+ 48 0 R
+ 49 0 R
+ 50 0 R
+ 51 0 R
+ 52 0 R
+ 53 0 R
+ 54 0 R
+ 55 0 R
+ 56 0 R
+ 57 0 R
+ 58 0 R
+ 59 0 R
+ 60 0 R
+ 61 0 R
+ 62 0 R
+ 63 0 R
+ 64 0 R
+ 65 0 R
+ 66 0 R
+ 67 0 R
+ 68 0 R
+ 69 0 R
+ 70 0 R
+ 71 0 R
+ 72 0 R
+ 73 0 R
+ 74 0 R
+ 75 0 R
+ 76 0 R
+ 77 0 R
+ 78 0 R
+ 79 0 R ]
+ /Contents 413 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER74': class PDFDictionary
+81 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/getopt.html) >>
@@ -603,14 +1470,14 @@ endobj
0
0 ]
/Rect [ 214.8914
- 248.5936
+ 720.5936
246.5585
- 260.5936 ]
+ 732.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER33': class PDFDictionary
-38 0 obj
+% 'Annot.NUMBER75': class PDFDictionary
+82 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html) >>
@@ -618,14 +1485,14 @@ endobj
0
0 ]
/Rect [ 346.507
- 248.5936
+ 720.5936
389.2842
- 260.5936 ]
+ 732.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER34': class PDFDictionary
-39 0 obj
+% 'Annot.NUMBER76': class PDFDictionary
+83 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -633,14 +1500,14 @@ endobj
0
0 ]
/Rect [ 493.1227
- 248.5936
+ 720.5936
531.4956
- 260.5936 ]
+ 732.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER35': class PDFDictionary
-40 0 obj
+% 'Annot.NUMBER77': class PDFDictionary
+84 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -648,14 +1515,14 @@ endobj
0
0 ]
/Rect [ 346.384
- 236.5936
+ 708.5936
388.8477
- 248.5936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER36': class PDFDictionary
-41 0 obj
+% 'Annot.NUMBER78': class PDFDictionary
+85 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.welton.it/articles/scalable_systems) >>
@@ -663,14 +1530,14 @@ endobj
0
0 ]
/Rect [ 311.5097
- 194.5936
+ 666.5936
371.5115
- 206.5936 ]
+ 678.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER37': class PDFDictionary
-42 0 obj
+% 'Annot.NUMBER79': class PDFDictionary
+86 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -678,14 +1545,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 146.5936
+ 618.5936
84.90623
- 158.5936 ]
+ 630.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER38': class PDFDictionary
-43 0 obj
+% 'Annot.NUMBER80': class PDFDictionary
+87 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -693,14 +1560,14 @@ endobj
0
0 ]
/Rect [ 453.4229
- 134.5936
+ 606.5936
492.8829
- 146.5936 ]
+ 618.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER39': class PDFDictionary
-44 0 obj
+% 'Annot.NUMBER81': class PDFDictionary
+88 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -708,14 +1575,14 @@ endobj
0
0 ]
/Rect [ 116.9711
- 116.5936
+ 588.5936
139.5794
- 128.5936 ]
+ 600.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER40': class PDFDictionary
-45 0 obj
+% 'Annot.NUMBER82': class PDFDictionary
+89 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -723,14 +1590,14 @@ endobj
0
0 ]
/Rect [ 277.9887
- 116.5936
+ 588.5936
321.7169
- 128.5936 ]
+ 600.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER41': class PDFDictionary
-46 0 obj
+% 'Annot.NUMBER83': class PDFDictionary
+90 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -738,14 +1605,14 @@ endobj
0
0 ]
/Rect [ 504.0394
- 104.5936
+ 576.5936
525.3627
- 116.5936 ]
+ 588.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER42': class PDFDictionary
-47 0 obj
+% 'Annot.NUMBER84': class PDFDictionary
+91 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -753,75 +1620,14 @@ endobj
0
0 ]
/Rect [ 351.0408
- 92.59362
+ 564.5936
390.5008
- 104.5936 ]
+ 576.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page1': class PDFPage
-48 0 obj
-% Page dictionary
-<< /Annots [ 5 0 R
- 6 0 R
- 7 0 R
- 9 0 R
- 10 0 R
- 11 0 R
- 12 0 R
- 13 0 R
- 14 0 R
- 15 0 R
- 16 0 R
- 17 0 R
- 18 0 R
- 19 0 R
- 20 0 R
- 21 0 R
- 22 0 R
- 23 0 R
- 24 0 R
- 25 0 R
- 26 0 R
- 27 0 R
- 28 0 R
- 29 0 R
- 30 0 R
- 31 0 R
- 32 0 R
- 33 0 R
- 34 0 R
- 35 0 R
- 36 0 R
- 37 0 R
- 38 0 R
- 39 0 R
- 40 0 R
- 41 0 R
- 42 0 R
- 43 0 R
- 44 0 R
- 45 0 R
- 46 0 R
- 47 0 R ]
- /Contents 186 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 185 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER43': class PDFDictionary
-49 0 obj
+% 'Annot.NUMBER85': class PDFDictionary
+92 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -829,14 +1635,14 @@ endobj
0
0 ]
/Rect [ 247.8817
- 744.5936
+ 540.5936
266.2217
- 756.5936 ]
+ 552.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER44': class PDFDictionary
-50 0 obj
+% 'Annot.NUMBER86': class PDFDictionary
+93 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -844,14 +1650,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 714.5936
+ 510.5936
85.3538
- 726.5936 ]
+ 522.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER45': class PDFDictionary
-51 0 obj
+% 'Annot.NUMBER87': class PDFDictionary
+94 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -859,14 +1665,14 @@ endobj
0
0 ]
/Rect [ 124.2211
- 642.5936
+ 438.5936
146.9252
- 654.5936 ]
+ 450.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'F5': class PDFType1Font
-52 0 obj
+95 0 obj
% Font Helvetica-Oblique
<< /BaseFont /Helvetica-Oblique
/Encoding /WinAnsiEncoding
@@ -874,8 +1680,41 @@ endobj
/Subtype /Type1
/Type /Font >>
endobj
-% 'Annot.NUMBER46': class PDFDictionary
-53 0 obj
+% 'Page3': class PDFPage
+96 0 obj
+% Page dictionary
+<< /Annots [ 81 0 R
+ 82 0 R
+ 83 0 R
+ 84 0 R
+ 85 0 R
+ 86 0 R
+ 87 0 R
+ 88 0 R
+ 89 0 R
+ 90 0 R
+ 91 0 R
+ 92 0 R
+ 93 0 R
+ 94 0 R ]
+ /Contents 414 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER88': class PDFDictionary
+97 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/getopt.html) >>
@@ -883,14 +1722,14 @@ endobj
0
0 ]
/Rect [ 325.341
- 250.3936
+ 720.5936
356.6198
- 262.3936 ]
+ 732.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER47': class PDFDictionary
-54 0 obj
+% 'Annot.NUMBER89': class PDFDictionary
+98 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html) >>
@@ -898,14 +1737,14 @@ endobj
0
0 ]
/Rect [ 376.7786
- 250.3936
+ 720.5936
419.1674
- 262.3936 ]
+ 732.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER48': class PDFDictionary
-55 0 obj
+% 'Annot.NUMBER90': class PDFDictionary
+99 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -913,39 +1752,14 @@ endobj
0
0 ]
/Rect [ 365.694
- 238.3936
+ 708.5936
408.8281
- 250.3936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page2': class PDFPage
-56 0 obj
-% Page dictionary
-<< /Annots [ 49 0 R
- 50 0 R
- 51 0 R
- 53 0 R
- 54 0 R
- 55 0 R ]
- /Contents 187 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 185 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER49': class PDFDictionary
-57 0 obj
+% 'Annot.NUMBER91': class PDFDictionary
+100 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -953,14 +1767,14 @@ endobj
0
0 ]
/Rect [ 83.82606
- 645.3936
+ 457.3936
106.0692
- 657.3936 ]
+ 469.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER50': class PDFDictionary
-58 0 obj
+% 'Annot.NUMBER92': class PDFDictionary
+101 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -968,14 +1782,14 @@ endobj
0
0 ]
/Rect [ 243.8829
- 633.3936
+ 445.3936
265.0029
- 645.3936 ]
+ 457.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER51': class PDFDictionary
-59 0 obj
+% 'Annot.NUMBER93': class PDFDictionary
+102 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -983,14 +1797,14 @@ endobj
0
0 ]
/Rect [ 83.6329
- 496.1936
+ 308.1936
105.6829
- 508.1936 ]
+ 320.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER52': class PDFDictionary
-60 0 obj
+% 'Annot.NUMBER94': class PDFDictionary
+103 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -998,14 +1812,14 @@ endobj
0
0 ]
/Rect [ 421.9727
- 496.1936
+ 308.1936
465.1427
- 508.1936 ]
+ 320.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER53': class PDFDictionary
-61 0 obj
+% 'Annot.NUMBER95': class PDFDictionary
+104 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1013,14 +1827,14 @@ endobj
0
0 ]
/Rect [ 107.8707
- 301.7936
+ 113.7936
129.1584
- 313.7936 ]
+ 125.7936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER54': class PDFDictionary
-62 0 obj
+% 'Annot.NUMBER96': class PDFDictionary
+105 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1028,27 +1842,30 @@ endobj
0
0 ]
/Rect [ 117.7229
- 289.7936
+ 101.7936
138.8429
- 301.7936 ]
+ 113.7936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page3': class PDFPage
-63 0 obj
+% 'Page4': class PDFPage
+106 0 obj
% Page dictionary
-<< /Annots [ 57 0 R
- 58 0 R
- 59 0 R
- 60 0 R
- 61 0 R
- 62 0 R ]
- /Contents 188 0 R
+<< /Annots [ 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 ]
+ /Contents 415 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1059,8 +1876,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER55': class PDFDictionary
-64 0 obj
+% 'Annot.NUMBER97': class PDFDictionary
+107 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1068,14 +1885,14 @@ endobj
0
0 ]
/Rect [ 321.4303
- 627.3936
+ 463.3936
363.754
- 639.3936 ]
+ 475.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER56': class PDFDictionary
-65 0 obj
+% 'Annot.NUMBER98': class PDFDictionary
+108 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1083,14 +1900,14 @@ endobj
0
0 ]
/Rect [ 126.0429
- 615.3936
+ 451.3936
147.1629
- 627.3936 ]
+ 463.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER57': class PDFDictionary
-66 0 obj
+% 'Annot.NUMBER99': class PDFDictionary
+109 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1098,24 +1915,24 @@ endobj
0
0 ]
/Rect [ 62.69291
- 376.9936
+ 212.9936
84.20915
- 388.9936 ]
+ 224.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page4': class PDFPage
-67 0 obj
+% 'Page5': class PDFPage
+110 0 obj
% Page dictionary
-<< /Annots [ 64 0 R
- 65 0 R
- 66 0 R ]
- /Contents 189 0 R
+<< /Annots [ 107 0 R
+ 108 0 R
+ 109 0 R ]
+ /Contents 416 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1126,8 +1943,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER58': class PDFDictionary
-68 0 obj
+% 'Annot.NUMBER100': class PDFDictionary
+111 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1135,14 +1952,14 @@ endobj
0
0 ]
/Rect [ 446.1627
- 675.3936
+ 514.1936
464.5027
- 687.3936 ]
+ 526.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER59': class PDFDictionary
-69 0 obj
+% 'Annot.NUMBER101': class PDFDictionary
+112 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1150,14 +1967,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 645.3936
+ 484.1936
86.84915
- 657.3936 ]
+ 496.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER60': class PDFDictionary
-70 0 obj
+% 'Annot.NUMBER102': class PDFDictionary
+113 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://code.activestate.com/recipes/278844-parsing-the-command-line/) >>
@@ -1165,14 +1982,36 @@ endobj
0
0 ]
/Rect [ 315.119
- 645.3936
+ 484.1936
367.369
- 657.3936 ]
+ 496.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER61': class PDFDictionary
-71 0 obj
+% 'Page6': class PDFPage
+114 0 obj
+% Page dictionary
+<< /Annots [ 111 0 R
+ 112 0 R
+ 113 0 R ]
+ /Contents 417 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER103': class PDFDictionary
+115 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1180,14 +2019,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 244.9936
+ 756.5936
83.81291
- 256.9936 ]
+ 768.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER62': class PDFDictionary
-72 0 obj
+% 'Annot.NUMBER104': class PDFDictionary
+116 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://code.activestate.com/recipes/278844-parsing-the-command-line/) >>
@@ -1195,14 +2034,14 @@ endobj
0
0 ]
/Rect [ 240.1228
- 145.9936
+ 660.5936
297.7099
- 157.9936 ]
+ 672.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER63': class PDFDictionary
-73 0 obj
+% 'Annot.NUMBER105': class PDFDictionary
+117 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://code.activestate.com/recipes/278844-parsing-the-command-line/) >>
@@ -1210,14 +2049,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 133.9936
+ 648.5936
114.9429
- 145.9936 ]
+ 660.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER64': class PDFDictionary
-74 0 obj
+% 'Annot.NUMBER106': class PDFDictionary
+118 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1225,40 +2064,14 @@ endobj
0
0 ]
/Rect [ 496.4721
- 133.9936
+ 648.5936
518.6827
- 145.9936 ]
+ 660.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page5': class PDFPage
-75 0 obj
-% Page dictionary
-<< /Annots [ 68 0 R
- 69 0 R
- 70 0 R
- 71 0 R
- 72 0 R
- 73 0 R
- 74 0 R ]
- /Contents 190 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 185 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER65': class PDFDictionary
-76 0 obj
+% 'Annot.NUMBER107': class PDFDictionary
+119 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1266,22 +2079,26 @@ endobj
0
0 ]
/Rect [ 494.1558
- 627.3936
+ 487.3936
515.9027
- 639.3936 ]
+ 499.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page6': class PDFPage
-77 0 obj
+% 'Page7': class PDFPage
+120 0 obj
% Page dictionary
-<< /Annots [ 76 0 R ]
- /Contents 191 0 R
+<< /Annots [ 115 0 R
+ 116 0 R
+ 117 0 R
+ 118 0 R
+ 119 0 R ]
+ /Contents 418 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1292,31 +2109,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER66': class PDFDictionary
-78 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 62.69291
- 195.5936
- 84.62846
- 207.5936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Page7': class PDFPage
-79 0 obj
+% 'Page8': class PDFPage
+121 0 obj
% Page dictionary
-<< /Annots [ 78 0 R ]
- /Contents 192 0 R
+<< /Contents 419 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1327,8 +2128,23 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER67': class PDFDictionary
-80 0 obj
+% 'Annot.NUMBER108': class PDFDictionary
+122 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 732.5936
+ 84.62846
+ 744.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER109': class PDFDictionary
+123 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1336,22 +2152,23 @@ endobj
0
0 ]
/Rect [ 110.2829
- 317.9936
+ 209.2999
132.8629
- 329.9936 ]
+ 221.2999 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page8': class PDFPage
-81 0 obj
+% 'Page9': class PDFPage
+124 0 obj
% Page dictionary
-<< /Annots [ 80 0 R ]
- /Contents 193 0 R
+<< /Annots [ 122 0 R
+ 123 0 R ]
+ /Contents 420 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1362,8 +2179,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER68': class PDFDictionary
-82 0 obj
+% 'Annot.NUMBER110': class PDFDictionary
+125 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1371,14 +2188,14 @@ endobj
0
0 ]
/Rect [ 392.5829
- 663.3936
+ 538.1936
413.7029
- 675.3936 ]
+ 550.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER69': class PDFDictionary
-83 0 obj
+% 'Annot.NUMBER111': class PDFDictionary
+126 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1386,14 +2203,14 @@ endobj
0
0 ]
/Rect [ 157.3904
- 612.3936
+ 490.1936
179.9938
- 624.3936 ]
+ 502.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER70': class PDFDictionary
-84 0 obj
+% 'Annot.NUMBER112': class PDFDictionary
+127 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1401,14 +2218,14 @@ endobj
0
0 ]
/Rect [ 184.0634
- 600.3936
+ 478.1936
223.5234
- 612.3936 ]
+ 490.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER71': class PDFDictionary
-85 0 obj
+% 'Annot.NUMBER113': class PDFDictionary
+128 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1416,14 +2233,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 588.3936
+ 466.1936
102.1529
- 600.3936 ]
+ 478.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER72': class PDFDictionary
-86 0 obj
+% 'Annot.NUMBER114': class PDFDictionary
+129 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1431,14 +2248,14 @@ endobj
0
0 ]
/Rect [ 192.7997
- 588.3936
+ 466.1936
237.9391
- 600.3936 ]
+ 478.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER73': class PDFDictionary
-87 0 obj
+% 'Annot.NUMBER115': class PDFDictionary
+130 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1446,14 +2263,14 @@ endobj
0
0 ]
/Rect [ 324.4372
- 588.3936
+ 466.1936
342.7772
- 600.3936 ]
+ 478.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER74': class PDFDictionary
-88 0 obj
+% 'Annot.NUMBER116': class PDFDictionary
+131 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1461,28 +2278,28 @@ endobj
0
0 ]
/Rect [ 360.0429
- 396.3936
+ 274.1936
402.2829
- 408.3936 ]
+ 286.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page9': class PDFPage
-89 0 obj
+% 'Page10': class PDFPage
+132 0 obj
% Page dictionary
-<< /Annots [ 82 0 R
- 83 0 R
- 84 0 R
- 85 0 R
- 86 0 R
- 87 0 R
- 88 0 R ]
- /Contents 194 0 R
+<< /Annots [ 125 0 R
+ 126 0 R
+ 127 0 R
+ 128 0 R
+ 129 0 R
+ 130 0 R
+ 131 0 R ]
+ /Contents 421 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1493,15 +2310,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page10': class PDFPage
-90 0 obj
+% 'Page11': class PDFPage
+133 0 obj
% Page dictionary
-<< /Contents 195 0 R
+<< /Contents 422 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1512,8 +2329,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER75': class PDFDictionary
-91 0 obj
+% 'Annot.NUMBER117': class PDFDictionary
+134 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1521,14 +2338,14 @@ endobj
0
0 ]
/Rect [ 338.1568
- 648.3936
+ 520.1936
360.5113
- 660.3936 ]
+ 532.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER76': class PDFDictionary
-92 0 obj
+% 'Annot.NUMBER118': class PDFDictionary
+135 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.sqlalchemy.org/) >>
@@ -1536,14 +2353,14 @@ endobj
0
0 ]
/Rect [ 110.6843
- 636.3936
+ 508.1936
169.0343
- 648.3936 ]
+ 520.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER77': class PDFDictionary
-93 0 obj
+% 'Annot.NUMBER119': class PDFDictionary
+136 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.sqlalchemy.org/docs/reference/ext/sqlsoup.html) >>
@@ -1551,24 +2368,24 @@ endobj
0
0 ]
/Rect [ 168.3029
- 624.3936
+ 496.1936
208.8829
- 636.3936 ]
+ 508.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page11': class PDFPage
-94 0 obj
+% 'Page12': class PDFPage
+137 0 obj
% Page dictionary
-<< /Annots [ 91 0 R
- 92 0 R
- 93 0 R ]
- /Contents 196 0 R
+<< /Annots [ 134 0 R
+ 135 0 R
+ 136 0 R ]
+ /Contents 423 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1579,8 +2396,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER78': class PDFDictionary
-95 0 obj
+% 'Annot.NUMBER120': class PDFDictionary
+138 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1588,14 +2405,14 @@ endobj
0
0 ]
/Rect [ 185.0709
- 588.3936
+ 481.3936
208.0228
- 600.3936 ]
+ 493.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER79': class PDFDictionary
-96 0 obj
+% 'Annot.NUMBER121': class PDFDictionary
+139 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1603,23 +2420,23 @@ endobj
0
0 ]
/Rect [ 220.5998
- 576.3936
+ 469.3936
243.819
- 588.3936 ]
+ 481.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page12': class PDFPage
-97 0 obj
+% 'Page13': class PDFPage
+140 0 obj
% Page dictionary
-<< /Annots [ 95 0 R
- 96 0 R ]
- /Contents 197 0 R
+<< /Annots [ 138 0 R
+ 139 0 R ]
+ /Contents 424 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1630,8 +2447,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER80': class PDFDictionary
-98 0 obj
+% 'Annot.NUMBER122': class PDFDictionary
+141 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1639,22 +2456,22 @@ endobj
0
0 ]
/Rect [ 374.4929
- 535.1936
+ 436.9936
395.6129
- 547.1936 ]
+ 448.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page13': class PDFPage
-99 0 obj
+% 'Page14': class PDFPage
+142 0 obj
% Page dictionary
-<< /Annots [ 98 0 R ]
- /Contents 198 0 R
+<< /Annots [ 141 0 R ]
+ /Contents 425 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1665,8 +2482,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER81': class PDFDictionary
-100 0 obj
+% 'Annot.NUMBER123': class PDFDictionary
+143 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1674,14 +2491,14 @@ endobj
0
0 ]
/Rect [ 304.0655
- 486.3936
+ 378.3936
348.3808
- 498.3936 ]
+ 390.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER82': class PDFDictionary
-101 0 obj
+% 'Annot.NUMBER124': class PDFDictionary
+144 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1689,23 +2506,23 @@ endobj
0
0 ]
/Rect [ 293.7749
- 312.3936
+ 204.3936
316.2402
- 324.3936 ]
+ 216.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page14': class PDFPage
-102 0 obj
+% 'Page15': class PDFPage
+145 0 obj
% Page dictionary
-<< /Annots [ 100 0 R
- 101 0 R ]
- /Contents 199 0 R
+<< /Annots [ 143 0 R
+ 144 0 R ]
+ /Contents 426 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1716,8 +2533,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER83': class PDFDictionary
-103 0 obj
+% 'Annot.NUMBER125': class PDFDictionary
+146 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1725,14 +2542,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 476.3936
+ 390.1936
84.8789
- 488.3936 ]
+ 402.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER84': class PDFDictionary
-104 0 obj
+% 'Annot.NUMBER126': class PDFDictionary
+147 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1740,14 +2557,14 @@ endobj
0
0 ]
/Rect [ 466.5307
- 476.3936
+ 390.1936
509.8367
- 488.3936 ]
+ 402.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER85': class PDFDictionary
-105 0 obj
+% 'Annot.NUMBER127': class PDFDictionary
+148 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1755,14 +2572,14 @@ endobj
0
0 ]
/Rect [ 124.3929
- 452.3936
+ 366.1936
163.8529
- 464.3936 ]
+ 378.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER86': class PDFDictionary
-106 0 obj
+% 'Annot.NUMBER128': class PDFDictionary
+149 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1770,14 +2587,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 371.3936
+ 285.1936
127.9329
- 383.3936 ]
+ 297.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER87': class PDFDictionary
-107 0 obj
+% 'Annot.NUMBER129': class PDFDictionary
+150 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1785,14 +2602,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 353.3936
+ 267.1936
107.9337
- 365.3936 ]
+ 279.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER88': class PDFDictionary
-108 0 obj
+% 'Annot.NUMBER130': class PDFDictionary
+151 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1800,14 +2617,14 @@ endobj
0
0 ]
/Rect [ 308.5389
- 353.3936
+ 267.1936
351.8997
- 365.3936 ]
+ 279.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER89': class PDFDictionary
-109 0 obj
+% 'Annot.NUMBER131': class PDFDictionary
+152 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1815,14 +2632,14 @@ endobj
0
0 ]
/Rect [ 380.6856
- 329.3936
+ 243.1936
423.7999
- 341.3936 ]
+ 255.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER90': class PDFDictionary
-110 0 obj
+% 'Annot.NUMBER132': class PDFDictionary
+153 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1830,14 +2647,14 @@ endobj
0
0 ]
/Rect [ 494.4684
- 329.3936
+ 243.1936
516.4627
- 341.3936 ]
+ 255.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER91': class PDFDictionary
-111 0 obj
+% 'Annot.NUMBER133': class PDFDictionary
+154 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1845,14 +2662,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 299.3936
+ 213.1936
108.3529
- 311.3936 ]
+ 225.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER92': class PDFDictionary
-112 0 obj
+% 'Annot.NUMBER134': class PDFDictionary
+155 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1860,14 +2677,14 @@ endobj
0
0 ]
/Rect [ 277.2428
- 299.3936
+ 213.1936
321.0228
- 311.3936 ]
+ 225.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER93': class PDFDictionary
-113 0 obj
+% 'Annot.NUMBER135': class PDFDictionary
+156 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1875,14 +2692,14 @@ endobj
0
0 ]
/Rect [ 404.5839
- 287.3936
+ 201.1936
426.0657
- 299.3936 ]
+ 213.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER94': class PDFDictionary
-114 0 obj
+% 'Annot.NUMBER136': class PDFDictionary
+157 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1890,14 +2707,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 233.3936
+ 147.1936
108.61
- 245.3936 ]
+ 159.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER95': class PDFDictionary
-115 0 obj
+% 'Annot.NUMBER137': class PDFDictionary
+158 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1905,14 +2722,46 @@ endobj
0
0 ]
/Rect [ 459.2622
- 221.3936
+ 135.1936
481.289
- 233.3936 ]
+ 147.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER96': class PDFDictionary
-116 0 obj
+% 'Page16': class PDFPage
+159 0 obj
+% Page dictionary
+<< /Annots [ 146 0 R
+ 147 0 R
+ 148 0 R
+ 149 0 R
+ 150 0 R
+ 151 0 R
+ 152 0 R
+ 153 0 R
+ 154 0 R
+ 155 0 R
+ 156 0 R
+ 157 0 R
+ 158 0 R ]
+ /Contents 427 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER138': class PDFDictionary
+160 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1920,14 +2769,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 191.3936
+ 753.5936
108.9242
- 203.3936 ]
+ 765.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER97': class PDFDictionary
-117 0 obj
+% 'Annot.NUMBER139': class PDFDictionary
+161 0 obj
<< /A << /S /URI
/Type /Action
/URI (file:///home/micheles/Dropbox/md/gcodedev/plac/in-writing) >>
@@ -1935,14 +2784,14 @@ endobj
0
0 ]
/Rect [ 340.9248
- 191.3936
+ 753.5936
470.1087
- 203.3936 ]
+ 765.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER98': class PDFDictionary
-118 0 obj
+% 'Annot.NUMBER140': class PDFDictionary
+162 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1950,14 +2799,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 161.3936
+ 723.5936
107.9247
- 173.3936 ]
+ 735.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER99': class PDFDictionary
-119 0 obj
+% 'Annot.NUMBER141': class PDFDictionary
+163 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1965,14 +2814,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 149.3936
+ 711.5936
104.0329
- 161.3936 ]
+ 723.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER100': class PDFDictionary
-120 0 obj
+% 'Annot.NUMBER142': class PDFDictionary
+164 0 obj
<< /A << /S /URI
/Type /Action
/URI (file:///home/micheles/Dropbox/md/gcodedev/plac/in-writing) >>
@@ -1980,14 +2829,14 @@ endobj
0
0 ]
/Rect [ 489.2227
- 149.3936
+ 711.5936
532.176
- 161.3936 ]
+ 723.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER101': class PDFDictionary
-121 0 obj
+% 'Annot.NUMBER143': class PDFDictionary
+165 0 obj
<< /A << /S /URI
/Type /Action
/URI (file:///home/micheles/Dropbox/md/gcodedev/plac/in-writing) >>
@@ -1995,14 +2844,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 137.3936
+ 699.5936
159.6229
- 149.3936 ]
+ 711.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER102': class PDFDictionary
-122 0 obj
+% 'Annot.NUMBER144': class PDFDictionary
+166 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2010,14 +2859,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 116.3936
+ 678.5936
83.81291
- 128.3936 ]
+ 690.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER103': class PDFDictionary
-123 0 obj
+% 'Annot.NUMBER145': class PDFDictionary
+167 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2025,54 +2874,14 @@ endobj
0
0 ]
/Rect [ 219.4229
- 116.3936
+ 678.5936
261.6629
- 128.3936 ]
+ 690.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page15': class PDFPage
-124 0 obj
-% Page dictionary
-<< /Annots [ 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
- 118 0 R
- 119 0 R
- 120 0 R
- 121 0 R
- 122 0 R
- 123 0 R ]
- /Contents 200 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 185 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER104': class PDFDictionary
-125 0 obj
+% 'Annot.NUMBER146': class PDFDictionary
+168 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/other-utilities.html?highlight=filetype#FileType) >>
@@ -2080,14 +2889,14 @@ endobj
0
0 ]
/Rect [ 455.2227
- 744.5936
+ 648.5936
534.3667
- 756.5936 ]
+ 660.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER105': class PDFDictionary
-126 0 obj
+% 'Annot.NUMBER147': class PDFDictionary
+169 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2095,14 +2904,14 @@ endobj
0
0 ]
/Rect [ 325.7268
- 577.3936
+ 481.3936
347.4138
- 589.3936 ]
+ 493.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER106': class PDFDictionary
-127 0 obj
+% 'Annot.NUMBER148': class PDFDictionary
+170 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html) >>
@@ -2110,14 +2919,14 @@ endobj
0
0 ]
/Rect [ 327.2261
- 410.1936
+ 314.1936
410.5152
- 422.1936 ]
+ 326.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER107': class PDFDictionary
-128 0 obj
+% 'Annot.NUMBER149': class PDFDictionary
+171 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2125,14 +2934,14 @@ endobj
0
0 ]
/Rect [ 275.5829
- 230.9936
+ 134.9936
317.8229
- 242.9936 ]
+ 146.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER108': class PDFDictionary
-129 0 obj
+% 'Annot.NUMBER150': class PDFDictionary
+172 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2140,14 +2949,14 @@ endobj
0
0 ]
/Rect [ 307.9178
- 212.9936
+ 116.9936
351.5999
- 224.9936 ]
+ 128.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER109': class PDFDictionary
-130 0 obj
+% 'Annot.NUMBER151': class PDFDictionary
+173 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2155,14 +2964,47 @@ endobj
0
0 ]
/Rect [ 329.8034
- 188.9936
+ 92.99362
352.1804
- 200.9936 ]
+ 104.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER110': class PDFDictionary
-131 0 obj
+% 'Page17': class PDFPage
+174 0 obj
+% Page dictionary
+<< /Annots [ 160 0 R
+ 161 0 R
+ 162 0 R
+ 163 0 R
+ 164 0 R
+ 165 0 R
+ 166 0 R
+ 167 0 R
+ 168 0 R
+ 169 0 R
+ 170 0 R
+ 171 0 R
+ 172 0 R
+ 173 0 R ]
+ /Contents 428 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER152': class PDFDictionary
+175 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2170,14 +3012,14 @@ endobj
0
0 ]
/Rect [ 109.0098
- 125.9936
+ 708.5936
131.9967
- 137.9936 ]
+ 720.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER111': class PDFDictionary
-132 0 obj
+% 'Annot.NUMBER153': class PDFDictionary
+176 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2185,41 +3027,14 @@ endobj
0
0 ]
/Rect [ 397.2929
- 101.9936
+ 684.5936
415.6329
- 113.9936 ]
+ 696.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page16': class PDFPage
-133 0 obj
-% Page dictionary
-<< /Annots [ 125 0 R
- 126 0 R
- 127 0 R
- 128 0 R
- 129 0 R
- 130 0 R
- 131 0 R
- 132 0 R ]
- /Contents 201 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 185 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
-% 'Annot.NUMBER112': class PDFDictionary
-134 0 obj
+% 'Annot.NUMBER154': class PDFDictionary
+177 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/opterator) >>
@@ -2227,14 +3042,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 753.5936
+ 663.5936
128.4929
- 765.5936 ]
+ 675.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER113': class PDFDictionary
-135 0 obj
+% 'Annot.NUMBER155': class PDFDictionary
+178 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/CLIArgs) >>
@@ -2242,14 +3057,14 @@ endobj
0
0 ]
/Rect [ 85.69291
- 735.5936
+ 645.5936
124.5929
- 747.5936 ]
+ 657.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER114': class PDFDictionary
-136 0 obj
+% 'Annot.NUMBER156': class PDFDictionary
+179 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2257,14 +3072,14 @@ endobj
0
0 ]
/Rect [ 464.3898
- 714.5936
+ 624.5936
503.8498
- 726.5936 ]
+ 636.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER115': class PDFDictionary
-137 0 obj
+% 'Annot.NUMBER157': class PDFDictionary
+180 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2272,14 +3087,14 @@ endobj
0
0 ]
/Rect [ 305.0429
- 702.5936
+ 612.5936
323.3829
- 714.5936 ]
+ 624.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER116': class PDFDictionary
-138 0 obj
+% 'Annot.NUMBER158': class PDFDictionary
+181 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/Clap/0.7) >>
@@ -2287,14 +3102,14 @@ endobj
0
0 ]
/Rect [ 455.0104
- 684.5936
+ 594.5936
479.9015
- 696.5936 ]
+ 606.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER117': class PDFDictionary
-139 0 obj
+% 'Annot.NUMBER159': class PDFDictionary
+182 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2302,14 +3117,14 @@ endobj
0
0 ]
/Rect [ 303.707
- 672.5936
+ 582.5936
322.047
- 684.5936 ]
+ 594.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER118': class PDFDictionary
-140 0 obj
+% 'Annot.NUMBER160': class PDFDictionary
+183 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/Clap/0.7) >>
@@ -2317,14 +3132,14 @@ endobj
0
0 ]
/Rect [ 328.8186
- 672.5936
+ 582.5936
353.3701
- 684.5936 ]
+ 594.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER119': class PDFDictionary
-141 0 obj
+% 'Annot.NUMBER161': class PDFDictionary
+184 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2332,14 +3147,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 660.5936
+ 570.5936
81.03291
- 672.5936 ]
+ 582.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER120': class PDFDictionary
-142 0 obj
+% 'Annot.NUMBER162': class PDFDictionary
+185 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2347,14 +3162,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 642.5936
+ 552.5936
84.4354
- 654.5936 ]
+ 564.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER121': class PDFDictionary
-143 0 obj
+% 'Annot.NUMBER163': class PDFDictionary
+186 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/cmd.html) >>
@@ -2362,14 +3177,14 @@ endobj
0
0 ]
/Rect [ 275.6978
- 642.5936
+ 552.5936
297.9903
- 654.5936 ]
+ 564.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER122': class PDFDictionary
-144 0 obj
+% 'Annot.NUMBER164': class PDFDictionary
+187 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://packages.python.org/cmd2/) >>
@@ -2377,14 +3192,14 @@ endobj
0
0 ]
/Rect [ 203.5285
- 630.5936
+ 540.5936
231.1357
- 642.5936 ]
+ 552.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER123': class PDFDictionary
-145 0 obj
+% 'Annot.NUMBER165': class PDFDictionary
+188 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://packages.python.org/cmd2/) >>
@@ -2392,14 +3207,14 @@ endobj
0
0 ]
/Rect [ 164.4129
- 618.5936
+ 528.5936
191.6429
- 630.5936 ]
+ 540.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER124': class PDFDictionary
-146 0 obj
+% 'Annot.NUMBER166': class PDFDictionary
+189 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2407,14 +3222,14 @@ endobj
0
0 ]
/Rect [ 302.7929
- 618.5936
+ 528.5936
321.1329
- 630.5936 ]
+ 540.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER125': class PDFDictionary
-147 0 obj
+% 'Annot.NUMBER167': class PDFDictionary
+190 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2422,14 +3237,14 @@ endobj
0
0 ]
/Rect [ 156.6051
- 567.5936
+ 480.5936
177.8606
- 579.5936 ]
+ 492.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER126': class PDFDictionary
-148 0 obj
+% 'Annot.NUMBER168': class PDFDictionary
+191 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2437,14 +3252,14 @@ endobj
0
0 ]
/Rect [ 186.6535
- 543.5936
+ 456.5936
226.1135
- 555.5936 ]
+ 468.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER127': class PDFDictionary
-149 0 obj
+% 'Annot.NUMBER169': class PDFDictionary
+192 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2452,14 +3267,14 @@ endobj
0
0 ]
/Rect [ 493.1227
- 543.5936
+ 456.5936
532.4646
- 555.5936 ]
+ 468.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER128': class PDFDictionary
-150 0 obj
+% 'Annot.NUMBER170': class PDFDictionary
+193 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2467,14 +3282,14 @@ endobj
0
0 ]
/Rect [ 72.7804
- 531.5936
+ 444.5936
96.20788
- 543.5936 ]
+ 456.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER129': class PDFDictionary
-151 0 obj
+% 'Annot.NUMBER171': class PDFDictionary
+194 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2482,14 +3297,14 @@ endobj
0
0 ]
/Rect [ 149.2229
- 501.5936
+ 414.5936
171.2704
- 513.5936 ]
+ 426.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER130': class PDFDictionary
-152 0 obj
+% 'Annot.NUMBER172': class PDFDictionary
+195 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2497,14 +3312,14 @@ endobj
0
0 ]
/Rect [ 128.0309
- 459.5936
+ 372.5936
149.4369
- 471.5936 ]
+ 384.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER131': class PDFDictionary
-153 0 obj
+% 'Annot.NUMBER173': class PDFDictionary
+196 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2512,14 +3327,14 @@ endobj
0
0 ]
/Rect [ 502.8367
- 459.5936
+ 372.5936
524.2427
- 471.5936 ]
+ 384.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER132': class PDFDictionary
-154 0 obj
+% 'Annot.NUMBER174': class PDFDictionary
+197 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2527,14 +3342,14 @@ endobj
0
0 ]
/Rect [ 187.4797
- 435.5936
+ 348.5936
209.0991
- 447.5936 ]
+ 360.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER133': class PDFDictionary
-155 0 obj
+% 'Annot.NUMBER175': class PDFDictionary
+198 0 obj
<< /A << /S /URI
/Type /Action
/URI (file:///home/micheles/Dropbox/md/gcodedev/plac/in-writing) >>
@@ -2542,14 +3357,14 @@ endobj
0
0 ]
/Rect [ 301.6965
- 435.5936
+ 348.5936
426.0446
- 447.5936 ]
+ 360.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER134': class PDFDictionary
-156 0 obj
+% 'Annot.NUMBER176': class PDFDictionary
+199 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2557,14 +3372,14 @@ endobj
0
0 ]
/Rect [ 83.6829
- 360.5936
+ 276.5936
105.7829
- 372.5936 ]
+ 288.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER135': class PDFDictionary
-157 0 obj
+% 'Annot.NUMBER177': class PDFDictionary
+200 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://code.activestate.com/recipes/278844-parsing-the-command-line/) >>
@@ -2572,14 +3387,14 @@ endobj
0
0 ]
/Rect [ 446.5627
- 360.5936
+ 276.5936
502.5727
- 372.5936 ]
+ 288.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER136': class PDFDictionary
-158 0 obj
+% 'Annot.NUMBER178': class PDFDictionary
+201 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2587,14 +3402,14 @@ endobj
0
0 ]
/Rect [ 275.6828
- 348.5936
+ 264.5936
297.3688
- 360.5936 ]
+ 276.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER137': class PDFDictionary
-159 0 obj
+% 'Annot.NUMBER179': class PDFDictionary
+202 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/optparse.html?highlight=optionparser#optparse.OptionParser) >>
@@ -2602,14 +3417,14 @@ endobj
0
0 ]
/Rect [ 77.19665
- 336.5936
+ 252.5936
139.4904
- 348.5936 ]
+ 264.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER138': class PDFDictionary
-160 0 obj
+% 'Annot.NUMBER180': class PDFDictionary
+203 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2617,14 +3432,14 @@ endobj
0
0 ]
/Rect [ 96.54131
- 324.5936
+ 240.5936
139.0255
- 336.5936 ]
+ 252.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER139': class PDFDictionary
-161 0 obj
+% 'Annot.NUMBER181': class PDFDictionary
+204 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2632,14 +3447,14 @@ endobj
0
0 ]
/Rect [ 203.5016
- 291.5936
+ 207.5936
245.8453
- 303.5936 ]
+ 219.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER140': class PDFDictionary
-162 0 obj
+% 'Annot.NUMBER182': class PDFDictionary
+205 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com/svn/tags/r11/doc/ArgumentParser.html) >>
@@ -2647,14 +3462,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 216.5936
+ 132.5936
138.7898
- 228.5936 ]
+ 144.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER141': class PDFDictionary
-163 0 obj
+% 'Annot.NUMBER183': class PDFDictionary
+206 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2662,14 +3477,14 @@ endobj
0
0 ]
/Rect [ 114.6649
- 204.5936
+ 120.5936
154.1249
- 216.5936 ]
+ 132.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER142': class PDFDictionary
-164 0 obj
+% 'Annot.NUMBER184': class PDFDictionary
+207 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -2677,14 +3492,66 @@ endobj
0
0 ]
/Rect [ 191.6329
- 192.5936
+ 108.5936
233.8729
- 204.5936 ]
+ 120.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER143': class PDFDictionary
-165 0 obj
+% 'Page18': class PDFPage
+208 0 obj
+% Page dictionary
+<< /Annots [ 175 0 R
+ 176 0 R
+ 177 0 R
+ 178 0 R
+ 179 0 R
+ 180 0 R
+ 181 0 R
+ 182 0 R
+ 183 0 R
+ 184 0 R
+ 185 0 R
+ 186 0 R
+ 187 0 R
+ 188 0 R
+ 189 0 R
+ 190 0 R
+ 191 0 R
+ 192 0 R
+ 193 0 R
+ 194 0 R
+ 195 0 R
+ 196 0 R
+ 197 0 R
+ 198 0 R
+ 199 0 R
+ 200 0 R
+ 201 0 R
+ 202 0 R
+ 203 0 R
+ 204 0 R
+ 205 0 R
+ 206 0 R
+ 207 0 R ]
+ /Contents 429 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER185': class PDFDictionary
+209 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/Clap/0.7) >>
@@ -2692,14 +3559,14 @@ endobj
0
0 ]
/Rect [ 263.3429
- 162.5936
+ 744.5936
286.6829
- 174.5936 ]
+ 756.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER144': class PDFDictionary
-166 0 obj
+% 'Annot.NUMBER186': class PDFDictionary
+210 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2707,54 +3574,1420 @@ endobj
0
0 ]
/Rect [ 258.5629
- 114.5936
+ 696.5936
276.9029
+ 708.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER187': class PDFDictionary
+211 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (mailto:michele.simionato@gmail.com) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 153.7323
+ 624.5936
+ 526.5827
+ 636.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER188': class PDFDictionary
+212 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 153.7323
+ 594.5936
+ 526.5827
+ 606.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER189': class PDFDictionary
+213 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://micheles.googlecode.com/hg/plac/doc/plac.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 153.7323
+ 567.5936
+ 526.5827
+ 579.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page19': class PDFPage
+214 0 obj
+% Page dictionary
+<< /Annots [ 209 0 R
+ 210 0 R
+ 211 0 R
+ 212 0 R
+ 213 0 R ]
+ /Contents 430 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER190': class LinkAnnotation
+215 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 9 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 62.69291
+ 726.5936
+ 286.0929
+ 738.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER191': class LinkAnnotation
+216 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 9 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 527.0227
+ 726.5936
+ 532.5827
+ 738.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER192': class LinkAnnotation
+217 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 96 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 708.5936
+ 223.8629
+ 720.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER193': class LinkAnnotation
+218 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 96 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 527.0227
+ 708.5936
+ 532.5827
+ 720.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER194': class LinkAnnotation
+219 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 96 0 R
+ /XYZ
+ 62.69291
+ 411.0236
+ 0 ]
+ /Rect [ 82.69291
+ 690.5936
+ 223.2929
+ 702.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER195': class LinkAnnotation
+220 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 96 0 R
+ /XYZ
+ 62.69291
+ 411.0236
+ 0 ]
+ /Rect [ 527.0227
+ 690.5936
+ 532.5827
+ 702.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER196': class LinkAnnotation
+221 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 110 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 672.5936
+ 216.6329
+ 684.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER197': class LinkAnnotation
+222 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 110 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 527.0227
+ 672.5936
+ 532.5827
+ 684.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER198': class LinkAnnotation
+223 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 120 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 82.69291
+ 654.5936
+ 257.7529
+ 666.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER199': class LinkAnnotation
+224 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 120 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 527.0227
+ 654.5936
+ 532.5827
+ 666.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER200': class LinkAnnotation
+225 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 124 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 636.5936
+ 157.7129
+ 648.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER201': class LinkAnnotation
+226 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 124 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 527.0227
+ 636.5936
+ 532.5827
+ 648.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER202': class LinkAnnotation
+227 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 124 0 R
+ /XYZ
+ 62.69291
+ 265.7299
+ 0 ]
+ /Rect [ 82.69291
+ 618.5936
+ 194.4129
+ 630.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER203': class LinkAnnotation
+228 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 124 0 R
+ /XYZ
+ 62.69291
+ 265.7299
+ 0 ]
+ /Rect [ 527.0227
+ 618.5936
+ 532.5827
+ 630.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER204': class LinkAnnotation
+229 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 132 0 R
+ /XYZ
+ 62.69291
+ 522.6236
+ 0 ]
+ /Rect [ 82.69291
+ 600.5936
+ 144.3829
+ 612.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER205': class LinkAnnotation
+230 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 132 0 R
+ /XYZ
+ 62.69291
+ 522.6236
+ 0 ]
+ /Rect [ 521.4627
+ 600.5936
+ 532.5827
+ 612.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER206': class LinkAnnotation
+231 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 137 0 R
+ /XYZ
+ 62.69291
+ 552.6236
+ 0 ]
+ /Rect [ 82.69291
+ 582.5936
+ 166.6029
+ 594.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER207': class LinkAnnotation
+232 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 137 0 R
+ /XYZ
+ 62.69291
+ 552.6236
+ 0 ]
+ /Rect [ 521.4627
+ 582.5936
+ 532.5827
+ 594.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER208': class LinkAnnotation
+233 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 140 0 R
+ /XYZ
+ 62.69291
+ 513.8236
+ 0 ]
+ /Rect [ 82.69291
+ 564.5936
+ 171.6129
+ 576.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER209': class LinkAnnotation
+234 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 140 0 R
+ /XYZ
+ 62.69291
+ 513.8236
+ 0 ]
+ /Rect [ 521.4627
+ 564.5936
+ 532.5827
+ 576.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER210': class LinkAnnotation
+235 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 142 0 R
+ /XYZ
+ 62.69291
+ 493.4236
+ 0 ]
+ /Rect [ 82.69291
+ 546.5936
+ 228.8629
+ 558.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER211': class LinkAnnotation
+236 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 142 0 R
+ /XYZ
+ 62.69291
+ 493.4236
+ 0 ]
+ /Rect [ 521.4627
+ 546.5936
+ 532.5827
+ 558.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER212': class LinkAnnotation
+237 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 159 0 R
+ /XYZ
+ 62.69291
+ 422.6236
+ 0 ]
+ /Rect [ 82.69291
+ 528.5936
+ 156.0529
+ 540.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER213': class LinkAnnotation
+238 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 159 0 R
+ /XYZ
+ 62.69291
+ 422.6236
+ 0 ]
+ /Rect [ 521.4627
+ 528.5936
+ 532.5827
+ 540.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER214': class LinkAnnotation
+239 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 82.69291
+ 510.5936
+ 204.4129
+ 522.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER215': class LinkAnnotation
+240 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 521.4627
+ 510.5936
+ 532.5827
+ 522.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER216': class LinkAnnotation
+241 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 513.0236
+ 0 ]
+ /Rect [ 82.69291
+ 492.5936
+ 128.2729
+ 504.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER217': class LinkAnnotation
+242 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 513.0236
+ 0 ]
+ /Rect [ 521.4627
+ 492.5936
+ 532.5827
+ 504.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER218': class LinkAnnotation
+243 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 309.0236
+ 0 ]
+ /Rect [ 82.69291
+ 474.5936
+ 228.3129
+ 486.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER219': class LinkAnnotation
+244 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 208 0 R
+ /XYZ
+ 62.69291
+ 309.0236
+ 0 ]
+ /Rect [ 521.4627
+ 474.5936
+ 532.5827
+ 486.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER220': class LinkAnnotation
+245 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 214 0 R
+ /XYZ
+ 62.69291
+ 681.0236
+ 0 ]
+ /Rect [ 62.69291
+ 456.5936
+ 182.7329
+ 468.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER221': class LinkAnnotation
+246 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 214 0 R
+ /XYZ
+ 62.69291
+ 681.0236
+ 0 ]
+ /Rect [ 521.4627
+ 456.5936
+ 532.5827
+ 468.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER222': class LinkAnnotation
+247 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 438.5936
+ 134.9429
+ 450.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER223': class LinkAnnotation
+248 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 438.5936
+ 532.5827
+ 450.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER224': class LinkAnnotation
+249 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 543.0236
+ 0 ]
+ /Rect [ 82.69291
+ 420.5936
+ 252.7429
+ 432.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER225': class LinkAnnotation
+250 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 543.0236
+ 0 ]
+ /Rect [ 521.4627
+ 420.5936
+ 532.5827
+ 432.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER226': class LinkAnnotation
+251 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 300 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 402.5936
+ 195.5229
+ 414.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER227': class LinkAnnotation
+252 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 300 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 402.5936
+ 532.5827
+ 414.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER228': class LinkAnnotation
+253 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 309 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 82.69291
+ 384.5936
+ 149.9429
+ 396.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER229': class LinkAnnotation
+254 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 309 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Rect [ 521.4627
+ 384.5936
+ 532.5827
+ 396.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER230': class LinkAnnotation
+255 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 314 0 R
+ /XYZ
+ 62.69291
+ 431.8485
+ 0 ]
+ /Rect [ 82.69291
+ 366.5936
+ 161.0529
+ 378.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER231': class LinkAnnotation
+256 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 314 0 R
+ /XYZ
+ 62.69291
+ 431.8485
+ 0 ]
+ /Rect [ 521.4627
+ 366.5936
+ 532.5827
+ 378.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER232': class LinkAnnotation
+257 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 319 0 R
+ /XYZ
+ 62.69291
+ 515.8236
+ 0 ]
+ /Rect [ 82.69291
+ 348.5936
+ 210.5129
+ 360.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER233': class LinkAnnotation
+258 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 319 0 R
+ /XYZ
+ 62.69291
+ 515.8236
+ 0 ]
+ /Rect [ 521.4627
+ 348.5936
+ 532.5827
+ 360.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER234': class LinkAnnotation
+259 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 324 0 R
+ /XYZ
+ 62.69291
+ 441.5042
+ 0 ]
+ /Rect [ 82.69291
+ 330.5936
+ 167.7229
+ 342.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER235': class LinkAnnotation
+260 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 324 0 R
+ /XYZ
+ 62.69291
+ 441.5042
+ 0 ]
+ /Rect [ 521.4627
+ 330.5936
+ 532.5827
+ 342.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER236': class LinkAnnotation
+261 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 332 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 312.5936
+ 158.2829
+ 324.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER237': class LinkAnnotation
+262 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 332 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 312.5936
+ 532.5827
+ 324.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER238': class LinkAnnotation
+263 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 343 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 82.69291
+ 294.5936
+ 152.7229
+ 306.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER239': class LinkAnnotation
+264 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 343 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 521.4627
+ 294.5936
+ 532.5827
+ 306.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER240': class LinkAnnotation
+265 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 347 0 R
+ /XYZ
+ 62.69291
+ 401.4236
+ 0 ]
+ /Rect [ 82.69291
+ 276.5936
+ 205.5229
+ 288.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER241': class LinkAnnotation
+266 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 347 0 R
+ /XYZ
+ 62.69291
+ 401.4236
+ 0 ]
+ /Rect [ 521.4627
+ 276.5936
+ 532.5827
+ 288.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER242': class LinkAnnotation
+267 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 350 0 R
+ /XYZ
+ 62.69291
+ 408.6236
+ 0 ]
+ /Rect [ 82.69291
+ 258.5936
+ 209.9529
+ 270.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER243': class LinkAnnotation
+268 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 350 0 R
+ /XYZ
+ 62.69291
+ 408.6236
+ 0 ]
+ /Rect [ 521.4627
+ 258.5936
+ 532.5827
+ 270.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER244': class LinkAnnotation
+269 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 354 0 R
+ /XYZ
+ 62.69291
+ 244.6236
+ 0 ]
+ /Rect [ 82.69291
+ 240.5936
+ 192.7429
+ 252.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER245': class LinkAnnotation
+270 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 354 0 R
+ /XYZ
+ 62.69291
+ 244.6236
+ 0 ]
+ /Rect [ 521.4627
+ 240.5936
+ 532.5827
+ 252.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER246': class LinkAnnotation
+271 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 357 0 R
+ /XYZ
+ 62.69291
+ 354.6236
+ 0 ]
+ /Rect [ 82.69291
+ 222.5936
+ 177.1729
+ 234.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER247': class LinkAnnotation
+272 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 357 0 R
+ /XYZ
+ 62.69291
+ 354.6236
+ 0 ]
+ /Rect [ 521.4627
+ 222.5936
+ 532.5827
+ 234.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER248': class LinkAnnotation
+273 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 361 0 R
+ /XYZ
+ 62.69291
+ 511.8236
+ 0 ]
+ /Rect [ 82.69291
+ 204.5936
+ 271.6529
+ 216.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER249': class LinkAnnotation
+274 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 361 0 R
+ /XYZ
+ 62.69291
+ 511.8236
+ 0 ]
+ /Rect [ 521.4627
+ 204.5936
+ 532.5827
+ 216.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER250': class LinkAnnotation
+275 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 363 0 R
+ /XYZ
+ 62.69291
+ 711.0236
+ 0 ]
+ /Rect [ 82.69291
+ 186.5936
+ 286.6829
+ 198.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER251': class LinkAnnotation
+276 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 363 0 R
+ /XYZ
+ 62.69291
+ 711.0236
+ 0 ]
+ /Rect [ 521.4627
+ 186.5936
+ 532.5827
+ 198.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER252': class LinkAnnotation
+277 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 365 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 82.69291
+ 168.5936
+ 206.6229
+ 180.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER253': class LinkAnnotation
+278 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 365 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Rect [ 521.4627
+ 168.5936
+ 532.5827
+ 180.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER254': class LinkAnnotation
+279 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 729.0236
+ 0 ]
+ /Rect [ 82.69291
+ 150.5936
+ 151.6029
+ 162.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER255': class LinkAnnotation
+280 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 729.0236
+ 0 ]
+ /Rect [ 521.4627
+ 150.5936
+ 532.5827
+ 162.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER256': class LinkAnnotation
+281 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 82.69291
+ 132.5936
+ 125.4729
+ 144.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER257': class LinkAnnotation
+282 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Rect [ 521.4627
+ 132.5936
+ 532.5827
+ 144.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER258': class LinkAnnotation
+283 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 371 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 82.69291
+ 114.5936
+ 246.1129
126.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page17': class PDFPage
-167 0 obj
+% 'Annot.NUMBER259': class LinkAnnotation
+284 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 371 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 521.4627
+ 114.5936
+ 532.5827
+ 126.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page20': class PDFPage
+285 0 obj
% Page dictionary
-<< /Annots [ 134 0 R
- 135 0 R
- 136 0 R
- 137 0 R
- 138 0 R
- 139 0 R
- 140 0 R
- 141 0 R
- 142 0 R
- 143 0 R
- 144 0 R
- 145 0 R
- 146 0 R
- 147 0 R
- 148 0 R
- 149 0 R
- 150 0 R
- 151 0 R
- 152 0 R
- 153 0 R
- 154 0 R
- 155 0 R
- 156 0 R
- 157 0 R
- 158 0 R
- 159 0 R
- 160 0 R
- 161 0 R
- 162 0 R
- 163 0 R
- 164 0 R
- 165 0 R
- 166 0 R ]
- /Contents 202 0 R
+<< /Annots [ 215 0 R
+ 216 0 R
+ 217 0 R
+ 218 0 R
+ 219 0 R
+ 220 0 R
+ 221 0 R
+ 222 0 R
+ 223 0 R
+ 224 0 R
+ 225 0 R
+ 226 0 R
+ 227 0 R
+ 228 0 R
+ 229 0 R
+ 230 0 R
+ 231 0 R
+ 232 0 R
+ 233 0 R
+ 234 0 R
+ 235 0 R
+ 236 0 R
+ 237 0 R
+ 238 0 R
+ 239 0 R
+ 240 0 R
+ 241 0 R
+ 242 0 R
+ 243 0 R
+ 244 0 R
+ 245 0 R
+ 246 0 R
+ 247 0 R
+ 248 0 R
+ 249 0 R
+ 250 0 R
+ 251 0 R
+ 252 0 R
+ 253 0 R
+ 254 0 R
+ 255 0 R
+ 256 0 R
+ 257 0 R
+ 258 0 R
+ 259 0 R
+ 260 0 R
+ 261 0 R
+ 262 0 R
+ 263 0 R
+ 264 0 R
+ 265 0 R
+ 266 0 R
+ 267 0 R
+ 268 0 R
+ 269 0 R
+ 270 0 R
+ 271 0 R
+ 272 0 R
+ 273 0 R
+ 274 0 R
+ 275 0 R
+ 276 0 R
+ 277 0 R
+ 278 0 R
+ 279 0 R
+ 280 0 R
+ 281 0 R
+ 282 0 R
+ 283 0 R
+ 284 0 R ]
+ /Contents 431 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 185 0 R
+ /Parent 411 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2765,234 +4998,1986 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'R168': class PDFCatalog
-168 0 obj
+% 'Annot.NUMBER260': class PDFDictionary
+286 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 185.4471
+ 732.5936
+ 207.1062
+ 744.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER261': class PDFDictionary
+287 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 177.6784
+ 720.5936
+ 199.6123
+ 732.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER262': class PDFDictionary
+288 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 666.5936
+ 83.81291
+ 678.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER263': class PDFDictionary
+289 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 278.4678
+ 648.5936
+ 300.0328
+ 660.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER264': class PDFDictionary
+290 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 117.3573
+ 636.5936
+ 138.5845
+ 648.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER265': class PDFDictionary
+291 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://twill.idyll.org/) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 82.74466
+ 594.5936
+ 104.4564
+ 606.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER266': class PDFDictionary
+292 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 127.2882
+ 594.5936
+ 145.6282
+ 606.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER267': class PDFDictionary
+293 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 410.1674
+ 594.5936
+ 433.5592
+ 606.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER268': class PDFDictionary
+294 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 265.9578
+ 570.5936
+ 284.2978
+ 582.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER269': class PDFDictionary
+295 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 487.7492
+ 570.5936
+ 506.0892
+ 582.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER270': class PDFDictionary
+296 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://micheles.googlecode.com/hg/plac/doc/plac.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 414.5936
+ 157.1829
+ 426.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page21': class PDFPage
+297 0 obj
+% Page dictionary
+<< /Annots [ 286 0 R
+ 287 0 R
+ 288 0 R
+ 289 0 R
+ 290 0 R
+ 291 0 R
+ 292 0 R
+ 293 0 R
+ 294 0 R
+ 295 0 R
+ 296 0 R ]
+ /Contents 432 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER271': class PDFDictionary
+298 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 383.9329
+ 127.7936
+ 405.0529
+ 139.7936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page22': class PDFPage
+299 0 obj
+% Page dictionary
+<< /Annots [ 298 0 R ]
+ /Contents 433 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page23': class PDFPage
+300 0 obj
+% Page dictionary
+<< /Contents 434 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER272': class PDFDictionary
+301 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 370.6785
+ 445.3936
+ 392.4956
+ 457.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER273': class PDFDictionary
+302 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 455.8742
+ 445.3936
+ 477.6913
+ 457.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER274': class PDFDictionary
+303 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 185.9351
+ 230.6093
+ 207.4695
+ 242.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER275': class PDFDictionary
+304 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/shlex.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 369.8905
+ 230.6093
+ 396.425
+ 242.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER276': class PDFDictionary
+305 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 408.8916
+ 218.6093
+ 427.2316
+ 230.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER277': class PDFDictionary
+306 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/shlex.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 206.6093
+ 86.03291
+ 218.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER278': class PDFDictionary
+307 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 92.4689
+ 206.6093
+ 114.4649
+ 218.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER279': class PDFDictionary
+308 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/shlex.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 149.3204
+ 194.6093
+ 176.9472
+ 206.6093 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page24': class PDFPage
+309 0 obj
+% Page dictionary
+<< /Annots [ 301 0 R
+ 302 0 R
+ 303 0 R
+ 304 0 R
+ 305 0 R
+ 306 0 R
+ 307 0 R
+ 308 0 R ]
+ /Contents 435 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER280': class PDFDictionary
+310 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 129.6923
+ 756.5936
+ 151.4655
+ 768.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER281': class PDFDictionary
+311 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 173.8529
+ 744.5936
+ 194.9729
+ 756.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER282': class PDFDictionary
+312 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 460.388
+ 387.4185
+ 482.0127
+ 399.4185 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER283': class PDFDictionary
+313 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 95.32996
+ 321.4185
+ 116.857
+ 333.4185 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page25': class PDFPage
+314 0 obj
+% Page dictionary
+<< /Annots [ 310 0 R
+ 311 0 R
+ 312 0 R
+ 313 0 R ]
+ /Contents 436 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER284': class PDFDictionary
+315 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://micheles.googlecode.com/hg/plac/doc/plac.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 316.3528
+ 483.3936
+ 409.2453
+ 495.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER285': class PDFDictionary
+316 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 419.1694
+ 471.3936
+ 440.4061
+ 483.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER286': class PDFDictionary
+317 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 441.3936
+ 84.70395
+ 453.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER287': class PDFDictionary
+318 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 293.2359
+ 363.3936
+ 316.4697
+ 375.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page26': class PDFPage
+319 0 obj
+% Page dictionary
+<< /Annots [ 315 0 R
+ 316 0 R
+ 317 0 R
+ 318 0 R ]
+ /Contents 437 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER288': class PDFDictionary
+320 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 431.7904
+ 375.3936
+ 453.7245
+ 387.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER289': class PDFDictionary
+321 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 255.5885
+ 345.3936
+ 278.2757
+ 357.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER290': class PDFDictionary
+322 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/cmd.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 513.6927
+ 321.3936
+ 532.1846
+ 333.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page27': class PDFPage
+323 0 obj
+% Page dictionary
+<< /Annots [ 320 0 R
+ 321 0 R
+ 322 0 R ]
+ /Contents 438 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page28': class PDFPage
+324 0 obj
+% Page dictionary
+<< /Contents 439 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page29': class PDFPage
+325 0 obj
+% Page dictionary
+<< /Contents 440 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER291': class PDFDictionary
+326 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 179.0529
+ 732.5936
+ 201.1953
+ 744.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER292': class PDFDictionary
+327 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://freshmeat.net/projects/rlwrap/) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 377.8504
+ 152.6007
+ 409.861
+ 164.6007 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER293': class PDFDictionary
+328 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 242.4466
+ 140.6007
+ 263.7922
+ 152.6007 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER294': class PDFDictionary
+329 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://ipython.scipy.org/moin/PyReadline/Intro) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 456.2271
+ 140.6007
+ 505.3627
+ 152.6007 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER295': class PDFDictionary
+330 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 363.1739
+ 116.6007
+ 386.5004
+ 128.6007 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER296': class PDFDictionary
+331 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 479.7508
+ 104.6007
+ 501.4627
+ 116.6007 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page30': class PDFPage
+332 0 obj
+% Page dictionary
+<< /Annots [ 326 0 R
+ 327 0 R
+ 328 0 R
+ 329 0 R
+ 330 0 R
+ 331 0 R ]
+ /Contents 441 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER297': class PDFDictionary
+333 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/cmd.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 366.9454
+ 756.5936
+ 388.8033
+ 768.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER298': class PDFDictionary
+334 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/cmd.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 170.8855
+ 744.5936
+ 189.7755
+ 756.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER299': class PDFDictionary
+335 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://argparse.googlecode.com) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 390.8027
+ 403.3936
+ 435.0027
+ 415.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER300': class PDFDictionary
+336 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 213.451
+ 391.3936
+ 237.5255
+ 403.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER301': class PDFDictionary
+337 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://argparse.googlecode.com) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 114.9429
+ 367.3936
+ 157.1829
+ 379.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER302': class PDFDictionary
+338 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 385.0429
+ 367.3936
+ 403.3829
+ 379.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER303': class PDFDictionary
+339 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 350.6129
+ 337.3936
+ 371.7329
+ 349.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER304': class PDFDictionary
+340 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 256.6729
+ 319.3936
+ 277.7929
+ 331.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER305': class PDFDictionary
+341 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 149.5469
+ 226.1936
+ 172.1982
+ 238.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER306': class PDFDictionary
+342 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/distutils/) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 224.3178
+ 214.1936
+ 260.8853
+ 226.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page31': class PDFPage
+343 0 obj
+% Page dictionary
+<< /Annots [ 333 0 R
+ 334 0 R
+ 335 0 R
+ 336 0 R
+ 337 0 R
+ 338 0 R
+ 339 0 R
+ 340 0 R
+ 341 0 R
+ 342 0 R ]
+ /Contents 442 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER307': class PDFDictionary
+344 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://argparse.googlecode.com) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 381.1529
+ 105.8205
+ 423.3929
+ 117.8205 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page32': class PDFPage
+345 0 obj
+% Page dictionary
+<< /Annots [ 344 0 R ]
+ /Contents 443 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER308': class PDFDictionary
+346 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 368.9936
+ 84.72012
+ 380.9936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page33': class PDFPage
+347 0 obj
+% Page dictionary
+<< /Annots [ 346 0 R ]
+ /Contents 444 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page34': class PDFPage
+348 0 obj
+% Page dictionary
+<< /Contents 445 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER309': class PDFDictionary
+349 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 182.479
+ 376.1936
+ 203.7662
+ 388.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page35': class PDFPage
+350 0 obj
+% Page dictionary
+<< /Annots [ 349 0 R ]
+ /Contents 446 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER310': class PDFDictionary
+351 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 255.1228
+ 415.3936
+ 276.5028
+ 427.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER311': class PDFDictionary
+352 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/multiprocessing.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 295.0229
+ 260.1936
+ 367.2629
+ 272.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER312': class PDFDictionary
+353 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 179.1295
+ 212.1936
+ 201.6839
+ 224.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page36': class PDFPage
+354 0 obj
+% Page dictionary
+<< /Annots [ 351 0 R
+ 352 0 R
+ 353 0 R ]
+ /Contents 447 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER313': class PDFDictionary
+355 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 414.8874
+ 382.1936
+ 436.9487
+ 394.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER314': class PDFDictionary
+356 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 122.7054
+ 238.1936
+ 145.2085
+ 250.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page37': class PDFPage
+357 0 obj
+% Page dictionary
+<< /Annots [ 355 0 R
+ 356 0 R ]
+ /Contents 448 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page38': class PDFPage
+358 0 obj
+% Page dictionary
+<< /Contents 449 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER315': class PDFDictionary
+359 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 183.3657
+ 467.3936
+ 207.8364
+ 479.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER316': class PDFDictionary
+360 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/multiprocessing.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 254.9929
+ 443.3936
+ 327.2329
+ 455.3936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page39': class PDFPage
+361 0 obj
+% Page dictionary
+<< /Annots [ 359 0 R
+ 360 0 R ]
+ /Contents 450 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER317': class PDFDictionary
+362 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 678.5936
+ 85.70846
+ 690.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page40': class PDFPage
+363 0 obj
+% Page dictionary
+<< /Annots [ 362 0 R ]
+ /Contents 451 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER318': class PDFDictionary
+364 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 62.69291
+ 732.5936
+ 84.98766
+ 744.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page41': class PDFPage
+365 0 obj
+% Page dictionary
+<< /Annots [ 364 0 R ]
+ /Contents 452 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page42': class PDFPage
+366 0 obj
+% Page dictionary
+<< /Contents 453 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER319': class PDFDictionary
+367 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 172.4311
+ 612.5936
+ 194.7087
+ 624.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER320': class PDFDictionary
+368 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 91.57623
+ 226.1936
+ 114.8995
+ 238.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page43': class PDFPage
+369 0 obj
+% Page dictionary
+<< /Annots [ 367 0 R
+ 368 0 R ]
+ /Contents 454 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER321': class PDFDictionary
+370 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 106.6216
+ 554.2472
+ 128.3202
+ 566.2472 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page44': class PDFPage
+371 0 obj
+% Page dictionary
+<< /Annots [ 370 0 R ]
+ /Contents 455 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Page45': class PDFPage
+372 0 obj
+% Page dictionary
+<< /Contents 456 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 411 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'R373': class PDFCatalog
+373 0 obj
% Document Root
-<< /Outlines 170 0 R
- /PageLabels 203 0 R
+<< /Outlines 375 0 R
+ /PageLabels 457 0 R
/PageMode /UseNone
- /Pages 185 0 R
+ /Pages 411 0 R
/Type /Catalog >>
endobj
-% 'R169': class PDFInfo
-169 0 obj
-<< /Author (Michele Simionato)
- /CreationDate (D:20100730114415-01'00')
+% 'R374': class PDFInfo
+374 0 obj
+<< /Author ()
+ /CreationDate (D:20100811080133-01'00')
/Keywords ()
/Producer (ReportLab http://www.reportlab.com)
/Subject (\(unspecified\))
- /Title (Plac: Parsing the Command Line the Easy Way) >>
+ /Title () >>
endobj
-% 'R170': class PDFOutlines
-170 0 obj
-<< /Count 14
- /First 171 0 R
- /Last 184 0 R
+% 'R375': class PDFOutlines
+375 0 obj
+<< /Count 37
+ /First 376 0 R
+ /Last 391 0 R
/Type /Outlines >>
endobj
% 'Outline.0': class OutlineEntryObject
-171 0 obj
-<< /Dest [ 48 0 R
+376 0 obj
+<< /Count 14
+ /Dest [ 9 0 R
/XYZ
62.69291
- 296.0236
+ 765.0236
0 ]
- /Next 172 0 R
- /Parent 170 0 R
+ /First 377 0 R
+ /Last 390 0 R
+ /Next 391 0 R
+ /Parent 375 0 R
+ /Title (Plac: Parsing the Command Line the Easy Way) >>
+endobj
+% 'Outline.36.0': class OutlineEntryObject
+377 0 obj
+<< /Dest [ 96 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 378 0 R
+ /Parent 376 0 R
/Title (The importance of scaling down) >>
endobj
-% 'Outline.1': class OutlineEntryObject
-172 0 obj
-<< /Dest [ 56 0 R
+% 'Outline.36.1': class OutlineEntryObject
+378 0 obj
+<< /Dest [ 96 0 R
/XYZ
62.69291
- 615.0236
+ 411.0236
0 ]
- /Next 173 0 R
- /Parent 170 0 R
- /Prev 171 0 R
+ /Next 379 0 R
+ /Parent 376 0 R
+ /Prev 377 0 R
/Title (Scripts with required arguments) >>
endobj
-% 'Outline.2': class OutlineEntryObject
-173 0 obj
-<< /Dest [ 63 0 R
+% 'Outline.36.2': class OutlineEntryObject
+379 0 obj
+<< /Dest [ 110 0 R
/XYZ
62.69291
- 274.2236
+ 765.0236
0 ]
- /Next 174 0 R
- /Parent 170 0 R
- /Prev 172 0 R
+ /Next 380 0 R
+ /Parent 376 0 R
+ /Prev 378 0 R
/Title (Scripts with default arguments) >>
endobj
-% 'Outline.3': class OutlineEntryObject
-174 0 obj
-<< /Dest [ 75 0 R
+% 'Outline.36.3': class OutlineEntryObject
+380 0 obj
+<< /Dest [ 120 0 R
/XYZ
62.69291
- 229.4236
+ 741.0236
0 ]
- /Next 175 0 R
- /Parent 170 0 R
- /Prev 173 0 R
+ /Next 381 0 R
+ /Parent 376 0 R
+ /Prev 379 0 R
/Title (Scripts with options \(and smart options\)) >>
endobj
-% 'Outline.4': class OutlineEntryObject
-175 0 obj
-<< /Dest [ 79 0 R
+% 'Outline.36.4': class OutlineEntryObject
+381 0 obj
+<< /Dest [ 124 0 R
/XYZ
62.69291
- 231.0236
+ 765.0236
0 ]
- /Next 176 0 R
- /Parent 170 0 R
- /Prev 174 0 R
+ /Next 382 0 R
+ /Parent 376 0 R
+ /Prev 380 0 R
/Title (Scripts with flags) >>
endobj
-% 'Outline.5': class OutlineEntryObject
-176 0 obj
-<< /Dest [ 81 0 R
+% 'Outline.36.5': class OutlineEntryObject
+382 0 obj
+<< /Dest [ 124 0 R
/XYZ
62.69291
- 377.4236
+ 265.7299
0 ]
- /Next 177 0 R
- /Parent 170 0 R
- /Prev 175 0 R
+ /Next 383 0 R
+ /Parent 376 0 R
+ /Prev 381 0 R
/Title (plac for Python 2.X users) >>
endobj
-% 'Outline.6': class OutlineEntryObject
-177 0 obj
-<< /Dest [ 89 0 R
+% 'Outline.36.6': class OutlineEntryObject
+383 0 obj
+<< /Dest [ 132 0 R
/XYZ
62.69291
- 647.8236
+ 522.6236
0 ]
- /Next 178 0 R
- /Parent 170 0 R
- /Prev 176 0 R
+ /Next 384 0 R
+ /Parent 376 0 R
+ /Prev 382 0 R
/Title (More features) >>
endobj
-% 'Outline.7': class OutlineEntryObject
-178 0 obj
-<< /Dest [ 94 0 R
+% 'Outline.36.7': class OutlineEntryObject
+384 0 obj
+<< /Dest [ 137 0 R
/XYZ
62.69291
- 683.8236
+ 552.6236
0 ]
- /Next 179 0 R
- /Parent 170 0 R
- /Prev 177 0 R
+ /Next 385 0 R
+ /Parent 376 0 R
+ /Prev 383 0 R
/Title (A realistic example) >>
endobj
-% 'Outline.8': class OutlineEntryObject
-179 0 obj
-<< /Dest [ 97 0 R
+% 'Outline.36.8': class OutlineEntryObject
+385 0 obj
+<< /Dest [ 140 0 R
/XYZ
62.69291
- 623.8236
+ 513.8236
0 ]
- /Next 180 0 R
- /Parent 170 0 R
- /Prev 178 0 R
+ /Next 386 0 R
+ /Parent 376 0 R
+ /Prev 384 0 R
/Title (Keyword arguments) >>
endobj
-% 'Outline.9': class OutlineEntryObject
-180 0 obj
-<< /Dest [ 99 0 R
+% 'Outline.36.9': class OutlineEntryObject
+386 0 obj
+<< /Dest [ 142 0 R
/XYZ
62.69291
- 594.6236
+ 493.4236
0 ]
- /Next 181 0 R
- /Parent 170 0 R
- /Prev 179 0 R
+ /Next 387 0 R
+ /Parent 376 0 R
+ /Prev 385 0 R
/Title (Final example: a shelve interface) >>
endobj
-% 'Outline.10': class OutlineEntryObject
-181 0 obj
-<< /Dest [ 124 0 R
+% 'Outline.36.10': class OutlineEntryObject
+387 0 obj
+<< /Dest [ 159 0 R
/XYZ
62.69291
- 511.8236
+ 422.6236
0 ]
- /Next 182 0 R
- /Parent 170 0 R
- /Prev 180 0 R
+ /Next 388 0 R
+ /Parent 376 0 R
+ /Prev 386 0 R
/Title (plac vs argparse) >>
endobj
-% 'Outline.11': class OutlineEntryObject
-182 0 obj
-<< /Dest [ 133 0 R
+% 'Outline.36.11': class OutlineEntryObject
+388 0 obj
+<< /Dest [ 208 0 R
/XYZ
62.69291
- 161.4236
+ 741.0236
0 ]
- /Next 183 0 R
- /Parent 170 0 R
- /Prev 181 0 R
+ /Next 389 0 R
+ /Parent 376 0 R
+ /Prev 387 0 R
/Title (plac vs the rest of the world) >>
endobj
-% 'Outline.12': class OutlineEntryObject
-183 0 obj
-<< /Dest [ 167 0 R
+% 'Outline.36.12': class OutlineEntryObject
+389 0 obj
+<< /Dest [ 208 0 R
/XYZ
62.69291
- 603.0236
+ 513.0236
0 ]
- /Next 184 0 R
- /Parent 170 0 R
- /Prev 182 0 R
+ /Next 390 0 R
+ /Parent 376 0 R
+ /Prev 388 0 R
/Title (The future) >>
endobj
-% 'Outline.13': class OutlineEntryObject
-184 0 obj
-<< /Dest [ 167 0 R
+% 'Outline.36.13': class OutlineEntryObject
+390 0 obj
+<< /Dest [ 208 0 R
/XYZ
62.69291
- 396.0236
+ 309.0236
0 ]
- /Parent 170 0 R
- /Prev 183 0 R
+ /Parent 376 0 R
+ /Prev 389 0 R
/Title (Trivia: the story behind the name) >>
endobj
-% 'R185': class PDFPages
-185 0 obj
+% 'Outline.1': class OutlineEntryObject
+391 0 obj
+<< /Count 19
+ /Dest [ 214 0 R
+ /XYZ
+ 62.69291
+ 681.0236
+ 0 ]
+ /First 392 0 R
+ /Last 410 0 R
+ /Parent 375 0 R
+ /Prev 376 0 R
+ /Title (Advanced usages of plac) >>
+endobj
+% 'Outline.37.0': class OutlineEntryObject
+392 0 obj
+<< /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 393 0 R
+ /Parent 391 0 R
+ /Title (Introduction) >>
+endobj
+% 'Outline.37.1': class OutlineEntryObject
+393 0 obj
+<< /Dest [ 297 0 R
+ /XYZ
+ 62.69291
+ 543.0236
+ 0 ]
+ /Next 394 0 R
+ /Parent 391 0 R
+ /Prev 392 0 R
+ /Title (From scripts to interactive applications) >>
+endobj
+% 'Outline.37.2': class OutlineEntryObject
+394 0 obj
+<< /Dest [ 300 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 395 0 R
+ /Parent 391 0 R
+ /Prev 393 0 R
+ /Title (Testing a plac application) >>
+endobj
+% 'Outline.37.3': class OutlineEntryObject
+395 0 obj
+<< /Dest [ 309 0 R
+ /XYZ
+ 62.69291
+ 741.0236
+ 0 ]
+ /Next 396 0 R
+ /Parent 391 0 R
+ /Prev 394 0 R
+ /Title (Plac easy tests) >>
+endobj
+% 'Outline.37.4': class OutlineEntryObject
+396 0 obj
+<< /Dest [ 314 0 R
+ /XYZ
+ 62.69291
+ 431.8485
+ 0 ]
+ /Next 397 0 R
+ /Parent 391 0 R
+ /Prev 395 0 R
+ /Title (Plac batch scripts) >>
+endobj
+% 'Outline.37.5': class OutlineEntryObject
+397 0 obj
+<< /Dest [ 319 0 R
+ /XYZ
+ 62.69291
+ 515.8236
+ 0 ]
+ /Next 398 0 R
+ /Parent 391 0 R
+ /Prev 396 0 R
+ /Title (Implementing subcommands) >>
+endobj
+% 'Outline.37.6': class OutlineEntryObject
+398 0 obj
+<< /Dest [ 324 0 R
+ /XYZ
+ 62.69291
+ 441.5042
+ 0 ]
+ /Next 399 0 R
+ /Parent 391 0 R
+ /Prev 397 0 R
+ /Title (plac.Interpreter.call) >>
+endobj
+% 'Outline.37.7': class OutlineEntryObject
+399 0 obj
+<< /Dest [ 332 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 400 0 R
+ /Parent 391 0 R
+ /Prev 398 0 R
+ /Title (Readline support) >>
+endobj
+% 'Outline.37.8': class OutlineEntryObject
+400 0 obj
+<< /Dest [ 343 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Next 401 0 R
+ /Parent 391 0 R
+ /Prev 399 0 R
+ /Title (The plac runner) >>
+endobj
+% 'Outline.37.9': class OutlineEntryObject
+401 0 obj
+<< /Dest [ 347 0 R
+ /XYZ
+ 62.69291
+ 401.4236
+ 0 ]
+ /Next 402 0 R
+ /Parent 391 0 R
+ /Prev 400 0 R
+ /Title (A non class-based example) >>
+endobj
+% 'Outline.37.10': class OutlineEntryObject
+402 0 obj
+<< /Dest [ 350 0 R
+ /XYZ
+ 62.69291
+ 408.6236
+ 0 ]
+ /Next 403 0 R
+ /Parent 391 0 R
+ /Prev 401 0 R
+ /Title (Writing your own plac runner) >>
+endobj
+% 'Outline.37.11': class OutlineEntryObject
+403 0 obj
+<< /Dest [ 354 0 R
+ /XYZ
+ 62.69291
+ 244.6236
+ 0 ]
+ /Next 404 0 R
+ /Parent 391 0 R
+ /Prev 402 0 R
+ /Title (Long running commands) >>
+endobj
+% 'Outline.37.12': class OutlineEntryObject
+404 0 obj
+<< /Dest [ 357 0 R
+ /XYZ
+ 62.69291
+ 354.6236
+ 0 ]
+ /Next 405 0 R
+ /Parent 391 0 R
+ /Prev 403 0 R
+ /Title (Threaded commands) >>
+endobj
+% 'Outline.37.13': class OutlineEntryObject
+405 0 obj
+<< /Dest [ 361 0 R
+ /XYZ
+ 62.69291
+ 511.8236
+ 0 ]
+ /Next 406 0 R
+ /Parent 391 0 R
+ /Prev 404 0 R
+ /Title (Running commands as external processes) >>
+endobj
+% 'Outline.37.14': class OutlineEntryObject
+406 0 obj
+<< /Dest [ 363 0 R
+ /XYZ
+ 62.69291
+ 711.0236
+ 0 ]
+ /Next 407 0 R
+ /Parent 391 0 R
+ /Prev 405 0 R
+ /Title (Managing the output of concurrent commands) >>
+endobj
+% 'Outline.37.15': class OutlineEntryObject
+407 0 obj
+<< /Dest [ 365 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 408 0 R
+ /Parent 391 0 R
+ /Prev 406 0 R
+ /Title (Parallel computing with plac) >>
+endobj
+% 'Outline.37.16': class OutlineEntryObject
+408 0 obj
+<< /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 729.0236
+ 0 ]
+ /Next 409 0 R
+ /Parent 391 0 R
+ /Prev 407 0 R
+ /Title (The plac server) >>
+endobj
+% 'Outline.37.17': class OutlineEntryObject
+409 0 obj
+<< /Dest [ 369 0 R
+ /XYZ
+ 62.69291
+ 258.6236
+ 0 ]
+ /Next 410 0 R
+ /Parent 391 0 R
+ /Prev 408 0 R
+ /Title (Summary) >>
+endobj
+% 'Outline.37.18': class OutlineEntryObject
+410 0 obj
+<< /Dest [ 371 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Parent 391 0 R
+ /Prev 409 0 R
+ /Title (Appendix: custom annotation objects) >>
+endobj
+% 'R411': class PDFPages
+411 0 obj
% page tree
-<< /Count 17
- /Kids [ 48 0 R
- 56 0 R
- 63 0 R
- 67 0 R
- 75 0 R
- 77 0 R
- 79 0 R
- 81 0 R
- 89 0 R
- 90 0 R
- 94 0 R
- 97 0 R
- 99 0 R
- 102 0 R
+<< /Count 45
+ /Kids [ 9 0 R
+ 80 0 R
+ 96 0 R
+ 106 0 R
+ 110 0 R
+ 114 0 R
+ 120 0 R
+ 121 0 R
124 0 R
+ 132 0 R
133 0 R
- 167 0 R ]
+ 137 0 R
+ 140 0 R
+ 142 0 R
+ 145 0 R
+ 159 0 R
+ 174 0 R
+ 208 0 R
+ 214 0 R
+ 285 0 R
+ 297 0 R
+ 299 0 R
+ 300 0 R
+ 309 0 R
+ 314 0 R
+ 319 0 R
+ 323 0 R
+ 324 0 R
+ 325 0 R
+ 332 0 R
+ 343 0 R
+ 345 0 R
+ 347 0 R
+ 348 0 R
+ 350 0 R
+ 354 0 R
+ 357 0 R
+ 358 0 R
+ 361 0 R
+ 363 0 R
+ 365 0 R
+ 366 0 R
+ 369 0 R
+ 371 0 R
+ 372 0 R ]
/Type /Pages >>
endobj
-% 'R186': class PDFStream
-186 0 obj
+% 'R412': class PDFStream
+412 0 obj
% page stream
-<< /Length 9341 >>
+<< /Length 2994 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 741.0236 cm
+1 0 0 1 62.69291 744.0236 cm
q
-BT 1 0 0 1 0 9.64 Tm 11.54488 0 Td 24 TL /F2 20 Tf 0 0 0 rg (Plac: Parsing the Command Line the Easy Way) Tj T* -11.54488 0 Td ET
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Plac: Parsing the Command Line the Easy Way) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 716.0236 cm
+1 0 0 1 62.69291 732.0236 cm
+Q
+q
+1 0 0 1 62.69291 717.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3013,7 +6998,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 701.0236 cm
+1 0 0 1 62.69291 702.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3035,7 +7020,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 686.0236 cm
+1 0 0 1 62.69291 687.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3056,7 +7041,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 659.0236 cm
+1 0 0 1 62.69291 660.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3078,7 +7063,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 644.0236 cm
+1 0 0 1 62.69291 645.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3100,7 +7085,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 629.0236 cm
+1 0 0 1 62.69291 630.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3121,7 +7106,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 614.0236 cm
+1 0 0 1 62.69291 615.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3142,7 +7127,7 @@ q
Q
Q
q
-1 0 0 1 62.69291 599.0236 cm
+1 0 0 1 62.69291 600.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -3163,19 +7148,330 @@ q
Q
Q
q
-1 0 0 1 62.69291 566.0236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (1) Tj T* -238.1649 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R413': class PDFStream
+413 0 obj
+% page stream
+<< /Length 9594 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 744.0236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Contents) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 308.0236 cm
+1 0 0 1 62.69291 108.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
+1 0 0 1 0 615 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Plac: Parsing the Command Line the Easy Way) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 615 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 597 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The importance of scaling down) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 597 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 579 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with required arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 579 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 561 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with default arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 561 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (5) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 543 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with options \(and smart options\)) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 543 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (7) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 525 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with flags) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 525 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 507 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac for Python 2.X users) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 507 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 489 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (More features) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 489 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (10) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 471 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (A realistic example) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 471 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (12) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 453 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Keyword arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 453 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (13) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 435 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Final example: a shelve interface) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 435 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (14) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 417 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac vs argparse) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 417 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (16) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 399 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac vs the rest of the world) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 399 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 381 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The future) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 381 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 363 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Trivia: the story behind the name) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 363 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 345 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Advanced usages of plac) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 345 cm
+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 (19) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 327 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Introduction) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 327 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (21) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 309 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (From scripts to interactive applications) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 309 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (21) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 291 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Testing a plac application) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 291 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (23) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 273 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Plac easy tests) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 273 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (24) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 255 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Plac batch scripts) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 255 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (25) Tj T* -60.88 0 Td ET
+Q
+Q
+q
1 0 0 1 0 237 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The importance of scaling down) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Implementing subcommands) Tj T* ET
Q
Q
q
@@ -3183,13 +7479,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (26) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 219 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Scripts with required arguments) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac.Interpreter.call) Tj T* ET
Q
Q
q
@@ -3197,13 +7493,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (28) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 201 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Scripts with default arguments) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Readline support) Tj T* ET
Q
Q
q
@@ -3211,13 +7507,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (30) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 183 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Scripts with options \(and smart options\)) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The plac runner) Tj T* ET
Q
Q
q
@@ -3225,13 +7521,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (5) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (31) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 165 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Scripts with flags) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (A non class-based example) Tj T* ET
Q
Q
q
@@ -3239,13 +7535,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (7) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (33) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 147 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (plac for Python 2.X users) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Writing your own plac runner) Tj T* ET
Q
Q
q
@@ -3253,13 +7549,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (8) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (35) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 129 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (More features) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Long running commands) Tj T* ET
Q
Q
q
@@ -3267,13 +7563,13 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (36) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 111 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A realistic example) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Threaded commands) Tj T* ET
Q
Q
q
@@ -3281,13 +7577,13 @@ 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 (11) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (37) Tj T* -60.88 0 Td ET
Q
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 (Keyword arguments) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Running commands as external processes) Tj T* ET
Q
Q
q
@@ -3295,13 +7591,13 @@ 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 (12) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (39) Tj T* -60.88 0 Td ET
Q
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 (Final example: a shelve interface) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Managing the output of concurrent commands) Tj T* ET
Q
Q
q
@@ -3309,13 +7605,13 @@ 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 (13) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (40) Tj T* -60.88 0 Td ET
Q
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 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Parallel computing with plac) Tj T* ET
Q
Q
q
@@ -3323,13 +7619,13 @@ 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 (15) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (41) Tj T* -60.88 0 Td ET
Q
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 (plac vs the rest of the world) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The plac server) Tj T* ET
Q
Q
q
@@ -3337,13 +7633,13 @@ 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 (16) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (43) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 21 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The future) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Summary) Tj T* ET
Q
Q
q
@@ -3351,13 +7647,13 @@ 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 (17) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (43) Tj T* -60.88 0 Td ET
Q
Q
q
1 0 0 1 0 3 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Trivia: the story behind the name) Tj T* ET
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Appendix: custom annotation objects) Tj T* ET
Q
Q
q
@@ -3365,79 +7661,73 @@ 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 (17) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (44) Tj T* -60.88 0 Td ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 275.0236 cm
-q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The importance of scaling down) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 209.0236 cm
+1 0 0 1 56.69291 56.69291 cm
q
-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.087126 Tw (contains three different modules: ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (\(from the stone age\), ) Tj 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (\(from Python 2.3\) and ) Tj 0 0 .501961 rg (argparse) Tj T* 0 Tw .223735 Tw 0 0 0 rg (\(from Python 2.7\). All of them are quite powerful and especially ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (is an industrial strength solution;) Tj T* 0 Tw 1.40311 Tw (unfortunately, all of them feature a non-zero learning curve and a certain verbosity. They do not scale) Tj T* 0 Tw (down well, at least in my opinion.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (2) Tj T* -238.1649 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R414': class PDFStream
+414 0 obj
+% page stream
+<< /Length 5985 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 131.0236 cm
+1 0 0 1 62.69291 747.0236 cm
q
-BT 1 0 0 1 0 64.82 Tm 2.20186 Tw 12 TL /F1 10 Tf 0 0 0 rg (It should not be necessary to stress the importance ) Tj 0 0 .501961 rg (scaling down) Tj 0 0 0 rg (; nevertheless, a lot of people are) Tj T* 0 Tw .968555 Tw (obsessed with features and concerned with the possibility of scaling up, forgetting the equally important) Tj T* 0 Tw .048221 Tw (issue of scaling down. This is an old meme in the computing world: programs should address the common) Tj T* 0 Tw .36311 Tw (cases simply and simple things should be kept simple, while at the same keeping difficult things possible.) Tj T* 0 Tw 1.09332 Tw 0 0 .501961 rg (plac ) Tj 0 0 0 rg (adhere as much as possible to this philosophy and it is designed to handle well the simple cases,) Tj T* 0 Tw (while retaining the ability to handle complex cases by relying on the underlying power of ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (.) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (The importance of scaling down) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 89.02362 cm
+1 0 0 1 62.69291 681.0236 cm
q
-BT 1 0 0 1 0 28.82 Tm 1.488221 Tw 12 TL /F1 10 Tf 0 0 0 rg (Technically ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is just a simple wrapper over ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (which hides most of its complexity by using a ) Tj T* 0 Tw .203318 Tw (declarative interface: the argument parser is inferred rather than written down by imperatively. Still, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is ) Tj T* 0 Tw .125984 Tw (surprisingly scalable upwards, even without using the underlying ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. I have been using Python for 8) Tj T* 0 Tw 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.087126 Tw (contains three different modules: ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (\(from the stone age\), ) Tj 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (\(from Python 2.3\) and ) Tj 0 0 .501961 rg (argparse) Tj T* 0 Tw .223735 Tw 0 0 0 rg (\(from Python 2.7\). All of them are quite powerful and especially ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (is an industrial strength solution;) Tj T* 0 Tw 1.40311 Tw (unfortunately, all of them feature a non-zero learning curve and a certain verbosity. They do not scale) Tj T* 0 Tw (down well, at least in my opinion.) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 603.0236 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (1) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 64.82 Tm 2.20186 Tw 12 TL /F1 10 Tf 0 0 0 rg (It should not be necessary to stress the importance ) Tj 0 0 .501961 rg (scaling down) Tj 0 0 0 rg (; nevertheless, a lot of people are) Tj T* 0 Tw .968555 Tw (obsessed with features and concerned with the possibility of scaling up, forgetting the equally important) Tj T* 0 Tw .048221 Tw (issue of scaling down. This is an old meme in the computing world: programs should address the common) Tj T* 0 Tw .36311 Tw (cases simply and simple things should be kept simple, while at the same keeping difficult things possible.) Tj T* 0 Tw 1.09332 Tw 0 0 .501961 rg (plac ) Tj 0 0 0 rg (adhere as much as possible to this philosophy and it is designed to handle well the simple cases,) Tj T* 0 Tw (while retaining the ability to handle complex cases by relying on the underlying power of ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (.) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R187': class PDFStream
-187 0 obj
-% page stream
-<< /Length 4921 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 729.0236 cm
+1 0 0 1 62.69291 525.0236 cm
q
-BT 1 0 0 1 0 28.82 Tm 1.618876 Tw 12 TL /F1 10 Tf 0 0 0 rg (years and in my experience it is extremely unlikely that you will ever need to go beyond the features) Tj T* 0 Tw 1.776457 Tw (provided by the declarative interface of ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (: they should be more than enough for 99.9% of the use) Tj T* 0 Tw (cases.) Tj T* ET
+BT 1 0 0 1 0 64.82 Tm 1.488221 Tw 12 TL /F1 10 Tf 0 0 0 rg (Technically ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is just a simple wrapper over ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (which hides most of its complexity by using a) Tj T* 0 Tw .203318 Tw (declarative interface: the argument parser is inferred rather than written down by imperatively. Still, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is) Tj T* 0 Tw .125984 Tw (surprisingly scalable upwards, even without using the underlying ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. I have been using Python for 8) Tj T* 0 Tw 1.618876 Tw (years and in my experience it is extremely unlikely that you will ever need to go beyond the features) Tj T* 0 Tw 1.776457 Tw (provided by the declarative interface of ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (: they should be more than enough for 99.9% of the use) Tj T* 0 Tw (cases.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 627.0236 cm
+1 0 0 1 62.69291 423.0236 cm
q
BT 1 0 0 1 0 88.82 Tm 1.540888 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is targetting especially unsophisticated users, programmers, sys-admins, scientists and in general) Tj T* 0 Tw .81284 Tw (people writing throw-away scripts for themselves, choosing the command line interface because it is the) Tj T* 0 Tw .471751 Tw (quick and simple. Such users are not interested in features, they are interested in a small learning curve:) Tj T* 0 Tw .984988 Tw (they just want to be able to write a simple command line tool from a simple specification, not to build a) Tj T* 0 Tw 1.127318 Tw (command-line parser by hand. Unfortunately, the modules in the standard library forces them to go the) Tj T* 0 Tw .014104 Tw (hard way. They are designed to implement power user tools and they have a non-trivial learning curve. On) Tj T* 0 Tw 1.584104 Tw (the contrary, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is designed to be simple to use and extremely concise, as the examples below will) Tj T* 0 Tw (show.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 594.0236 cm
+1 0 0 1 62.69291 393.0236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Scripts with required arguments) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Scripts with required arguments) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 528.0236 cm
+1 0 0 1 62.69291 327.0236 cm
q
BT 1 0 0 1 0 52.82 Tm .352209 Tw 12 TL /F1 10 Tf 0 0 0 rg (Let me start with the simplest possible thing: a script that takes a single argument and does something to) Tj T* 0 Tw 1.053984 Tw (it. It cannot get simpler than that, unless you consider a script without command-line arguments, where) Tj T* 0 Tw .735488 Tw (there is nothing to parse. Still, it is a use case ) Tj /F5 10 Tf (extremely common) Tj /F1 10 Tf (: I need to write scripts like that nearly) Tj T* 0 Tw .486655 Tw (every day, I wrote hundreds of them in the last few years and I have never been happy. Here is a typical) Tj T* 0 Tw (example of code I have been writing by hand for years:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 326.8236 cm
+1 0 0 1 62.69291 125.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3458,51 +7748,36 @@ Q
Q
Q
q
-1 0 0 1 62.69291 222.8236 cm
+1 0 0 1 62.69291 93.82362 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.972927 Tw (should not exist. Actually I think the language should recognize the main function and pass to it the) Tj T* 0 Tw 3.309147 Tw (command-line arguments automatically; 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 .69881 Tw (does not help for this incredibly common use case. Using ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (and ) Tj 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (does not help, since they) Tj T* 0 Tw .894104 Tw (are intended to manage options and not positional arguments; the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module helps a bit and it is) Tj T* 0 Tw (able to reduce the boilerplate from nine lines to six lines:) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 93.62362 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 120 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 101.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* ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import argparse) Tj T* ( p = argparse.ArgumentParser\(\)) Tj T* ET
-Q
-Q
-Q
+BT 1 0 0 1 0 16.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.972927 Tw (should not exist. Actually I think the language should recognize the main function and pass to it the) Tj T* 0 Tw ET
Q
Q
q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (2) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (3) Tj T* -238.1649 0 Td ET
Q
Q
endstream
endobj
-% 'R188': class PDFStream
-188 0 obj
+% 'R415': class PDFStream
+415 0 obj
% page stream
-<< /Length 4194 >>
+<< /Length 4448 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 715.8236 cm
+1 0 0 1 62.69291 693.0236 cm
+q
+BT 1 0 0 1 0 64.82 Tm 3.309147 Tw 12 TL /F1 10 Tf 0 0 0 rg (command-line arguments automatically; 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 .69881 Tw (does not help for this incredibly common use case. Using ) Tj 0 0 .501961 rg (getopt ) Tj 0 0 0 rg (and ) Tj 0 0 .501961 rg (optparse ) Tj 0 0 0 rg (does not help, since they) Tj T* 0 Tw .894104 Tw (are intended to manage options and not positional arguments; the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (module helps a bit and it is) Tj T* 0 Tw (able to reduce the boilerplate from nine lines to six lines:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 527.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3512,31 +7787,31 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 48 re B*
+n -6 -6 468.6898 156 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL ( p.add_argument\('dsn'\)) Tj T* ( arg = p.parse_args\(\)) Tj T* ( main\(arg.dsn\)) Tj T* ET
+BT 1 0 0 1 0 137.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* ( # ...) 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
Q
Q
q
-1 0 0 1 62.69291 659.8236 cm
+1 0 0 1 62.69291 471.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 40.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 2.206303 Tw (switch to Python 2.7, which at the time of this writing is just about to be released, for many years.) Tj T* 0 Tw .678488 Tw (Moreover, it just feels too complex to instantiate a class and to define a parser by hand for such a trivial) Tj T* 0 Tw (task.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 629.8236 cm
+1 0 0 1 62.69291 441.8236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.123145 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (module is designed to manage well such use cases, and it is able to reduce the original nine) Tj T* 0 Tw (lines of boiler plate to two lines. With the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (module all you need to write is) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 512.6236 cm
+1 0 0 1 62.69291 324.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3557,13 +7832,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 480.6236 cm
+1 0 0 1 62.69291 292.6236 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 447.4236 cm
+1 0 0 1 62.69291 259.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3584,7 +7859,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 318.2236 cm
+1 0 0 1 62.69291 130.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3605,63 +7880,43 @@ Q
Q
Q
q
-1 0 0 1 62.69291 286.2236 cm
+1 0 0 1 62.69291 98.22362 cm
q
BT 1 0 0 1 0 16.82 Tm .167765 Tw 12 TL /F1 10 Tf 0 0 0 rg (Moreover ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (manages the case of missing arguments and of too many arguments. This is only the tip of) Tj T* 0 Tw (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 253.2236 cm
-q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Scripts with default arguments) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 223.2236 cm
+1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 2.609984 Tw (The need to have suitable defaults for command-line scripts is quite common. For instance I have) Tj T* 0 Tw (encountered this use case at work hundreds of times:) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (4) Tj T* -238.1649 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R416': class PDFStream
+416 0 obj
+% page stream
+<< /Length 4050 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 94.02362 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 120 re B*
-Q
+1 0 0 1 62.69291 747.0236 cm
q
-BT 1 0 0 1 0 101.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* ET
-Q
-Q
-Q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Scripts with default arguments) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 717.0236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (3) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 2.609984 Tw (The need to have suitable defaults for command-line scripts is quite common. For instance I have) Tj T* 0 Tw (encountered this use case at work hundreds of times:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R189': class PDFStream
-189 0 obj
-% page stream
-<< /Length 3999 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 679.8236 cm
+1 0 0 1 62.69291 515.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3671,23 +7926,23 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 84 re B*
+n -6 -6 468.6898 192 re B*
Q
q
-BT 1 0 0 1 0 65.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( 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
Q
Q
q
-1 0 0 1 62.69291 611.8236 cm
+1 0 0 1 62.69291 447.8236 cm
q
BT 1 0 0 1 0 52.82 Tm .038488 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here I want to perform a query on a database table, by extracting the most recent data: it makes sense for) Tj T* 0 Tw .299988 Tw /F4 10 Tf (today ) Tj /F1 10 Tf (to be a default argument. If there is a most used table \(in this example a table called ) Tj /F4 10 Tf ('product') Tj /F1 10 Tf (\)) Tj T* 0 Tw 3.313984 Tw (it also makes sense to make it a default argument. Performing the parsing of the command-line) Tj T* 0 Tw .083735 Tw (arguments by hand takes 8 ugly lines of boilerplate \(using ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (would require about the same number) Tj T* 0 Tw (of lines\). 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 566.6236 cm
+1 0 0 1 62.69291 402.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3708,14 +7963,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 546.6236 cm
+1 0 0 1 62.69291 382.6236 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 we get the usage message for free:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 393.4236 cm
+1 0 0 1 62.69291 229.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3736,13 +7991,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 361.4236 cm
+1 0 0 1 62.69291 197.4236 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 SQL scripts:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 208.2236 cm
+1 0 0 1 62.69291 92.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -3752,25 +8007,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 144 re B*
+n -6 -6 468.6898 96 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 125.71 Tm /F4 10 Tf 12 TL (# example7.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* ( # ...) Tj T* 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 (# example7.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* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 188.2236 cm
+1 0 0 1 56.69291 56.69291 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
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (5) Tj T* -238.1649 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R417': class PDFStream
+417 0 obj
+% page stream
+<< /Length 3901 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 95.02362 cm
+1 0 0 1 62.69291 703.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3780,35 +8045,25 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 84 re B*
+n -6 -6 468.6898 60 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL (usage: example7.py [-h] dsn [scripts [scripts ...]]) Tj T* T* (Run the given scripts on the database) Tj T* T* (positional arguments:) Tj T* ( dsn) Tj T* ET
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 683.8236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (4) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage message:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R190': class PDFStream
-190 0 obj
-% page stream
-<< /Length 4674 >>
-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 542.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3818,36 +8073,36 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 60 re B*
+n -6 -6 468.6898 132 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ( scripts) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ET
+BT 1 0 0 1 0 113.71 Tm /F4 10 Tf 12 TL (usage: example7.py [-h] dsn [scripts [scripts ...]]) Tj T* T* (Run the given scripts on the database) Tj T* T* (positional arguments:) Tj T* ( dsn) Tj T* ( scripts) 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 659.8236 cm
+1 0 0 1 62.69291 498.6236 cm
q
BT 1 0 0 1 0 28.82 Tm .952485 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 .899988 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 the 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 617.8236 cm
+1 0 0 1 62.69291 456.6236 cm
q
BT 1 0 0 1 0 28.82 Tm 3.036235 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is inspired to an old Python Cookbook recipe \() Tj 0 0 .501961 rg (optionparse) Tj 0 0 0 rg (\), in the sense that it delivers the) Tj T* 0 Tw .847209 Tw (programmer from the burden of writing the parser, but is less of a hack: instead of extracting the parser) Tj T* 0 Tw (from the docstring of the module, it 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 587.8236 cm
+1 0 0 1 62.69291 426.6236 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 434.6236 cm
+1 0 0 1 62.69291 273.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3868,13 +8123,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 402.6236 cm
+1 0 0 1 62.69291 241.4236 cm
q
BT 1 0 0 1 0 16.82 Tm .17528 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here the arguments of the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function have been annotated with strings which are intented to be used) Tj T* 0 Tw (in the help message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 261.4236 cm
+1 0 0 1 62.69291 100.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3895,42 +8150,42 @@ Q
Q
Q
q
-1 0 0 1 62.69291 241.4236 cm
+1 0 0 1 56.69291 56.69291 cm
q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to recognize much more complex annotations, as I will show in the next paragraphs.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (6) Tj T* -238.1649 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R418': class PDFStream
+418 0 obj
+% page stream
+<< /Length 5019 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 208.4236 cm
+1 0 0 1 62.69291 753.0236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Scripts with options \(and smart options\)) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to recognize much more complex annotations, as I will show in the next paragraphs.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 118.4236 cm
+1 0 0 1 62.69291 723.0236 cm
q
-BT 1 0 0 1 0 76.82 Tm .016457 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.02311 Tw (a hundred\), compared to the number of scripts with positional arguments I wrote \(certainly more than a) Tj T* 0 Tw .177045 Tw (thousand of them\). Still, this use case cannot be neglected. The standard library modules \(all of them\) are) Tj T* 0 Tw 2.30686 Tw (quite verbose when it comes to specifying the options and frankly I have never used them directly.) Tj T* 0 Tw 2.557126 Tw (Instead, I have always relied on the ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe, which provides a convenient wrapper over) Tj T* 0 Tw 1.09061 Tw 0 0 .501961 rg (optionparse) Tj 0 0 0 rg (. Alternatively, in the simplest cases, I have just performed the parsing by hand. In ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (the) Tj T* 0 Tw (parser is inferred by the function annotations. Here is an example:) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Scripts with options \(and smart options\)) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 633.0236 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (5) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 76.82 Tm .016457 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.02311 Tw (a hundred\), compared to the number of scripts with positional arguments I wrote \(certainly more than a) Tj T* 0 Tw .177045 Tw (thousand of them\). Still, this use case cannot be neglected. The standard library modules \(all of them\) are) Tj T* 0 Tw 2.30686 Tw (quite verbose when it comes to specifying the options and frankly I have never used them directly.) Tj T* 0 Tw 2.557126 Tw (Instead, I have always relied on the ) Tj 0 0 .501961 rg (optionparse ) Tj 0 0 0 rg (recipe, which provides a convenient wrapper over) Tj T* 0 Tw 1.09061 Tw 0 0 .501961 rg (optionparse) Tj 0 0 0 rg (. Alternatively, in the simplest cases, I have just performed the parsing by hand. In ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (the) Tj T* 0 Tw (parser is inferred by the function annotations. Here is an example:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R191': class PDFStream
-191 0 obj
-% page stream
-<< /Length 4134 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 655.8236 cm
+1 0 0 1 62.69291 515.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3951,13 +8206,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 599.8236 cm
+1 0 0 1 62.69291 459.8236 cm
q
BT 1 0 0 1 0 40.82 Tm .929213 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here the argument ) Tj /F4 10 Tf (command ) Tj /F1 10 Tf (has been annotated with the tuple ) Tj /F4 10 Tf (\("SQL query", 'option', 'c'\)) Tj /F1 10 Tf (:) Tj T* 0 Tw .62683 Tw (the first string is the help string which will appear in the usage message, the second string tells ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (that) Tj T* 0 Tw .931894 Tw /F4 10 Tf (command ) Tj /F1 10 Tf (is an option and the third string that there is also a short form of the option ) Tj /F4 10 Tf (-c) Tj /F1 10 Tf (, the long form) Tj T* 0 Tw (being ) Tj /F4 10 Tf (--command) Tj /F1 10 Tf (. The usage message is the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 470.6236 cm
+1 0 0 1 62.69291 330.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3978,14 +8233,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 450.6236 cm
+1 0 0 1 62.69291 310.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 369.4236 cm
+1 0 0 1 62.69291 229.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4006,13 +8261,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 313.4236 cm
+1 0 0 1 62.69291 173.4236 cm
q
BT 1 0 0 1 0 40.82 Tm .268935 Tw 12 TL /F1 10 Tf 0 0 0 rg (The third argument in the function annotation can be omitted: in such case it will be assumed to be ) Tj /F4 10 Tf (None) Tj /F1 10 Tf (.) Tj T* 0 Tw 2.839213 Tw (The consequence is that the usual dichotomy between long and short options \(GNU-style options\)) Tj T* 0 Tw .396235 Tw (disappears: we get ) Tj /F5 10 Tf (smart options) Tj /F1 10 Tf (, which have the single character prefix of short options and behave like) Tj T* 0 Tw (both long and short options, since they can be abbreviated. Here is an example featuring smart options:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 220.2236 cm
+1 0 0 1 62.69291 92.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -4022,18 +8277,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 84 re B*
+n -6 -6 468.6898 72 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL (# example6.py) Tj T* (def main\(dsn, command: \("SQL query", 'option'\)\):) Tj T* ( print\('executing %r on %s' % \(command, dsn\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (# example6.py) Tj T* (def main\(dsn, command: \("SQL query", 'option'\)\):) Tj T* ( print\('executing %r on %s' % \(command, dsn\)\)) Tj T* T* (if __name__ == '__main__':) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 103.0236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (7) Tj T* -238.1649 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R419': class PDFStream
+419 0 obj
+% page stream
+<< /Length 4318 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 739.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4043,42 +8315,46 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 108 re B*
+n -6 -6 468.6898 24 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL (usage: example6.py [-h] [-command COMMAND] dsn) Tj T* T* (positional arguments:) Tj T* ( dsn) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -command COMMAND SQL query) Tj T* ET
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 622.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 108 re B*
+Q
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (6) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL (usage: example6.py [-h] [-command COMMAND] dsn) Tj T* T* (positional arguments:) Tj T* ( dsn) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -command COMMAND SQL query) Tj T* ET
+Q
+Q
+Q
Q
Q
-
-endstream
-
-endobj
-% 'R192': class PDFStream
-192 0 obj
-% page stream
-<< /Length 4491 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 753.0236 cm
+1 0 0 1 62.69291 602.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (The following are all valid invocations ot the script:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 659.8236 cm
+1 0 0 1 62.69291 509.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4099,13 +8375,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 639.8236 cm
+1 0 0 1 62.69291 489.4236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Notice that the form ) Tj /F4 10 Tf (-command=SQL ) Tj /F1 10 Tf (is recognized only for the full option, not for its abbreviations:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 582.6236 cm
+1 0 0 1 62.69291 432.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -4126,13 +8402,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 550.6236 cm
+1 0 0 1 62.69291 400.2236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.724987 Tw 12 TL /F1 10 Tf 0 0 0 rg (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 (. However, it is possible to) Tj T* 0 Tw (specify a non-trivial default. Here is an example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 457.4236 cm
+1 0 0 1 62.69291 307.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -4153,14 +8429,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 437.4236 cm
+1 0 0 1 62.69291 287.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Notice that the default value appears in the help message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 308.2236 cm
+1 0 0 1 62.69291 157.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4181,13 +8457,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 288.2236 cm
+1 0 0 1 62.69291 137.8236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (When you run the script and you do not pass the ) Tj /F4 10 Tf (-command ) Tj /F1 10 Tf (option, the default query will be executed:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 243.0236 cm
+1 0 0 1 62.69291 92.62362 cm
q
q
1 0 0 1 0 0 cm
@@ -4208,78 +8484,57 @@ Q
Q
Q
q
-1 0 0 1 62.69291 210.0236 cm
-q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Scripts with flags) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 180.0236 cm
-q
-BT 1 0 0 1 0 16.82 Tm .815542 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to recognize flags, i.e. boolean options which are ) Tj /F4 10 Tf (True ) Tj /F1 10 Tf (if they are passed to the command) Tj T* 0 Tw (line and ) Tj /F4 10 Tf (False ) Tj /F1 10 Tf (if they are absent. Here is an example:) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 101.4244 cm
-q
-q
-.96447 0 0 .96447 0 0 cm
-q
-1 0 0 1 6.6 6.843137 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 486 72 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (# example9.py) Tj T* T* (def main\(verbose: \('prints more info', 'flag', 'v'\), dsn: 'connection string'\):) Tj T* ( if verbose:) Tj T* ( print\('connecting to %s' % dsn\)) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (7) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (8) Tj T* -238.1649 0 Td ET
Q
Q
endstream
endobj
-% 'R193': class PDFStream
-193 0 obj
+% 'R420': class PDFStream
+420 0 obj
% page stream
-<< /Length 5065 >>
+<< /Length 4916 >>
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 747.0236 cm
q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Scripts with flags) Tj T* ET
+Q
+Q
q
-1 0 0 1 0 0 cm
+1 0 0 1 62.69291 717.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .815542 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to recognize flags, i.e. boolean options which are ) Tj /F4 10 Tf (True ) Tj /F1 10 Tf (if they are passed to the command) Tj T* 0 Tw (line and ) Tj /F4 10 Tf (False ) Tj /F1 10 Tf (if they are absent. Here is an example:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 592.1299 cm
q
-1 0 0 1 6.6 6.6 cm
+q
+.96447 0 0 .96447 0 0 cm
+q
+1 0 0 1 6.6 6.843137 cm
q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 60 re B*
+n -6 -6 486 120 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 101.71 Tm /F4 10 Tf 12 TL (# example9.py) Tj T* T* (def main\(verbose: \('prints more info', 'flag', 'v'\), dsn: 'connection string'\):) Tj T* ( if verbose:) Tj T* ( print\('connecting to %s' % dsn\)) Tj T* ( # ...) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 586.6236 cm
+1 0 0 1 62.69291 474.9299 cm
q
q
1 0 0 1 0 0 cm
@@ -4300,7 +8555,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 541.4236 cm
+1 0 0 1 62.69291 429.7299 cm
q
q
1 0 0 1 0 0 cm
@@ -4321,37 +8576,37 @@ Q
Q
Q
q
-1 0 0 1 62.69291 497.4236 cm
+1 0 0 1 62.69291 385.7299 cm
q
BT 1 0 0 1 0 28.82 Tm .31408 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that it is an error trying to specify a default for flags: the default value for a flag is always ) Tj /F4 10 Tf (False) Tj /F1 10 Tf (. If) Tj T* 0 Tw 2.652485 Tw (you feel the need to implement non-boolean flags, you should use an option with two choices, as) Tj T* 0 Tw (explained in the "more features" section.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 431.4236 cm
+1 0 0 1 62.69291 319.7299 cm
q
BT 1 0 0 1 0 52.82 Tm 5.832651 Tw 12 TL /F1 10 Tf 0 0 0 rg (For consistency with the way the usage message is printed, I suggest you to follow the) Tj T* 0 Tw 1.895433 Tw (Flag-Option-Required-Default \(FORD\) convention: in the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function write first the flag arguments,) Tj T* 0 Tw .881235 Tw (then the option arguments, then the required arguments and finally the default arguments. This is just a) Tj T* 0 Tw .110574 Tw (convention and you are not forced to use it, except for the default arguments \(including the varargs\) which) Tj T* 0 Tw (must stay at the end as it is required by the Python syntax.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 389.4236 cm
+1 0 0 1 62.69291 277.7299 cm
q
BT 1 0 0 1 0 28.82 Tm .897045 Tw 12 TL /F1 10 Tf 0 0 0 rg (I also suggests to specify a one-character abbreviation for flags: in this way you can use the GNU-style) Tj T* 0 Tw 2.034431 Tw (composition of flags \(i.e. ) Tj /F4 10 Tf (-zxvf ) Tj /F1 10 Tf (is an abbreviation of ) Tj /F4 10 Tf (-z -x -v -f) Tj /F1 10 Tf (\). I usually do not provide the) Tj T* 0 Tw (one-character abbreviation for options, since it does not make sense to compose them.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 356.4236 cm
+1 0 0 1 62.69291 247.7299 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (plac for Python 2.X users) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (plac for Python 2.X users) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 290.4236 cm
+1 0 0 1 62.69291 181.7299 cm
q
BT 1 0 0 1 0 52.82 Tm .211807 Tw 12 TL /F1 10 Tf 0 0 0 rg (I do not use Python 3. At work we are just starting to think about migrating to Python 2.6. It will take years) Tj T* 0 Tw .304724 Tw (before we think to migrate to Python 3. I am pretty much sure most Pythonistas are in the same situation.) Tj T* 0 Tw 1.459984 Tw (Therefore ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (provides a way to work with function annotations even in Python 2.X \(including Python) Tj T* 0 Tw 2.692339 Tw (2.3\). There is no magic involved; you just need to add the annotations by hand. For instance the) Tj T* 0 Tw (annotated function declaration) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 245.2236 cm
+1 0 0 1 62.69291 136.5299 cm
q
q
1 0 0 1 0 0 cm
@@ -4372,14 +8627,31 @@ Q
Q
Q
q
-1 0 0 1 62.69291 225.2236 cm
+1 0 0 1 62.69291 116.5299 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (is equivalent to the following code:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 144.0236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (9) Tj T* -238.1649 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R421': class PDFStream
+421 0 obj
+% page stream
+<< /Length 5845 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 691.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4400,30 +8672,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 100.0236 cm
+1 0 0 1 62.69291 647.8236 cm
q
BT 1 0 0 1 0 28.82 Tm .536098 Tw 12 TL /F1 10 Tf 0 0 0 rg (One should be careful to match the keys of the annotation dictionary with the names of the arguments in) Tj T* 0 Tw 3.347485 Tw (the annotated function; for lazy people with Python 2.4 available the simplest way is to use the) Tj T* 0 Tw /F4 10 Tf (plac.annotations ) Tj /F1 10 Tf (decorator that performs the check for you:) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (8) Tj T* -238.1649 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R194': class PDFStream
-194 0 obj
-% page stream
-<< /Length 5334 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 691.8236 cm
+1 0 0 1 62.69291 566.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4444,28 +8699,28 @@ Q
Q
Q
q
-1 0 0 1 62.69291 659.8236 cm
+1 0 0 1 62.69291 534.6236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.846077 Tw 12 TL /F1 10 Tf 0 0 0 rg (In the rest of this article I will assume that you are using Python 2.X with X >) Tj (= 4 and I will use the) Tj T* 0 Tw /F4 10 Tf (plac.annotations ) Tj /F1 10 Tf (decorator. Notice however that the core features of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (run even on Python 2.3.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 626.8236 cm
+1 0 0 1 62.69291 504.6236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (More features) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (More features) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 572.8236 cm
+1 0 0 1 62.69291 450.6236 cm
q
BT 1 0 0 1 0 40.82 Tm 1.483488 Tw 12 TL /F1 10 Tf 0 0 0 rg (One of the goals of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is to have a learning curve of ) Tj /F5 10 Tf (minutes ) Tj /F1 10 Tf (for its core features, compared to the) Tj T* 0 Tw 1.152093 Tw (learning curve of ) Tj /F5 10 Tf (hours ) Tj /F1 10 Tf (of ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. In order to reach this goal, I have ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (sacrificed all the features of) Tj T* 0 Tw 2.89936 Tw 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. Actually a lot of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (power persists in ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (. Until now, I have only showed simple) Tj T* 0 Tw (annotations, but in general an annotation is a 6-tuple of the form) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 566.8236 cm
+1 0 0 1 62.69291 444.6236 cm
Q
q
-1 0 0 1 62.69291 554.8236 cm
+1 0 0 1 62.69291 432.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -4480,40 +8735,40 @@ q
Q
Q
q
-1 0 0 1 62.69291 554.8236 cm
+1 0 0 1 62.69291 432.6236 cm
Q
q
-1 0 0 1 62.69291 512.8236 cm
+1 0 0 1 62.69291 390.6236 cm
q
BT 1 0 0 1 0 28.82 Tm 1.068735 Tw 12 TL /F1 10 Tf 0 0 0 rg (where ) Tj /F4 10 Tf (help ) Tj /F1 10 Tf (is the help message, ) Tj /F4 10 Tf (kind ) Tj /F1 10 Tf (is a string in the set { ) Tj /F4 10 Tf ("flag") Tj /F1 10 Tf (, ) Tj /F4 10 Tf ("option") Tj /F1 10 Tf (, ) Tj /F4 10 Tf ("positional") Tj /F1 10 Tf (},) Tj T* 0 Tw 1.579431 Tw /F4 10 Tf (abbrev ) Tj /F1 10 Tf (is a one-character string or ) Tj /F4 10 Tf (None) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (type ) Tj /F1 10 Tf (is a callable taking a string in input, ) Tj /F4 10 Tf (choices ) Tj /F1 10 Tf (is a) Tj T* 0 Tw (discrete sequence of values and ) Tj /F4 10 Tf (metavar ) Tj /F1 10 Tf (is a string.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 482.8236 cm
+1 0 0 1 62.69291 360.6236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.05061 Tw 12 TL /F4 10 Tf 0 0 0 rg (type ) Tj /F1 10 Tf (is used to automagically convert the command line arguments from the string type to any Python) Tj T* 0 Tw (type; by default there is no conversion and ) Tj /F4 10 Tf (type=None) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 452.8236 cm
+1 0 0 1 62.69291 330.6236 cm
q
BT 1 0 0 1 0 16.82 Tm 2.904692 Tw 12 TL /F4 10 Tf 0 0 0 rg (choices ) Tj /F1 10 Tf (is used to restrict the number of the valid options; by default there is no restriction i.e.) Tj T* 0 Tw /F4 10 Tf (choices=None) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 410.8236 cm
+1 0 0 1 62.69291 288.6236 cm
q
BT 1 0 0 1 0 28.82 Tm 1.071751 Tw 12 TL /F4 10 Tf 0 0 0 rg (metavar ) Tj /F1 10 Tf (is used to change the argument name in the usage message \(and only there\); by default the) Tj T* 0 Tw 1.056654 Tw (metavar is ) Tj /F4 10 Tf (None) Tj /F1 10 Tf (: this means that the name in the usage message is the same as the argument name,) Tj T* 0 Tw (unless the argument has a default and in such a case is equal to the stringified form of the default.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 392.8236 cm
+1 0 0 1 62.69291 270.6236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Here is an example showing many of the features \(copied from the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (documentation\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 137.5749 cm
+1 0 0 1 62.69291 97.40054 cm
q
q
.976496 0 0 .976496 0 0 cm
@@ -4523,42 +8778,63 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 480 252 re B*
+n -6 -6 480 168 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 233.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* ( if operator == 'mul':) Tj T* ( op = float.__mul__) Tj T* ( result = 1.0) Tj T* ( else: # operator == 'add') Tj T* ( op = float.__add__) Tj T* ( result = 0.0) Tj T* ( for n in numbers:) Tj T* ( result = op\(result, n\)) Tj T* ( return result) Tj T* T* (if __name__ == '__main__':) Tj T* ( print\(plac.call\(main\)\)) Tj T* ET
-Q
-Q
+BT 1 0 0 1 0 149.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* ( if operator == 'mul':) Tj T* ( op = float.__mul__) Tj T* ( result = 1.0) Tj T* ( else: # operator == 'add') Tj T* ( op = float.__add__) Tj T* ET
Q
Q
Q
-q
-1 0 0 1 62.69291 117.5749 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage:) Tj T* ET
Q
Q
q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 238.1649 0 Td (9) Tj T* -238.1649 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (10) Tj T* -235.3849 0 Td ET
Q
Q
endstream
endobj
-% 'R195': class PDFStream
-195 0 obj
+% 'R422': class PDFStream
+422 0 obj
% page stream
-<< /Length 4511 >>
+<< /Length 4152 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 631.8236 cm
+1 0 0 1 62.69291 667.8236 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 96 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL ( result = 0.0) Tj T* ( for n in numbers:) Tj T* ( result = op\(result, n\)) Tj T* ( return result) Tj T* T* (if __name__ == '__main__':) Tj T* ( print\(plac.call\(main\)\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 647.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:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 506.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4579,13 +8855,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 599.8236 cm
+1 0 0 1 62.69291 474.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 506.4849 cm
+1 0 0 1 62.69291 381.2849 cm
q
q
.87797 0 0 .87797 0 0 cm
@@ -4606,13 +8882,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 486.4849 cm
+1 0 0 1 62.69291 361.2849 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (plac.call ) Tj /F1 10 Tf (can also be used in doctests like this:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 429.2849 cm
+1 0 0 1 62.69291 304.0849 cm
q
q
1 0 0 1 0 0 cm
@@ -4632,13 +8908,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 409.2849 cm
+1 0 0 1 62.69291 284.0849 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (plac.call ) Tj /F1 10 Tf (works for generators too:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 328.0849 cm
+1 0 0 1 62.69291 202.8849 cm
q
q
1 0 0 1 0 0 cm
@@ -4658,19 +8934,36 @@ Q
Q
Q
q
-1 0 0 1 62.69291 284.0849 cm
+1 0 0 1 62.69291 158.8849 cm
q
BT 1 0 0 1 0 28.82 Tm .158409 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (tries to convert the output of the main function into a list, if possible. If the output is) Tj T* 0 Tw .725703 Tw (not iterable or it is a string, it is left unchanged, but if it is iterable it is converted. In particular, generator) Tj T* 0 Tw (objects are exhausted by ) Tj /F4 10 Tf (plac.call) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 254.0849 cm
+1 0 0 1 62.69291 128.8849 cm
q
BT 1 0 0 1 0 16.82 Tm 1.450751 Tw 12 TL /F1 10 Tf 0 0 0 rg (This behavior avoids mistakes like forgetting of applying ) Tj /F4 10 Tf (list\(result\) ) Tj /F1 10 Tf (to the result of ) Tj /F4 10 Tf (plac.call) Tj /F1 10 Tf (;) Tj T* 0 Tw (moreover it makes errors visible early, and avoids mistakes in code like the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 184.8849 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (11) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R423': class PDFStream
+423 0 obj
+% page stream
+<< /Length 4298 >>
+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
q
q
1 0 0 1 0 0 cm
@@ -4691,37 +8984,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 152.8849 cm
+1 0 0 1 62.69291 671.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 3.122126 Tw (Without the "listify" functionality, a main function returning a generator object would not raise any) Tj T* 0 Tw (exception until the generator is iterated over.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 122.8849 cm
+1 0 0 1 62.69291 641.8236 cm
q
BT 1 0 0 1 0 16.82 Tm .647262 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you are a fan of lazyness, you can still have it by setting the ) Tj /F4 10 Tf (eager ) Tj /F1 10 Tf (flag to ) Tj /F4 10 Tf (False) Tj /F1 10 Tf (, as in the following) Tj T* 0 Tw (example:) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (10) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R196': class PDFStream
-196 0 obj
-% page stream
-<< /Length 4236 >>
-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 596.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4742,25 +9018,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 695.8236 cm
+1 0 0 1 62.69291 564.6236 cm
q
BT 1 0 0 1 0 16.82 Tm 1.35528 Tw 12 TL /F1 10 Tf 0 0 0 rg (If ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (returns a generator object this example will print each line as soon as available, whereas the) Tj T* 0 Tw (default behaviour is to print all the lines together and the end of the computation.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 662.8236 cm
+1 0 0 1 62.69291 534.6236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A realistic example) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (A realistic example) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 620.8236 cm
+1 0 0 1 62.69291 492.6236 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 251.6236 cm
+1 0 0 1 62.69291 123.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4781,58 +9057,43 @@ Q
Q
Q
q
-1 0 0 1 62.69291 195.6236 cm
+1 0 0 1 62.69291 91.42362 cm
q
-BT 1 0 0 1 0 40.82 Tm .049987 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can see the ) Tj /F5 10 Tf (yield-is-print ) Tj /F1 10 Tf (pattern here: instead of using ) Tj /F4 10 Tf (print ) Tj /F1 10 Tf (in the main function, I use ) Tj /F4 10 Tf (yield) Tj /F1 10 Tf (, and) Tj T* 0 Tw 3.55061 Tw (I perform the print in the ) Tj /F4 10 Tf (__main__ ) Tj /F1 10 Tf (block. The advantage of the pattern is that tests invoking) Tj T* 0 Tw .52936 Tw /F4 10 Tf (plac.call ) Tj /F1 10 Tf (and checking the result become trivial: had I performed the printing in the main function, the) Tj T* 0 Tw (test would have involved an ugly hack like redirecting ) Tj /F4 10 Tf (sys.stdout ) Tj /F1 10 Tf (to a ) Tj /F4 10 Tf (StringIO ) Tj /F1 10 Tf (object.) Tj T* ET
+BT 1 0 0 1 0 16.82 Tm .049987 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can see the ) Tj /F5 10 Tf (yield-is-print ) Tj /F1 10 Tf (pattern here: instead of using ) Tj /F4 10 Tf (print ) Tj /F1 10 Tf (in the main function, I use ) Tj /F4 10 Tf (yield) Tj /F1 10 Tf (, and ) Tj T* 0 Tw 3.55061 Tw (I perform the print in the ) Tj /F4 10 Tf (__main__ ) Tj /F1 10 Tf (block. The advantage of the pattern is that tests invoking) Tj T* 0 Tw ET
Q
Q
q
-1 0 0 1 62.69291 177.6236 cm
+1 0 0 1 56.69291 56.69291 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
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (12) Tj T* -235.3849 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R424': class PDFStream
+424 0 obj
+% page stream
+<< /Length 3562 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 96.42362 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 72 re B*
-Q
+1 0 0 1 62.69291 741.0236 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (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* ET
-Q
-Q
-Q
+BT 1 0 0 1 0 16.82 Tm .52936 Tw 12 TL /F4 10 Tf 0 0 0 rg (plac.call ) Tj /F1 10 Tf (and checking the result become trivial: had I performed the printing in the main function, the) Tj T* 0 Tw (test would have involved an ugly hack like redirecting ) Tj /F4 10 Tf (sys.stdout ) Tj /F1 10 Tf (to a ) Tj /F4 10 Tf (StringIO ) Tj /F1 10 Tf (object.) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 723.0236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (11) Tj T* -235.3849 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the usage message:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R197': class PDFStream
-197 0 obj
-% page stream
-<< /Length 3423 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 655.8236 cm
+1 0 0 1 62.69291 545.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4842,37 +9103,37 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 108 re B*
+n -6 -6 468.6898 168 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL ( 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
+BT 1 0 0 1 0 149.71 Tm /F4 10 Tf 12 TL (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 635.8236 cm
+1 0 0 1 62.69291 525.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (You can check for yourself that the script works.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 602.8236 cm
+1 0 0 1 62.69291 495.8236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Keyword arguments) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Keyword arguments) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 560.8236 cm
+1 0 0 1 62.69291 453.8236 cm
q
BT 1 0 0 1 0 28.82 Tm 1.831984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Starting from release 0.4, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (supports keyword arguments. In practice that means that if your main) Tj T* 0 Tw 2.099213 Tw (function has keyword arguments, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (treats specially arguments of the form ) Tj /F4 10 Tf ("name=value" ) Tj /F1 10 Tf (in the) Tj T* 0 Tw (command line. Here is an example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 323.6236 cm
+1 0 0 1 62.69291 216.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4893,14 +9154,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 303.6236 cm
+1 0 0 1 62.69291 196.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is the generated usage message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 174.4236 cm
+1 0 0 1 62.69291 91.42362 cm
q
q
1 0 0 1 0 0 cm
@@ -4910,25 +9171,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 120 re B*
+n -6 -6 468.6898 96 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 101.71 Tm /F4 10 Tf 12 TL (usage: example12.py [-h] [-opt OPT] [args [args ...]] [kw [kw ...]]) Tj T* T* (positional arguments:) Tj T* ( args default arguments) Tj T* ( kw keyword arguments) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -opt OPT some option) Tj T* ET
+BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL (usage: example12.py [-h] [-opt OPT] [args [args ...]] [kw [kw ...]]) Tj T* T* (positional arguments:) Tj T* ( args default arguments) Tj T* ( kw keyword arguments) Tj T* T* (optional arguments:) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 154.4236 cm
+1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is how you call the script:) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (13) Tj T* -235.3849 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R425': class PDFStream
+425 0 obj
+% page stream
+<< /Length 4297 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 97.22362 cm
+1 0 0 1 62.69291 727.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4938,35 +9209,25 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 48 re B*
+n -6 -6 468.6898 36 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL ($ python example12.py -o X a1 a2 name=value) Tj T* (opt=X) Tj T* (args=\('a1', 'a2'\)) Tj T* ET
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL ( -h, --help show this help message and exit) Tj T* ( -opt OPT some option) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 707.8236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (12) Tj T* -235.3849 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is how you call the script:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R198': class PDFStream
-198 0 obj
-% page stream
-<< /Length 4089 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 739.8236 cm
+1 0 0 1 62.69291 638.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4976,24 +9237,24 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 24 re B*
+n -6 -6 468.6898 60 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (kw={'name': 'value'}) Tj T* ET
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ($ python example12.py -o X a1 a2 name=value) Tj T* (opt=X) Tj T* (args=\('a1', 'a2'\)) Tj T* (kw={'name': 'value'}) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 707.8236 cm
+1 0 0 1 62.69291 606.6236 cm
q
BT 1 0 0 1 0 16.82 Tm 2.133735 Tw 12 TL /F1 10 Tf 0 0 0 rg (When using keyword arguments, one must be careful to use names which are not alreay taken; for) Tj T* 0 Tw (instance in this examples the name ) Tj /F4 10 Tf (opt ) Tj /F1 10 Tf (is taken:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 650.6236 cm
+1 0 0 1 62.69291 549.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5014,26 +9275,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 606.6236 cm
+1 0 0 1 62.69291 505.4236 cm
q
0 0 0 rg
BT 1 0 0 1 0 28.82 Tm /F1 10 Tf 12 TL 1.024104 Tw (The names taken are the names of the flags, of the options, and of the positional arguments, excepted) Tj T* 0 Tw .60561 Tw (varargs and keywords. This limitation is a consequence of the way the argument names are managed in) Tj T* 0 Tw (function calls by the Python language.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 573.6236 cm
+1 0 0 1 62.69291 475.4236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Final example: a shelve interface) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Final example: a shelve interface) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 531.6236 cm
+1 0 0 1 62.69291 433.4236 cm
q
BT 1 0 0 1 0 28.82 Tm .603516 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here is a less trivial example for the keyword arguments feature. The use case is the following: suppose) Tj T* 0 Tw .82881 Tw (we have stored the configuration parameters of a given application into a Python shelve and we need a) Tj T* 0 Tw (command-line tool to edit the shelve. A possible implementation using ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (could be the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 110.8981 cm
+1 0 0 1 62.69291 115.5936 cm
q
q
.952737 0 0 .952737 0 0 cm
@@ -5043,10 +9304,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 492 432 re B*
+n -6 -6 492 324 re B*
Q
q
-BT 1 0 0 1 0 413.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (# ishelve.py) Tj T* (import os, shelve, plac) Tj T* T* (DEFAULT_SHELVE = os.path.expanduser\('~/conf.shelve'\)) Tj T* T* (@plac.annotations\() Tj T* ( help=\('show help', 'flag'\),) Tj T* ( showall=\('show all parameters in the shelve', 'flag'\),) Tj T* ( clear=\('clear the shelve', 'flag'\),) Tj T* ( delete=\('delete an element', 'option'\),) Tj T* ( filename=\('filename of the shelve', 'option'\),) Tj T* ( params='names of the parameters in the shelve',) Tj T* ( setters='setters param=value'\)) Tj T* (def main\(help, showall, clear, delete, filename=DEFAULT_SHELVE,) Tj T* ( *params, **setters\):) Tj T* ( "A simple interface to a shelve. Use .help to see the available commands.") Tj T* ( sh = shelve.open\(filename\)) Tj T* ( try:) Tj T* ( if not any\([help, showall, clear, delete, params, setters]\):) Tj T* ( yield 'no arguments passed, use .help to see the available commands') Tj T* ( elif help: # custom help) Tj T* ( yield 'Commands: .help, .showall, .clear, .delete') Tj T* ( yield ') Tj (<) Tj (param) Tj (>) Tj ( ...') Tj T* ( yield ') Tj (<) Tj (param=value) Tj (>) Tj ( ...') Tj T* ( elif showall:) Tj T* ( for param, name in sh.items\(\):) Tj T* ( yield '%s=%s' % \(param, name\)) Tj T* ( elif clear:) Tj T* ( sh.clear\(\)) Tj T* ( yield 'cleared the shelve') Tj T* ( elif delete:) Tj T* ( try:) Tj T* ( del sh[delete]) Tj T* ( except KeyError:) Tj T* ( yield '%s: not found' % delete) Tj T* ET
+BT 1 0 0 1 0 305.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (# ishelve.py) Tj T* (import os, shelve, plac) Tj T* T* (DEFAULT_SHELVE = os.path.expanduser\('~/conf.shelve'\)) Tj T* T* (@plac.annotations\() Tj T* ( help=\('show help', 'flag'\),) Tj T* ( showall=\('show all parameters in the shelve', 'flag'\),) Tj T* ( clear=\('clear the shelve', 'flag'\),) Tj T* ( delete=\('delete an element', 'option'\),) Tj T* ( filename=\('filename of the shelve', 'option'\),) Tj T* ( params='names of the parameters in the shelve',) Tj T* ( setters='setters param=value'\)) Tj T* (def main\(help, showall, clear, delete, filename=DEFAULT_SHELVE,) Tj T* ( *params, **setters\):) Tj T* ( "A simple interface to a shelve. Use .help to see the available commands.") Tj T* ( sh = shelve.open\(filename\)) Tj T* ( try:) Tj T* ( if not any\([help, showall, clear, delete, params, setters]\):) Tj T* ( yield 'no arguments passed, use .help to see the available commands') Tj T* ( elif help: # custom help) Tj T* ( yield 'Commands: .help, .showall, .clear, .delete') Tj T* ( yield ') Tj (<) Tj (param) Tj (>) Tj ( ...') Tj T* ( yield ') Tj (<) Tj (param=value) Tj (>) Tj ( ...') Tj T* ( elif showall:) Tj T* ( for param, name in sh.items\(\):) Tj T* ET
Q
Q
Q
@@ -5056,21 +9317,21 @@ q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (13) Tj T* -235.3849 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (14) Tj T* -235.3849 0 Td ET
Q
Q
endstream
endobj
-% 'R199': class PDFStream
-199 0 obj
+% 'R426': class PDFStream
+426 0 obj
% page stream
-<< /Length 6795 >>
+<< /Length 6595 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 523.8236 cm
+1 0 0 1 62.69291 415.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5080,30 +9341,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 240 re B*
+n -6 -6 468.6898 348 re B*
Q
q
-BT 1 0 0 1 0 221.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( else:) Tj T* ( yield 'deleted %s' % delete) Tj T* ( for param in params:) Tj T* ( try:) Tj T* ( yield sh[param]) Tj T* ( except KeyError:) Tj T* ( yield '%s: not found' % param ) Tj T* ( for param, value in setters.items\(\):) Tj T* ( sh[param] = value) Tj T* ( yield 'setting %s=%s' % \(param, value\)) Tj T* ( finally:) Tj T* ( sh.close\(\)) Tj T* T* (main.add_help = False # there is a custom help, remove the default one) Tj T* (main.prefix_chars = '.' # use dot-prefixed commands) Tj T* T* (if __name__ == '__main__':) Tj T* ( for output in plac.call\(main\):) Tj T* ( print\(output\)) Tj T* ET
+BT 1 0 0 1 0 329.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( yield '%s=%s' % \(param, name\)) Tj T* ( elif clear:) Tj T* ( sh.clear\(\)) Tj T* ( yield 'cleared the shelve') Tj T* ( elif delete:) Tj T* ( try:) Tj T* ( del sh[delete]) Tj T* ( except KeyError:) Tj T* ( yield '%s: not found' % delete) Tj T* ( else:) Tj T* ( yield 'deleted %s' % delete) Tj T* ( for param in params:) Tj T* ( try:) Tj T* ( yield sh[param]) Tj T* ( except KeyError:) Tj T* ( yield '%s: not found' % param ) Tj T* ( for param, value in setters.items\(\):) Tj T* ( sh[param] = value) Tj T* ( yield 'setting %s=%s' % \(param, value\)) Tj T* ( finally:) Tj T* ( sh.close\(\)) Tj T* T* (main.add_help = False # there is a custom help, remove the default one) Tj T* (main.prefix_chars = '.' # use dot-prefixed commands) Tj T* T* (if __name__ == '__main__':) Tj T* ( for output in plac.call\(main\):) Tj T* ( print\(output\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 503.8236 cm
+1 0 0 1 62.69291 395.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (A few notes are in order:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 497.8236 cm
+1 0 0 1 62.69291 389.8236 cm
Q
q
-1 0 0 1 62.69291 497.8236 cm
+1 0 0 1 62.69291 389.8236 cm
Q
q
-1 0 0 1 62.69291 467.8236 cm
+1 0 0 1 62.69291 359.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5123,13 +9384,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 467.8236 cm
+1 0 0 1 62.69291 359.8236 cm
Q
q
-1 0 0 1 62.69291 467.8236 cm
+1 0 0 1 62.69291 359.8236 cm
Q
q
-1 0 0 1 62.69291 449.8236 cm
+1 0 0 1 62.69291 341.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5150,13 +9411,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 449.8236 cm
+1 0 0 1 62.69291 341.8236 cm
Q
q
-1 0 0 1 62.69291 449.8236 cm
+1 0 0 1 62.69291 341.8236 cm
Q
q
-1 0 0 1 62.69291 419.8236 cm
+1 0 0 1 62.69291 311.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5176,13 +9437,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 419.8236 cm
+1 0 0 1 62.69291 311.8236 cm
Q
q
-1 0 0 1 62.69291 419.8236 cm
+1 0 0 1 62.69291 311.8236 cm
Q
q
-1 0 0 1 62.69291 389.8236 cm
+1 0 0 1 62.69291 281.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5202,13 +9463,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 389.8236 cm
+1 0 0 1 62.69291 281.8236 cm
Q
q
-1 0 0 1 62.69291 389.8236 cm
+1 0 0 1 62.69291 281.8236 cm
Q
q
-1 0 0 1 62.69291 371.8236 cm
+1 0 0 1 62.69291 263.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5228,13 +9489,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 371.8236 cm
+1 0 0 1 62.69291 263.8236 cm
Q
q
-1 0 0 1 62.69291 371.8236 cm
+1 0 0 1 62.69291 263.8236 cm
Q
q
-1 0 0 1 62.69291 353.8236 cm
+1 0 0 1 62.69291 245.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5254,13 +9515,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 353.8236 cm
+1 0 0 1 62.69291 245.8236 cm
Q
q
-1 0 0 1 62.69291 353.8236 cm
+1 0 0 1 62.69291 245.8236 cm
Q
q
-1 0 0 1 62.69291 335.8236 cm
+1 0 0 1 62.69291 227.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5280,13 +9541,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 335.8236 cm
+1 0 0 1 62.69291 227.8236 cm
Q
q
-1 0 0 1 62.69291 335.8236 cm
+1 0 0 1 62.69291 227.8236 cm
Q
q
-1 0 0 1 62.69291 293.8236 cm
+1 0 0 1 62.69291 185.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5306,19 +9567,19 @@ q
Q
Q
q
-1 0 0 1 62.69291 293.8236 cm
+1 0 0 1 62.69291 185.8236 cm
Q
q
-1 0 0 1 62.69291 293.8236 cm
+1 0 0 1 62.69291 185.8236 cm
Q
q
-1 0 0 1 62.69291 275.8236 cm
+1 0 0 1 62.69291 167.8236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (If you run ) Tj /F4 10 Tf (ishelve.py ) Tj /F1 10 Tf (without arguments you get the following message:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 230.6236 cm
+1 0 0 1 62.69291 122.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5339,13 +9600,30 @@ Q
Q
Q
q
-1 0 0 1 62.69291 210.6236 cm
+1 0 0 1 62.69291 102.6236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (If you run ) Tj /F4 10 Tf (ishelve.py ) Tj /F1 10 Tf (with the option ) Tj /F4 10 Tf (.h ) Tj /F1 10 Tf (\(or any abbreviation of ) Tj /F4 10 Tf (.help) Tj /F1 10 Tf (\) you get:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 141.4236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (15) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R427': class PDFStream
+427 0 obj
+% page stream
+<< /Length 6264 >>
+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
q
q
1 0 0 1 0 0 cm
@@ -5365,31 +9643,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 121.4236 cm
+1 0 0 1 62.69291 683.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (You can check by hand that the tool work:) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (14) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R200': class PDFStream
-200 0 obj
-% page stream
-<< /Length 7204 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 523.8236 cm
+1 0 0 1 62.69291 434.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5410,25 +9671,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 490.8236 cm
+1 0 0 1 62.69291 404.6236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (plac vs argparse) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (plac vs argparse) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 448.8236 cm
+1 0 0 1 62.69291 362.6236 cm
q
BT 1 0 0 1 0 28.82 Tm 1.065988 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is opinionated and by design it does not try to make available all of the features of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (in an) Tj T* 0 Tw .177126 Tw (easy way. In particular you should be aware of the following limitations/differences \(the following assumes) Tj T* 0 Tw (knowledge of ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 442.8236 cm
+1 0 0 1 62.69291 356.6236 cm
Q
q
-1 0 0 1 62.69291 442.8236 cm
+1 0 0 1 62.69291 356.6236 cm
Q
q
-1 0 0 1 62.69291 364.8236 cm
+1 0 0 1 62.69291 278.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5448,13 +9709,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 364.8236 cm
+1 0 0 1 62.69291 278.6236 cm
Q
q
-1 0 0 1 62.69291 364.8236 cm
+1 0 0 1 62.69291 278.6236 cm
Q
q
-1 0 0 1 62.69291 310.8236 cm
+1 0 0 1 62.69291 224.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5474,13 +9735,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 310.8236 cm
+1 0 0 1 62.69291 224.6236 cm
Q
q
-1 0 0 1 62.69291 310.8236 cm
+1 0 0 1 62.69291 224.6236 cm
Q
q
-1 0 0 1 62.69291 244.8236 cm
+1 0 0 1 62.69291 158.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5500,13 +9761,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 244.8236 cm
+1 0 0 1 62.69291 158.6236 cm
Q
q
-1 0 0 1 62.69291 244.8236 cm
+1 0 0 1 62.69291 158.6236 cm
Q
q
-1 0 0 1 62.69291 202.8236 cm
+1 0 0 1 62.69291 116.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5526,13 +9787,30 @@ q
Q
Q
q
-1 0 0 1 62.69291 202.8236 cm
+1 0 0 1 62.69291 116.6236 cm
+Q
+q
+1 0 0 1 62.69291 116.6236 cm
Q
q
-1 0 0 1 62.69291 202.8236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (16) Tj T* -235.3849 0 Td ET
+Q
Q
+
+endstream
+
+endobj
+% 'R428': class PDFStream
+428 0 obj
+% page stream
+<< /Length 7562 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 172.8236 cm
+1 0 0 1 62.69291 735.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5552,13 +9830,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 172.8236 cm
+1 0 0 1 62.69291 735.0236 cm
Q
q
-1 0 0 1 62.69291 172.8236 cm
+1 0 0 1 62.69291 735.0236 cm
Q
q
-1 0 0 1 62.69291 130.8236 cm
+1 0 0 1 62.69291 693.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5578,48 +9856,31 @@ q
Q
Q
q
-1 0 0 1 62.69291 130.8236 cm
+1 0 0 1 62.69291 693.0236 cm
Q
q
-1 0 0 1 62.69291 130.8236 cm
+1 0 0 1 62.69291 693.0236 cm
Q
q
-1 0 0 1 62.69291 112.8236 cm
+1 0 0 1 62.69291 675.0236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (can leverage directly on many ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (features.) Tj T* ET
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (15) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R201': class PDFStream
-201 0 obj
-% page stream
-<< /Length 6860 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 729.0236 cm
+1 0 0 1 62.69291 633.0236 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 1.435976 Tw /F4 10 Tf ('==SUPPRESS==' ) Tj /F1 10 Tf (as help string \(or ) Tj /F4 10 Tf (argparse.SUPPRESS) Tj /F1 10 Tf (\). Similarly, you can use ) Tj 0 0 .501961 rg (argparse.FileType) Tj T* 0 Tw 0 0 0 rg (directly.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 675.0236 cm
+1 0 0 1 62.69291 579.0236 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 605.8236 cm
+1 0 0 1 62.69291 509.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5640,26 +9901,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 561.8236 cm
+1 0 0 1 62.69291 465.8236 cm
q
BT 1 0 0 1 0 28.82 Tm .239318 Tw 12 TL /F1 10 Tf 0 0 0 rg (disables the recognition of the help flag ) Tj /F4 10 Tf (-h, --help) Tj /F1 10 Tf (. This mechanism does not look particularly elegant,) Tj T* 0 Tw .566988 Tw (but it works well enough. I assume that the typical user of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (will be happy with the defaults and would) Tj T* 0 Tw (not want to change them; still it is possible if she wants to.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 531.8236 cm
+1 0 0 1 62.69291 435.8236 cm
q
BT 1 0 0 1 0 16.82 Tm 2.391235 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, by setting the ) Tj /F4 10 Tf (description ) Tj /F1 10 Tf (attribute, it is possible to add a comment to the usage) Tj T* 0 Tw (message \(by default the docstring of the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (function is used as description\).) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 501.8236 cm
+1 0 0 1 62.69291 405.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .392619 Tw (It 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 line:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 468.6236 cm
+1 0 0 1 62.69291 372.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5680,19 +9941,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 424.6236 cm
+1 0 0 1 62.69291 328.6236 cm
q
BT 1 0 0 1 0 28.82 Tm .924198 Tw 12 TL /F1 10 Tf 0 0 0 rg (The first prefix char \() Tj /F4 10 Tf (/) Tj /F1 10 Tf (\) is used as the default for the recognition of options and flags; the second prefix) Tj T* 0 Tw .26832 Tw (char \() Tj /F4 10 Tf (-) Tj /F1 10 Tf (\) is kept to keep the ) Tj /F4 10 Tf (-h/--help ) Tj /F1 10 Tf (option working: however you can disable it and reimplement it, if) Tj T* 0 Tw (you like, as seen in the ) Tj /F4 10 Tf (ishelve ) Tj /F1 10 Tf (example.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 394.6236 cm
+1 0 0 1 62.69291 298.6236 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 301.4236 cm
+1 0 0 1 62.69291 205.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5712,60 +9973,66 @@ Q
Q
Q
q
-1 0 0 1 62.69291 257.4236 cm
+1 0 0 1 62.69291 161.4236 cm
q
BT 1 0 0 1 0 28.82 Tm 2.646905 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (uses ) Tj /F4 10 Tf (plac.parser_from ) Tj /F1 10 Tf (and adds the parser to the main function as an) Tj T* 0 Tw .982126 Tw (attribute. When ) Tj /F4 10 Tf (plac.call\(func\) ) Tj /F1 10 Tf (is invoked multiple time, the parser is re-used and not rebuilt from) Tj T* 0 Tw (scratch again.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 227.4236 cm
+1 0 0 1 62.69291 131.4236 cm
q
BT 1 0 0 1 0 16.82 Tm .982765 Tw 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 not need to use it,) Tj T* 0 Tw (unless they want to access ) Tj /F5 10 Tf (all ) Tj /F1 10 Tf (of the features of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (directly without calling the main function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 173.4236 cm
+1 0 0 1 62.69291 89.42362 cm
q
-BT 1 0 0 1 0 40.82 Tm 1.442126 Tw 12 TL /F1 10 Tf 0 0 0 rg (Interested readers should read the documentation of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (to understand the meaning of the other) Tj T* 0 Tw .771567 Tw (options. If there is a set of options that you use very often, you may consider writing a decorator adding) Tj T* 0 Tw 1.257045 Tw (such options 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 except the) Tj T* 0 Tw (addition of the ) Tj /F4 10 Tf (.p ) Tj /F1 10 Tf (attribute.) Tj T* ET
+BT 1 0 0 1 0 28.82 Tm 1.442126 Tw 12 TL /F1 10 Tf 0 0 0 rg (Interested readers should read the documentation of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (to understand the meaning of the other ) Tj T* 0 Tw .771567 Tw (options. If there is a set of options that you use very often, you may consider writing a decorator adding ) Tj T* 0 Tw 1.257045 Tw (such options 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 except the) Tj T* 0 Tw ET
Q
Q
q
-1 0 0 1 62.69291 140.4236 cm
+1 0 0 1 56.69291 56.69291 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (plac vs the rest of the world) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (17) Tj T* -235.3849 0 Td ET
Q
Q
+
+endstream
+
+endobj
+% 'R429': class PDFStream
+429 0 obj
+% page stream
+<< /Length 8202 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 98.42362 cm
+1 0 0 1 62.69291 753.0236 cm
q
-BT 1 0 0 1 0 28.82 Tm 1.866905 Tw 12 TL /F1 10 Tf 0 0 0 rg (Originally ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (boasted about being "the easiest command-line arguments parser in the world". Since) Tj T* 0 Tw .306457 Tw (then, people started pointing out to me various projects which are based on the same idea \(extracting the) Tj T* 0 Tw (parser from the main function signature\) and are arguably even easier than ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (:) Tj T* ET
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (addition of the ) Tj /F4 10 Tf (.p ) Tj /F1 10 Tf (attribute.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 92.42362 cm
-Q
+1 0 0 1 62.69291 723.0236 cm
q
-1 0 0 1 62.69291 92.42362 cm
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (plac vs the rest of the world) Tj T* ET
+Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 681.0236 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (16) Tj T* -235.3849 0 Td ET
+BT 1 0 0 1 0 28.82 Tm 1.866905 Tw 12 TL /F1 10 Tf 0 0 0 rg (Originally ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (boasted about being "the easiest command-line arguments parser in the world". Since) Tj T* 0 Tw .306457 Tw (then, people started pointing out to me various projects which are based on the same idea \(extracting the) Tj T* 0 Tw (parser from the main function signature\) and are arguably even easier than ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (:) Tj T* ET
Q
Q
-
-endstream
-
-endobj
-% 'R202': class PDFStream
-202 0 obj
-% page stream
-<< /Length 8225 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 747.0236 cm
+1 0 0 1 62.69291 675.0236 cm
+Q
+q
+1 0 0 1 62.69291 675.0236 cm
+Q
+q
+1 0 0 1 62.69291 657.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5785,13 +10052,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 747.0236 cm
+1 0 0 1 62.69291 657.0236 cm
Q
q
-1 0 0 1 62.69291 747.0236 cm
+1 0 0 1 62.69291 657.0236 cm
Q
q
-1 0 0 1 62.69291 729.0236 cm
+1 0 0 1 62.69291 639.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5811,73 +10078,73 @@ q
Q
Q
q
-1 0 0 1 62.69291 729.0236 cm
+1 0 0 1 62.69291 639.0236 cm
Q
q
-1 0 0 1 62.69291 729.0236 cm
+1 0 0 1 62.69291 639.0236 cm
Q
q
-1 0 0 1 62.69291 699.0236 cm
+1 0 0 1 62.69291 609.0236 cm
q
BT 1 0 0 1 0 16.82 Tm 2.136457 Tw 12 TL /F1 10 Tf 0 0 0 rg (Luckily for me none of such projects had the idea of using function annotations and ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (; as a) Tj T* 0 Tw (consequence, they are no match for the capabilities of ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 657.0236 cm
+1 0 0 1 62.69291 567.0236 cm
q
BT 1 0 0 1 0 28.82 Tm 1.551163 Tw 12 TL /F1 10 Tf 0 0 0 rg (Of course, there are tons of other libraries to parse the command line. For instance ) Tj 0 0 .501961 rg (Clap ) Tj 0 0 0 rg (by Matthew) Tj T* 0 Tw 1.211567 Tw (Frazier which appeared on PyPI just the day before ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (; ) Tj 0 0 .501961 rg (Clap ) Tj 0 0 0 rg (is fine but it is certainly not easier than) Tj T* 0 Tw 0 0 .501961 rg (plac) Tj 0 0 0 rg (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 615.0236 cm
+1 0 0 1 62.69291 525.0236 cm
q
BT 1 0 0 1 0 28.82 Tm .622488 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (can also be used as a replacement of the ) Tj 0 0 .501961 rg (cmd ) Tj 0 0 0 rg (module in the standard library and as such it shares) Tj T* 0 Tw .377126 Tw (many features with the module ) Tj 0 0 .501961 rg (cmd2 ) Tj 0 0 0 rg (by Catherine Devlin. However, this is completely coincidental, since) Tj T* 0 Tw (I became aware of the ) Tj 0 0 .501961 rg (cmd2 ) Tj 0 0 0 rg (module only after writing ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 582.0236 cm
+1 0 0 1 62.69291 495.0236 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
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (The future) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 516.0236 cm
+1 0 0 1 62.69291 429.0236 cm
q
BT 1 0 0 1 0 52.82 Tm .135542 Tw 12 TL /F1 10 Tf 0 0 0 rg (Currently the core of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is around 200 lines of code, not counting blanks, comments and docstrings. I do) Tj T* 0 Tw .968626 Tw (not plan to extend the core much in the future. The idea is to keep the module short: it is and it should) Tj T* 0 Tw .11811 Tw (remain a little wrapper over ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (. Actually I have thought about contributing the core back to ) Tj 0 0 .501961 rg (argparse) Tj T* 0 Tw 2.307485 Tw 0 0 0 rg (if ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (becomes successfull and gains a reasonable number of users. For the moment it should be) Tj T* 0 Tw (considered in alpha status.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 474.0236 cm
+1 0 0 1 62.69291 387.0236 cm
q
BT 1 0 0 1 0 28.82 Tm .927488 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that even if ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (has been designed to be simple to use for simple stuff, its power should not be) Tj T* 0 Tw 1.02186 Tw (underestimated; it is actually a quite advanced tool with a domain of applicability which far exceeds the) Tj T* 0 Tw (realm of command-line arguments parsers.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 408.0236 cm
+1 0 0 1 62.69291 321.0236 cm
q
BT 1 0 0 1 0 52.82 Tm .285988 Tw 12 TL /F1 10 Tf 0 0 0 rg (Version 0.5 of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (doubled the code base and the documentation: it is based on the idea of using ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (to) Tj T* 0 Tw .408555 Tw (implement command-line interpreters, i.e. something akin to the ) Tj /F4 10 Tf (cmd ) Tj /F1 10 Tf (module in the standard library, only) Tj T* 0 Tw .49936 Tw (better. The new features of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (are described in the ) Tj 0 0 .501961 rg (advanced usage document ) Tj 0 0 0 rg (. They are implemented) Tj T* 0 Tw .313828 Tw (in a separated module \() Tj /F4 10 Tf (plac_ext.py) Tj /F1 10 Tf (\), since they require Python 2.5 to work, whereas ) Tj /F4 10 Tf (plac_core.py) Tj T* 0 Tw /F1 10 Tf (only requires Python 2.3.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 375.0236 cm
+1 0 0 1 62.69291 291.0236 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Trivia: the story behind the name) Tj T* ET
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Trivia: the story behind the name) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 309.0236 cm
+1 0 0 1 62.69291 225.0236 cm
q
BT 1 0 0 1 0 52.82 Tm .979984 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 humbly: 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
-1 0 0 1 62.69291 303.0236 cm
+1 0 0 1 62.69291 219.0236 cm
Q
q
-1 0 0 1 62.69291 303.0236 cm
+1 0 0 1 62.69291 219.0236 cm
Q
q
-1 0 0 1 62.69291 273.0236 cm
+1 0 0 1 62.69291 189.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5897,13 +10164,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 273.0236 cm
+1 0 0 1 62.69291 189.0236 cm
Q
q
-1 0 0 1 62.69291 273.0236 cm
+1 0 0 1 62.69291 189.0236 cm
Q
q
-1 0 0 1 62.69291 243.0236 cm
+1 0 0 1 62.69291 159.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -5924,189 +10191,4487 @@ q
Q
Q
q
-1 0 0 1 62.69291 243.0236 cm
+1 0 0 1 62.69291 159.0236 cm
Q
q
-1 0 0 1 62.69291 243.0236 cm
+1 0 0 1 62.69291 159.0236 cm
Q
q
-1 0 0 1 62.69291 189.0236 cm
+1 0 0 1 62.69291 105.0236 cm
q
BT 1 0 0 1 0 40.82 Tm .600574 Tw 12 TL /F1 10 Tf 0 0 0 rg (Putting together these two observations with the original idea of inferring the parser I decided to build an) Tj T* 0 Tw .516905 Tw 0 0 .501961 rg (ArgumentParser ) Tj 0 0 0 rg (object from function annotations. The ) Tj /F4 10 Tf (optionparser ) Tj /F1 10 Tf (name was ruled out, since I was) Tj T* 0 Tw 2.085984 Tw (now using ) Tj 0 0 .501961 rg (argparse) Tj 0 0 0 rg (; a name like ) Tj /F4 10 Tf (argparse_plus ) Tj /F1 10 Tf (was also ruled out, since the typical usage was) Tj T* 0 Tw (completely different from the ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (usage.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 159.0236 cm
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (18) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R430': class PDFStream
+430 0 obj
+% page stream
+<< /Length 4313 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 741.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 ) Tj /F5 10 Tf (clap ) Tj /F1 10 Tf (\(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 (!) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 129.0236 cm
+1 0 0 1 62.69291 711.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .877209 Tw (Having little imagination, I decided to rename everything again to plac, 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
q
-1 0 0 1 62.69291 111.0236 cm
+1 0 0 1 62.69291 693.0236 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (That's all, I hope you will enjoy working with ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (!) Tj T* ET
Q
Q
q
+1 0 0 1 62.69291 660.0236 cm
+q
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Advanced usages of plac) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 648.0236 cm
+Q
+q
+1 0 0 1 62.69291 633.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 36.93937 0 Td (Author:) Tj T* -36.93937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Michele Simionato) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 618.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 39.69937 0 Td (E-mail:) Tj T* -39.69937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (michele.simionato@gmail.com) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 603.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 48.03937 0 Td (Date:) Tj T* -48.03937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (August 2010) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 576.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F2 10 Tf 12 TL 25.25937 0 Td (Download) Tj T* 21.11 0 Td (page:) Tj T* -46.36937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 15 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/plac) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 561.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 9.68937 0 Td (Project page:) Tj T* -9.68937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (http://micheles.googlecode.com/hg/plac/doc/plac.html) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 546.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 16.91937 0 Td (Installation:) Tj T* -16.91937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (easy_install -U plac) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 531.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 32.46937 0 Td (License:) Tj T* -32.46937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (BSD license) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 516.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 26.91937 0 Td (Requires:) Tj T* -26.91937 0 Td ET
+Q
+Q
+q
+1 0 0 1 91.03937 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Python 2.5+) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 474.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 28.82 Tm /F5 10 Tf 12 TL 2.399986 Tw (The present document discusses a few of the advanced use cases for plac. It shows how to write) Tj T* 0 Tw 2.164651 Tw (interactive and non-interactive interpreters with plac, and how to use plac for testing and scripting a) Tj T* 0 Tw (generic application. It assumes you have already read an understood the basic documentation.) Tj T* ET
+Q
+Q
+q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (17) Tj T* -235.3849 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (19) Tj T* -235.3849 0 Td ET
Q
Q
endstream
endobj
-% 'R203': class PDFPageLabels
-203 0 obj
+% 'R431': class PDFStream
+431 0 obj
+% page stream
+<< /Length 9595 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 744.0236 cm
+q
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Contents) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 108.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 0 615 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Plac: Parsing the Command Line the Easy Way) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 615 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 597 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The importance of scaling down) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 597 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 579 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with required arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 579 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 561 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with default arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 561 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (5) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 543 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with options \(and smart options\)) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 543 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (7) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 525 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Scripts with flags) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 525 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 507 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac for Python 2.X users) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 507 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 489 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (More features) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 489 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (10) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 471 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (A realistic example) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 471 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (12) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 453 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Keyword arguments) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 453 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (13) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 435 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Final example: a shelve interface) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 435 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (14) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 417 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac vs argparse) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 417 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (16) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 399 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac vs the rest of the world) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 399 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 381 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The future) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 381 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 363 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Trivia: the story behind the name) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 363 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 345 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Advanced usages of plac) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 345 cm
+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 (19) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 327 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Introduction) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 327 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (21) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 309 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (From scripts to interactive applications) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 309 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (21) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 291 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Testing a plac application) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 291 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (23) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 273 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Plac easy tests) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 273 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (24) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 255 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Plac batch scripts) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 255 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (25) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 237 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Implementing subcommands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 237 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (26) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 219 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (plac.Interpreter.call) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 219 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (28) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 201 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Readline support) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 201 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (30) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 183 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The plac runner) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 183 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (31) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 165 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (A non class-based example) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 165 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (33) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 147 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Writing your own plac runner) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 147 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (35) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 129 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Long running commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 129 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (36) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 111 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Threaded commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 111 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (37) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 93 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Running commands as external processes) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 93 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (39) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 75 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Managing the output of concurrent commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 75 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (40) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 57 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Parallel computing with plac) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 57 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (41) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 39 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (The plac server) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 39 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (43) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 21 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Summary) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 21 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (43) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+1 0 0 1 0 3 cm
+q
+BT 1 0 0 1 20 4.82 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (Appendix: custom annotation objects) Tj T* ET
+Q
+Q
+q
+1 0 0 1 397.8898 3 cm
+q
+0 0 .501961 rg
+0 0 .501961 RG
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 60.88 0 Td (44) Tj T* -60.88 0 Td ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (20) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R432': class PDFStream
+432 0 obj
+% page stream
+<< /Length 5414 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 747.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Introduction) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 705.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .539036 Tw 12 TL /F1 10 Tf 0 0 0 rg (One of the design goals of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is to make it dead easy to write a scriptable and testable interface for an) Tj T* 0 Tw .813876 Tw (application. You can use ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (whenever you have an API with strings in input and strings in output, and) Tj T* 0 Tw (that includes a ) Tj /F5 10 Tf (huge ) Tj /F1 10 Tf (domain of applications.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 663.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.756651 Tw 12 TL /F1 10 Tf 0 0 0 rg (A string-oriented interface is a scriptable interface by construction. That means that you can define a) Tj T* 0 Tw .918735 Tw (command language for your application and that it is possible to write scripts which are interpretable by) Tj T* 0 Tw 0 0 .501961 rg (plac ) Tj 0 0 0 rg (and can be run as batch scripts.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 621.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .444987 Tw 12 TL /F1 10 Tf 0 0 0 rg (Actually, at the most general level, you can see ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (as a generic tool to write domain specific languages) Tj T* 0 Tw .107209 Tw (\(DSL\). With ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (you can test your application interactively as well as with batch scripts, and even with the) Tj T* 0 Tw (analogous of Python doctests for your defined language.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 555.0236 cm
+q
+BT 1 0 0 1 0 52.82 Tm .694104 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can easily replace the ) Tj /F4 10 Tf (cmd ) Tj /F1 10 Tf (module of the standard library and you could easily write an application) Tj T* 0 Tw 2.271751 Tw (like ) Tj 0 0 .501961 rg (twill ) Tj 0 0 0 rg (with ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (. Or you could use it to script your building procedure. ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (also supports parallel) Tj T* 0 Tw .907765 Tw (execution of multiple commands and can be used as task manager and monitor. It is also quite easy to) Tj T* 0 Tw 1.483488 Tw (build a GUI or a Web application on top of ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (. When speaking of things you can do with ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (, your) Tj T* 0 Tw (imagination is the only limit!) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 525.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (From scripts to interactive applications) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 471.0236 cm
+q
+BT 1 0 0 1 0 40.82 Tm 1.300751 Tw 12 TL /F1 10 Tf 0 0 0 rg (Command-line scripts have many advantages, but they are no substitute for interactive applications. In) Tj T* 0 Tw .088171 Tw (particular, if you have a script with a large startup time which must be run multiple times, it is best to turn it) Tj T* 0 Tw 4.582126 Tw (into an interactive application, so that the startup is performed only once. ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (provides an) Tj T* 0 Tw /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (class just for this purpose.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 441.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.293984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (class wraps the main function of a script and provides an ) Tj /F4 10 Tf (.interact ) Tj /F1 10 Tf (method to) Tj T* 0 Tw (start an interactive interpreter reading commands from the console.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 411.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.49436 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, you can define an interactive interpreter on top of the ) Tj /F4 10 Tf (ishelve ) Tj /F1 10 Tf (script introduced in the) Tj T* 0 Tw 0 0 .501961 rg (basic documentation ) Tj 0 0 0 rg (as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 161.8236 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 240 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 221.71 Tm /F4 10 Tf 12 TL (# shelve_interpreter.py) Tj T* (import plac, ishelve) Tj T* T* (@plac.annotations\() Tj T* ( interactive=\('start interactive interface', 'flag'\),) Tj T* ( subcommands='the commands of the underlying ishelve interpreter'\)) Tj T* (def main\(interactive, *subcommands\):) Tj T* ( """) Tj T* ( This script works both interactively and non-interactively.) Tj T* ( Use .help to see the internal commands.) Tj T* ( """) Tj T* ( if interactive:) Tj T* ( plac.Interpreter\(ishelve.main\).interact\(\)) Tj T* ( else:) Tj T* ( for out in plac.call\(ishelve.main, subcommands\):) Tj T* ( print\(out\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.call\(main\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 117.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 2.200651 Tw 12 TL /F1 10 Tf 0 0 0 rg (A trick has been used here: the ishelve command-line interface has been hidden inside an external) Tj T* 0 Tw .917674 Tw (interface. They are distinct: for instance the external interface recognizes the ) Tj /F4 10 Tf (-h/--help ) Tj /F1 10 Tf (flag whereas) Tj T* 0 Tw (the internal interface only recognizes the ) Tj /F4 10 Tf (.help ) Tj /F1 10 Tf (command:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (21) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R433': class PDFStream
+433 0 obj
+% page stream
+<< /Length 4068 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 739.8236 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 24 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL ($ python shelve_interpreter.py -h) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 562.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 168 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 149.71 Tm /F4 10 Tf 12 TL (usage: shelve_interpreter.py [-h] [-interactive]) Tj T* ( [subcommands [subcommands ...]]) Tj T* T* ( This script works both interactively and non-interactively.) Tj T* ( Use .help to see the internal commands.) Tj T* ( ) Tj T* T* (positional arguments:) Tj T* ( subcommands the commands of the underlying ishelve interpreter) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -interactive start interactive interface) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 542.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Thanks to this ingenuous trick, the script can be run both interactively and non-interactively:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 497.4236 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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL ($ python shelve_interpreter.py .clear # non-interactive use) Tj T* (cleared the shelve) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 477.4236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is an usage session:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 192.2236 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 276 re B*
+Q
+q
+BT 1 0 0 1 0 257.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python shelve_interpreter.py -i # interactive use) Tj T* (A simple interface to a shelve. Use .help to see the available commands.) Tj T* (i) Tj (>) Tj ( .help) Tj T* (Commands: .help, .showall, .clear, .delete) Tj T* (<) Tj (param) Tj (>) Tj ( ...) Tj T* (<) Tj (param=value) Tj (>) Tj ( ...) Tj T* (i) Tj (>) Tj ( a=1) Tj T* (setting a=1) Tj T* (i) Tj (>) Tj ( a) Tj T* (1) Tj T* (i) Tj (>) Tj ( b=2) Tj T* (setting b=2) Tj T* (i) Tj (>) Tj ( a b) Tj T* (1) Tj T* (2) Tj T* (i) Tj (>) Tj ( .del a) Tj T* (deleted a) Tj T* (i) Tj (>) Tj ( a) Tj T* (a: not found) Tj T* (i) Tj (>) Tj ( .show) Tj T* (b=2) Tj T* (i) Tj (>) Tj ( [CTRL-D]) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 124.2236 cm
+q
+BT 1 0 0 1 0 52.82 Tm .256412 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (.interact ) Tj /F1 10 Tf (method reads commands from the console and send them to the underlying interpreter,) Tj T* 0 Tw .065984 Tw (until the user send a CTRL-D command \(CTRL-Z in Windows\). There is a default argument ) Tj /F4 10 Tf (prompt='i) Tj (>) Tj T* 0 Tw .41832 Tw (' ) Tj /F1 10 Tf (which can be used to change the prompt. The text displayed at the beginning of the interactive session) Tj T* 0 Tw 1.407126 Tw (is the docstring of the main function. ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (also understands command abbreviations: in this example) Tj T* 0 Tw /F4 10 Tf (del ) Tj /F1 10 Tf (is an abbreviation for ) Tj /F4 10 Tf (delete) Tj /F1 10 Tf (. In case of ambiguous abbreviations ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (raises a ) Tj /F4 10 Tf (NameError) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 94.22362 cm
+q
+BT 1 0 0 1 0 16.82 Tm .847045 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally I must notice that the ) Tj /F4 10 Tf (plac.Interpreter ) Tj /F1 10 Tf (is available only if you are using a recent version of) Tj T* 0 Tw (Python \() Tj (>) Tj (= 2.5\), because it is a context manager object which uses extended generators internally.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (22) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R434': class PDFStream
+434 0 obj
+% page stream
+<< /Length 5808 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 747.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Testing a plac application) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 717.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 3.034269 Tw (You can conveniently test your application in interactive mode. However manual testing is a poor) Tj T* 0 Tw (substitute for automatic testing.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 699.0236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (In principle, one could write automatic tests for the ) Tj /F4 10 Tf (ishelve ) Tj /F1 10 Tf (application by using ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (directly:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 533.8236 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 156 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 137.71 Tm /F4 10 Tf 12 TL (# test_ishelve.py) Tj T* (import plac, ishelve) Tj T* T* (def test\(\):) Tj T* ( assert plac.call\(ishelve.main, ['.clear']\) == ['cleared the shelve']) Tj T* ( assert plac.call\(ishelve.main, ['a=1']\) == ['setting a=1']) Tj T* ( assert plac.call\(ishelve.main, ['a']\) == ['1']) Tj T* ( assert plac.call\(ishelve.main, ['.delete=a']\) == ['deleted a']) Tj T* ( assert plac.call\(ishelve.main, ['a']\) == ['a: not found']) Tj T* T* (if __name__ == '__main__':) Tj T* ( test\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 489.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .390651 Tw 12 TL /F1 10 Tf 0 0 0 rg (However, using ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (is not especially nice. The big issue is that ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (responds to invalid) Tj T* 0 Tw 1.249987 Tw (input by printing an error message on stderr and by raising a ) Tj /F4 10 Tf (SystemExit) Tj /F1 10 Tf (: this is certainly not a nice) Tj T* 0 Tw (thing to do in a test.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 447.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.616457 Tw 12 TL /F1 10 Tf 0 0 0 rg (As a consequence of this behavior it is impossible to test for invalid commands, unless you wrap the) Tj T* 0 Tw .259985 Tw /F4 10 Tf (SystemExit ) Tj /F1 10 Tf (exception by hand each time \(a possibly you do something with the error message in stderr) Tj T* 0 Tw (too\). Luckily, ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (offers a better testing support through the ) Tj /F4 10 Tf (check ) Tj /F1 10 Tf (method of ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (objects:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 294.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 144 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 125.71 Tm /F4 10 Tf 12 TL (# test_ishelve_more.py) Tj T* (from __future__ import with_statement) Tj T* (import plac, ishelve) Tj T* T* (def test\(\):) Tj T* ( with plac.Interpreter\(ishelve.main\) as i:) Tj T* ( i.check\('.clear', 'cleared the shelve'\)) Tj T* ( i.check\('a=1', 'setting a=1'\)) Tj T* ( i.check\('a', '1'\)) Tj T* ( i.check\('.delete=a', 'deleted a'\)) Tj T* ( i.check\('a', 'a: not found'\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 238.6236 cm
+q
+BT 1 0 0 1 0 40.82 Tm 6.299974 Tw 12 TL /F1 10 Tf 0 0 0 rg (The method ) Tj /F4 10 Tf (.check\(given_input, expected_output\) ) Tj /F1 10 Tf (works on strings and raises an) Tj T* 0 Tw .971318 Tw /F4 10 Tf (AssertionError ) Tj /F1 10 Tf (if the output produced by the interpreter is different from the expected output for the) Tj T* 0 Tw 2.186905 Tw (given input. Notice that ) Tj /F4 10 Tf (AssertionError ) Tj /F1 10 Tf (is catched by tools like ) Tj /F4 10 Tf (py.test ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (nosetests ) Tj /F1 10 Tf (and) Tj T* 0 Tw (actually ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (tests are intended to be run with such tools.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 184.6236 cm
+q
+BT 1 0 0 1 0 40.82 Tm .239984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Interpreters offer a minor syntactic advantage with respect to calling ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (directly, but they offer a) Tj T* 0 Tw .96748 Tw /F5 10 Tf (major ) Tj /F1 10 Tf (semantic advantage when things go wrong \(read exceptions\): an ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (object internally) Tj T* 0 Tw 1.181318 Tw (invokes something like ) Tj /F4 10 Tf (plac.call) Tj /F1 10 Tf (, but it wraps all exceptions, so that ) Tj /F4 10 Tf (i.check ) Tj /F1 10 Tf (is guaranteed not to) Tj T* 0 Tw (raise any exception except ) Tj /F4 10 Tf (AssertionError) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 166.6236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Even the ) Tj /F4 10 Tf (SystemExit ) Tj /F1 10 Tf (exception is captured and you can write your test as) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 160.6236 cm
+Q
+q
+1 0 0 1 62.69291 148.6236 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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (i.check\('-cler', 'SystemExit: unrecognized arguments: -cler'\)) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 148.6236 cm
+Q
+q
+1 0 0 1 62.69291 130.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (without risk of exiting from the Python interpreter.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 100.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.422651 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is a second advantage of interpreters: if the main function contains some initialization code and ) Tj T* 0 Tw .454651 Tw (finalization code \() Tj /F4 10 Tf (__enter__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (functions\) they will be run only once at the beginning and) Tj T* 0 Tw ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (23) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R435': class PDFStream
+435 0 obj
+% page stream
+<< /Length 5996 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 753.0236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (at the end of the interpreter loop. ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (instead ignores the initialization/finalization code.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 723.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Plac easy tests) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 681.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.517126 Tw 12 TL /F1 10 Tf 0 0 0 rg (Writing your tests in terms of ) Tj /F4 10 Tf (Interpreter.check ) Tj /F1 10 Tf (is certainly an improvement over writing them in) Tj T* 0 Tw 1.807318 Tw (terms of ) Tj /F4 10 Tf (plac.call) Tj /F1 10 Tf (, but they are still too low-level for my taste. The ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (class provides) Tj T* 0 Tw (support for doctest-style tests, a.k.a. ) Tj /F5 10 Tf (plac easy tests) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 639.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 2.142209 Tw 12 TL /F1 10 Tf 0 0 0 rg (By using plac easy tests you can cut and paste your interactive session and turn it into a runnable) Tj T* 0 Tw .519213 Tw (automatics test. Consider for instance the following file ) Tj /F4 10 Tf (ishelve.placet ) Tj /F1 10 Tf (\(the ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (extension is a) Tj T* 0 Tw (mnemonic for plac easy tests\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 461.8236 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 168 re B*
+Q
+q
+BT 1 0 0 1 0 149.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (#!ishelve.py) Tj T* (i) Tj (>) Tj ( .clear # start from a clean state) Tj T* (cleared the shelve) Tj T* (i) Tj (>) Tj ( a=1) Tj T* (setting a=1) Tj T* (i) Tj (>) Tj ( a) Tj T* (1) Tj T* (i) Tj (>) Tj ( .del a) Tj T* (deleted a) Tj T* (i) Tj (>) Tj ( a) Tj T* (a: not found) Tj T* (i) Tj (>) Tj ( .cler # spelling error) Tj T* (.cler: not found) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 405.8236 cm
+q
+BT 1 0 0 1 0 40.82 Tm .697132 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice the precence of the shebang line containing the name of the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (tool to test \(a ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (tool is just a) Tj T* 0 Tw 1.511751 Tw (Python module with a function called ) Tj /F4 10 Tf (main) Tj /F1 10 Tf (\). The shebang is ignored by the interpreter \(it looks like a) Tj T* 0 Tw .487608 Tw (comment to it\) but it is there so that external tools \(say a test runner\) can infer the plac interpreter to use) Tj T* 0 Tw (to test the file.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 375.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.419984 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can test ) Tj /F4 10 Tf (ishelve.placet ) Tj /F1 10 Tf (file by calling the ) Tj /F4 10 Tf (.doctest ) Tj /F1 10 Tf (method of the interpreter, as in this) Tj T* 0 Tw (example:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 331.0393 cm
+q
+q
+.988825 0 0 .988825 0 0 cm
+q
+1 0 0 1 6.6 6.674587 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 474 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL ($ python -c"import plac, ishelve) Tj T* (plac.Interpreter\(ishelve.main\).doctest\(open\('ishelve.placet'\), verbose=True\)") Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 287.0393 cm
+q
+BT 1 0 0 1 0 28.82 Tm 4.007109 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (Interpreter.doctests ) Tj /F1 10 Tf (invokes something like ) Tj /F4 10 Tf (Interpreter.check ) Tj /F1 10 Tf (multiple times) Tj T* 0 Tw .226654 Tw (inside the same context and compare the output with the expected output: if even a check fails, the whole) Tj T* 0 Tw (test fail.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 245.0393 cm
+q
+BT 1 0 0 1 0 28.82 Tm .175868 Tw 12 TL /F1 10 Tf 0 0 0 rg (You should realize tha the easy tests supported by ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (are ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (unittests: they are functional tests. They) Tj T* 0 Tw 1.22936 Tw (model then user interaction and the order of the operations generally matters. The single subtests in a) Tj T* 0 Tw /F4 10 Tf (.placet ) Tj /F1 10 Tf (file are not independent and it makes sense to exit immediately at the first failure.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 167.0393 cm
+q
+BT 1 0 0 1 0 64.82 Tm .414431 Tw 12 TL /F1 10 Tf 0 0 0 rg (The support for doctests in ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (comes nearly for free, thanks to the ) Tj 0 0 .501961 rg (shlex ) Tj 0 0 0 rg (module in the standard library,) Tj T* 0 Tw .352765 Tw (which is able to parse simple languages as the ones you can implement with ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (. In particular, thanks to) Tj T* 0 Tw .875984 Tw 0 0 .501961 rg (shlex) Tj 0 0 0 rg (, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to recognize comments \(the default comment character is ) Tj /F4 10 Tf (#) Tj /F1 10 Tf (\), escape sequences and) Tj T* 0 Tw 1.50686 Tw (more. Look at the ) Tj 0 0 .501961 rg (shlex ) Tj 0 0 0 rg (documentation if you need to customize how the language is interpreted. For) Tj T* 0 Tw 2.794985 Tw (more flexibility, it is even possible to pass to the interpreter a custom split function with signature) Tj T* 0 Tw /F4 10 Tf (split\(line, commentchar\)) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 113.0393 cm
+q
+BT 1 0 0 1 0 40.82 Tm .136654 Tw 12 TL /F1 10 Tf 0 0 0 rg (In addition, I have implemented from scratch some support for line number recognition, so that if a test fail) Tj T* 0 Tw .042093 Tw (you get the line number of the failing command. This is especially useful if your tests are stored in external) Tj T* 0 Tw .610898 Tw (files, even if plac easy tests does not need to be in a file: you can just pass to the ) Tj /F4 10 Tf (.doctest ) Tj /F1 10 Tf (method a) Tj T* 0 Tw (list of strings corresponding to the lines of the file.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (24) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R436': class PDFStream
+436 0 obj
+% page stream
+<< /Length 5577 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 741.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .653145 Tw 12 TL /F1 10 Tf 0 0 0 rg (At the present ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (does not use any code from the doctest module, but the situation may change in the) Tj T* 0 Tw (future \(it would be nice if ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (could reuse doctests directives like ELLIPSIS\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 711.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.447318 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is straighforward to integrate your ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (tests with standard testing tools. For instance, you can) Tj T* 0 Tw (integrate your doctests with ) Tj /F4 10 Tf (nose ) Tj /F1 10 Tf (or ) Tj /F4 10 Tf (py.test ) Tj /F1 10 Tf (as follow:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 523.8485 cm
+q
+q
+.988825 0 0 .988825 0 0 cm
+q
+1 0 0 1 6.6 6.674587 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 474 180 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 161.71 Tm /F4 10 Tf 12 TL (import os, shlex, plac) Tj T* T* (def test_doct\(\):) Tj T* ( """) Tj T* ( Find all the doctests in the current directory and run them with the) Tj T* ( corresponding plac interpreter \(the shebang rules!\)) Tj T* ( """) Tj T* ( placets = [f for f in os.listdir\('.'\) if f.endswith\('.placet'\)]) Tj T* ( for placet in placets:) Tj T* ( lines = list\(open\(placet\)\)) Tj T* ( assert lines[0].startswith\('#!'\), 'Missing or incorrect shebang line!') Tj T* ( firstline = lines[0][2:] # strip the shebang) Tj T* ( main = plac.import_main\(*shlex.split\(firstline\)\)) Tj T* ( yield plac.Interpreter\(main\).doctest, lines[1:]) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 443.8485 cm
+q
+BT 1 0 0 1 0 64.82 Tm 1.44811 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here you should notice that usage of ) Tj /F4 10 Tf (plac.import_main) Tj /F1 10 Tf (, an utility which is able to import the main) Tj T* 0 Tw .775703 Tw (function of the script specified in the shebang line. You can use both the full path name of the tool, or a) Tj T* 0 Tw .87686 Tw (relative path name. In this case the runner look at the environment variable ) Tj /F4 10 Tf (PLACPATH ) Tj /F1 10 Tf (and it searches) Tj T* 0 Tw 1.900651 Tw (the plac tool in the directories specified there \() Tj /F4 10 Tf (PLACPATH ) Tj /F1 10 Tf (is just a string containing directory names) Tj T* 0 Tw .56332 Tw (separated by colons\). If the variable ) Tj /F4 10 Tf (PLACPATH ) Tj /F1 10 Tf (is not defined, it just looks in the current directory. If the) Tj T* 0 Tw (plac tool is not found, an ) Tj /F4 10 Tf (ImportError ) Tj /F1 10 Tf (is raised.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 413.8485 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Plac batch scripts) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 371.8485 cm
+q
+BT 1 0 0 1 0 28.82 Tm .772093 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is pretty easy to realize that an interactive interpreter can also be used to run batch scripts: instead of) Tj T* 0 Tw .504692 Tw (reading the commands from the console, it is enough to read the commands from a file. ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (interpreters) Tj T* 0 Tw (provide an ) Tj /F4 10 Tf (.execute ) Tj /F1 10 Tf (method to perform just that.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 305.8485 cm
+q
+BT 1 0 0 1 0 52.82 Tm .098935 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is just a subtle point to notice: whereas in an interactive loop one wants to manage all exceptions, a) Tj T* 0 Tw 3.866412 Tw (batch script should not in the background in case of unexpected errors. The implementation of) Tj T* 0 Tw .103059 Tw /F4 10 Tf (Interpreter.execute ) Tj /F1 10 Tf (makes sure that any error raised by ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (internally is re-raised. In other) Tj T* 0 Tw .407045 Tw (words, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (interpreters ) Tj /F5 10 Tf (wrap the errors, but does not eat them) Tj /F1 10 Tf (: the errors are always accessible and can) Tj T* 0 Tw (be re-raised on demand.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 275.8485 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.239318 Tw 12 TL /F1 10 Tf 0 0 0 rg (The exception is the case of invalid commands, which are skipped. Consider for instance the following) Tj T* 0 Tw (batch file, which contains a mispelled command \() Tj /F4 10 Tf (.dl ) Tj /F1 10 Tf (instead of ) Tj /F4 10 Tf (.del) Tj /F1 10 Tf (\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 170.6485 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 96 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL (#!ishelve.py) Tj T* (.clear ) Tj T* (a=1 b=2) Tj T* (.show) Tj T* (.del a) Tj T* (.dl b) Tj T* (.show) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 138.6485 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.939461 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you execute the batch file, the interpreter will print a ) Tj /F4 10 Tf (.dl: not found ) Tj /F1 10 Tf (at the ) Tj /F4 10 Tf (.dl ) Tj /F1 10 Tf (line and will) Tj T* 0 Tw (continue:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 93.44848 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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python -c "import plac, ishelve) Tj T* (plac.Interpreter\(ishelve.main\).execute\(open\('ishelve.plac'\), verbose=True\)") Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (25) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R437': class PDFStream
+437 0 obj
+% page stream
+<< /Length 4296 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 571.8236 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 192 re B*
+Q
+q
+BT 1 0 0 1 0 173.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .clear) Tj T* (cleared the shelve) Tj T* (i) Tj (>) Tj ( a=1 b=2) Tj T* (setting a=1) Tj T* (setting b=2) Tj T* (i) Tj (>) Tj ( .show) Tj T* (b=2) Tj T* (a=1) Tj T* (i) Tj (>) Tj ( .del a) Tj T* (deleted a) Tj T* (i) Tj (>) Tj ( .dl b) Tj T* (2) Tj T* (.dl: not found) Tj T* (i) Tj (>) Tj ( .show) Tj T* (b=2) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 527.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .159988 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (verbose ) Tj /F1 10 Tf (flag is there to show the lines which are being interpreted \(prefixed by ) Tj /F4 10 Tf (i) Tj (>) Tj /F1 10 Tf (\). This is done on) Tj T* 0 Tw 1.359988 Tw (purpose, so that you can cut and paste the output of the batch script and turn it into a ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (test) Tj T* 0 Tw (\(cool, isn't it?\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 497.8236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Implementing subcommands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 455.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.182485 Tw 12 TL /F1 10 Tf 0 0 0 rg (When I discussed the ) Tj /F4 10 Tf (ishelve ) Tj /F1 10 Tf (implementation in the ) Tj 0 0 .501961 rg (basic documentation) Tj 0 0 0 rg (, I said that it looked like a) Tj T* 0 Tw .116655 Tw (poor man implementation of an object system as a chain of elifs; I also said that ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (was able to do much) Tj T* 0 Tw (better than that. Here I will substantiate my claim.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 413.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .89104 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is actually able to infer a set of subparsers from a generic container of commands. This is useful if) Tj T* 0 Tw 3.125814 Tw (you want to implement ) Tj /F5 10 Tf (subcommands ) Tj /F1 10 Tf (\(a familiar example of a command-line application featuring) Tj T* 0 Tw (subcommands is subversion\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 347.8236 cm
+q
+BT 1 0 0 1 0 52.82 Tm .015868 Tw 12 TL /F1 10 Tf 0 0 0 rg (Technically a container of commands is any object with a ) Tj /F4 10 Tf (.commands ) Tj /F1 10 Tf (attribute listing a set of functions or) Tj T* 0 Tw 2.550888 Tw (methods which are valid commands. A command container may have initialization/finalization hooks) Tj T* 0 Tw 2.55664 Tw (\() Tj /F4 10 Tf (__enter__/__exit__) Tj /F1 10 Tf (\) and dispatch hooks \() Tj /F4 10 Tf (__missing__) Tj /F1 10 Tf (, invoked for invalid command names\).) Tj T* 0 Tw 2.113828 Tw (Moreover, only when using command containers ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is able to provide automatic autocompletion of) Tj T* 0 Tw (commands.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 329.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (The shelve interface can be rewritten in an object-oriented way as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 92.62362 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 228 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 209.71 Tm /F4 10 Tf 12 TL (# ishelve2.py) Tj T* (import shelve, os, sys, plac) Tj T* T* (class ShelveInterface\(object\):) Tj T* ( "A minimal interface over a shelve object.") Tj T* ( commands = 'set', 'show', 'showall', 'delete') Tj T* ( @plac.annotations\() Tj T* ( configfile=\('path name of the shelve', 'option'\)\)) Tj T* ( def __init__\(self, configfile\):) Tj T* ( self.configfile = configfile or '~/conf.shelve') Tj T* ( self.fname = os.path.expanduser\(self.configfile\)) Tj T* ( self.__doc__ += '\\nOperating on %s.\\n.help to see '\\) Tj T* ( 'the available commands.\\n' % self.fname) Tj T* ( def __enter__\(self\):) Tj T* ( self.sh = shelve.open\(self.fname\)) Tj T* ( return self) Tj T* ( def __exit__\(self, etype, exc, tb\):) Tj T* ( self.sh.close\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (26) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R438': class PDFStream
+438 0 obj
+% page stream
+<< /Length 4325 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 451.8236 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 312 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 293.71 Tm /F4 10 Tf 12 TL ( def set\(self, name, value\):) Tj T* ( "set name value") Tj T* ( yield 'setting %s=%s' % \(name, value\)) Tj T* ( self.sh[name] = value) Tj T* ( def show\(self, *names\):) Tj T* ( "show given parameters") Tj T* ( for name in names:) Tj T* ( yield '%s = %s' % \(name, self.sh[name]\) # no error checking) Tj T* ( def showall\(self\):) Tj T* ( "show all parameters") Tj T* ( for name in self.sh:) Tj T* ( yield '%s = %s' % \(name, self.sh[name]\)) Tj T* ( def delete\(self, name=None\):) Tj T* ( "delete given parameter \(or everything\)") Tj T* ( if name is None:) Tj T* ( yield 'deleting everything') Tj T* ( self.sh.clear\(\)) Tj T* ( else:) Tj T* ( yield 'deleting %s' % name) Tj T* ( del self.sh[name] # no error checking) Tj T* T* (main = ShelveInterface # useful for the tests) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.Interpreter\(plac.call\(ShelveInterface\)\).interact\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 359.8236 cm
+q
+BT 1 0 0 1 0 76.82 Tm .885366 Tw 12 TL /F4 10 Tf 0 0 0 rg (plac.Interpreter ) Tj /F1 10 Tf (objects wrap context manager objects consistently. In other words, if you wrap an) Tj T* 0 Tw 2.323828 Tw (object with ) Tj /F4 10 Tf (__enter__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (methods, they are invoked in the right order \() Tj /F4 10 Tf (__enter__) Tj T* 0 Tw .23528 Tw /F1 10 Tf (before the interpreter loop starts and ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (after the interpreter loop ends, both in the regular and in) Tj T* 0 Tw 1.916412 Tw (the exceptional case\). In our example, the methods ) Tj /F4 10 Tf (__enter__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (make sure the the) Tj T* 0 Tw .339398 Tw (shelve is opened and closed correctly even in the case of exceptions. Notice that I have not implemented) Tj T* 0 Tw .814104 Tw (any error checking in the ) Tj /F4 10 Tf (show ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (delete ) Tj /F1 10 Tf (methods on purpose, to verify that ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (works correctly in) Tj T* 0 Tw (the presence of exceptions.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 281.8236 cm
+q
+BT 1 0 0 1 0 64.82 Tm 1.567126 Tw 12 TL /F1 10 Tf 0 0 0 rg (When working with command containers, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (automatically adds two special commands to the set of) Tj T* 0 Tw 1.176136 Tw (provided commands: ) Tj /F4 10 Tf (.help ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (.last_tb) Tj /F1 10 Tf (. The ) Tj /F4 10 Tf (.help ) Tj /F1 10 Tf (command is the easier to understand: when) Tj T* 0 Tw .39811 Tw (invoked without arguments it displays the list of available commands with the same formatting of the ) Tj 0 0 .501961 rg (cmd) Tj T* 0 Tw 1.19561 Tw 0 0 0 rg (module; when invoked with the name of a command it displays the usage message for that command.) Tj T* 0 Tw 2.33686 Tw (The ) Tj /F4 10 Tf (.last_tb ) Tj /F1 10 Tf (command is useful when debugging: in case of errors, it allows you to display the) Tj T* 0 Tw (traceback of the last executed command.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 263.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is a session of usage on an Unix-like operating system:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 98.62362 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 156 re B*
+Q
+q
+BT 1 0 0 1 0 137.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python ishelve2.py) Tj T* (A minimal interface over a shelve object.) Tj T* (Operating on /home/micheles/conf.shelve.) Tj T* (.help to see the available commands.) Tj T* (i) Tj (>) Tj ( .help) Tj T* T* (special commands) Tj T* (================) Tj T* (.help .last_tb) Tj T* T* (custom commands) Tj T* (===============) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (27) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R439': class PDFStream
+439 0 obj
+% page stream
+<< /Length 4757 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 485.5042 cm
+q
+q
+.773863 0 0 .773863 0 0 cm
+q
+1 0 0 1 6.6 8.528639 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 606 360 re B*
+Q
+q
+BT 1 0 0 1 0 341.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (delete set show showall) Tj T* T* (i) Tj (>) Tj ( delete) Tj T* (deleting everything) Tj T* (i) Tj (>) Tj ( set a pippo) Tj T* (setting a=pippo) Tj T* (i) Tj (>) Tj ( set b lippo) Tj T* (setting b=lippo) Tj T* (i) Tj (>) Tj ( showall) Tj T* (b = lippo) Tj T* (a = pippo) Tj T* (i) Tj (>) Tj ( show a b) Tj T* (a = pippo) Tj T* (b = lippo) Tj T* (i) Tj (>) Tj ( del a) Tj T* (deleting a) Tj T* (i) Tj (>) Tj ( showall) Tj T* (b = lippo) Tj T* (i) Tj (>) Tj ( delete a) Tj T* (deleting a) Tj T* (KeyError: 'a') Tj T* (i) Tj (>) Tj ( .last_tb) Tj T* ( File "/usr/local/lib/python2.6/dist-packages/plac-0.6.0-py2.6.egg/plac_ext.py", line 190, in _wrap) Tj T* ( for value in genobj:) Tj T* ( File "./ishelve2.py", line 37, in delete) Tj T* ( del self.sh[name] # no error checking) Tj T* ( File "/usr/lib/python2.6/shelve.py", line 136, in __delitem__) Tj T* ( del self.dict[key]) Tj T* (i) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 453.5042 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.571235 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that in interactive mode the traceback is hidden, unless you pass the ) Tj /F4 10 Tf (verbose ) Tj /F1 10 Tf (flag to the) Tj T* 0 Tw /F4 10 Tf (Interpreter.interact ) Tj /F1 10 Tf (method.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 423.5042 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (plac.Interpreter.call) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 381.5042 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.066303 Tw 12 TL /F1 10 Tf 0 0 0 rg (At the core of ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (there is the ) Tj /F4 10 Tf (call ) Tj /F1 10 Tf (function which invokes a callable with the list of the arguments) Tj T* 0 Tw .937674 Tw (passed at the command-line \() Tj /F4 10 Tf (sys.argv[1:]) Tj /F1 10 Tf (\). Thanks to ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (you can launch your module by) Tj T* 0 Tw (simply adding the lines:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 336.3042 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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL (if __name__ == '__main__':) Tj T* ( plac.call\(main\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 280.3042 cm
+q
+BT 1 0 0 1 0 40.82 Tm .50436 Tw 12 TL /F1 10 Tf 0 0 0 rg (Everything works fine if ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (is a simple callable performing some action; however, in many cases, one) Tj T* 0 Tw .087633 Tw (has a ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf ("function" which is a actually a factory returning a command container object. For instance, in) Tj T* 0 Tw .573318 Tw (my second shelve example the main function is the class ) Tj /F4 10 Tf (ShelveInterface) Tj /F1 10 Tf (, and the two lines needed) Tj T* 0 Tw (to run the module are a bit ugly:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 235.1042 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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL (if __name__ == '__main__':) Tj T* ( plac.Interpreter\(plac.call\(ShelveInterface\)\).interact\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 131.1042 cm
+q
+BT 1 0 0 1 0 88.82 Tm .435227 Tw 12 TL /F1 10 Tf 0 0 0 rg (Moreover, now the program runs, but only in interactive mode, i.e. it is not possible to run it as a script. It) Tj T* 0 Tw .721098 Tw (would be nice instead to be able to specify the command to execute on the command-line and have the) Tj T* 0 Tw 4.08229 Tw (interpreter start, execute the command and finish properly \(I mean by calling ) Tj /F4 10 Tf (__enter__ ) Tj /F1 10 Tf (and) Tj T* 0 Tw .427633 Tw /F4 10 Tf (__exit__) Tj /F1 10 Tf (\) without needing user input. The the script could be called from a batch shell script working in) Tj T* 0 Tw 2.26816 Tw (the background. In order to provide such functionality ) Tj /F4 10 Tf (plac.Interpreter ) Tj /F1 10 Tf (provides a classmethod) Tj T* 0 Tw 1.173318 Tw (named ) Tj /F4 10 Tf (.call ) Tj /F1 10 Tf (which takes the factory, instantiates it with the arguments read from the command line,) Tj T* 0 Tw 1.517045 Tw (wraps the resulting container object as an interpreter and runs it with the rest arguments found in the) Tj T* 0 Tw (command line. Here is the code to turn the ) Tj /F4 10 Tf (ShelveInterface ) Tj /F1 10 Tf (into a script) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (28) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R440': class PDFStream
+440 0 obj
+% page stream
+<< /Length 4534 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 691.8236 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 72 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (# ishelve3.py) Tj T* (from ishelve2 import ShelveInterface as main) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.Interpreter.call\(main\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 671.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (and here are a few examples of usage:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 638.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 24 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL ($ python ishelve3.py -h) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 521.4236 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 108 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL (usage: ishelve3.py [-h] [-configfile CONFIGFILE]) Tj T* T* (A minimal interface over a shelve object.) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -configfile CONFIGFILE) Tj T* ( path name of the shelve) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 452.2236 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 60 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ($ python ishelve3.py set a 1) Tj T* (setting a=1) Tj T* ($ python ishelve3.py show a) Tj T* (a = 1) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 420.2236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 1.77881 Tw (If you do not pass enough arguments in the command line, then the script will automatically enter in) Tj T* 0 Tw (interactive mode and ask the user for the command to execute:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 327.0236 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 84 re B*
+Q
+q
+BT 1 0 0 1 0 65.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python ishelve3.py) Tj T* (A minimal interface over a shelve object.) Tj T* (Operating on /home/micheles/conf.shelve.) Tj T* (.help to see the available commands.) Tj T* T* (i) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 283.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .221417 Tw 12 TL /F1 10 Tf 0 0 0 rg (In a sense, I have closed the circle: at the beginning of this document I discussed how to turn a script into) Tj T* 0 Tw .784147 Tw (an interactive application \(the ) Tj /F4 10 Tf (shelve_interpreter.py ) Tj /F1 10 Tf (example\), whereas here I have show how to) Tj T* 0 Tw (turn an interactive application into a script.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 265.0236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (The complete signature of ) Tj /F4 10 Tf (plac.Interpreter.call ) Tj /F1 10 Tf (is the following:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 207.8236 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 48 re B*
+Q
+q
+BT 1 0 0 1 0 29.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (call\(factory, arglist=sys.argv[1:],) Tj T* ( commentchar='#', split=shlex.split,) Tj T* ( stdin=sys.stdin, prompt='i) Tj (>) Tj ( ', verbose=False\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 127.8236 cm
+q
+BT 1 0 0 1 0 64.82 Tm 1.756651 Tw 12 TL /F1 10 Tf 0 0 0 rg (The factory must have a fixed number of positional arguments \(no default arguments, no varargs, no) Tj T* 0 Tw 1.87881 Tw (kwargs\), otherwise a ) Tj /F4 10 Tf (TypeError ) Tj /F1 10 Tf (is raised: the reason is that we want to be able to distinguish the) Tj T* 0 Tw .829984 Tw (command-line arguments needed to instantiate the factory from the rest arguments that must be sent to) Tj T* 0 Tw 2.609984 Tw (the corresponding interpreter object. It is also possible to specify a list of arguments different from) Tj T* 0 Tw .513318 Tw /F4 10 Tf (sys.argv[1:] ) Tj /F1 10 Tf (\(useful in tests\), the character to be recognized as a comment, the splitting function, the) Tj T* 0 Tw (input source and the prompt to use while in interactive mode, and a verbose flag.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (29) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R441': class PDFStream
+441 0 obj
+% page stream
+<< /Length 5174 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 747.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Readline support) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 669.0236 cm
+q
+BT 1 0 0 1 0 64.82 Tm 1.022485 Tw 12 TL /F1 10 Tf 0 0 0 rg (Starting from release 0.6 ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (offers full readline support. That means that if your Python was compiled) Tj T* 0 Tw 2.120697 Tw (with readline support you get autocompletion and persistent command history for free. By default all) Tj T* 0 Tw .144104 Tw (commands are autocomplete in a case sensitive way. If you want to add new words to the autocompletion) Tj T* 0 Tw .116488 Tw (set, or you want to change the location of the ) Tj /F4 10 Tf (.history ) Tj /F1 10 Tf (file, or to change the case sensitivity, the way to) Tj T* 0 Tw .18436 Tw (go is to pass a ) Tj /F4 10 Tf (plac.ReadlineInput ) Tj /F1 10 Tf (object to the interpreter. Here is an example, assuming you want) Tj T* 0 Tw (to build a database interface understanding SQL commands:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 324.2307 cm
+q
+q
+.96447 0 0 .96447 0 0 cm
+q
+1 0 0 1 6.6 6.843137 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 486 348 re B*
+Q
+q
+BT 1 0 0 1 0 329.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (import os, plac) Tj T* (from sqlalchemy.ext.sqlsoup import SqlSoup) Tj T* T* (SQLKEYWORDS = set\(['select', 'from', 'inner', 'join', 'outer', 'left', 'right']) Tj T* ( \) # and many others) Tj T* (DBTABLES = set\(['table1', 'table2']\) # you can read them from the db schema) Tj T* T* (COMPLETIONS = SQLKEYWORDS | DBTABLES) Tj T* T* (class SqlInterface\(object\):) Tj T* ( commands = ['SELECT']) Tj T* ( def __init__\(self, dsn\):) Tj T* ( self.soup = SqlSoup\(dsn\)) Tj T* ( def SELECT\(self, argstring\):) Tj T* ( sql = 'SELECT ' + argstring) Tj T* ( for row in self.soup.bind.execute\(sql\):) Tj T* ( yield str\(row\) # the formatting can be much improved) Tj T* T* (rl_input = plac.ReadlineInput\() Tj T* ( COMPLETIONS, histfile=os.path.expanduser\('~/.sql_interface.history'\), ) Tj T* ( case_sensitive=False\)) Tj T* T* (def split_on_first_space\(line, commentchar\):) Tj T* ( return line.strip\(\).split\(' ', 1\) # ignoring comments) Tj T* ( ) Tj T* (if __name__ == '__main__':) Tj T* ( plac.Interpreter.call\(SqlInterface, split=split_on_first_space,) Tj T* ( stdin=rl_input, prompt='sql) Tj (>) Tj ( '\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 304.2307 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 247.0307 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 48 re B*
+Q
+q
+BT 1 0 0 1 0 29.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python sql_interface.py ) Tj (<) Tj (some dsn) Tj (>) Tj T* (sql) Tj (>) Tj ( SELECT a.* FROM TABLE1 AS a INNER JOIN TABLE2 AS b ON a.id = b.id) Tj T* (...) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 167.0307 cm
+q
+BT 1 0 0 1 0 64.82 Tm 1.951318 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can check that entering just ) Tj /F4 10 Tf (sel ) Tj /F1 10 Tf (and pressing TAB the readline library completes the ) Tj /F4 10 Tf (SELECT) Tj T* 0 Tw .797356 Tw /F1 10 Tf (keyword for you and makes it upper case; idem for ) Tj /F4 10 Tf (FROM) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (INNER) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (JOIN ) Tj /F1 10 Tf (and even for the names of the) Tj T* 0 Tw .256235 Tw (tables. An obvious improvement is to read the names of the tables by introspecting the database: actually) Tj T* 0 Tw 1.616654 Tw (you can even read the names of the views and of the columns, and have full autocompletion. All the) Tj T* 0 Tw 2.047251 Tw (entered commands and recorded and saved in the file ) Tj /F4 10 Tf (~/.sql_interface.history ) Tj /F1 10 Tf (when exiting) Tj T* 0 Tw (from the command-line interface.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 89.03071 cm
+q
+BT 1 0 0 1 0 64.82 Tm 2.010574 Tw 12 TL /F1 10 Tf 0 0 0 rg (If the readline library is not available, my suggestion is to use the ) Tj 0 0 .501961 rg (rlwrap ) Tj 0 0 0 rg (tool which provides similar) Tj T* 0 Tw .22561 Tw (features, at least on Unix-like platforms. ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (should also work fine on Windows with the ) Tj 0 0 .501961 rg (pyreadline ) Tj 0 0 0 rg (library) Tj T* 0 Tw .389989 Tw (\(I do not use Windows, so this part is very little tested: I tried it only once and it worked, but your mileage) Tj T* 0 Tw 2.206457 Tw (may vary\). For people worried about licenses, I will notice that ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (uses the readline library only if) Tj T* 0 Tw .591894 Tw (available, it does not include it and it does not rely on it in any fundamental way, so that the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (licence) Tj T* 0 Tw (does not need to be the GPL \(actually it is a BSD do-whatever-you-want-with-it licence\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (30) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R442': class PDFStream
+442 0 obj
+% page stream
+<< /Length 4651 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 729.0236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .187882 Tw 12 TL /F1 10 Tf 0 0 0 rg (The interactive mode of ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (can be used as a replacement of the ) Tj 0 0 .501961 rg (cmd ) Tj 0 0 0 rg (module in the standard library. It) Tj T* 0 Tw 2.730651 Tw (is actually better than ) Tj 0 0 .501961 rg (cmd) Tj 0 0 0 rg (: for instance, the ) Tj /F4 10 Tf (.help ) Tj /F1 10 Tf (command is more powerful, since it provides) Tj T* 0 Tw (information about the arguments accepted by the given command:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 419.8236 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 300 re B*
+Q
+q
+BT 1 0 0 1 0 281.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .help set) Tj T* (usage: set name value) Tj T* T* (set name value) Tj T* T* (positional arguments:) Tj T* ( name) Tj T* ( value) Tj T* T* (i) Tj (>) Tj ( .help delete) Tj T* (usage: delete [name]) Tj T* T* (delete given parameter \(or everything\)) Tj T* T* (positional arguments:) Tj T* ( name) Tj T* T* (i) Tj (>) Tj ( .help show) Tj T* (usage: show [names [names ...]]) Tj T* T* (show given parameters) Tj T* T* (positional arguments:) Tj T* ( names) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 363.8236 cm
+q
+BT 1 0 0 1 0 40.82 Tm 1.959985 Tw 12 TL /F1 10 Tf 0 0 0 rg (As you can imagine, the help message is provided by the underlying ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (subparser \(there is a) Tj T* 0 Tw 2.954524 Tw (subparser for each command\). ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (commands accept options, flags, varargs, keyword arguments,) Tj T* 0 Tw .719318 Tw (arguments with defaults, arguments with a fixed number of choices, type conversion and all the features) Tj T* 0 Tw (provided of ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (which should be reimplemented from scratch using ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 333.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.78248 Tw 12 TL /F1 10 Tf 0 0 0 rg (Moreover at the moment ) Tj /F4 10 Tf (plac ) Tj /F1 10 Tf (also understands command abbreviations. However, this feature may) Tj T* 0 Tw (disappear in future releases. It was meaningful in the past, when ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (did not support readline.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 315.8236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Notice that if an abbreviation is ambiguous, ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (warns you:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 270.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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( sh) Tj T* (NameError: Ambiguous command 'sh': matching ['showall', 'show']) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 240.6236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (The plac runner) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 174.6236 cm
+q
+BT 1 0 0 1 0 52.82 Tm 1.531318 Tw 12 TL /F1 10 Tf 0 0 0 rg (The distribution of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (includes a runner script named ) Tj /F4 10 Tf (plac_runner.py) Tj /F1 10 Tf (, which will be installed in a) Tj T* 0 Tw .44748 Tw (suitable directory in your system by ) Tj 0 0 .501961 rg (distutils ) Tj 0 0 0 rg (\(say in ) Tj /F4 10 Tf (\\usr\\local\\bin\\plac_runner.py ) Tj /F1 10 Tf (in a Unix-like) Tj T* 0 Tw .680651 Tw (operative system\). The runner provides many facilities to run ) Tj /F4 10 Tf (.plac ) Tj /F1 10 Tf (scripts and ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (files, as well) Tj T* 0 Tw 1.47311 Tw (as Python modules containg a ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (object, which can be a function, a command container object or) Tj T* 0 Tw (even a command container class.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 144.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.994269 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, suppose you want to execute a script containing commands defined in the ) Tj /F4 10 Tf (ishelve2) Tj T* 0 Tw /F1 10 Tf (module like the following one:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 99.42362 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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL (#!ishelve2.py:ShelveInterface -c ~/conf.shelve) Tj T* (set a 1) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (31) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R443': class PDFStream
+443 0 obj
+% page stream
+<< /Length 4565 >>
+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
+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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL (del a) Tj T* (del a # intentional error) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 659.8236 cm
+q
+BT 1 0 0 1 0 52.82 Tm .575868 Tw 12 TL /F1 10 Tf 0 0 0 rg (The first line of the ) Tj /F4 10 Tf (.plac ) Tj /F1 10 Tf (script contains the name of the python module containing the plac interpreter) Tj T* 0 Tw 2.327209 Tw (and the arguments which must be passed to its main function in order to be able to instantiate an) Tj T* 0 Tw .202485 Tw (interpreter object. In this case I appended ) Tj /F4 10 Tf (:ShelveInterface ) Tj /F1 10 Tf (to the name of the module to specify the) Tj T* 0 Tw 1.030574 Tw (object that must be imported: if not specified, by default the object named 'main' is imported. The other) Tj T* 0 Tw (lines contains commands. You can run the script as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 570.6505 cm
+q
+q
+.952737 0 0 .952737 0 0 cm
+q
+1 0 0 1 6.6 6.927412 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 492 84 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL ($ plac_runner.py --batch ishelve2.plac) Tj T* (setting a=1) Tj T* (deleting a) Tj T* (Traceback \(most recent call last\):) Tj T* ( ...) Tj T* (_bsddb.DBNotFoundError: \(-30988, 'DB_NOTFOUND: No matching key/data pair found'\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 538.6505 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 2.79186 Tw (The last command intentionally contained an error, to show that the plac runner does not eat the) Tj T* 0 Tw (traceback.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 508.6505 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .437633 Tw (The runner can also be used to run Python modules in interactive mode and non-interactive mode. If you) Tj T* 0 Tw (put this alias in your bashrc) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 502.6505 cm
+Q
+q
+1 0 0 1 62.69291 490.6505 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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (alias plac="plac_runner.py") Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 490.6505 cm
+Q
+q
+1 0 0 1 62.69291 460.6505 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.955318 Tw 12 TL /F1 10 Tf 0 0 0 rg (\(or you define a suitable ) Tj /F4 10 Tf (plac.bat ) Tj /F1 10 Tf (script in Windows\) you can run the ) Tj /F4 10 Tf (ishelve2.py ) Tj /F1 10 Tf (script in) Tj T* 0 Tw (interactive mode as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 283.4505 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 168 re B*
+Q
+q
+BT 1 0 0 1 0 149.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ plac -i ishelve2.py) Tj T* (A minimal interface over a shelve object.) Tj T* (Operating on /home/micheles/conf.shelve.) Tj T* (.help to see the available commands.) Tj T* T* (i) Tj (>) Tj ( del) Tj T* (deleting everything) Tj T* (i) Tj (>) Tj ( set a 1) Tj T* (setting a=1) Tj T* (i) Tj (>) Tj ( set b 2) Tj T* (setting b=2) Tj T* (i) Tj (>) Tj ( show b) Tj T* (b = 2) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 263.4505 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Now you can cut and paste the interactive session an turns into into a ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (file like the following:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 134.2505 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 120 re B*
+Q
+q
+BT 1 0 0 1 0 101.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (#!ishelve2.py:ShelveInterface -configfile=~/test.shelve) Tj T* (i) Tj (>) Tj ( del) Tj T* (deleting everything) Tj T* (i) Tj (>) Tj ( set a 1) Tj T* (setting a=1) Tj T* (i) Tj (>) Tj ( set b 2) Tj T* (setting b=2) Tj T* (i) Tj (>) Tj ( show a) Tj T* (a = 1) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 102.2505 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.145697 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that the first line specifies a test database ) Tj /F4 10 Tf (~/test.shelve) Tj /F1 10 Tf (, to avoid clobbering your default) Tj T* 0 Tw (shelve. If you mispell the arguments in the first line plac will give you an ) Tj 0 0 .501961 rg (argparse ) Tj 0 0 0 rg (error message \(just try\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (32) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R444': class PDFStream
+444 0 obj
+% page stream
+<< /Length 4981 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 753.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (You can run placets following the shebang convention directly with the plac runner:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 707.8236 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 36 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL ($ plac --test ishelve2.placet) Tj T* (run 1 plac test\(s\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 663.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .32104 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you want to see the output of the tests, pass the ) Tj /F4 10 Tf (-v/--verbose ) Tj /F1 10 Tf (flag. Notice that he runner ignore the) Tj T* 0 Tw .24856 Tw (extension, so you can actually use any extension your like, but ) Tj /F5 10 Tf (it relies on the first line of the file to invoke) Tj T* 0 Tw (the corresponding plac tool with the given arguments) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 633.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .537209 Tw 12 TL /F1 10 Tf 0 0 0 rg (The plac runner does not provide any test discovery facility, but you can use standard Unix tools to help.) Tj T* 0 Tw (For instance, you can run all the ) Tj /F4 10 Tf (.placet ) Tj /F1 10 Tf (files into a directory and its subdirectories as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 600.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 24 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL ($ find . -name \\*.placet | xargs plac_runner.py -t) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 568.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .760988 Tw 12 TL /F1 10 Tf 0 0 0 rg (The plac runner expects the main function of your script to return a plac tool, i.e. a function or an object) Tj T* 0 Tw (with a ) Tj /F4 10 Tf (.commands ) Tj /F1 10 Tf (attribute. It this is not the case the runner gracefully exits.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 550.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (It also works in non-interactive mode, if you call it as) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 544.6236 cm
+Q
+q
+1 0 0 1 62.69291 532.6236 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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL ($ plac module.py args ...) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 532.6236 cm
+Q
+q
+1 0 0 1 62.69291 514.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is an example:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 445.4236 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 60 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL ($ plac ishelve.py a=1) Tj T* (setting a=1) Tj T* ($ plac ishelve.py .show) Tj T* (a=1) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 413.4236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .01561 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that in non-interactive mode the runner just invokes ) Tj /F4 10 Tf (plac.call ) Tj /F1 10 Tf (on the ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (object of the Python) Tj T* 0 Tw (module.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 383.4236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (A non class-based example) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 341.4236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .907209 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (does not force you to use classes to define command containers. Even a simple function can be a) Tj T* 0 Tw 1.796651 Tw (valid command container, it is enough to add to it a ) Tj /F4 10 Tf (.commands ) Tj /F1 10 Tf (attribute and possibly ) Tj /F4 10 Tf (__enter__) Tj T* 0 Tw /F1 10 Tf (and/or ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (attributes.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 311.4236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .327485 Tw (In particular, a Python module is a perfect container of commands. As an example, consider the following) Tj T* 0 Tw (module implementing a fake Version Control System:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 98.22362 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 204 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 185.71 Tm /F4 10 Tf 12 TL ("A Fake Version Control System") Tj T* T* (import plac) Tj T* T* (commands = 'checkout', 'commit', 'status') Tj T* T* (@plac.annotations\(url='url of the source code'\)) Tj T* (def checkout\(url\):) Tj T* ( "A fake checkout command") Tj T* ( return \('checkout ', url\)) Tj T* T* (@plac.annotations\(message=\('commit message', 'option'\)\)) Tj T* (def commit\(message\):) Tj T* ( "A fake commit command") Tj T* ( return \('commit ', message\)) Tj T* T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (33) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R445': class PDFStream
+445 0 obj
+% page stream
+<< /Length 3891 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 583.8236 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 (@plac.annotations\(quiet=\('summary information', 'flag', 'q'\)\)) Tj T* (def status\(quiet\):) Tj T* ( "A fake status command") Tj T* ( return \('status ', quiet\)) Tj T* T* (def __missing__\(name\):) Tj T* ( return 'Command %r does not exist' % name) Tj T* T* (def __exit__\(etype, exc, tb\):) Tj T* ( "Will be called automatically at the end of the call/cmdloop") Tj T* ( if etype in \(None, GeneratorExit\): # success) Tj T* ( print\('ok'\)) Tj T* T* (main = __import__\(__name__\) # the module imports itself!) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 539.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .431318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that I have defined both an ) Tj /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (hook and a ) Tj /F4 10 Tf (__missing__ ) Tj /F1 10 Tf (hook, invoked for non-existing) Tj T* 0 Tw .592651 Tw (commands. The real trick here is the line ) Tj /F4 10 Tf (main = __import__\(__name__\)) Tj /F1 10 Tf (, which define ) Tj /F4 10 Tf (main ) Tj /F1 10 Tf (to be) Tj T* 0 Tw (an alias for the current module.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 509.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.259986 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (vcs ) Tj /F1 10 Tf (module does not contain an ) Tj /F4 10 Tf (if __name__ == '__main__' ) Tj /F1 10 Tf (block, but you can still run it) Tj T* 0 Tw (through the plac runner \(try ) Tj /F4 10 Tf (plac vcs.py -h) Tj /F1 10 Tf (\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 368.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 132 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 113.71 Tm /F4 10 Tf 12 TL (usage: plac_runner.py vcs.py [-h] {status,commit,checkout} ...) Tj T* T* (A Fake Version Control System) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* T* (subcommands:) Tj T* ( {status,commit,checkout}) Tj T* ( -h to get additional help) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 348.6236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (You can get help for the subcommands by postponing ) Tj /F4 10 Tf (-h ) Tj /F1 10 Tf (after the name of the command:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 231.4236 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 108 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL ($ plac vcs.py status -h) Tj T* (usage: vcs.py status [-h] [-q]) Tj T* T* (A fake status command) Tj T* T* (optional arguments:) Tj T* ( -h, --help show this help message and exit) Tj T* ( -q, --quiet summary information) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 199.4236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.064985 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice how the docstring of the command is automatically shown in usage message, as well as the) Tj T* 0 Tw (documentation for the sub flag ) Tj /F4 10 Tf (-q) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 181.4236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here is an example of a non-interactive session:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 100.2236 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 72 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL ($ plac vcs.py check url) Tj T* (checkout) Tj T* (url) Tj T* ($ plac vcs.py st -q) Tj T* (status) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (34) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R446': class PDFStream
+446 0 obj
+% page stream
+<< /Length 5654 >>
+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
+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 60 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL (True) Tj T* ($ plac vcs.py co) Tj T* (commit) Tj T* (None) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 683.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (and here is an interactive session:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 482.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 192 re B*
+Q
+q
+BT 1 0 0 1 0 173.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ plac -i vcs.py) Tj T* (usage: plac_runner.py vcs.py [-h] {status,commit,checkout} ...) Tj T* (i) Tj (>) Tj ( check url) Tj T* (checkout) Tj T* (url) Tj T* (i) Tj (>) Tj ( st -q) Tj T* (status) Tj T* (True) Tj T* (i) Tj (>) Tj ( co) Tj T* (commit) Tj T* (None) Tj T* (i) Tj (>) Tj ( sto) Tj T* (Command 'sto' does not exist) Tj T* (i) Tj (>) Tj ( [CTRL-D]) Tj T* (ok) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 450.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.986905 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice the invocation of the ) Tj /F4 10 Tf (__missing__ ) Tj /F1 10 Tf (hook for non-existing commands. Notice also that the) Tj T* 0 Tw /F4 10 Tf (__exit__ ) Tj /F1 10 Tf (hook gets called only in interactive mode.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 420.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 1.614104 Tw (If the commands are completely independent, a module is a good fit for a method container. In other) Tj T* 0 Tw (situations, it is best to use a custom class.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 390.6236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Writing your own plac runner) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 336.6236 cm
+q
+BT 1 0 0 1 0 40.82 Tm .167209 Tw 12 TL /F1 10 Tf 0 0 0 rg (The runner included in the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (distribution is intentionally kept small \(around 50 lines of code\) so that you) Tj T* 0 Tw .081294 Tw (can study it and write your own runner if want to. If you need to go to such level of detail, you should know) Tj T* 0 Tw .42061 Tw (that the most important method of the ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (class is the ) Tj /F4 10 Tf (.send ) Tj /F1 10 Tf (method, which takes strings in) Tj T* 0 Tw (input and returns a four-tuple with attributes ) Tj /F4 10 Tf (.str) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (.etype) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (.exc ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (.tb) Tj /F1 10 Tf (:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 330.6236 cm
+Q
+q
+1 0 0 1 62.69291 330.6236 cm
+Q
+q
+1 0 0 1 62.69291 312.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (.str ) Tj /F1 10 Tf (is the output of the command, if successful \(a string\);) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 312.6236 cm
+Q
+q
+1 0 0 1 62.69291 312.6236 cm
+Q
+q
+1 0 0 1 62.69291 294.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (.etype ) Tj /F1 10 Tf (is the class of the exception, if the command fail;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 294.6236 cm
+Q
+q
+1 0 0 1 62.69291 294.6236 cm
+Q
+q
+1 0 0 1 62.69291 276.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (.exc ) Tj /F1 10 Tf (is the exception instance;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 276.6236 cm
+Q
+q
+1 0 0 1 62.69291 276.6236 cm
+Q
+q
+1 0 0 1 62.69291 258.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (.tb ) Tj /F1 10 Tf (is the traceback.) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 258.6236 cm
+Q
+q
+1 0 0 1 62.69291 258.6236 cm
+Q
+q
+1 0 0 1 62.69291 216.6236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .937485 Tw 12 TL /F1 10 Tf 0 0 0 rg (Moreover the ) Tj /F4 10 Tf (__str__ ) Tj /F1 10 Tf (representation of the output object is redefined to return the output string if the) Tj T* 0 Tw 2.686651 Tw (command was successful or the error message if the command failed \(actually it returns the error) Tj T* 0 Tw (message preceded by the name of the exception class\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 198.6236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (For instance, if you send a mispelled option to the interpreter a ) Tj /F4 10 Tf (SystemExit ) Tj /F1 10 Tf (will be trapped:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 105.4236 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 84 re B*
+Q
+q
+BT 1 0 0 1 0 65.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (>) Tj (>) Tj (>) Tj ( import plac) Tj T* (>) Tj (>) Tj (>) Tj ( from ishelve import ishelve) Tj T* (>) Tj (>) Tj (>) Tj ( with plac.Interpreter\(ishelve\) as i:) Tj T* (... print\(i.send\('.cler'\)\)) Tj T* (...) Tj T* (SystemExit: unrecognized arguments: .cler) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (35) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R447': class PDFStream
+447 0 obj
+% page stream
+<< /Length 4883 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 741.0236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.90561 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is important to invoke the ) Tj /F4 10 Tf (.send ) Tj /F1 10 Tf (method inside the context manager, otherwise you will get a) Tj T* 0 Tw /F4 10 Tf (RuntimeError) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 699.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 28.82 Tm /F1 10 Tf 12 TL .29311 Tw (For instance, suppose you want to implement a graphical runner for a plac-based interpreter with two text) Tj T* 0 Tw 1.548221 Tw (widgets: one to enter the commands and one to display the results. Suppose you want to display the) Tj T* 0 Tw (errors with tracebacks in red. You will need to code something like that \(pseudocode follows\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 461.8236 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 228 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 209.71 Tm /F4 10 Tf 12 TL (input_widget = WidgetReadingInput\(\)) Tj T* (output_widget = WidgetDisplayingOutput\(\)) Tj T* T* (def send\(interpreter, line\):) Tj T* ( out = interpreter.send\(line\)) Tj T* ( if out.tb: # there was an error) Tj T* ( output_widget.display\(out.tb, color='red'\)) Tj T* ( else:) Tj T* ( output_widget.display\(out.str\)) Tj T* T* (main = plac.import_main\(tool_path\) # get the main object) Tj T* T* (with plac.Interpreter\(main\) as i:) Tj T* ( def callback\(event\):) Tj T* ( if event.user_pressed_ENTER\(\):) Tj T* ( send\(i, input_widget.last_line\)) Tj T* ( input_widget.addcallback\(callback\)) Tj T* ( gui_mainloop.start\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 429.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .102765 Tw (You can adapt the pseudocode to your GUI toolkit of choice and you can also change the file associations) Tj T* 0 Tw (in such a way that clicking on a plac tool file the graphical user interface starts.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 399.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .259988 Tw 12 TL /F1 10 Tf 0 0 0 rg (An example of GUI program built on top of ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is given later on, in the paragraph ) Tj /F5 10 Tf (Managing the output of) Tj T* 0 Tw (concurrent commands ) Tj /F1 10 Tf (\(using Tkinter for simplicity and portability\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 345.8236 cm
+q
+BT 1 0 0 1 0 40.82 Tm 2.090651 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is a final ) Tj /F5 10 Tf (caveat) Tj /F1 10 Tf (: since the plac interpreter loop is implemented via extended generators, plac) Tj T* 0 Tw .988651 Tw (interpreters are single threaded: you will get an error if you ) Tj /F4 10 Tf (.send ) Tj /F1 10 Tf (commands from separated threads.) Tj T* 0 Tw .947882 Tw (You can circumvent the problem by using a queue. If EXIT is a sentinel value to signal exiting from the) Tj T* 0 Tw (interpreter look, you can write code like this:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 288.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 48 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL (with interpreter:) Tj T* ( for input_value in iter\(input_queue.get, EXIT\):) Tj T* ( output_queue.put\(interpreter.send\(input_value\)\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 256.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .106098 Tw 12 TL /F1 10 Tf 0 0 0 rg (The same trick also work for processes; you could run the interpreter loop in a separate process and send) Tj T* 0 Tw (commands to it via the Queue class provided by the ) Tj 0 0 .501961 rg (multiprocessing ) Tj 0 0 0 rg (module.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 226.6236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Long running commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 184.6236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 1.434431 Tw 12 TL /F1 10 Tf 0 0 0 rg (As we saw, by default a ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (interpreter blocks until the command terminates. This is an issue, in the) Tj T* 0 Tw 1.201318 Tw (sense that it makes the interactive experience quite painful for long running commands. An example is) Tj T* 0 Tw (better than a thousand words, so consider the following fake importer:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 91.42362 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 84 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL (import time) Tj T* (import plac) Tj T* T* (class FakeImporter\(object\):) Tj T* ( "A fake importer with an import_file command") Tj T* ( commands = ['import_file']) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (36) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R448': class PDFStream
+448 0 obj
+% page stream
+<< /Length 4625 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 583.8236 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 ( def __init__\(self, dsn\):) Tj T* ( self.dsn = dsn) Tj T* ( def import_file\(self, fname\):) Tj T* ( "Import a file into the database") Tj T* ( try:) Tj T* ( for n in range\(10000\):) Tj T* ( time.sleep\(.01\)) Tj T* ( if n % 100 == 99:) Tj T* ( yield 'Imported %d lines' % \(n+1\)) Tj T* ( finally:) Tj T* ( print\('closing the file'\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.Interpreter.call\(FakeImporter\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 551.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.466457 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you run the ) Tj /F4 10 Tf (import_file ) Tj /F1 10 Tf (command, you will have to wait for 200 seconds before entering a new) Tj T* 0 Tw (command:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 410.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 132 re B*
+Q
+q
+BT 1 0 0 1 0 113.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ python importer1.py dsn) Tj T* (A fake importer with an import_file command) Tj T* (i) Tj (>) Tj ( import_file file1) Tj T* (... ) Tj (<) Tj (wait 3+ minutes) Tj (>) Tj T* (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* (Imported 300 lines) Tj T* (...) Tj T* (Imported 10000 lines) Tj T* (closing the file) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 366.6236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .96832 Tw 12 TL /F1 10 Tf 0 0 0 rg (Being unable to enter any other command is quite annoying: in such situation one would like to run the) Tj T* 0 Tw .941318 Tw (long running commands in the background, to keep the interface responsive. ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (provides two ways to) Tj T* 0 Tw (reach this goal: threads and processes.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 336.6236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Threaded commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 306.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .317988 Tw (The most familiar way to execute a task in the background \(even if not necessarily the best way\) is to run) Tj T* 0 Tw (it into a separated thread. In our example it is sufficient to replace the line) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 300.6236 cm
+Q
+q
+1 0 0 1 62.69291 288.6236 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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (commands = ['import_file']) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 288.6236 cm
+Q
+q
+1 0 0 1 62.69291 270.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (with) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 264.6236 cm
+Q
+q
+1 0 0 1 62.69291 252.6236 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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (thcommands = ['import_file']) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 252.6236 cm
+Q
+q
+1 0 0 1 62.69291 222.6236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.38311 Tw 12 TL /F1 10 Tf 0 0 0 rg (to tell to the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (interpreter that the command ) Tj /F4 10 Tf (import_file ) Tj /F1 10 Tf (should be run into a separated thread.) Tj T* 0 Tw (Here is an example session:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 177.4236 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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( import_file file1) Tj T* (<) Tj (ThreadedTask 1 [import_file file1] RUNNING) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 145.4236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .595777 Tw 12 TL /F1 10 Tf 0 0 0 rg (The import task started in a separated thread. You can see the progress of the task by using the special) Tj T* 0 Tw (command ) Tj /F4 10 Tf (.output) Tj /F1 10 Tf (:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 100.2236 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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .output 1) Tj T* (<) Tj (ThreadedTask 1 [import_file file1] RUNNING) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (37) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R449': class PDFStream
+449 0 obj
+% page stream
+<< /Length 5121 >>
+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
+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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 707.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (If you look after a while, you will get more lines of output:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 614.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 84 re B*
+Q
+q
+BT 1 0 0 1 0 65.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .output 1) Tj T* (<) Tj (ThreadedTask 1 [import_file file1] RUNNING) Tj (>) Tj T* (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* (Imported 300 lines) Tj T* (Imported 400 lines) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 594.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (If you look after a time long enough, the task will be finished:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 549.4236 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 36 re B*
+Q
+q
+BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .output 1) Tj T* (<) Tj (ThreadedTask 1 [import_file file1] FINISHED) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 517.4236 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.045868 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can even skip the number argument: then ) Tj /F4 10 Tf (.output ) Tj /F1 10 Tf (will the return the output of the last launched) Tj T* 0 Tw (command \(the special commands like .output do not count\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 499.4236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (You can launch many tasks one after the other:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 430.2236 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 60 re B*
+Q
+q
+BT 1 0 0 1 0 41.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( import_file file2) Tj T* (<) Tj (ThreadedTask 5 [import_file file2] RUNNING) Tj (>) Tj T* (i) Tj (>) Tj ( import_file file3) Tj T* (<) Tj (ThreadedTask 6 [import_file file3] RUNNING) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 410.2236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (.list ) Tj /F1 10 Tf (command displays all the running tasks:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 353.0236 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 48 re B*
+Q
+q
+BT 1 0 0 1 0 29.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .list) Tj T* (<) Tj (ThreadedTask 5 [import_file file2] RUNNING) Tj (>) Tj T* (<) Tj (ThreadedTask 6 [import_file file3] RUNNING) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 333.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (It is even possible to kill a task:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 239.8236 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 84 re B*
+Q
+q
+BT 1 0 0 1 0 65.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( .kill 5) Tj T* (<) Tj (ThreadedTask 5 [import_file file2] TOBEKILLED) Tj (>) Tj T* (# wait a bit ...) Tj T* (closing the file) Tj T* (i) Tj (>) Tj ( .output 5) Tj T* (<) Tj (ThreadedTask 5 [import_file file2] KILLED) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 147.8236 cm
+q
+BT 1 0 0 1 0 76.82 Tm 1.100542 Tw 12 TL /F1 10 Tf 0 0 0 rg (You should notice that since at the Python level it is impossible to kill a thread, the ) Tj /F4 10 Tf (.kill ) Tj /F1 10 Tf (commands) Tj T* 0 Tw 1.793984 Tw (works by setting the status of the task to ) Tj /F4 10 Tf (TOBEKILLED) Tj /F1 10 Tf (. Internally the generator corresponding to the) Tj T* 0 Tw .632927 Tw (command is executed in the thread and the status is checked at each iteration: when the status become) Tj T* 0 Tw 2.578443 Tw /F4 10 Tf (TOBEKILLED ) Tj /F1 10 Tf (a ) Tj /F4 10 Tf (GeneratorExit ) Tj /F1 10 Tf (exception is raised and the thread terminates \(softly, so that the) Tj T* 0 Tw 2.328651 Tw /F4 10 Tf (finally ) Tj /F1 10 Tf (clause is honored\). In our example the generator is yielding back control once every 100) Tj T* 0 Tw 1.152619 Tw (iterations, i.e. every two seconds \(not much\). In order to get a responsive interface it is a good idea to) Tj T* 0 Tw (yield more often, for instance every 10 iterations \(i.e. 5 times per second\), as in the following code:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 90.62362 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 48 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL (import time) Tj T* (import plac) Tj T* T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (38) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R450': class PDFStream
+450 0 obj
+% page stream
+<< /Length 4760 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 523.8236 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 240 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 221.71 Tm /F4 10 Tf 12 TL (class FakeImporter\(object\):) Tj T* ( "A fake importer with an import_file command") Tj T* ( thcommands = ['import_file']) Tj T* ( def __init__\(self, dsn\):) Tj T* ( self.dsn = dsn) Tj T* ( def import_file\(self, fname\):) Tj T* ( "Import a file into the database") Tj T* ( try:) Tj T* ( for n in range\(10000\):) Tj T* ( time.sleep\(.02\)) Tj T* ( if n % 100 == 99: # every two seconds) Tj T* ( yield 'Imported %d lines' % \(n+1\)) Tj T* ( if n % 10 == 9: # every 0.2 seconds) Tj T* ( yield # go back and check the TOBEKILLED status) Tj T* ( finally:) Tj T* ( print\('closing the file'\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( plac.Interpreter.call\(FakeImporter\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 493.8236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Running commands as external processes) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 439.8236 cm
+q
+BT 1 0 0 1 0 40.82 Tm 2.30686 Tw 12 TL /F1 10 Tf 0 0 0 rg (Threads are not loved much in the Python world and actually most people prefer to use processes) Tj T* 0 Tw 3.350697 Tw (instead. For this reason ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (provides the option to execute long running commands as external) Tj T* 0 Tw .632706 Tw (processes. Unfortunately the current implementation only works in Unix-like operating systems \(including) Tj T* 0 Tw (Mac OS X\) because it relies on fork via the ) Tj 0 0 .501961 rg (multiprocessing ) Tj 0 0 0 rg (module.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 421.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (In our example, to enable the feature it is sufficient to replace the line) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 415.8236 cm
+Q
+q
+1 0 0 1 62.69291 403.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
+0 0 0 rg
+BT 1 0 0 1 0 5.71 Tm /F4 10 Tf 12 TL (thcommands = ['import_file']) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 403.8236 cm
+Q
+q
+1 0 0 1 62.69291 385.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (with) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 379.8236 cm
+Q
+q
+1 0 0 1 62.69291 367.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
+BT 1 0 0 1 0 4.82 Tm 12 TL /F4 10 Tf 0 0 0 rg (mpcommands = ['import_file']) Tj /F1 10 Tf (.) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 367.8236 cm
+Q
+q
+1 0 0 1 62.69291 337.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .772619 Tw (The user experience is exactly the same as with threads and you will not see any difference at the user) Tj T* 0 Tw (interface level:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 196.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 132 re B*
+Q
+q
+BT 1 0 0 1 0 113.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (i) Tj (>) Tj ( import_file file3) Tj T* (<) Tj (MPTask 1 [import_file file3] SUBMITTED) Tj (>) Tj T* (i) Tj (>) Tj ( .kill 1) Tj T* (<) Tj (MPTask 1 [import_file file3] RUNNING) Tj (>) Tj T* (closing the file) Tj T* (i) Tj (>) Tj ( .o 1) Tj T* (<) Tj (MPTask 1 [import_file file3] KILLED) Tj (>) Tj T* (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* (i) Tj (>) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 140.6236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 40.82 Tm /F1 10 Tf 12 TL 1.201318 Tw (Still, using processes is quite different than using threads: in particular, when using processes you can) Tj T* 0 Tw 2.313318 Tw (only yield pickleable values and you cannot re-raise an exception first raised in a different process,) Tj T* 0 Tw 1.445697 Tw (because traceback objects are not pickleable. Moreover, you cannot rely on automatic sharing of your) Tj T* 0 Tw (objects.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 98.62362 cm
+q
+BT 1 0 0 1 0 28.82 Tm .128935 Tw 12 TL /F1 10 Tf 0 0 0 rg (On the plus side, when using processes you do not need to worry about killing a command: they are killed ) Tj T* 0 Tw .466412 Tw (immediately using a SIGTERM signal, and there is not a ) Tj /F4 10 Tf (TOBEKILLED ) Tj /F1 10 Tf (mechanism. Moreover, the killing ) Tj T* 0 Tw 1.50229 Tw (is guaranteed to be soft: internally a command receiving a SIGTERM raises a ) Tj /F4 10 Tf (TerminatedProcess) Tj T* 0 Tw ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (39) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R451': class PDFStream
+451 0 obj
+% page stream
+<< /Length 3752 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 753.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (exception which is trapped in the generator loop, so that the command is closed properly.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 723.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .242927 Tw (Using processes allows to take full advantage of multicore machines and it is safer than using threads, so) Tj T* 0 Tw (it is the recommended approach unless you are working on Windows.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 693.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Managing the output of concurrent commands) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 591.0236 cm
+q
+BT 1 0 0 1 0 88.82 Tm 1.895542 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (acts as a command-line task launcher and can be used as the base to build a GUI-based task) Tj T* 0 Tw .38561 Tw (launcher and task monitor. To this aim the interpreter class provides a ) Tj /F4 10 Tf (.submit ) Tj /F1 10 Tf (method which returns a) Tj T* 0 Tw 1.792339 Tw (task object and a ) Tj /F4 10 Tf (.tasks ) Tj /F1 10 Tf (method returning the list of all the tasks submitted to the interpreter. The) Tj T* 0 Tw .373516 Tw /F4 10 Tf (submit ) Tj /F1 10 Tf (method does not start the task and thus it is nonblocking. Each task has an ) Tj /F4 10 Tf (.outlist ) Tj /F1 10 Tf (attribute) Tj T* 0 Tw .106098 Tw (which is a list storing the value yielded by the generator underlying the task \(the ) Tj /F4 10 Tf (None ) Tj /F1 10 Tf (values are skipped) Tj T* 0 Tw .633318 Tw (though\): the ) Tj /F4 10 Tf (.outlist ) Tj /F1 10 Tf (grows as the task runs and more values are yielded. Accessing the ) Tj /F4 10 Tf (.outlist) Tj T* 0 Tw 1.051654 Tw /F1 10 Tf (is nonblocking and can be done freely. Finally there is a ) Tj /F4 10 Tf (.result ) Tj /F1 10 Tf (property which waits for the task to) Tj T* 0 Tw (finish and returns the last yielded value or raises an exception.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 561.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL .014692 Tw (Here is some example code to visualize the output of the FakeImporter in Tkinter \(I chose Tkinter because) Tj T* 0 Tw (it is easy to use and it is in the standard library, but you can use any GUI\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 191.8236 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 360 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 341.71 Tm /F4 10 Tf 12 TL (from Tkinter import *) Tj T* (from importer3 import FakeImporter) Tj T* T* (def taskwidget\(root, task, tick=500\):) Tj T* ( "A Label widget showing the output of a task every 500 ms") Tj T* ( sv = StringVar\(root\)) Tj T* ( lb = Label\(root, textvariable=sv\)) Tj T* ( def show_outlist\(\):) Tj T* ( try:) Tj T* ( out = task.outlist[-1]) Tj T* ( except IndexError: # no output yet) Tj T* ( out = '') Tj T* ( sv.set\('%s %s' % \(task, out\)\)) Tj T* ( root.after\(tick, show_outlist\)) Tj T* ( root.after\(0, show_outlist\)) Tj T* ( return lb) Tj T* T* (def monitor\(tasks\):) Tj T* ( root = Tk\(\)) Tj T* ( for task in tasks:) Tj T* ( task.run\(\)) Tj T* ( taskwidget\(root, task\).pack\(\)) Tj T* ( root.mainloop\(\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac) Tj T* ( with plac.Interpreter\(plac.call\(FakeImporter\)\) as i:) Tj T* ( tasks = [i.submit\('import_file f1'\), i.submit\('import_file f2'\)]) Tj T* ( monitor\(tasks\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (40) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R452': class PDFStream
+452 0 obj
+% page stream
+<< /Length 4667 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 747.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Parallel computing with plac) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 633.0236 cm
+q
+BT 1 0 0 1 0 100.82 Tm 1.174751 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is certainly not intended as a tool for parallel computing, but still you can use it to launch a set of) Tj T* 0 Tw .494269 Tw (commands and to collect the results, similarly to the MapReduce pattern recently popularized by Google.) Tj T* 0 Tw .329431 Tw (In order to give an example, I will consider the "Hello World" of parallel computing, i.e. the computation of) Tj T* 0 Tw .229431 Tw (pi with independent processes. There is a huge number of algorithms to compute pi; here I will describe a) Tj T* 0 Tw .30683 Tw (trivial one chosen for simplicity, not per efficienty. The trick is to consider the first quadrant of a circle with) Tj T* 0 Tw .102488 Tw (radius 1 and to extract a number of points ) Tj /F4 10 Tf (\(x, y\) ) Tj /F1 10 Tf (with ) Tj /F4 10 Tf (x ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (y ) Tj /F1 10 Tf (random variables in the interval ) Tj /F4 10 Tf ([0,1]) Tj /F1 10 Tf (.) Tj T* 0 Tw .743876 Tw (The probability of extracting a number inside the quadrant \(i.e. with ) Tj /F4 10 Tf (x^2 + y^2 < 1) Tj /F1 10 Tf (\) is proportional to) Tj T* 0 Tw .725251 Tw (the area of the quadrant \(i.e. ) Tj /F4 10 Tf (pi/4) Tj /F1 10 Tf (\). The value of ) Tj /F4 10 Tf (pi ) Tj /F1 10 Tf (therefore can be extracted by multiplying by 4 the) Tj T* 0 Tw (ratio between the number of points in the quadrant versus the total number of points ) Tj /F4 10 Tf (N) Tj /F1 10 Tf (, for ) Tj /F4 10 Tf (N ) Tj /F1 10 Tf (large:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 527.8236 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 96 re B*
+Q
+q
+BT 1 0 0 1 0 77.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (def calc_pi\(N\):) Tj T* ( inside = 0) Tj T* ( for j in xrange\(N\):) Tj T* ( x, y = random\(\), random\(\)) Tj T* ( if x*x + y*y ) Tj (<) Tj ( 1:) Tj T* ( inside += 1) Tj T* ( return \(4.0 * inside\) / N) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 459.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 52.82 Tm /F1 10 Tf 12 TL .046654 Tw (The algorithm is trivially parallelizable: if you have n CPUs, you can compute pi n times with N/n iterations,) Tj T* 0 Tw 1.122488 Tw (sum the results and divide the total by n. I have a Macbook with two cores, therefore I would expect a) Tj T* 0 Tw 2.347984 Tw (speedup factor of 2 with respect to a sequential computation. Moreover, I would expect a threaded) Tj T* 0 Tw 2.827984 Tw (computation to be even slower than a sequential computation, due to the GIL and the scheduling) Tj T* 0 Tw (overhead.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 429.8236 cm
+q
+BT 1 0 0 1 0 16.82 Tm .313984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here is a script implementing the algorithm and working in three different modes \(parallel mode, threaded) Tj T* 0 Tw (mode and sequential mode\) depending on a ) Tj /F4 10 Tf (mode ) Tj /F1 10 Tf (option:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 96.62362 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 324 re B*
+Q
+q
+BT 1 0 0 1 0 305.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (from __future__ import with_statement) Tj T* (from random import random) Tj T* (import multiprocessing) Tj T* (import plac) Tj T* T* (class PiCalculator\(object\):) Tj T* ( """Compute pi in parallel with threads or processes""") Tj T* ( ) Tj T* ( @plac.annotations\() Tj T* ( npoints=\('number of integration points', 'positional', None, int\),) Tj T* ( mode=\('sequential|parallel|threaded', 'option', 'm', str, 'SPT'\)\)) Tj T* ( def __init__\(self, npoints, mode='S'\):) Tj T* ( self.npoints = npoints) Tj T* ( if mode == 'P':) Tj T* ( self.mpcommands = ['calc_pi']) Tj T* ( elif mode == 'T':) Tj T* ( self.thcommands = ['calc_pi']) Tj T* ( elif mode == 'S':) Tj T* ( self.commands = ['calc_pi']) Tj T* ( self.n_cpu = multiprocessing.cpu_count\(\)) Tj T* ( ) Tj T* ( def submit_tasks\(self\):) Tj T* ( self.i = plac.Interpreter\(self\).__enter__\(\) ) Tj T* ( return [self.i.submit\('calc_pi %d' % \(self.npoints / self.n_cpu\)\)) Tj T* ( for _ in range\(self.n_cpu\)]) Tj T* T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (41) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R453': class PDFStream
+453 0 obj
+% page stream
+<< /Length 3359 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 307.8236 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 456 re B*
+Q
+q
+BT 1 0 0 1 0 437.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( def close\(self\):) Tj T* ( self.i.close\(\)) Tj T* T* ( @plac.annotations\() Tj T* ( npoints=\('npoints', 'positional', None, int\)\)) Tj T* ( def calc_pi\(self, npoints\):) Tj T* ( counts = 0) Tj T* ( for j in xrange\(npoints\):) Tj T* ( n, r = divmod\(j, 1000000\)) Tj T* ( if r == 0:) Tj T* ( yield '%dM iterations' % n) Tj T* ( x, y = random\(\), random\(\)) Tj T* ( if x*x + y*y ) Tj (<) Tj ( 1:) Tj T* ( counts += 1) Tj T* ( yield \(4.0 * counts\)/npoints) Tj T* T* ( def run\(self\):) Tj T* ( tasks = self.i.tasks\(\)) Tj T* ( for t in tasks:) Tj T* ( t.run\(\)) Tj T* ( try:) Tj T* ( total = 0) Tj T* ( for task in tasks:) Tj T* ( total += task.result) Tj T* ( except: # the task was killed) Tj T* ( print tasks) Tj T* ( return) Tj T* ( return total / self.n_cpu) Tj T* T* (if __name__ == '__main__':) Tj T* ( pc = plac.call\(PiCalculator\)) Tj T* ( pc.submit_tasks\(\)) Tj T* ( try:) Tj T* ( import time; t0 = time.time\(\)) Tj T* ( print '%f in %f seconds ' % \(pc.run\(\), time.time\(\) - t0\)) Tj T* ( finally:) Tj T* ( pc.close\(\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 227.8236 cm
+q
+BT 1 0 0 1 0 64.82 Tm .381797 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice the ) Tj /F4 10 Tf (submit_tasks ) Tj /F1 10 Tf (method, which instantiates and initializes a ) Tj /F4 10 Tf (plac.Interpreter ) Tj /F1 10 Tf (object and) Tj T* 0 Tw 3.38152 Tw (submits a number of commands corresponding to the number of available CPUs. The ) Tj /F4 10 Tf (calc_pi) Tj T* 0 Tw 3.796651 Tw /F1 10 Tf (command yield a log message every million of interactions, just to monitor the progress of the) Tj T* 0 Tw 1.751318 Tw (computation. The ) Tj /F4 10 Tf (run ) Tj /F1 10 Tf (method starts all the submitted commands in parallel and sums the results. It) Tj T* 0 Tw 1.17104 Tw (returns the average value of ) Tj /F4 10 Tf (pi ) Tj /F1 10 Tf (after the slowest CPU has finished its job \(if the CPUs are equal and) Tj T* 0 Tw (equally busy they should finish more or less at the same time\).) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 209.8236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Here are the results on my old Macbook with Ubuntu 10.04 and Python 2.6, for 10 million of iterations:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 116.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 84 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL ($ python picalculator.py -mP 10000000) Tj T* (3.141904 in 5.744545 seconds) Tj T* ($ python picalculator.py -mT 10000000) Tj T* (3.141272 in 13.875645 seconds) Tj T* ($ python picalculator.py -mS 10000000) Tj T* (3.141586 in 11.353841 seconds) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (42) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R454': class PDFStream
+454 0 obj
+% page stream
+<< /Length 5571 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 741.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 16.82 Tm /F1 10 Tf 12 TL 1.711751 Tw (As you see using processes one gets a 2x speedup indeed, where the threaded mode is some 20%) Tj T* 0 Tw (slower than the sequential mode.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 711.0236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (The plac server) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 597.0236 cm
+q
+BT 1 0 0 1 0 100.82 Tm 1.258443 Tw 12 TL /F1 10 Tf 0 0 0 rg (A command-line oriented interface can be easily converted into a socket-based interface. Starting from) Tj T* 0 Tw .930574 Tw (release 0.7 plac features a builtin server which is able to accept commands from multiple clients and to) Tj T* 0 Tw .994692 Tw (execute them. The server works by instantiating a separate interpreter for each client, so that if a client) Tj T* 0 Tw 1.08784 Tw (interpreter dies for any reason the other interpreters keep working. To avoid external dependencies the) Tj T* 0 Tw .872209 Tw (server is based on the ) Tj /F4 10 Tf (asynchat ) Tj /F1 10 Tf (module in the standard library, but it would not be difficult to replace) Tj T* 0 Tw 2.386412 Tw (the server with a different one \(for instance, a Twisted server\). Since ) Tj /F4 10 Tf (asynchat) Tj /F1 10 Tf (-based servers are) Tj T* 0 Tw .755984 Tw (asynchronous, any blocking command in the interpreter should be run in a separated process or thread.) Tj T* 0 Tw 1.157633 Tw (The default port for the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (server is 2199, and the command to signal end-of-connection is EOF. For) Tj T* 0 Tw (instance, here is how you could manage remote import on a database \(say a SQLite db\):) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 467.8236 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 120 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 101.71 Tm /F4 10 Tf 12 TL (import plac) Tj T* (from importer2 import FakeImporter) Tj T* T* (def main\(port=2199\):) Tj T* ( main = FakeImporter\('dsn'\)) Tj T* ( plac.Interpreter\(main\).start_server\(port\)) Tj T* ( ) Tj T* (if __name__ == '__main__':) Tj T* ( plac.call\(main\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 447.8236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (You can connect to the server with ) Tj /F4 10 Tf (telnet ) Tj /F1 10 Tf (on port 2199, as follows:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 270.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 168 re B*
+Q
+q
+BT 1 0 0 1 0 149.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ($ telnet localhost 2199) Tj T* (Trying ::1...) Tj T* (Trying 127.0.0.1...) Tj T* (Connected to localhost.) Tj T* (Escape character is '^]'.) Tj T* (i) Tj (>) Tj ( import_file f1) Tj T* (i) Tj (>) Tj ( .list) Tj T* (<) Tj (ThreadedTask 1 [import_file f1] RUNNING) Tj (>) Tj T* (i) Tj (>) Tj ( .out) Tj T* (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* (i) Tj (>) Tj ( EOF) Tj T* (Connection closed by foreign host.) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 240.6236 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Summary) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 198.6236 cm
+q
+BT 1 0 0 1 0 28.82 Tm 2.203318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Once ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (claimed to be the easiest command-line arguments parser in the world. Having read this) Tj T* 0 Tw .673322 Tw (document you may think that it is not so easy after all. But it is a false impression. Actually the rules are) Tj T* 0 Tw (quite simple:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 192.6236 cm
+Q
+q
+1 0 0 1 62.69291 192.6236 cm
+Q
+q
+1 0 0 1 62.69291 174.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (1.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (if you want to implement a command-line script, use ) Tj /F4 10 Tf (plac.call) Tj /F1 10 Tf (;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 174.6236 cm
+Q
+q
+1 0 0 1 62.69291 174.6236 cm
+Q
+q
+1 0 0 1 62.69291 114.6236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 45 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (2.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 45 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (if you want to implement a command interpreter, use ) Tj /F4 10 Tf (plac.Interpreter) Tj /F1 10 Tf (:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 23 39 cm
+Q
+q
+1 0 0 1 23 39 cm
+Q
+q
+1 0 0 1 23 21 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (for an interactive interpreter, call the ) Tj /F4 10 Tf (.interact ) Tj /F1 10 Tf (method;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 23 21 cm
+Q
+q
+1 0 0 1 23 21 cm
+Q
+q
+1 0 0 1 23 3 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (for an batch interpreter, call the ) Tj /F4 10 Tf (.execute ) Tj /F1 10 Tf (method;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 23 3 cm
+Q
+q
+1 0 0 1 23 3 cm
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 114.6236 cm
+Q
+q
+1 0 0 1 62.69291 114.6236 cm
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (43) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R455': class PDFStream
+455 0 obj
+% page stream
+<< /Length 5394 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 735.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 15 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (3.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 16.82 Tm 5.126647 Tw 12 TL /F1 10 Tf 0 0 0 rg (for testing call the ) Tj /F4 10 Tf (Interpreter.check ) Tj /F1 10 Tf (method in the appropriate context or use the) Tj T* 0 Tw /F4 10 Tf (Interpreter.doctest ) Tj /F1 10 Tf (feature;) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 735.0236 cm
+Q
+q
+1 0 0 1 62.69291 735.0236 cm
+Q
+q
+1 0 0 1 62.69291 705.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 15 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (4.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.356457 Tw 12 TL /F1 10 Tf 0 0 0 rg (if you need to go at a lower level, you may need to call the ) Tj /F4 10 Tf (Interpreter.send ) Tj /F1 10 Tf (method which) Tj T* 0 Tw (returns a \(finished\) ) Tj /F4 10 Tf (Task ) Tj /F1 10 Tf (object.) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 705.0236 cm
+Q
+q
+1 0 0 1 62.69291 705.0236 cm
+Q
+q
+1 0 0 1 62.69291 675.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 15 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (5.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 16.82 Tm 1.469269 Tw 12 TL /F1 10 Tf 0 0 0 rg (long running command can be executed in the background as threads or processes: just declare) Tj T* 0 Tw (them in the lists ) Tj /F4 10 Tf (thcommands ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (mpcommands ) Tj /F1 10 Tf (respectively.) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 675.0236 cm
+Q
+q
+1 0 0 1 62.69291 675.0236 cm
+Q
+q
+1 0 0 1 62.69291 645.0236 cm
+0 0 0 rg
+BT /F3 10 Tf 12 TL ET
+q
+1 0 0 1 6 15 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 5.66 0 Td (6.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 3 cm
+q
+BT 1 0 0 1 0 16.82 Tm 2.171647 Tw 12 TL /F1 10 Tf 0 0 0 rg (the ) Tj /F4 10 Tf (.start_server ) Tj /F1 10 Tf (method starts an asynchronous server on the given port number \(default) Tj T* 0 Tw (2199\)) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 645.0236 cm
+Q
+q
+1 0 0 1 62.69291 645.0236 cm
+Q
+q
+1 0 0 1 62.69291 627.0236 cm
+q
+BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (Moreover, remember that ) Tj /F4 10 Tf (plac_runner.py ) Tj /F1 10 Tf (is your friend.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 598.6772 cm
+n 0 14.17323 m 469.8898 14.17323 l S
+Q
+q
+1 0 0 1 62.69291 568.6772 cm
+q
+BT 1 0 0 1 0 7.23 Tm 18 TL /F2 15 Tf 0 0 0 rg (Appendix: custom annotation objects) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 538.6772 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 508.6772 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 379.4772 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 120 re B*
+Q
+q
+0 0 0 rg
+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
+Q
+Q
+q
+1 0 0 1 62.69291 359.4772 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 182.2772 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 168 re B*
+Q
+q
+0 0 0 rg
+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
+Q
+Q
+q
+1 0 0 1 62.69291 162.2772 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
+Q
+Q
+q
+1 0 0 1 62.69291 93.07717 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 60 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 41.71 Tm /F4 10 Tf 12 TL (usage: example11.py [-h] i n [rest [rest ...]]) Tj T* T* (positional arguments:) Tj T* ( i This is an int) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (44) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R456': class PDFStream
+456 0 obj
+% page stream
+<< /Length 1103 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 691.8236 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 72 re B*
+Q
+q
+0 0 0 rg
+BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL ( n This is a float) Tj T* ( rest Other arguments) 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 647.8236 cm
+q
+BT 1 0 0 1 0 28.82 Tm .713516 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can go on and define ) Tj /F4 10 Tf (Option ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (Flag ) Tj /F1 10 Tf (classes, if you like. Using custom annotation objects you) Tj T* 0 Tw .17528 Tw (could do advanced things like extracting the annotations from a configuration file or from a database, but I) Tj T* 0 Tw (expect such use cases to be quite rare: the default mechanism should work pretty well for most users.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 56.69291 56.69291 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL 235.3849 0 Td (45) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R457': class PDFPageLabels
+457 0 obj
% Document Root
<< /Nums [ 0
- 204 0 R
+ 458 0 R
1
- 205 0 R
+ 459 0 R
2
- 206 0 R
+ 460 0 R
3
- 207 0 R
+ 461 0 R
4
- 208 0 R
+ 462 0 R
5
- 209 0 R
+ 463 0 R
6
- 210 0 R
+ 464 0 R
7
- 211 0 R
+ 465 0 R
8
- 212 0 R
+ 466 0 R
9
- 213 0 R
+ 467 0 R
10
- 214 0 R
+ 468 0 R
11
- 215 0 R
+ 469 0 R
12
- 216 0 R
+ 470 0 R
13
- 217 0 R
+ 471 0 R
14
- 218 0 R
+ 472 0 R
15
- 219 0 R
+ 473 0 R
16
- 220 0 R ] >>
-endobj
-% 'R204': class PDFPageLabel
-204 0 obj
+ 474 0 R
+ 17
+ 475 0 R
+ 18
+ 476 0 R
+ 19
+ 477 0 R
+ 20
+ 478 0 R
+ 21
+ 479 0 R
+ 22
+ 480 0 R
+ 23
+ 481 0 R
+ 24
+ 482 0 R
+ 25
+ 483 0 R
+ 26
+ 484 0 R
+ 27
+ 485 0 R
+ 28
+ 486 0 R
+ 29
+ 487 0 R
+ 30
+ 488 0 R
+ 31
+ 489 0 R
+ 32
+ 490 0 R
+ 33
+ 491 0 R
+ 34
+ 492 0 R
+ 35
+ 493 0 R
+ 36
+ 494 0 R
+ 37
+ 495 0 R
+ 38
+ 496 0 R
+ 39
+ 497 0 R
+ 40
+ 498 0 R
+ 41
+ 499 0 R
+ 42
+ 500 0 R
+ 43
+ 501 0 R
+ 44
+ 502 0 R ] >>
+endobj
+% 'R458': class PDFPageLabel
+458 0 obj
% None
<< /S /D
/St 1 >>
endobj
-% 'R205': class PDFPageLabel
-205 0 obj
+% 'R459': class PDFPageLabel
+459 0 obj
% None
<< /S /D
/St 2 >>
endobj
-% 'R206': class PDFPageLabel
-206 0 obj
+% 'R460': class PDFPageLabel
+460 0 obj
% None
<< /S /D
/St 3 >>
endobj
-% 'R207': class PDFPageLabel
-207 0 obj
+% 'R461': class PDFPageLabel
+461 0 obj
% None
<< /S /D
/St 4 >>
endobj
-% 'R208': class PDFPageLabel
-208 0 obj
+% 'R462': class PDFPageLabel
+462 0 obj
% None
<< /S /D
/St 5 >>
endobj
-% 'R209': class PDFPageLabel
-209 0 obj
+% 'R463': class PDFPageLabel
+463 0 obj
% None
<< /S /D
/St 6 >>
endobj
-% 'R210': class PDFPageLabel
-210 0 obj
+% 'R464': class PDFPageLabel
+464 0 obj
% None
<< /S /D
/St 7 >>
endobj
-% 'R211': class PDFPageLabel
-211 0 obj
+% 'R465': class PDFPageLabel
+465 0 obj
% None
<< /S /D
/St 8 >>
endobj
-% 'R212': class PDFPageLabel
-212 0 obj
+% 'R466': class PDFPageLabel
+466 0 obj
% None
<< /S /D
/St 9 >>
endobj
-% 'R213': class PDFPageLabel
-213 0 obj
+% 'R467': class PDFPageLabel
+467 0 obj
% None
<< /S /D
/St 10 >>
endobj
-% 'R214': class PDFPageLabel
-214 0 obj
+% 'R468': class PDFPageLabel
+468 0 obj
% None
<< /S /D
/St 11 >>
endobj
-% 'R215': class PDFPageLabel
-215 0 obj
+% 'R469': class PDFPageLabel
+469 0 obj
% None
<< /S /D
/St 12 >>
endobj
-% 'R216': class PDFPageLabel
-216 0 obj
+% 'R470': class PDFPageLabel
+470 0 obj
% None
<< /S /D
/St 13 >>
endobj
-% 'R217': class PDFPageLabel
-217 0 obj
+% 'R471': class PDFPageLabel
+471 0 obj
% None
<< /S /D
/St 14 >>
endobj
-% 'R218': class PDFPageLabel
-218 0 obj
+% 'R472': class PDFPageLabel
+472 0 obj
% None
<< /S /D
/St 15 >>
endobj
-% 'R219': class PDFPageLabel
-219 0 obj
+% 'R473': class PDFPageLabel
+473 0 obj
% None
<< /S /D
/St 16 >>
endobj
-% 'R220': class PDFPageLabel
-220 0 obj
+% 'R474': class PDFPageLabel
+474 0 obj
% None
<< /S /D
/St 17 >>
endobj
+% 'R475': class PDFPageLabel
+475 0 obj
+% None
+<< /S /D
+ /St 18 >>
+endobj
+% 'R476': class PDFPageLabel
+476 0 obj
+% None
+<< /S /D
+ /St 19 >>
+endobj
+% 'R477': class PDFPageLabel
+477 0 obj
+% None
+<< /S /D
+ /St 20 >>
+endobj
+% 'R478': class PDFPageLabel
+478 0 obj
+% None
+<< /S /D
+ /St 21 >>
+endobj
+% 'R479': class PDFPageLabel
+479 0 obj
+% None
+<< /S /D
+ /St 22 >>
+endobj
+% 'R480': class PDFPageLabel
+480 0 obj
+% None
+<< /S /D
+ /St 23 >>
+endobj
+% 'R481': class PDFPageLabel
+481 0 obj
+% None
+<< /S /D
+ /St 24 >>
+endobj
+% 'R482': class PDFPageLabel
+482 0 obj
+% None
+<< /S /D
+ /St 25 >>
+endobj
+% 'R483': class PDFPageLabel
+483 0 obj
+% None
+<< /S /D
+ /St 26 >>
+endobj
+% 'R484': class PDFPageLabel
+484 0 obj
+% None
+<< /S /D
+ /St 27 >>
+endobj
+% 'R485': class PDFPageLabel
+485 0 obj
+% None
+<< /S /D
+ /St 28 >>
+endobj
+% 'R486': class PDFPageLabel
+486 0 obj
+% None
+<< /S /D
+ /St 29 >>
+endobj
+% 'R487': class PDFPageLabel
+487 0 obj
+% None
+<< /S /D
+ /St 30 >>
+endobj
+% 'R488': class PDFPageLabel
+488 0 obj
+% None
+<< /S /D
+ /St 31 >>
+endobj
+% 'R489': class PDFPageLabel
+489 0 obj
+% None
+<< /S /D
+ /St 32 >>
+endobj
+% 'R490': class PDFPageLabel
+490 0 obj
+% None
+<< /S /D
+ /St 33 >>
+endobj
+% 'R491': class PDFPageLabel
+491 0 obj
+% None
+<< /S /D
+ /St 34 >>
+endobj
+% 'R492': class PDFPageLabel
+492 0 obj
+% None
+<< /S /D
+ /St 35 >>
+endobj
+% 'R493': class PDFPageLabel
+493 0 obj
+% None
+<< /S /D
+ /St 36 >>
+endobj
+% 'R494': class PDFPageLabel
+494 0 obj
+% None
+<< /S /D
+ /St 37 >>
+endobj
+% 'R495': class PDFPageLabel
+495 0 obj
+% None
+<< /S /D
+ /St 38 >>
+endobj
+% 'R496': class PDFPageLabel
+496 0 obj
+% None
+<< /S /D
+ /St 39 >>
+endobj
+% 'R497': class PDFPageLabel
+497 0 obj
+% None
+<< /S /D
+ /St 40 >>
+endobj
+% 'R498': class PDFPageLabel
+498 0 obj
+% None
+<< /S /D
+ /St 41 >>
+endobj
+% 'R499': class PDFPageLabel
+499 0 obj
+% None
+<< /S /D
+ /St 42 >>
+endobj
+% 'R500': class PDFPageLabel
+500 0 obj
+% None
+<< /S /D
+ /St 43 >>
+endobj
+% 'R501': class PDFPageLabel
+501 0 obj
+% None
+<< /S /D
+ /St 44 >>
+endobj
+% 'R502': class PDFPageLabel
+502 0 obj
+% None
+<< /S /D
+ /St 45 >>
+endobj
xref
-0 221
+0 503
0000000000 65535 f
0000000113 00000 n
0000000258 00000 n
@@ -6116,226 +14681,508 @@ xref
0000001031 00000 n
0000001281 00000 n
0000001539 00000 n
-0000001713 00000 n
-0000001954 00000 n
-0000002196 00000 n
-0000002438 00000 n
-0000002680 00000 n
-0000002922 00000 n
-0000003165 00000 n
-0000003408 00000 n
-0000003651 00000 n
-0000003894 00000 n
-0000004137 00000 n
-0000004380 00000 n
-0000004623 00000 n
-0000004866 00000 n
-0000005109 00000 n
-0000005352 00000 n
-0000005595 00000 n
-0000005838 00000 n
-0000006081 00000 n
-0000006324 00000 n
-0000006567 00000 n
-0000006811 00000 n
-0000007055 00000 n
-0000007299 00000 n
-0000007543 00000 n
-0000007787 00000 n
-0000008031 00000 n
-0000008275 00000 n
-0000008518 00000 n
-0000008780 00000 n
-0000009043 00000 n
-0000009293 00000 n
-0000009542 00000 n
-0000009808 00000 n
-0000010060 00000 n
-0000010310 00000 n
-0000010562 00000 n
-0000010812 00000 n
-0000011064 00000 n
-0000011299 00000 n
-0000011982 00000 n
-0000012234 00000 n
-0000012485 00000 n
-0000012724 00000 n
-0000012919 00000 n
-0000013180 00000 n
-0000013444 00000 n
-0000013678 00000 n
-0000014041 00000 n
-0000014293 00000 n
-0000014545 00000 n
-0000014796 00000 n
-0000015046 00000 n
-0000015298 00000 n
-0000015535 00000 n
-0000015898 00000 n
-0000016147 00000 n
-0000016399 00000 n
-0000016636 00000 n
-0000016972 00000 n
-0000017224 00000 n
-0000017476 00000 n
-0000017762 00000 n
-0000018014 00000 n
-0000018302 00000 n
-0000018590 00000 n
-0000018827 00000 n
-0000019199 00000 n
-0000019436 00000 n
-0000019754 00000 n
-0000019991 00000 n
-0000020309 00000 n
-0000020546 00000 n
-0000020864 00000 n
-0000021116 00000 n
-0000021368 00000 n
-0000021618 00000 n
-0000021868 00000 n
-0000022118 00000 n
-0000022370 00000 n
-0000022605 00000 n
-0000022963 00000 n
-0000023260 00000 n
-0000023512 00000 n
-0000023758 00000 n
-0000024021 00000 n
-0000024357 00000 n
-0000024609 00000 n
-0000024846 00000 n
-0000025173 00000 n
-0000025411 00000 n
-0000025729 00000 n
-0000025980 00000 n
-0000026219 00000 n
-0000026549 00000 n
-0000026801 00000 n
-0000027052 00000 n
-0000027303 00000 n
-0000027554 00000 n
-0000027807 00000 n
-0000028058 00000 n
-0000028309 00000 n
-0000028562 00000 n
-0000028815 00000 n
-0000029066 00000 n
-0000029319 00000 n
-0000029570 00000 n
-0000029822 00000 n
-0000030075 00000 n
-0000030353 00000 n
-0000030606 00000 n
-0000030860 00000 n
-0000031138 00000 n
-0000031417 00000 n
-0000031671 00000 n
-0000031908 00000 n
-0000032429 00000 n
-0000032747 00000 n
-0000033001 00000 n
-0000033290 00000 n
-0000033542 00000 n
-0000033794 00000 n
-0000034048 00000 n
-0000034302 00000 n
-0000034541 00000 n
-0000034932 00000 n
-0000035191 00000 n
-0000035448 00000 n
-0000035700 00000 n
-0000035954 00000 n
-0000036212 00000 n
-0000036464 00000 n
-0000036722 00000 n
-0000036976 00000 n
-0000037229 00000 n
-0000037490 00000 n
-0000037744 00000 n
-0000037998 00000 n
-0000038252 00000 n
-0000038506 00000 n
-0000038758 00000 n
-0000039010 00000 n
-0000039263 00000 n
-0000039517 00000 n
-0000039771 00000 n
-0000040025 00000 n
-0000040279 00000 n
-0000040558 00000 n
-0000040811 00000 n
-0000041101 00000 n
-0000041355 00000 n
-0000041666 00000 n
-0000041918 00000 n
-0000042170 00000 n
-0000042459 00000 n
-0000042711 00000 n
-0000042963 00000 n
-0000043221 00000 n
-0000043460 00000 n
-0000044087 00000 n
-0000044251 00000 n
-0000044525 00000 n
-0000044654 00000 n
-0000044848 00000 n
-0000045059 00000 n
-0000045269 00000 n
-0000045491 00000 n
-0000045689 00000 n
-0000045894 00000 n
-0000046087 00000 n
-0000046286 00000 n
-0000046483 00000 n
-0000046697 00000 n
-0000046895 00000 n
-0000047106 00000 n
-0000047298 00000 n
-0000047481 00000 n
-0000047740 00000 n
-0000057184 00000 n
-0000062208 00000 n
-0000066505 00000 n
-0000070607 00000 n
-0000075384 00000 n
-0000079621 00000 n
-0000084215 00000 n
-0000089383 00000 n
-0000094820 00000 n
-0000099434 00000 n
-0000103773 00000 n
-0000107299 00000 n
-0000111491 00000 n
-0000118389 00000 n
-0000125696 00000 n
-0000132659 00000 n
-0000140991 00000 n
-0000141318 00000 n
-0000141397 00000 n
-0000141476 00000 n
-0000141555 00000 n
-0000141634 00000 n
-0000141713 00000 n
-0000141792 00000 n
-0000141871 00000 n
-0000141950 00000 n
-0000142029 00000 n
-0000142109 00000 n
-0000142189 00000 n
-0000142269 00000 n
-0000142349 00000 n
-0000142429 00000 n
-0000142509 00000 n
-0000142589 00000 n
+0000001698 00000 n
+0000002030 00000 n
+0000002271 00000 n
+0000002512 00000 n
+0000002754 00000 n
+0000002996 00000 n
+0000003238 00000 n
+0000003481 00000 n
+0000003725 00000 n
+0000003969 00000 n
+0000004213 00000 n
+0000004457 00000 n
+0000004701 00000 n
+0000004945 00000 n
+0000005189 00000 n
+0000005433 00000 n
+0000005677 00000 n
+0000005921 00000 n
+0000006165 00000 n
+0000006409 00000 n
+0000006653 00000 n
+0000006897 00000 n
+0000007141 00000 n
+0000007385 00000 n
+0000007629 00000 n
+0000007873 00000 n
+0000008117 00000 n
+0000008361 00000 n
+0000008605 00000 n
+0000008849 00000 n
+0000009093 00000 n
+0000009337 00000 n
+0000009581 00000 n
+0000009825 00000 n
+0000010069 00000 n
+0000010313 00000 n
+0000010557 00000 n
+0000010801 00000 n
+0000011045 00000 n
+0000011289 00000 n
+0000011533 00000 n
+0000011777 00000 n
+0000012021 00000 n
+0000012265 00000 n
+0000012509 00000 n
+0000012753 00000 n
+0000012997 00000 n
+0000013241 00000 n
+0000013485 00000 n
+0000013729 00000 n
+0000013973 00000 n
+0000014217 00000 n
+0000014461 00000 n
+0000014705 00000 n
+0000014949 00000 n
+0000015193 00000 n
+0000015437 00000 n
+0000015681 00000 n
+0000015925 00000 n
+0000016169 00000 n
+0000016413 00000 n
+0000016657 00000 n
+0000016901 00000 n
+0000017145 00000 n
+0000017389 00000 n
+0000017633 00000 n
+0000017877 00000 n
+0000018121 00000 n
+0000018365 00000 n
+0000018609 00000 n
+0000018853 00000 n
+0000019081 00000 n
+0000020020 00000 n
+0000020282 00000 n
+0000020545 00000 n
+0000020795 00000 n
+0000021044 00000 n
+0000021310 00000 n
+0000021562 00000 n
+0000021812 00000 n
+0000022064 00000 n
+0000022314 00000 n
+0000022566 00000 n
+0000022816 00000 n
+0000023068 00000 n
+0000023319 00000 n
+0000023558 00000 n
+0000023738 00000 n
+0000024173 00000 n
+0000024434 00000 n
+0000024698 00000 n
+0000024947 00000 n
+0000025200 00000 n
+0000025453 00000 n
+0000025705 00000 n
+0000025956 00000 n
+0000026209 00000 n
+0000026447 00000 n
+0000026844 00000 n
+0000027094 00000 n
+0000027347 00000 n
+0000027585 00000 n
+0000027926 00000 n
+0000028180 00000 n
+0000028434 00000 n
+0000028706 00000 n
+0000029047 00000 n
+0000029301 00000 n
+0000029591 00000 n
+0000029881 00000 n
+0000030135 00000 n
+0000030373 00000 n
+0000030718 00000 n
+0000031017 00000 n
+0000031271 00000 n
+0000031509 00000 n
+0000031840 00000 n
+0000032094 00000 n
+0000032348 00000 n
+0000032600 00000 n
+0000032852 00000 n
+0000033104 00000 n
+0000033358 00000 n
+0000033595 00000 n
+0000033961 00000 n
+0000034260 00000 n
+0000034514 00000 n
+0000034762 00000 n
+0000035026 00000 n
+0000035367 00000 n
+0000035621 00000 n
+0000035859 00000 n
+0000036190 00000 n
+0000036429 00000 n
+0000036750 00000 n
+0000037002 00000 n
+0000037241 00000 n
+0000037572 00000 n
+0000037825 00000 n
+0000038077 00000 n
+0000038329 00000 n
+0000038581 00000 n
+0000038835 00000 n
+0000039087 00000 n
+0000039339 00000 n
+0000039593 00000 n
+0000039847 00000 n
+0000040099 00000 n
+0000040353 00000 n
+0000040605 00000 n
+0000040843 00000 n
+0000041284 00000 n
+0000041538 00000 n
+0000041817 00000 n
+0000042071 00000 n
+0000042325 00000 n
+0000042603 00000 n
+0000042882 00000 n
+0000043136 00000 n
+0000043388 00000 n
+0000043706 00000 n
+0000043960 00000 n
+0000044249 00000 n
+0000044501 00000 n
+0000044753 00000 n
+0000044992 00000 n
+0000045443 00000 n
+0000045697 00000 n
+0000045951 00000 n
+0000046210 00000 n
+0000046467 00000 n
+0000046719 00000 n
+0000046973 00000 n
+0000047231 00000 n
+0000047483 00000 n
+0000047741 00000 n
+0000047995 00000 n
+0000048248 00000 n
+0000048509 00000 n
+0000048763 00000 n
+0000049017 00000 n
+0000049271 00000 n
+0000049525 00000 n
+0000049777 00000 n
+0000050029 00000 n
+0000050282 00000 n
+0000050536 00000 n
+0000050790 00000 n
+0000051044 00000 n
+0000051298 00000 n
+0000051577 00000 n
+0000051830 00000 n
+0000052120 00000 n
+0000052374 00000 n
+0000052685 00000 n
+0000052937 00000 n
+0000053189 00000 n
+0000053478 00000 n
+0000053730 00000 n
+0000053967 00000 n
+0000054608 00000 n
+0000054866 00000 n
+0000055120 00000 n
+0000055376 00000 n
+0000055630 00000 n
+0000055889 00000 n
+0000056251 00000 n
+0000056495 00000 n
+0000056739 00000 n
+0000056984 00000 n
+0000057229 00000 n
+0000057474 00000 n
+0000057719 00000 n
+0000057965 00000 n
+0000058211 00000 n
+0000058457 00000 n
+0000058703 00000 n
+0000058949 00000 n
+0000059195 00000 n
+0000059441 00000 n
+0000059687 00000 n
+0000059933 00000 n
+0000060179 00000 n
+0000060425 00000 n
+0000060671 00000 n
+0000060917 00000 n
+0000061163 00000 n
+0000061409 00000 n
+0000061655 00000 n
+0000061901 00000 n
+0000062147 00000 n
+0000062393 00000 n
+0000062639 00000 n
+0000062885 00000 n
+0000063131 00000 n
+0000063377 00000 n
+0000063623 00000 n
+0000063869 00000 n
+0000064115 00000 n
+0000064361 00000 n
+0000064607 00000 n
+0000064853 00000 n
+0000065099 00000 n
+0000065345 00000 n
+0000065591 00000 n
+0000065837 00000 n
+0000066083 00000 n
+0000066329 00000 n
+0000066575 00000 n
+0000066821 00000 n
+0000067067 00000 n
+0000067313 00000 n
+0000067559 00000 n
+0000067805 00000 n
+0000068051 00000 n
+0000068297 00000 n
+0000068543 00000 n
+0000068789 00000 n
+0000069035 00000 n
+0000069281 00000 n
+0000069527 00000 n
+0000069773 00000 n
+0000070019 00000 n
+0000070265 00000 n
+0000070511 00000 n
+0000070757 00000 n
+0000071003 00000 n
+0000071249 00000 n
+0000071495 00000 n
+0000071741 00000 n
+0000071987 00000 n
+0000072233 00000 n
+0000072479 00000 n
+0000072725 00000 n
+0000072971 00000 n
+0000073217 00000 n
+0000073447 00000 n
+0000074458 00000 n
+0000074712 00000 n
+0000074966 00000 n
+0000075220 00000 n
+0000075474 00000 n
+0000075728 00000 n
+0000075973 00000 n
+0000076227 00000 n
+0000076481 00000 n
+0000076735 00000 n
+0000076989 00000 n
+0000077248 00000 n
+0000077669 00000 n
+0000077908 00000 n
+0000078214 00000 n
+0000078513 00000 n
+0000078767 00000 n
+0000079021 00000 n
+0000079275 00000 n
+0000079537 00000 n
+0000079791 00000 n
+0000080054 00000 n
+0000080307 00000 n
+0000080555 00000 n
+0000080946 00000 n
+0000081200 00000 n
+0000081454 00000 n
+0000081707 00000 n
+0000081945 00000 n
+0000082296 00000 n
+0000082570 00000 n
+0000082824 00000 n
+0000083078 00000 n
+0000083317 00000 n
+0000083668 00000 n
+0000083922 00000 n
+0000084176 00000 n
+0000084422 00000 n
+0000084748 00000 n
+0000085032 00000 n
+0000085331 00000 n
+0000085585 00000 n
+0000085843 00000 n
+0000086097 00000 n
+0000086365 00000 n
+0000086619 00000 n
+0000086858 00000 n
+0000087229 00000 n
+0000087490 00000 n
+0000087751 00000 n
+0000088003 00000 n
+0000088256 00000 n
+0000088508 00000 n
+0000088762 00000 n
+0000089016 00000 n
+0000089270 00000 n
+0000089524 00000 n
+0000089764 00000 n
+0000090175 00000 n
+0000090412 00000 n
+0000090733 00000 n
+0000090972 00000 n
+0000091278 00000 n
+0000091577 00000 n
+0000091815 00000 n
+0000092136 00000 n
+0000092390 00000 n
+0000092663 00000 n
+0000092902 00000 n
+0000093243 00000 n
+0000093497 00000 n
+0000093736 00000 n
+0000094052 00000 n
+0000094351 00000 n
+0000094605 00000 n
+0000094863 00000 n
+0000095194 00000 n
+0000095433 00000 n
+0000095754 00000 n
+0000095993 00000 n
+0000096299 00000 n
+0000096598 00000 n
+0000096852 00000 n
+0000097091 00000 n
+0000097422 00000 n
+0000097661 00000 n
+0000097967 00000 n
+0000098252 00000 n
+0000098416 00000 n
+0000098630 00000 n
+0000098759 00000 n
+0000099013 00000 n
+0000099210 00000 n
+0000099424 00000 n
+0000099638 00000 n
+0000099864 00000 n
+0000100066 00000 n
+0000100275 00000 n
+0000100472 00000 n
+0000100675 00000 n
+0000100876 00000 n
+0000101094 00000 n
+0000101295 00000 n
+0000101509 00000 n
+0000101704 00000 n
+0000101902 00000 n
+0000102138 00000 n
+0000102318 00000 n
+0000102542 00000 n
+0000102752 00000 n
+0000102951 00000 n
+0000103153 00000 n
+0000103361 00000 n
+0000103566 00000 n
+0000103766 00000 n
+0000103965 00000 n
+0000104175 00000 n
+0000104388 00000 n
+0000104594 00000 n
+0000104796 00000 n
+0000105019 00000 n
+0000105246 00000 n
+0000105459 00000 n
+0000105659 00000 n
+0000105851 00000 n
+0000106036 00000 n
+0000106584 00000 n
+0000109681 00000 n
+0000119378 00000 n
+0000125466 00000 n
+0000130017 00000 n
+0000134170 00000 n
+0000138174 00000 n
+0000143296 00000 n
+0000147717 00000 n
+0000152736 00000 n
+0000158684 00000 n
+0000162939 00000 n
+0000167340 00000 n
+0000171005 00000 n
+0000175405 00000 n
+0000182103 00000 n
+0000188470 00000 n
+0000196135 00000 n
+0000204440 00000 n
+0000208856 00000 n
+0000218554 00000 n
+0000224071 00000 n
+0000228242 00000 n
+0000234153 00000 n
+0000240252 00000 n
+0000245932 00000 n
+0000250331 00000 n
+0000254759 00000 n
+0000259619 00000 n
+0000264256 00000 n
+0000269533 00000 n
+0000274287 00000 n
+0000278955 00000 n
+0000284039 00000 n
+0000288033 00000 n
+0000293790 00000 n
+0000298776 00000 n
+0000303504 00000 n
+0000308728 00000 n
+0000313591 00000 n
+0000317446 00000 n
+0000322216 00000 n
+0000325678 00000 n
+0000331352 00000 n
+0000336849 00000 n
+0000338059 00000 n
+0000338806 00000 n
+0000338885 00000 n
+0000338964 00000 n
+0000339043 00000 n
+0000339122 00000 n
+0000339201 00000 n
+0000339280 00000 n
+0000339359 00000 n
+0000339438 00000 n
+0000339517 00000 n
+0000339597 00000 n
+0000339677 00000 n
+0000339757 00000 n
+0000339837 00000 n
+0000339917 00000 n
+0000339997 00000 n
+0000340077 00000 n
+0000340157 00000 n
+0000340237 00000 n
+0000340317 00000 n
+0000340397 00000 n
+0000340477 00000 n
+0000340557 00000 n
+0000340637 00000 n
+0000340717 00000 n
+0000340797 00000 n
+0000340877 00000 n
+0000340957 00000 n
+0000341037 00000 n
+0000341117 00000 n
+0000341197 00000 n
+0000341277 00000 n
+0000341357 00000 n
+0000341437 00000 n
+0000341517 00000 n
+0000341597 00000 n
+0000341677 00000 n
+0000341757 00000 n
+0000341837 00000 n
+0000341917 00000 n
+0000341997 00000 n
+0000342077 00000 n
+0000342157 00000 n
+0000342237 00000 n
+0000342317 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(h\344_g\030\351%P\347\313k\017\322\274~\366) (h\344_g\030\351%P\347\313k\017\322\274~\366)]
+ [(A\305\006\345,=\244\353v\354H\363\3127\016\356) (A\305\006\345,=\244\353v\354H\363\3127\016\356)]
- /Info 169 0 R
- /Root 168 0 R
- /Size 221 >>
+ /Info 374 0 R
+ /Root 373 0 R
+ /Size 503 >>
startxref
-142638
+342366
%%EOF
diff --git a/plac/doc/plac.txt b/plac/doc/plac_core.txt
index ab797b6..ab797b6 100644
--- a/plac/doc/plac.txt
+++ b/plac/doc/plac_core.txt
diff --git a/plac/plac.py b/plac/plac.py
index 9aed3a7..0b1c3bd 100644
--- a/plac/plac.py
+++ b/plac/plac.py
@@ -27,7 +27,7 @@
See doc/plac.pdf, doc/plac_adv.pdf for the documentation.
"""
-__version__ = '0.7.0'
+__version__ = '0.7.1'
from plac_core import *
diff --git a/plac/plac_core.py b/plac/plac_core.py
index 2237cab..fbd63b8 100644
--- a/plac/plac_core.py
+++ b/plac/plac_core.py
@@ -94,14 +94,12 @@ def parser_from(obj, **confparams):
conf = pconf(obj).copy()
conf.update(confparams)
parser_registry[obj] = parser = ArgumentParser(**conf)
+ parser.obj = obj
parser.case_sensitive = confparams.get(
'case_sensitive', getattr(obj, 'case_sensitive', True))
if hasattr(obj, 'commands') and obj.commands and not inspect.isclass(obj):
# a command container instance
parser.addsubcommands(obj.commands, obj, 'subcommands')
- parser.missing = getattr(
- obj, '__missing__',
- lambda name: parser.error('No command %r' % name))
else:
parser.populate_from(obj)
return parser
@@ -160,7 +158,7 @@ class ArgumentParser(argparse.ArgumentParser):
# ignore unrecognized arguments
ns, extraopts = self.parse_known_args(arglist)
else:
- ns, extraopts = self.parse_args(arglist), []
+ ns, extraopts = self.parse_args(arglist), [] # may raise an exit
args = [getattr(ns, a) for a in self.argspec.args]
varargs = getattr(ns, self.argspec.varargs or '', [])
collision = set(self.argspec.args) & set(kwargs)
@@ -203,7 +201,10 @@ class ArgumentParser(argparse.ArgumentParser):
self.argspec = getfullargspec(obj)
del self.argspec.args[0] # remove first argument
elif inspect.isclass(obj):
- self.argspec = getfullargspec(obj.__init__)
+ if obj.__init__ is object.__init__: # to avoid an error
+ self.argspec = getfullargspec(lambda self: None)
+ else:
+ self.argspec = getfullargspec(obj.__init__)
del self.argspec.args[0] # remove first argument
elif hasattr(obj, '__call__'):
self.argspec = getfullargspec(obj.__call__)
@@ -265,6 +266,11 @@ class ArgumentParser(argparse.ArgumentParser):
self.add_argument(f.varkw, nargs='*', help=a.help, default={},
type=a.type, metavar=a.metavar)
+ def missing(self, name):
+ miss = getattr(self.obj, '__missing__', lambda name:
+ self.error('No command %r' % name))
+ return miss(name)
+
def help_cmd(self, cmd):
"Return the help message for a subcommand"
p = self.subparsers._name_parser_map.get(cmd)
diff --git a/plac/plac_ext.py b/plac/plac_ext.py
index e175514..7a4e528 100644
--- a/plac/plac_ext.py
+++ b/plac/plac_ext.py
@@ -142,12 +142,12 @@ except:
def import_main(path, *args, **pconf):
"""
An utility to import the main function of a plac tool. It also
- works with tool factories, if you pass the arguments.
+ works with command container factories.
"""
- if ':' in path:
- path, main_name = path.split(':')
- else:
- main_name = 'main'
+ if ':' in path: # importing a factory
+ path, factory_name = path.split(':')
+ else: # importing the main function
+ factory_name = None
if not os.path.isabs(path): # relative path, look at PLACDIRS
for placdir in PLACDIRS:
fullpath = os.path.join(placdir, path)
@@ -159,12 +159,11 @@ def import_main(path, *args, **pconf):
fullpath = path
name, ext = os.path.splitext(os.path.basename(fullpath))
module = imp.load_module(name, open(fullpath), fullpath, (ext, 'U', 1))
- main = getattr(module, main_name)
- if args:
- cmd, tool = plac_core.parser_from(main).consume(args)
+ if factory_name:
+ tool = plac_core.call(getattr(module, factory_name), args)
else:
- tool = main
- # set the parser configuration and possibly raise a TypeError early
+ tool = module.main
+ # set the parser configuration
plac_core.parser_from(tool, **pconf)
return tool
@@ -259,6 +258,8 @@ class BaseTask(object):
self.__class__.__name__, self.no,
' '.join(self.arglist), self.status)
+nulltask = BaseTask(0, [], ('skip' for dummy in (1,)))
+
########################## synchronous tasks ###############################
class SynTask(BaseTask):
@@ -591,21 +592,23 @@ class Interpreter(object):
"""
@classmethod
- def call(cls, factory, arglist=sys.argv[1:],
- commentchar='#', split=shlex.split,
- stdin=sys.stdin, prompt='i> ', verbose=False):
- """Call a container factory with the arglist and instantiate an
- interpreter object. If there are remaining arguments, send them to the
- interpreter, else start an interactive session"""
+ def instance(cls, factory, arglist=sys.argv[1:],
+ commentchar='#', split=shlex.split):
+ """
+ Call a container factory with the arglist and return an
+ interpreter object.
+ """
a = plac_core.parser_from(factory).argspec
if a.defaults or a.varargs or a.varkw:
raise TypeError('Interpreter.call must be invoked on '
'factories with required arguments only')
required_args = ', '.join(a.args)
- code = '''def makeobj(%s, *args):
+ if required_args:
+ required_args += ',' # trailing comma
+ code = '''def makeobj(%s *args):
obj = factory(%s)
obj.args = args
- return obj'''% (required_args, required_args)
+ return obj\n'''% (required_args, required_args)
dic = dict(factory=factory)
exec code in dic
makeobj = dic['makeobj']
@@ -616,16 +619,27 @@ class Interpreter(object):
makeobj.__annotations__ = getattr(
factory, '__annotations__', {})
obj = plac_core.call(makeobj, arglist)
- i = cls(obj, commentchar, split) # interpreter
- if obj.args:
+ return cls(obj, commentchar, split) # interpreter
+
+ @classmethod
+ def call(cls, factory, arglist=sys.argv[1:],
+ commentchar='#', split=shlex.split,
+ stdin=sys.stdin, prompt='i> ', verbose=False):
+ """
+ Call a container factory with the arglist and instantiate an
+ interpreter object. If there are remaining arguments, send them to the
+ interpreter, else start an interactive session.
+ """
+ i = cls.instance(factory, arglist, commentchar, split)
+ if i.obj.args:
with i:
- task = i.send(obj.args) # synchronous
+ task = i.send(i.obj.args) # synchronous
if task.exc:
raise task.etype, task.exc, task.tb
print(task)
else:
i.interact(stdin, prompt, verbose)
-
+
def __init__(self, obj, commentchar='#', split=shlex.split):
self.obj = obj
try:
@@ -685,9 +699,10 @@ class Interpreter(object):
arglist = self.split(line, self.commentchar)
else: # expects a list of strings
arglist = line
+ if not arglist:
+ return nulltask
task = self._interpreter.send(arglist) # nonblocking
- if arglist and not plac_core._match_cmd(
- arglist[0], self.tm.specialcommands):
+ if not plac_core._match_cmd(arglist[0], self.tm.specialcommands):
self.tm.registry[task.no] = task
return task