summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2010-08-07 08:36:23 +0200
committerMichele Simionato <michele.simionato@gmail.com>2010-08-07 08:36:23 +0200
commit4d370234721062eb9191f91a2ea22cb03230891e (patch)
treebab0db3d74efe28b475778d528af1e36fb68dcfb
parent9fa4477827d818fc81a3b20c799eb1f0f06a5d1e (diff)
downloadmicheles-4d370234721062eb9191f91a2ea22cb03230891e.tar.gz
Final fixes for plac 0.7 (and added plac.Interpreter.call)
-rw-r--r--plac/CHANGES.txt3
-rw-r--r--plac/doc/importer1.py2
-rw-r--r--plac/doc/importer2.py2
-rw-r--r--plac/doc/importer3.py2
-rw-r--r--plac/doc/ishelve2.help4
-rw-r--r--plac/doc/ishelve2.py5
-rw-r--r--plac/doc/ishelve3.help8
-rw-r--r--plac/doc/ishelve3.py5
-rw-r--r--plac/doc/plac_adv.html294
-rw-r--r--plac/doc/plac_adv.pdf3521
-rw-r--r--plac/doc/plac_adv.txt143
-rw-r--r--plac/doc/sql_interface.py5
-rw-r--r--plac/doc/test_plac.py1
-rw-r--r--plac/doc/test_server.py2
-rw-r--r--plac/plac_ext.py41
15 files changed, 2084 insertions, 1954 deletions
diff --git a/plac/CHANGES.txt b/plac/CHANGES.txt
index 9d1414a..fb7fa04 100644
--- a/plac/CHANGES.txt
+++ b/plac/CHANGES.txt
@@ -2,8 +2,7 @@ HISTORY
----------
0.7.0 Improved and documented the support for parallel programming;
- added multiline and emacs support; added an asynchronous server
- (2010-08-XX)
+ 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
function; added two forgotten files; added a reference to cmd2 by
Catherine Devlin (2010-07-12)
diff --git a/plac/doc/importer1.py b/plac/doc/importer1.py
index 43e6833..233f910 100644
--- a/plac/doc/importer1.py
+++ b/plac/doc/importer1.py
@@ -17,4 +17,4 @@ class FakeImporter(object):
print('closing the file')
if __name__ == '__main__':
- plac.Interpreter(plac.call(FakeImporter)).interact()
+ plac.Interpreter.call(FakeImporter)
diff --git a/plac/doc/importer2.py b/plac/doc/importer2.py
index b448aa6..61a99b1 100644
--- a/plac/doc/importer2.py
+++ b/plac/doc/importer2.py
@@ -19,4 +19,4 @@ class FakeImporter(object):
print('closing the file')
if __name__ == '__main__':
- plac.Interpreter(plac.call(FakeImporter)).interact()
+ plac.Interpreter.call(FakeImporter)
diff --git a/plac/doc/importer3.py b/plac/doc/importer3.py
index fb3aee5..2a47e99 100644
--- a/plac/doc/importer3.py
+++ b/plac/doc/importer3.py
@@ -17,4 +17,4 @@ class FakeImporter(object):
print('closing the file')
if __name__ == '__main__':
- plac.Interpreter(plac.call(FakeImporter)).interact()
+ plac.Interpreter.call(FakeImporter)
diff --git a/plac/doc/ishelve2.help b/plac/doc/ishelve2.help
index 2ce64db..ade74c0 100644
--- a/plac/doc/ishelve2.help
+++ b/plac/doc/ishelve2.help
@@ -1,8 +1,8 @@
-usage: ishelve2.py [-h] [-configfile ~/conf.shelve]
+usage: ishelve2.py [-h] [-configfile CONFIGFILE]
A minimal interface over a shelve object.
optional arguments:
-h, --help show this help message and exit
- -configfile ~/conf.shelve
+ -configfile CONFIGFILE
path name of the shelve
diff --git a/plac/doc/ishelve2.py b/plac/doc/ishelve2.py
index baef210..fffa0b4 100644
--- a/plac/doc/ishelve2.py
+++ b/plac/doc/ishelve2.py
@@ -6,8 +6,9 @@ class ShelveInterface(object):
commands = 'set', 'show', 'showall', 'delete'
@plac.annotations(
configfile=('path name of the shelve', 'option'))
- def __init__(self, configfile='~/conf.shelve'):
- self.fname = os.path.expanduser(configfile)
+ 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):
diff --git a/plac/doc/ishelve3.help b/plac/doc/ishelve3.help
new file mode 100644
index 0000000..018cd02
--- /dev/null
+++ b/plac/doc/ishelve3.help
@@ -0,0 +1,8 @@
+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
diff --git a/plac/doc/ishelve3.py b/plac/doc/ishelve3.py
new file mode 100644
index 0000000..c37178b
--- /dev/null
+++ b/plac/doc/ishelve3.py
@@ -0,0 +1,5 @@
+# ishelve3.py
+from ishelve2 import ShelveInterface as main
+
+if __name__ == '__main__':
+ import plac; plac.Interpreter.call(main)
diff --git a/plac/doc/plac_adv.html b/plac/doc/plac_adv.html
index 45328f4..cae35d1 100644
--- a/plac/doc/plac_adv.html
+++ b/plac/doc/plac_adv.html
@@ -451,18 +451,19 @@ basic documentation.</em></p>
<li><a class="reference internal" href="#plac-easy-tests" id="id4">Plac easy tests</a></li>
<li><a class="reference internal" href="#plac-batch-scripts" id="id5">Plac batch scripts</a></li>
<li><a class="reference internal" href="#implementing-subcommands" id="id6">Implementing subcommands</a></li>
-<li><a class="reference internal" href="#readline-support" id="id7">Readline support</a></li>
-<li><a class="reference internal" href="#the-plac-runner" id="id8">The plac runner</a></li>
-<li><a class="reference internal" href="#a-non-class-based-example" id="id9">A non class-based example</a></li>
-<li><a class="reference internal" href="#writing-your-own-plac-runner" id="id10">Writing your own plac runner</a></li>
-<li><a class="reference internal" href="#long-running-commands" id="id11">Long running commands</a></li>
-<li><a class="reference internal" href="#threaded-commands" id="id12">Threaded commands</a></li>
-<li><a class="reference internal" href="#running-commands-as-external-processes" id="id13">Running commands as external processes</a></li>
-<li><a class="reference internal" href="#managing-the-output-of-concurrent-commands" id="id14">Managing the output of concurrent commands</a></li>
-<li><a class="reference internal" href="#parallel-computing-with-plac" id="id15">Parallel computing with plac</a></li>
-<li><a class="reference internal" href="#the-plac-server" id="id16">The plac server</a></li>
-<li><a class="reference internal" href="#summary" id="id17">Summary</a></li>
-<li><a class="reference internal" href="#appendix-custom-annotation-objects" id="id18">Appendix: custom annotation objects</a></li>
+<li><a class="reference internal" href="#plac-interpreter-call" id="id7">plac.Interpreter.call</a></li>
+<li><a class="reference internal" href="#readline-support" id="id8">Readline support</a></li>
+<li><a class="reference internal" href="#the-plac-runner" id="id9">The plac runner</a></li>
+<li><a class="reference internal" href="#a-non-class-based-example" id="id10">A non class-based example</a></li>
+<li><a class="reference internal" href="#writing-your-own-plac-runner" id="id11">Writing your own plac runner</a></li>
+<li><a class="reference internal" href="#long-running-commands" id="id12">Long running commands</a></li>
+<li><a class="reference internal" href="#threaded-commands" id="id13">Threaded commands</a></li>
+<li><a class="reference internal" href="#running-commands-as-external-processes" id="id14">Running commands as external processes</a></li>
+<li><a class="reference internal" href="#managing-the-output-of-concurrent-commands" id="id15">Managing the output of concurrent commands</a></li>
+<li><a class="reference internal" href="#parallel-computing-with-plac" id="id16">Parallel computing with plac</a></li>
+<li><a class="reference internal" href="#the-plac-server" id="id17">The plac server</a></li>
+<li><a class="reference internal" href="#summary" id="id18">Summary</a></li>
+<li><a class="reference internal" href="#appendix-custom-annotation-objects" id="id19">Appendix: custom annotation objects</a></li>
</ul>
</div>
<div class="section" id="introduction">
@@ -828,8 +829,9 @@ class ShelveInterface(object):
commands = 'set', 'show', 'showall', 'delete'
&#64;plac.annotations(
configfile=('path name of the shelve', 'option'))
- def __init__(self, configfile='~/conf.shelve'):
- self.fname = os.path.expanduser(configfile)
+ 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):
@@ -930,8 +932,101 @@ i&gt;
<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">
+<h1><a class="toc-backref" href="#id7">plac.Interpreter.call</a></h1>
+<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">
-<h1><a class="toc-backref" href="#id7">Readline support</a></h1>
+<h1><a class="toc-backref" href="#id8">Readline support</a></h1>
<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
@@ -968,9 +1063,8 @@ def split_on_first_space(line, commentchar):
return line.strip().split(' ', 1) # ignoring comments
if __name__ == '__main__':
- si = plac.call(SqlInterface)
- i = plac.Interpreter(si, split=split_on_first_space)
- i.interact(rl_input, prompt='sql&gt; ')
+ plac.Interpreter.call(SqlInterface, split=split_on_first_space,
+ stdin=rl_input, prompt='sql&gt; ')
</pre>
<p>Here is an example of usage:</p>
@@ -989,7 +1083,7 @@ and recorded and saved in the file <tt class="docutils literal"><span class="pre
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 href="#id19"><span class="problematic" id="id20">pyreadline_</span></a>
+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
@@ -1044,7 +1138,7 @@ NameError: Ambiguous command 'sh': matching ['showall', 'show']
</pre>
</div>
<div class="section" id="the-plac-runner">
-<h1><a class="toc-backref" href="#id8">The plac runner</a></h1>
+<h1><a class="toc-backref" href="#id9">The plac runner</a></h1>
<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).
@@ -1152,129 +1246,9 @@ 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>
-<!-- -->
-<blockquote>
-<p>Multiline support and Emacs integration</p>
-<p><a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is optimized for the simplest use case and by default it provide
-support for simple command-line languages where a command take
-a single line. This is the simplest case: it is easy to keep
-track of the line number and to print it in the error message, if
-there is some error in a <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> script. Starting from release 0.7
-<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> is beginning to support multiline input: it is now possible
-to define command-line languages with commands spanning multiple
-lines. The topical use case is the implementation of a tool
-to interact with a relational database: the tool must be able to send
-complex SQL queries spanning multiple lines to the backend.
-To support multiline input the <tt class="docutils literal">Interpreter</tt> class provides
-a method <tt class="docutils literal">multiline(stdin=sys.stdin, <span class="pre">terminator=';',</span> verbose=False)</tt>
-which reads input from <tt class="docutils literal">stdin</tt> until the terminator character
-(by default a semicolon) is reached.</p>
-<p>Since the Python readline module does not expose the
-multiline functionality of the underlying C library (which is there),
-<a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> multiline mode does not have readline functionality. This is
-not a big deal really, because if you are writing multiple line
-commands you don't really want to type them at the command-line. It is
-much better to use a real editor to type them, and to call <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> from
-the editor. Since I use Emacs I will give the recipe to integrate
-Emacs with <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a>: something equivalent can be done for vi and for
-other editors/IDEs.</p>
-<p>The multiline mode can be enabled by invoking the <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> runner with
-the <tt class="docutils literal"><span class="pre">-m</span></tt> option. Since the multiline mode is intended for use with
-Emacs in inferior mode, it does not print any prompt. Here is an example
-of usage:</p>
-<pre class="literal-block">
-$ plac -m ishelve2.py
-set a 1;
-setting a=1
-show a;
-a = 1
-</pre>
-<p>To integrate <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> with Emacs, enters the following lines in your
-.emacs:</p>
-<pre class="literal-block">
-;;; Emacs-plac integration: add the following to your .emacs
-
-(define-generic-mode 'plac-mode
- '(&quot;#&quot;) ; comment chars
- '(); highlighted commands
- nil
- '(&quot;.plac\\'&quot;); file extensions
- nil)
-
-(add-hook 'plac-mode-hook (lambda () (local-set-key [f4] 'plac-start)))
-(add-hook 'plac-mode-hook (lambda () (local-set-key [f5] 'plac-send)))
-(add-hook 'plac-mode-hook (lambda () (local-set-key [f6] 'plac-stop)))
-
-(defconst terminator 59); ASCII code for the semicolon
-(defvar *plac-process* nil)
-
-(defun plac-start ()
- &quot;Start an inferior plac process by inferring the script to use from the
- shebang line&quot;
- (interactive)
- (let ((shebang-line
- (save-excursion
- (goto-line 1) (end-of-line)
- (buffer-substring-no-properties 3 (point)))))
- (if *plac-process* (princ &quot;plac already started&quot;)
- (setq *plac-process*
- (start-process
- &quot;plac&quot; &quot;*plac*&quot; &quot;plac_runner.py&quot; &quot;-m&quot; shebang-line))))
- (display-buffer &quot;*plac*&quot;))
-
-;(defun plac-send ()
-; &quot;Send the current region to the inferior plac process&quot;
-; (interactive)
-; (save-excursion (set-buffer &quot;*plac*&quot;) (erase-buffer))
-; (process-send-region *plac-process* (region-beginning) (region-end)))
-
-(defun current-paragraph-beg-end ()
- &quot;Returns the extrema of the current paragraph, delimited by semicolons&quot;
- (interactive)
- (save-excursion
- (let ((beg (save-excursion (goto-line 2) (point))); skip the shebang
- (end (point-max)))
- ;; go backward
- (while (&gt; (point) beg)
- (goto-char (1- (point)))
- (if (= terminator (following-char))
- (setq beg (point))))
- (if (= terminator (following-char))
- (setq beg (1+ beg)))
- ;; go forward
- (while (&lt; (point) end)
- (goto-char (1+ (point)))
- (if (= 59 (following-char))
- (setq end (point))))
- (if (= 59 (following-char))
- (setq end (1+ end)))
- (list beg end))))
-
-(defun plac-send ()
- &quot;Send the current region to the inferior plac process&quot;
- (interactive)
- (save-excursion (set-buffer &quot;*plac*&quot;) (erase-buffer))
- (let ((p (apply 'buffer-substring-no-properties (current-paragraph-beg-end))))
- (message p)
- (process-send-string *plac-process* (concat p &quot;\n&quot;))))
- ;(switch-to-buffer-other-window &quot;*plac*&quot;)))
- ;(save-excursion (set-buffer &quot;*plac*&quot;)
- ; (set-window-start (selected-window) 1 nil))))
-
-(defun plac-stop ()
- &quot;Stop the inferior plac process by sending to it an EOF&quot;
- (interactive)
- (process-send-eof *plac-process*)
- (setq *plac-process* nil)
- &quot;killed *plac-process*&quot;)
-
-(provide 'plac)
-
-</pre>
-</blockquote>
</div>
<div class="section" id="a-non-class-based-example">
-<h1><a class="toc-backref" href="#id9">A non class-based example</a></h1>
+<h1><a class="toc-backref" href="#id10">A non class-based example</a></h1>
<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
@@ -1387,7 +1361,7 @@ 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">
-<h1><a class="toc-backref" href="#id10">Writing your own plac runner</a></h1>
+<h1><a class="toc-backref" href="#id11">Writing your own plac runner</a></h1>
<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
@@ -1445,6 +1419,9 @@ with plac.Interpreter(main) as i:
<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.
@@ -1461,7 +1438,7 @@ 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">
-<h1><a class="toc-backref" href="#id11">Long running commands</a></h1>
+<h1><a class="toc-backref" href="#id12">Long running commands</a></h1>
<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
@@ -1487,7 +1464,7 @@ class FakeImporter(object):
print('closing the file')
if __name__ == '__main__':
- plac.Interpreter(plac.call(FakeImporter)).interact()
+ 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
@@ -1496,10 +1473,11 @@ before entering a new command:</p>
$ 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
-... &lt;wait 3+ minutes&gt;
+...
Imported 10000 lines
closing the file
</pre>
@@ -1509,7 +1487,7 @@ the interface responsive. <a class="reference external" href="http://pypi.python
and processes.</p>
</div>
<div class="section" id="threaded-commands">
-<h1><a class="toc-backref" href="#id12">Threaded commands</a></h1>
+<h1><a class="toc-backref" href="#id13">Threaded commands</a></h1>
<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>
@@ -1604,12 +1582,12 @@ class FakeImporter(object):
print('closing the file')
if __name__ == '__main__':
- plac.Interpreter(plac.call(FakeImporter)).interact()
+ plac.Interpreter.call(FakeImporter)
</pre>
</div>
<div class="section" id="running-commands-as-external-processes">
-<h1><a class="toc-backref" href="#id13">Running commands as external processes</a></h1>
+<h1><a class="toc-backref" href="#id14">Running commands as external processes</a></h1>
<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
@@ -1652,7 +1630,7 @@ 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">
-<h1><a class="toc-backref" href="#id14">Managing the output of concurrent commands</a></h1>
+<h1><a class="toc-backref" href="#id15">Managing the output of concurrent commands</a></h1>
<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
@@ -1704,7 +1682,7 @@ if __name__ == '__main__':
</pre>
</div>
<div class="section" id="parallel-computing-with-plac">
-<h1><a class="toc-backref" href="#id15">Parallel computing with plac</a></h1>
+<h1><a class="toc-backref" href="#id16">Parallel computing with plac</a></h1>
<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
@@ -1826,7 +1804,7 @@ $ python picalculator.py -mS 10000000
mode is some 20% slower than the sequential mode.</p>
</div>
<div class="section" id="the-plac-server">
-<h1><a class="toc-backref" href="#id16">The plac server</a></h1>
+<h1><a class="toc-backref" href="#id17">The plac server</a></h1>
<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
@@ -1840,7 +1818,8 @@ Since <tt class="docutils literal">asynchat</tt>-based servers are asynchronous,
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:</p>
+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
@@ -1871,7 +1850,7 @@ Connection closed by foreign host.
</pre>
</div>
<div class="section" id="summary">
-<h1><a class="toc-backref" href="#id17">Summary</a></h1>
+<h1><a class="toc-backref" href="#id18">Summary</a></h1>
<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
@@ -1895,8 +1874,9 @@ 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">
-<h1><a class="toc-backref" href="#id18">Appendix: custom annotation objects</a></h1>
+<h1><a class="toc-backref" href="#id19">Appendix: custom annotation objects</a></h1>
<p>Internally <a class="reference external" href="http://pypi.python.org/pypi/plac">plac</a> uses an <tt class="docutils literal">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>
@@ -1951,12 +1931,6 @@ annotations from a configuration file or from a database, but I expect such
use cases to be quite rare: the default mechanism should work
pretty well for most users.</p>
</div>
-<div class="system-messages section">
-<h1>Docutils System Messages</h1>
-<div class="system-message" id="id19">
-<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">plac_adv.txt</tt>, line 438); <em><a href="#id20">backlink</a></em></p>
-Unknown target name: &quot;pyreadline&quot;.</div>
-</div>
</div>
</body>
</html>
diff --git a/plac/doc/plac_adv.pdf b/plac/doc/plac_adv.pdf
index ce9ae5f..dff9a0b 100644
--- a/plac/doc/plac_adv.pdf
+++ b/plac/doc/plac_adv.pdf
@@ -105,10 +105,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 182.0236
+ 164.0236
0 ]
/Rect [ 62.69291
506.5936
@@ -123,10 +123,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 182.0236
+ 164.0236
0 ]
/Rect [ 527.0227
506.5936
@@ -141,10 +141,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 58 0 R
+ /Dest [ 60 0 R
/XYZ
62.69291
- 633.0236
+ 609.0236
0 ]
/Rect [ 62.69291
488.5936
@@ -159,10 +159,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 58 0 R
+ /Dest [ 60 0 R
/XYZ
62.69291
- 633.0236
+ 609.0236
0 ]
/Rect [ 527.0227
488.5936
@@ -177,10 +177,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 60 0 R
+ /Dest [ 62 0 R
/XYZ
62.69291
- 175.4236
+ 151.4236
0 ]
/Rect [ 62.69291
470.5936
@@ -195,10 +195,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 60 0 R
+ /Dest [ 62 0 R
/XYZ
62.69291
- 175.4236
+ 151.4236
0 ]
/Rect [ 527.0227
470.5936
@@ -213,7 +213,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 72 0 R
+ /Dest [ 74 0 R
/XYZ
62.69291
765.0236
@@ -231,7 +231,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 72 0 R
+ /Dest [ 74 0 R
/XYZ
62.69291
765.0236
@@ -249,7 +249,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 75 0 R
+ /Dest [ 77 0 R
/XYZ
62.69291
461.8485
@@ -267,7 +267,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 75 0 R
+ /Dest [ 77 0 R
/XYZ
62.69291
461.8485
@@ -285,7 +285,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 80 0 R
+ /Dest [ 82 0 R
/XYZ
62.69291
539.8236
@@ -303,7 +303,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 80 0 R
+ /Dest [ 82 0 R
/XYZ
62.69291
539.8236
@@ -321,14 +321,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 86 0 R
+ /Dest [ 87 0 R
/XYZ
62.69291
- 469.3633
+ 460.0769
0 ]
/Rect [ 62.69291
398.5936
- 144.3729
+ 154.9529
410.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -339,10 +339,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 86 0 R
+ /Dest [ 87 0 R
/XYZ
62.69291
- 469.3633
+ 460.0769
0 ]
/Rect [ 527.0227
398.5936
@@ -357,14 +357,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 102 0 R
+ /Dest [ 95 0 R
/XYZ
62.69291
- 566.6236
+ 765.0236
0 ]
/Rect [ 62.69291
380.5936
- 137.7129
+ 144.3729
392.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -375,10 +375,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 102 0 R
+ /Dest [ 95 0 R
/XYZ
62.69291
- 566.6236
+ 765.0236
0 ]
/Rect [ 521.4627
380.5936
@@ -393,14 +393,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 116 0 R
+ /Dest [ 106 0 R
/XYZ
62.69291
- 765.0236
+ 240.6236
0 ]
/Rect [ 62.69291
362.5936
- 193.8529
+ 137.7129
374.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -411,10 +411,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 116 0 R
+ /Dest [ 106 0 R
/XYZ
62.69291
- 765.0236
+ 240.6236
0 ]
/Rect [ 521.4627
362.5936
@@ -429,14 +429,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 119 0 R
+ /Dest [ 110 0 R
/XYZ
62.69291
- 765.0236
+ 371.4236
0 ]
/Rect [ 62.69291
344.5936
- 201.6029
+ 193.8529
356.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -447,10 +447,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 119 0 R
+ /Dest [ 110 0 R
/XYZ
62.69291
- 765.0236
+ 371.4236
0 ]
/Rect [ 521.4627
344.5936
@@ -465,14 +465,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 123 0 R
+ /Dest [ 113 0 R
/XYZ
62.69291
- 615.8236
+ 384.6236
0 ]
/Rect [ 62.69291
326.5936
- 182.7029
+ 201.6029
338.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -483,10 +483,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 123 0 R
+ /Dest [ 113 0 R
/XYZ
62.69291
- 615.8236
+ 384.6236
0 ]
/Rect [ 521.4627
326.5936
@@ -501,14 +501,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 125 0 R
+ /Dest [ 117 0 R
/XYZ
62.69291
- 741.0236
+ 211.4236
0 ]
/Rect [ 62.69291
308.5936
- 163.2729
+ 182.7029
320.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -519,10 +519,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 125 0 R
+ /Dest [ 117 0 R
/XYZ
62.69291
- 741.0236
+ 211.4236
0 ]
/Rect [ 521.4627
308.5936
@@ -537,14 +537,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 128 0 R
+ /Dest [ 120 0 R
/XYZ
62.69291
- 237.4236
+ 318.6236
0 ]
/Rect [ 62.69291
290.5936
- 266.0929
+ 163.2729
302.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -555,10 +555,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 128 0 R
+ /Dest [ 120 0 R
/XYZ
62.69291
- 237.4236
+ 318.6236
0 ]
/Rect [ 521.4627
290.5936
@@ -573,14 +573,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 130 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 447.8236
+ 475.8236
0 ]
/Rect [ 62.69291
272.5936
- 283.8229
+ 266.0929
284.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -591,10 +591,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 130 0 R
+ /Dest [ 124 0 R
/XYZ
62.69291
- 447.8236
+ 475.8236
0 ]
/Rect [ 521.4627
272.5936
@@ -609,14 +609,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 132 0 R
+ /Dest [ 126 0 R
/XYZ
62.69291
- 571.8236
+ 675.0236
0 ]
/Rect [ 62.69291
254.5936
- 197.7329
+ 283.8229
266.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -627,10 +627,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 132 0 R
+ /Dest [ 126 0 R
/XYZ
62.69291
- 571.8236
+ 675.0236
0 ]
/Rect [ 521.4627
254.5936
@@ -645,14 +645,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 135 0 R
+ /Dest [ 128 0 R
/XYZ
62.69291
- 537.8236
+ 765.0236
0 ]
/Rect [ 62.69291
236.5936
- 136.0629
+ 197.7329
248.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -663,10 +663,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 135 0 R
+ /Dest [ 128 0 R
/XYZ
62.69291
- 537.8236
+ 765.0236
0 ]
/Rect [ 521.4627
236.5936
@@ -681,14 +681,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 138 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 715.8236
+ 729.0236
0 ]
/Rect [ 62.69291
218.5936
- 108.2629
+ 136.0629
230.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -699,10 +699,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 138 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 715.8236
+ 729.0236
0 ]
/Rect [ 521.4627
218.5936
@@ -717,14 +717,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 138 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 418.8236
+ 255.6236
0 ]
/Rect [ 62.69291
200.5936
- 241.6029
+ 108.2629
212.5936 ]
/Subtype /Link
/Type /Annot >>
@@ -735,10 +735,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 138 0 R
+ /Dest [ 132 0 R
/XYZ
62.69291
- 418.8236
+ 255.6236
0 ]
/Rect [ 521.4627
200.5936
@@ -747,8 +747,44 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER40': class PDFDictionary
+% 'Annot.NUMBER40': class LinkAnnotation
46 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 134 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 62.69291
+ 182.5936
+ 241.6029
+ 194.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER41': class LinkAnnotation
+47 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 134 0 R
+ /XYZ
+ 62.69291
+ 586.6772
+ 0 ]
+ /Rect [ 521.4627
+ 182.5936
+ 532.5827
+ 194.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER42': class PDFDictionary
+48 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -756,14 +792,14 @@ endobj
0
0 ]
/Rect [ 185.4471
- 146.5936
+ 128.5936
207.1062
- 158.5936 ]
+ 140.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER41': class PDFDictionary
-47 0 obj
+% 'Annot.NUMBER43': class PDFDictionary
+49 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -771,14 +807,14 @@ endobj
0
0 ]
/Rect [ 177.6784
- 134.5936
+ 116.5936
199.6123
- 146.5936 ]
+ 128.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page1': class PDFPage
-48 0 obj
+50 0 obj
% Page dictionary
<< /Annots [ 5 0 R
6 0 R
@@ -820,13 +856,15 @@ endobj
44 0 R
45 0 R
46 0 R
- 47 0 R ]
- /Contents 162 0 R
+ 47 0 R
+ 48 0 R
+ 49 0 R ]
+ /Contents 159 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -837,8 +875,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER42': class PDFDictionary
-49 0 obj
+% 'Annot.NUMBER44': class PDFDictionary
+51 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -846,14 +884,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 756.5936
+ 732.5936
83.81291
- 768.5936 ]
+ 744.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER43': class PDFDictionary
-50 0 obj
+% 'Annot.NUMBER45': class PDFDictionary
+52 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -861,14 +899,14 @@ endobj
0
0 ]
/Rect [ 278.4678
- 738.5936
+ 714.5936
300.0328
- 750.5936 ]
+ 726.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER44': class PDFDictionary
-51 0 obj
+% 'Annot.NUMBER46': class PDFDictionary
+53 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -876,14 +914,14 @@ endobj
0
0 ]
/Rect [ 117.3573
- 726.5936
+ 702.5936
138.5845
- 738.5936 ]
+ 714.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER45': class PDFDictionary
-52 0 obj
+% 'Annot.NUMBER47': class PDFDictionary
+54 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://twill.idyll.org/) >>
@@ -891,14 +929,14 @@ endobj
0
0 ]
/Rect [ 82.74466
- 684.5936
+ 660.5936
104.4564
- 696.5936 ]
+ 672.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER46': class PDFDictionary
-53 0 obj
+% 'Annot.NUMBER48': class PDFDictionary
+55 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -906,14 +944,14 @@ endobj
0
0 ]
/Rect [ 127.2882
- 684.5936
+ 660.5936
145.6282
- 696.5936 ]
+ 672.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER47': class PDFDictionary
-54 0 obj
+% 'Annot.NUMBER49': class PDFDictionary
+56 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -921,14 +959,14 @@ endobj
0
0 ]
/Rect [ 410.1674
- 684.5936
+ 660.5936
433.5592
- 696.5936 ]
+ 672.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER48': class PDFDictionary
-55 0 obj
+% 'Annot.NUMBER50': class PDFDictionary
+57 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -936,14 +974,14 @@ endobj
0
0 ]
/Rect [ 265.9578
- 660.5936
+ 636.5936
284.2978
- 672.5936 ]
+ 648.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER49': class PDFDictionary
-56 0 obj
+% 'Annot.NUMBER51': class PDFDictionary
+58 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -951,14 +989,14 @@ endobj
0
0 ]
/Rect [ 487.7492
- 660.5936
+ 636.5936
506.0892
- 672.5936 ]
+ 648.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER50': class PDFDictionary
-57 0 obj
+% 'Annot.NUMBER52': class PDFDictionary
+59 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://micheles.googlecode.com/hg/plac/doc/plac.html) >>
@@ -966,30 +1004,30 @@ endobj
0
0 ]
/Rect [ 62.69291
- 501.5936
+ 477.5936
157.1829
- 513.5936 ]
+ 489.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page2': class PDFPage
-58 0 obj
+60 0 obj
% Page dictionary
-<< /Annots [ 49 0 R
- 50 0 R
- 51 0 R
+<< /Annots [ 51 0 R
52 0 R
53 0 R
54 0 R
55 0 R
56 0 R
- 57 0 R ]
- /Contents 163 0 R
+ 57 0 R
+ 58 0 R
+ 59 0 R ]
+ /Contents 160 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1000,8 +1038,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER51': class PDFDictionary
-59 0 obj
+% 'Annot.NUMBER53': class PDFDictionary
+61 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1009,22 +1047,22 @@ endobj
0
0 ]
/Rect [ 383.9329
- 220.9936
+ 196.9936
405.0529
- 232.9936 ]
+ 208.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page3': class PDFPage
-60 0 obj
+62 0 obj
% Page dictionary
-<< /Annots [ 59 0 R ]
- /Contents 164 0 R
+<< /Annots [ 61 0 R ]
+ /Contents 161 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1036,14 +1074,14 @@ endobj
/Type /Page >>
endobj
% 'Page4': class PDFPage
-61 0 obj
+63 0 obj
% Page dictionary
-<< /Contents 165 0 R
+<< /Contents 162 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1054,8 +1092,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER52': class PDFDictionary
-62 0 obj
+% 'Annot.NUMBER54': class PDFDictionary
+64 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1069,8 +1107,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER53': class PDFDictionary
-63 0 obj
+% 'Annot.NUMBER55': class PDFDictionary
+65 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1084,8 +1122,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER54': class PDFDictionary
-64 0 obj
+% 'Annot.NUMBER56': class PDFDictionary
+66 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1099,8 +1137,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER55': class PDFDictionary
-65 0 obj
+% 'Annot.NUMBER57': class PDFDictionary
+67 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/shlex.html) >>
@@ -1114,8 +1152,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER56': class PDFDictionary
-66 0 obj
+% 'Annot.NUMBER58': class PDFDictionary
+68 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1129,8 +1167,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER57': class PDFDictionary
-67 0 obj
+% 'Annot.NUMBER59': class PDFDictionary
+69 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/shlex.html) >>
@@ -1144,8 +1182,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER58': class PDFDictionary
-68 0 obj
+% 'Annot.NUMBER60': class PDFDictionary
+70 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1159,8 +1197,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER59': class PDFDictionary
-69 0 obj
+% 'Annot.NUMBER61': class PDFDictionary
+71 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/shlex.html) >>
@@ -1174,8 +1212,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER60': class PDFDictionary
-70 0 obj
+% 'Annot.NUMBER62': class PDFDictionary
+72 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1189,8 +1227,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER61': class PDFDictionary
-71 0 obj
+% 'Annot.NUMBER63': class PDFDictionary
+73 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1205,24 +1243,24 @@ endobj
/Type /Annot >>
endobj
% 'Page5': class PDFPage
-72 0 obj
+74 0 obj
% Page dictionary
-<< /Annots [ 62 0 R
- 63 0 R
- 64 0 R
+<< /Annots [ 64 0 R
65 0 R
66 0 R
67 0 R
68 0 R
69 0 R
70 0 R
- 71 0 R ]
- /Contents 166 0 R
+ 71 0 R
+ 72 0 R
+ 73 0 R ]
+ /Contents 163 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1233,8 +1271,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER62': class PDFDictionary
-73 0 obj
+% 'Annot.NUMBER64': class PDFDictionary
+75 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1248,8 +1286,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER63': class PDFDictionary
-74 0 obj
+% 'Annot.NUMBER65': class PDFDictionary
+76 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1264,16 +1302,16 @@ endobj
/Type /Annot >>
endobj
% 'Page6': class PDFPage
-75 0 obj
+77 0 obj
% Page dictionary
-<< /Annots [ 73 0 R
- 74 0 R ]
- /Contents 167 0 R
+<< /Annots [ 75 0 R
+ 76 0 R ]
+ /Contents 164 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1284,8 +1322,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER64': class PDFDictionary
-76 0 obj
+% 'Annot.NUMBER66': class PDFDictionary
+78 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://micheles.googlecode.com/hg/plac/doc/plac.html) >>
@@ -1299,8 +1337,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER65': class PDFDictionary
-77 0 obj
+% 'Annot.NUMBER67': class PDFDictionary
+79 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1314,8 +1352,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER66': class PDFDictionary
-78 0 obj
+% 'Annot.NUMBER68': class PDFDictionary
+80 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1329,8 +1367,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER67': class PDFDictionary
-79 0 obj
+% 'Annot.NUMBER69': class PDFDictionary
+81 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1345,18 +1383,18 @@ endobj
/Type /Annot >>
endobj
% 'Page7': class PDFPage
-80 0 obj
+82 0 obj
% Page dictionary
-<< /Annots [ 76 0 R
- 77 0 R
- 78 0 R
- 79 0 R ]
- /Contents 168 0 R
+<< /Annots [ 78 0 R
+ 79 0 R
+ 80 0 R
+ 81 0 R ]
+ /Contents 165 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1367,8 +1405,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER68': class PDFDictionary
-81 0 obj
+% 'Annot.NUMBER70': class PDFDictionary
+83 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1376,14 +1414,14 @@ endobj
0
0 ]
/Rect [ 431.7904
- 411.3936
+ 399.3936
453.7245
- 423.3936 ]
+ 411.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER69': class PDFDictionary
-82 0 obj
+% 'Annot.NUMBER71': class PDFDictionary
+84 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1391,14 +1429,14 @@ endobj
0
0 ]
/Rect [ 255.5885
- 381.3936
+ 369.3936
278.2757
- 393.3936 ]
+ 381.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER70': class PDFDictionary
-83 0 obj
+% 'Annot.NUMBER72': class PDFDictionary
+85 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/cmd.html) >>
@@ -1406,24 +1444,24 @@ endobj
0
0 ]
/Rect [ 513.6927
- 357.3936
+ 345.3936
532.1846
- 369.3936 ]
+ 357.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page8': class PDFPage
-84 0 obj
+86 0 obj
% Page dictionary
-<< /Annots [ 81 0 R
- 82 0 R
- 83 0 R ]
- /Contents 169 0 R
+<< /Annots [ 83 0 R
+ 84 0 R
+ 85 0 R ]
+ /Contents 166 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1434,31 +1472,34 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER71': class PDFDictionary
-85 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
+% 'Page9': class PDFPage
+87 0 obj
+% Page dictionary
+<< /Contents 167 0 R
+ /MediaBox [ 0
0
- 0 ]
- /Rect [ 179.0529
- 433.9333
- 201.1953
- 445.9333 ]
- /Subtype /Link
- /Type /Annot >>
+ 595.2756
+ 841.8898 ]
+ /Parent 158 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
endobj
-% 'Page9': class PDFPage
-86 0 obj
+% 'Page10': class PDFPage
+88 0 obj
% Page dictionary
-<< /Annots [ 85 0 R ]
- /Contents 170 0 R
+<< /Contents 168 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1469,111 +1510,111 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER72': class PDFDictionary
-87 0 obj
+% 'Annot.NUMBER73': class PDFDictionary
+89 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://freshmeat.net/projects/rlwrap/) >>
+ /URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 377.8504
- 484.1936
- 409.861
- 496.1936 ]
+ /Rect [ 179.0529
+ 729.5936
+ 201.1953
+ 741.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER73': class PDFDictionary
-88 0 obj
+% 'Annot.NUMBER74': class PDFDictionary
+90 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
+ /URI (http://freshmeat.net/projects/rlwrap/) >>
/Border [ 0
0
0 ]
- /Rect [ 252.3128
- 472.1936
- 275.3028
- 484.1936 ]
+ /Rect [ 377.8504
+ 149.6007
+ 409.861
+ 161.6007 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER74': class PDFDictionary
-89 0 obj
+% 'Annot.NUMBER75': class PDFDictionary
+91 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 381.9869
- 448.1936
- 403.548
- 460.1936 ]
+ /Rect [ 242.4466
+ 137.6007
+ 263.7922
+ 149.6007 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER75': class PDFDictionary
-90 0 obj
+% 'Annot.NUMBER76': class PDFDictionary
+92 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
+ /URI (http://ipython.scipy.org/moin/PyReadline/Intro) >>
/Border [ 0
0
0 ]
- /Rect [ 480.1313
- 436.1936
- 501.4627
- 448.1936 ]
+ /Rect [ 456.2271
+ 137.6007
+ 505.3627
+ 149.6007 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER76': class PDFDictionary
-91 0 obj
+% 'Annot.NUMBER77': class PDFDictionary
+93 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://docs.python.org/library/cmd.html) >>
+ /URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 366.9454
- 406.1936
- 388.8033
- 418.1936 ]
+ /Rect [ 363.1739
+ 113.6007
+ 386.5004
+ 125.6007 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER77': class PDFDictionary
-92 0 obj
+% 'Annot.NUMBER78': class PDFDictionary
+94 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://docs.python.org/library/cmd.html) >>
+ /URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 170.8855
- 394.1936
- 189.7755
- 406.1936 ]
+ /Rect [ 479.7508
+ 101.6007
+ 501.4627
+ 113.6007 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page10': class PDFPage
-93 0 obj
+% 'Page11': class PDFPage
+95 0 obj
% Page dictionary
-<< /Annots [ 87 0 R
- 88 0 R
- 89 0 R
+<< /Annots [ 89 0 R
90 0 R
91 0 R
- 92 0 R ]
- /Contents 171 0 R
+ 92 0 R
+ 93 0 R
+ 94 0 R ]
+ /Contents 169 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1584,8 +1625,38 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER78': class PDFDictionary
-94 0 obj
+% 'Annot.NUMBER79': class PDFDictionary
+96 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/cmd.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 366.9454
+ 738.5936
+ 388.8033
+ 750.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER80': class PDFDictionary
+97 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/cmd.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 170.8855
+ 726.5936
+ 189.7755
+ 738.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER81': class PDFDictionary
+98 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1593,14 +1664,14 @@ endobj
0
0 ]
/Rect [ 390.8027
- 711.3936
+ 385.3936
435.0027
- 723.3936 ]
+ 397.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER79': class PDFDictionary
-95 0 obj
+% 'Annot.NUMBER82': class PDFDictionary
+99 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1608,14 +1679,14 @@ endobj
0
0 ]
/Rect [ 213.451
- 699.3936
+ 373.3936
237.5255
- 711.3936 ]
+ 385.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER80': class PDFDictionary
-96 0 obj
+% 'Annot.NUMBER83': class PDFDictionary
+100 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://argparse.googlecode.com) >>
@@ -1623,14 +1694,14 @@ endobj
0
0 ]
/Rect [ 114.9429
- 675.3936
+ 349.3936
157.1829
- 687.3936 ]
+ 361.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER81': class PDFDictionary
-97 0 obj
+% 'Annot.NUMBER84': class PDFDictionary
+101 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1638,14 +1709,14 @@ endobj
0
0 ]
/Rect [ 385.0429
- 675.3936
+ 349.3936
403.3829
- 687.3936 ]
+ 361.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER82': class PDFDictionary
-98 0 obj
+% 'Annot.NUMBER85': class PDFDictionary
+102 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1653,14 +1724,14 @@ endobj
0
0 ]
/Rect [ 350.6129
- 645.3936
+ 319.3936
371.7329
- 657.3936 ]
+ 331.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER83': class PDFDictionary
-99 0 obj
+% 'Annot.NUMBER86': class PDFDictionary
+103 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1668,14 +1739,14 @@ endobj
0
0 ]
/Rect [ 256.6729
- 627.3936
+ 301.3936
277.7929
- 639.3936 ]
+ 313.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER84': class PDFDictionary
-100 0 obj
+% 'Annot.NUMBER87': class PDFDictionary
+104 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -1683,14 +1754,14 @@ endobj
0
0 ]
/Rect [ 149.5469
- 531.1936
+ 205.1936
172.1982
- 543.1936 ]
+ 217.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER85': class PDFDictionary
-101 0 obj
+% 'Annot.NUMBER88': class PDFDictionary
+105 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/distutils/) >>
@@ -1698,29 +1769,31 @@ endobj
0
0 ]
/Rect [ 224.3178
- 519.1936
+ 193.1936
260.8853
- 531.1936 ]
+ 205.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page11': class PDFPage
-102 0 obj
+% 'Page12': class PDFPage
+106 0 obj
% Page dictionary
-<< /Annots [ 94 0 R
- 95 0 R
- 96 0 R
+<< /Annots [ 96 0 R
97 0 R
98 0 R
99 0 R
100 0 R
- 101 0 R ]
- /Contents 172 0 R
+ 101 0 R
+ 102 0 R
+ 103 0 R
+ 104 0 R
+ 105 0 R ]
+ /Contents 170 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1731,31 +1804,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER86': class PDFDictionary
-103 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://argparse.googlecode.com) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 381.1529
- 418.1936
- 423.3929
- 430.1936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Page12': class PDFPage
-104 0 obj
+% 'Page13': class PDFPage
+107 0 obj
% Page dictionary
-<< /Annots [ 103 0 R ]
- /Contents 173 0 R
+<< /Contents 171 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1766,67 +1823,22 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER87': class PDFDictionary
-105 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 82.69291
- 692.7662
- 104.1773
- 704.7662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER88': class PDFDictionary
-106 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 445.3587
- 668.7662
- 467.5757
- 680.7662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
% 'Annot.NUMBER89': class PDFDictionary
-107 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 157.9797
- 656.7662
- 179.1854
- 668.7662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER90': class PDFDictionary
108 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
+ /URI (http://argparse.googlecode.com) >>
/Border [ 0
0
0 ]
- /Rect [ 187.0217
- 566.7662
- 208.3864
- 578.7662 ]
+ /Rect [ 381.1529
+ 744.5936
+ 423.3929
+ 756.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER91': class PDFDictionary
+% 'Annot.NUMBER90': class PDFDictionary
109 0 obj
<< /A << /S /URI
/Type /Action
@@ -1834,75 +1846,24 @@ endobj
/Border [ 0
0
0 ]
- /Rect [ 440.3127
- 542.7662
- 462.7327
- 554.7662 ]
+ /Rect [ 62.69291
+ 335.9936
+ 84.72012
+ 347.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER92': class PDFDictionary
+% 'Page14': class PDFPage
110 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 377.541
- 530.7662
- 395.881
- 542.7662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER93': class PDFDictionary
-111 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 310.5934
- 500.7662
- 331.7145
- 512.7662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER94': class PDFDictionary
-112 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 138.8329
- 369.5662
- 159.9529
- 381.5662 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Page13': class PDFPage
-113 0 obj
% Page dictionary
-<< /Annots [ 105 0 R
- 106 0 R
- 107 0 R
- 108 0 R
- 109 0 R
- 110 0 R
- 111 0 R
- 112 0 R ]
- /Contents 174 0 R
+<< /Annots [ 108 0 R
+ 109 0 R ]
+ /Contents 172 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1913,15 +1874,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page14': class PDFPage
-114 0 obj
+% 'Page15': class PDFPage
+111 0 obj
% Page dictionary
-<< /Contents 175 0 R
+<< /Contents 173 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1932,31 +1893,31 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER95': class PDFDictionary
-115 0 obj
+% 'Annot.NUMBER91': class PDFDictionary
+112 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 62.69291
- 729.5936
- 84.72012
- 741.5936 ]
+ /Rect [ 182.479
+ 349.1936
+ 203.7662
+ 361.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page15': class PDFPage
-116 0 obj
+% 'Page16': class PDFPage
+113 0 obj
% Page dictionary
-<< /Annots [ 115 0 R ]
- /Contents 176 0 R
+<< /Annots [ 112 0 R ]
+ /Contents 174 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1967,50 +1928,63 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page16': class PDFPage
-117 0 obj
-% Page dictionary
-<< /Contents 177 0 R
- /MediaBox [ 0
+% 'Annot.NUMBER92': class PDFDictionary
+114 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
0
- 595.2756
- 841.8898 ]
- /Parent 161 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
+ 0 ]
+ /Rect [ 255.1228
+ 382.1936
+ 276.5028
+ 394.1936 ]
+ /Subtype /Link
+ /Type /Annot >>
endobj
-% 'Annot.NUMBER96': class PDFDictionary
-118 0 obj
+% 'Annot.NUMBER93': class PDFDictionary
+115 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://docs.python.org/library/multiprocessing.html) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 295.0229
+ 226.9936
+ 367.2629
+ 238.9936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER94': class PDFDictionary
+116 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 182.479
- 729.5936
- 203.7662
- 741.5936 ]
+ /Rect [ 179.1295
+ 175.9936
+ 201.6839
+ 187.9936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page17': class PDFPage
-119 0 obj
+117 0 obj
% Page dictionary
-<< /Annots [ 118 0 R ]
- /Contents 178 0 R
+<< /Annots [ 114 0 R
+ 115 0 R
+ 116 0 R ]
+ /Contents 175 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2021,63 +1995,47 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER97': class PDFDictionary
-120 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://docs.python.org/library/multiprocessing.html) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 295.0229
- 631.3936
- 367.2629
- 643.3936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER98': class PDFDictionary
-121 0 obj
+% 'Annot.NUMBER95': class PDFDictionary
+118 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 179.1295
- 580.3936
- 201.6839
- 592.3936 ]
+ /Rect [ 414.8874
+ 346.1936
+ 436.9487
+ 358.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER99': class PDFDictionary
-122 0 obj
+% 'Annot.NUMBER96': class PDFDictionary
+119 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
/Border [ 0
0
0 ]
- /Rect [ 414.8874
- 101.9936
- 436.9487
- 113.9936 ]
+ /Rect [ 122.7054
+ 199.1936
+ 145.2085
+ 211.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page18': class PDFPage
-123 0 obj
+120 0 obj
% Page dictionary
-<< /Annots [ 120 0 R
- 121 0 R
- 122 0 R ]
- /Contents 179 0 R
+<< /Annots [ 118 0 R
+ 119 0 R ]
+ /Contents 176 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2088,31 +2046,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER100': class PDFDictionary
-124 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 122.7054
- 621.5936
- 145.2085
- 633.5936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
% 'Page19': class PDFPage
-125 0 obj
+121 0 obj
% Page dictionary
-<< /Annots [ 124 0 R ]
- /Contents 180 0 R
+<< /Contents 177 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2123,8 +2065,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER101': class PDFDictionary
-126 0 obj
+% 'Annot.NUMBER97': class PDFDictionary
+122 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2132,14 +2074,14 @@ endobj
0
0 ]
/Rect [ 183.3657
- 189.9936
+ 428.3936
207.8364
- 201.9936 ]
+ 440.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER102': class PDFDictionary
-127 0 obj
+% 'Annot.NUMBER98': class PDFDictionary
+123 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docs.python.org/library/multiprocessing.html) >>
@@ -2147,23 +2089,23 @@ endobj
0
0 ]
/Rect [ 254.9929
- 165.9936
+ 404.3936
327.2329
- 177.9936 ]
+ 416.3936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page20': class PDFPage
-128 0 obj
+124 0 obj
% Page dictionary
-<< /Annots [ 126 0 R
- 127 0 R ]
- /Contents 181 0 R
+<< /Annots [ 122 0 R
+ 123 0 R ]
+ /Contents 178 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2174,8 +2116,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER103': class PDFDictionary
-129 0 obj
+% 'Annot.NUMBER99': class PDFDictionary
+125 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2183,22 +2125,22 @@ endobj
0
0 ]
/Rect [ 62.69291
- 412.3936
+ 639.5936
85.70846
- 424.3936 ]
+ 651.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page21': class PDFPage
-130 0 obj
+126 0 obj
% Page dictionary
-<< /Annots [ 129 0 R ]
- /Contents 182 0 R
+<< /Annots [ 125 0 R ]
+ /Contents 179 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2209,8 +2151,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER104': class PDFDictionary
-131 0 obj
+% 'Annot.NUMBER100': class PDFDictionary
+127 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2218,22 +2160,22 @@ endobj
0
0 ]
/Rect [ 62.69291
- 536.3936
+ 729.5936
84.98766
- 548.3936 ]
+ 741.5936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page22': class PDFPage
-132 0 obj
+128 0 obj
% Page dictionary
-<< /Annots [ 131 0 R ]
- /Contents 183 0 R
+<< /Annots [ 127 0 R ]
+ /Contents 180 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2245,14 +2187,14 @@ endobj
/Type /Page >>
endobj
% 'Page23': class PDFPage
-133 0 obj
+129 0 obj
% Page dictionary
-<< /Contents 184 0 R
+<< /Contents 181 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2263,8 +2205,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER105': class PDFDictionary
-134 0 obj
+% 'Annot.NUMBER101': class PDFDictionary
+130 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2272,22 +2214,38 @@ endobj
0
0 ]
/Rect [ 172.4311
- 418.3936
+ 609.5936
194.7087
- 430.3936 ]
+ 621.5936 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER102': class PDFDictionary
+131 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://pypi.python.org/pypi/plac) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 91.57623
+ 220.1936
+ 114.8995
+ 232.1936 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page24': class PDFPage
-135 0 obj
+132 0 obj
% Page dictionary
-<< /Annots [ 134 0 R ]
- /Contents 185 0 R
+<< /Annots [ 130 0 R
+ 131 0 R ]
+ /Contents 182 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2298,23 +2256,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER106': class PDFDictionary
-136 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://pypi.python.org/pypi/plac) >>
- /Border [ 0
- 0
- 0 ]
- /Rect [ 91.57623
- 680.3936
- 114.8995
- 692.3936 ]
- /Subtype /Link
- /Type /Annot >>
-endobj
-% 'Annot.NUMBER107': class PDFDictionary
-137 0 obj
+% 'Annot.NUMBER103': class PDFDictionary
+133 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pypi.python.org/pypi/plac) >>
@@ -2322,23 +2265,22 @@ endobj
0
0 ]
/Rect [ 106.6216
- 383.3936
+ 551.2472
128.3202
- 395.3936 ]
+ 563.2472 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page25': class PDFPage
-138 0 obj
+134 0 obj
% Page dictionary
-<< /Annots [ 136 0 R
- 137 0 R ]
- /Contents 186 0 R
+<< /Annots [ 133 0 R ]
+ /Contents 183 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2350,14 +2292,14 @@ endobj
/Type /Page >>
endobj
% 'Page26': class PDFPage
-139 0 obj
+135 0 obj
% Page dictionary
-<< /Contents 187 0 R
+<< /Contents 184 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 161 0 R
+ /Parent 158 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -2368,281 +2310,293 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'R140': class PDFCatalog
-140 0 obj
+% 'R136': class PDFCatalog
+136 0 obj
% Document Root
-<< /Outlines 142 0 R
- /PageLabels 188 0 R
+<< /Outlines 138 0 R
+ /PageLabels 185 0 R
/PageMode /UseNone
- /Pages 161 0 R
+ /Pages 158 0 R
/Type /Catalog >>
endobj
-% 'R141': class PDFInfo
-141 0 obj
+% 'R137': class PDFInfo
+137 0 obj
<< /Author (Michele Simionato)
- /CreationDate (D:20100802070955-01'00')
+ /CreationDate (D:20100807083546-01'00')
/Keywords ()
/Producer (ReportLab http://www.reportlab.com)
/Subject (\(unspecified\))
/Title (Advanced usages of plac) >>
endobj
-% 'R142': class PDFOutlines
-142 0 obj
-<< /Count 18
- /First 143 0 R
- /Last 160 0 R
+% 'R138': class PDFOutlines
+138 0 obj
+<< /Count 19
+ /First 139 0 R
+ /Last 157 0 R
/Type /Outlines >>
endobj
% 'Outline.0': class OutlineEntryObject
-143 0 obj
-<< /Dest [ 48 0 R
+139 0 obj
+<< /Dest [ 50 0 R
/XYZ
62.69291
- 182.0236
+ 164.0236
0 ]
- /Next 144 0 R
- /Parent 142 0 R
+ /Next 140 0 R
+ /Parent 138 0 R
/Title (Introduction) >>
endobj
% 'Outline.1': class OutlineEntryObject
+140 0 obj
+<< /Dest [ 60 0 R
+ /XYZ
+ 62.69291
+ 609.0236
+ 0 ]
+ /Next 141 0 R
+ /Parent 138 0 R
+ /Prev 139 0 R
+ /Title (From scripts to interactive applications) >>
+endobj
+% 'Outline.2': class OutlineEntryObject
+141 0 obj
+<< /Dest [ 62 0 R
+ /XYZ
+ 62.69291
+ 151.4236
+ 0 ]
+ /Next 142 0 R
+ /Parent 138 0 R
+ /Prev 140 0 R
+ /Title (Testing a plac application) >>
+endobj
+% 'Outline.3': class OutlineEntryObject
+142 0 obj
+<< /Dest [ 74 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 143 0 R
+ /Parent 138 0 R
+ /Prev 141 0 R
+ /Title (Plac easy tests) >>
+endobj
+% 'Outline.4': class OutlineEntryObject
+143 0 obj
+<< /Dest [ 77 0 R
+ /XYZ
+ 62.69291
+ 461.8485
+ 0 ]
+ /Next 144 0 R
+ /Parent 138 0 R
+ /Prev 142 0 R
+ /Title (Plac batch scripts) >>
+endobj
+% 'Outline.5': class OutlineEntryObject
144 0 obj
-<< /Dest [ 58 0 R
+<< /Dest [ 82 0 R
/XYZ
62.69291
- 633.0236
+ 539.8236
0 ]
/Next 145 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 143 0 R
- /Title (From scripts to interactive applications) >>
+ /Title (Implementing subcommands) >>
endobj
-% 'Outline.2': class OutlineEntryObject
+% 'Outline.6': class OutlineEntryObject
145 0 obj
-<< /Dest [ 60 0 R
+<< /Dest [ 87 0 R
/XYZ
62.69291
- 175.4236
+ 460.0769
0 ]
/Next 146 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 144 0 R
- /Title (Testing a plac application) >>
+ /Title (plac.Interpreter.call) >>
endobj
-% 'Outline.3': class OutlineEntryObject
+% 'Outline.7': class OutlineEntryObject
146 0 obj
-<< /Dest [ 72 0 R
+<< /Dest [ 95 0 R
/XYZ
62.69291
765.0236
0 ]
/Next 147 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 145 0 R
- /Title (Plac easy tests) >>
+ /Title (Readline support) >>
endobj
-% 'Outline.4': class OutlineEntryObject
+% 'Outline.8': class OutlineEntryObject
147 0 obj
-<< /Dest [ 75 0 R
+<< /Dest [ 106 0 R
/XYZ
62.69291
- 461.8485
+ 240.6236
0 ]
/Next 148 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 146 0 R
- /Title (Plac batch scripts) >>
+ /Title (The plac runner) >>
endobj
-% 'Outline.5': class OutlineEntryObject
+% 'Outline.9': class OutlineEntryObject
148 0 obj
-<< /Dest [ 80 0 R
+<< /Dest [ 110 0 R
/XYZ
62.69291
- 539.8236
+ 371.4236
0 ]
/Next 149 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 147 0 R
- /Title (Implementing subcommands) >>
+ /Title (A non class-based example) >>
endobj
-% 'Outline.6': class OutlineEntryObject
+% 'Outline.10': class OutlineEntryObject
149 0 obj
-<< /Dest [ 86 0 R
+<< /Dest [ 113 0 R
/XYZ
62.69291
- 469.3633
+ 384.6236
0 ]
/Next 150 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 148 0 R
- /Title (Readline support) >>
+ /Title (Writing your own plac runner) >>
endobj
-% 'Outline.7': class OutlineEntryObject
+% 'Outline.11': class OutlineEntryObject
150 0 obj
-<< /Dest [ 102 0 R
+<< /Dest [ 117 0 R
/XYZ
62.69291
- 566.6236
+ 211.4236
0 ]
/Next 151 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 149 0 R
- /Title (The plac runner) >>
+ /Title (Long running commands) >>
endobj
-% 'Outline.8': class OutlineEntryObject
+% 'Outline.12': class OutlineEntryObject
151 0 obj
-<< /Dest [ 116 0 R
+<< /Dest [ 120 0 R
/XYZ
62.69291
- 765.0236
+ 318.6236
0 ]
/Next 152 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 150 0 R
- /Title (A non class-based example) >>
+ /Title (Threaded commands) >>
endobj
-% 'Outline.9': class OutlineEntryObject
+% 'Outline.13': class OutlineEntryObject
152 0 obj
-<< /Dest [ 119 0 R
+<< /Dest [ 124 0 R
/XYZ
62.69291
- 765.0236
+ 475.8236
0 ]
/Next 153 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 151 0 R
- /Title (Writing your own plac runner) >>
+ /Title (Running commands as external processes) >>
endobj
-% 'Outline.10': class OutlineEntryObject
+% 'Outline.14': class OutlineEntryObject
153 0 obj
-<< /Dest [ 123 0 R
+<< /Dest [ 126 0 R
/XYZ
62.69291
- 615.8236
+ 675.0236
0 ]
/Next 154 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 152 0 R
- /Title (Long running commands) >>
+ /Title (Managing the output of concurrent commands) >>
endobj
-% 'Outline.11': class OutlineEntryObject
+% 'Outline.15': class OutlineEntryObject
154 0 obj
-<< /Dest [ 125 0 R
+<< /Dest [ 128 0 R
/XYZ
62.69291
- 741.0236
+ 765.0236
0 ]
/Next 155 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 153 0 R
- /Title (Threaded commands) >>
+ /Title (Parallel computing with plac) >>
endobj
-% 'Outline.12': class OutlineEntryObject
+% 'Outline.16': class OutlineEntryObject
155 0 obj
-<< /Dest [ 128 0 R
+<< /Dest [ 132 0 R
/XYZ
62.69291
- 237.4236
+ 729.0236
0 ]
/Next 156 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 154 0 R
- /Title (Running commands as external processes) >>
+ /Title (The plac server) >>
endobj
-% 'Outline.13': class OutlineEntryObject
+% 'Outline.17': class OutlineEntryObject
156 0 obj
-<< /Dest [ 130 0 R
+<< /Dest [ 132 0 R
/XYZ
62.69291
- 447.8236
+ 255.6236
0 ]
/Next 157 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 155 0 R
- /Title (Managing the output of concurrent commands) >>
+ /Title (Summary) >>
endobj
-% 'Outline.14': class OutlineEntryObject
+% 'Outline.18': class OutlineEntryObject
157 0 obj
-<< /Dest [ 132 0 R
+<< /Dest [ 134 0 R
/XYZ
62.69291
- 571.8236
+ 586.6772
0 ]
- /Next 158 0 R
- /Parent 142 0 R
+ /Parent 138 0 R
/Prev 156 0 R
- /Title (Parallel computing with plac) >>
-endobj
-% 'Outline.15': class OutlineEntryObject
-158 0 obj
-<< /Dest [ 135 0 R
- /XYZ
- 62.69291
- 537.8236
- 0 ]
- /Next 159 0 R
- /Parent 142 0 R
- /Prev 157 0 R
- /Title (The plac server) >>
-endobj
-% 'Outline.16': class OutlineEntryObject
-159 0 obj
-<< /Dest [ 138 0 R
- /XYZ
- 62.69291
- 715.8236
- 0 ]
- /Next 160 0 R
- /Parent 142 0 R
- /Prev 158 0 R
- /Title (Summary) >>
-endobj
-% 'Outline.17': class OutlineEntryObject
-160 0 obj
-<< /Dest [ 138 0 R
- /XYZ
- 62.69291
- 418.8236
- 0 ]
- /Parent 142 0 R
- /Prev 159 0 R
/Title (Appendix: custom annotation objects) >>
endobj
-% 'R161': class PDFPages
-161 0 obj
+% 'R158': class PDFPages
+158 0 obj
% page tree
<< /Count 26
- /Kids [ 48 0 R
- 58 0 R
+ /Kids [ 50 0 R
60 0 R
- 61 0 R
- 72 0 R
- 75 0 R
- 80 0 R
- 84 0 R
+ 62 0 R
+ 63 0 R
+ 74 0 R
+ 77 0 R
+ 82 0 R
86 0 R
- 93 0 R
- 102 0 R
- 104 0 R
+ 87 0 R
+ 88 0 R
+ 95 0 R
+ 106 0 R
+ 107 0 R
+ 110 0 R
+ 111 0 R
113 0 R
- 114 0 R
- 116 0 R
117 0 R
- 119 0 R
- 123 0 R
- 125 0 R
+ 120 0 R
+ 121 0 R
+ 124 0 R
+ 126 0 R
128 0 R
- 130 0 R
+ 129 0 R
132 0 R
- 133 0 R
- 135 0 R
- 138 0 R
- 139 0 R ]
+ 134 0 R
+ 135 0 R ]
/Type /Pages >>
endobj
-% 'R162': class PDFStream
-162 0 obj
+% 'R159': class PDFStream
+159 0 obj
% page stream
-<< /Length 9279 >>
+<< /Length 9186 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2836,17 +2790,17 @@ 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 194.0236 cm
+1 0 0 1 62.69291 176.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
-1 0 0 1 0 309 cm
+1 0 0 1 0 327 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Introduction) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 309 cm
+1 0 0 1 397.8898 327 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2854,13 +2808,13 @@ 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 291 cm
+1 0 0 1 0 309 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (From scripts to interactive applications) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 291 cm
+1 0 0 1 397.8898 309 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2868,13 +2822,13 @@ 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
Q
Q
q
-1 0 0 1 0 273 cm
+1 0 0 1 0 291 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Testing a plac application) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 273 cm
+1 0 0 1 397.8898 291 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2882,13 +2836,13 @@ 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
Q
Q
q
-1 0 0 1 0 255 cm
+1 0 0 1 0 273 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Plac easy tests) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 255 cm
+1 0 0 1 397.8898 273 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2896,13 +2850,13 @@ 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
Q
Q
q
-1 0 0 1 0 237 cm
+1 0 0 1 0 255 cm
q
BT 1 0 0 1 0 4.82 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Plac batch scripts) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 237 cm
+1 0 0 1 397.8898 255 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2910,13 +2864,13 @@ BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (6) Tj T* -66.44 0 Td ET
Q
Q
q
-1 0 0 1 0 219 cm
+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 (Implementing subcommands) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 219 cm
+1 0 0 1 397.8898 237 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -2924,6 +2878,20 @@ 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
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 (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 /F2 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 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 (Readline support) Tj T* ET
@@ -2934,7 +2902,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (11) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -2948,7 +2916,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (11) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (12) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -2962,7 +2930,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (15) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (14) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -2976,7 +2944,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (17) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (16) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -2990,7 +2958,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (17) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -3004,7 +2972,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (19) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (18) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -3074,7 +3042,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (25) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 4.82 Tm /F2 10 Tf 12 TL 60.88 0 Td (24) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -3095,24 +3063,18 @@ q
Q
Q
q
-1 0 0 1 62.69291 161.0236 cm
+1 0 0 1 62.69291 143.0236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Introduction) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 119.0236 cm
+1 0 0 1 62.69291 101.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 89.02362 cm
-q
-BT 1 0 0 1 0 16.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 ET
-Q
-Q
-q
1 0 0 1 56.69291 56.69291 cm
q
0 0 0 rg
@@ -3123,56 +3085,56 @@ Q
endstream
endobj
-% 'R163': class PDFStream
-163 0 obj
+% 'R160': class PDFStream
+160 0 obj
% page stream
-<< /Length 5305 >>
+<< /Length 5450 >>
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 729.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 (and can be run as batch scripts.) Tj T* ET
+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 711.0236 cm
+1 0 0 1 62.69291 687.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 645.0236 cm
+1 0 0 1 62.69291 621.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 612.0236 cm
+1 0 0 1 62.69291 588.0236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (From scripts to interactive applications) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 558.0236 cm
+1 0 0 1 62.69291 534.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 528.0236 cm
+1 0 0 1 62.69291 504.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 498.0236 cm
+1 0 0 1 62.69291 474.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 248.8236 cm
+1 0 0 1 62.69291 224.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3193,13 +3155,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 204.8236 cm
+1 0 0 1 62.69291 180.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 62.69291 171.6236 cm
+1 0 0 1 62.69291 147.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3230,11 +3192,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 72 re B*
+n -6 -6 468.6898 48 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 53.71 Tm /F4 10 Tf 12 TL (usage: 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* ET
+BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL (usage: shelve_interpreter.py [-h] [-interactive]) Tj T* ( [subcommands [subcommands ...]]) Tj T* T* ET
Q
Q
Q
@@ -3251,14 +3213,14 @@ Q
endstream
endobj
-% 'R164': class PDFStream
-164 0 obj
+% 'R161': class PDFStream
+161 0 obj
% page stream
-<< /Length 4183 >>
+<< /Length 4041 >>
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 631.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3268,25 +3230,25 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 108 re B*
+n -6 -6 468.6898 132 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 89.71 Tm /F4 10 Tf 12 TL ( ) 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
+BT 1 0 0 1 0 113.71 Tm /F4 10 Tf 12 TL ( 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 635.8236 cm
+1 0 0 1 62.69291 611.8236 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 590.6236 cm
+1 0 0 1 62.69291 566.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3307,14 +3269,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 570.6236 cm
+1 0 0 1 62.69291 546.6236 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 285.4236 cm
+1 0 0 1 62.69291 261.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3334,37 +3296,31 @@ Q
Q
Q
q
-1 0 0 1 62.69291 217.4236 cm
+1 0 0 1 62.69291 193.4236 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 187.4236 cm
+1 0 0 1 62.69291 163.4236 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 62.69291 154.4236 cm
+1 0 0 1 62.69291 130.4236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Testing a plac application) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 124.4236 cm
+1 0 0 1 62.69291 100.4236 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 106.4236 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 56.69291 56.69291 cm
q
0 0 0 rg
@@ -3375,14 +3331,20 @@ Q
endstream
endobj
-% 'R165': class PDFStream
-165 0 obj
+% 'R162': class PDFStream
+162 0 obj
% page stream
-<< /Length 5294 >>
+<< /Length 5561 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 607.8236 cm
+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 (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 587.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3403,19 +3365,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 563.8236 cm
+1 0 0 1 62.69291 543.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 521.8236 cm
+1 0 0 1 62.69291 501.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 368.6236 cm
+1 0 0 1 62.69291 348.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3436,28 +3398,28 @@ Q
Q
Q
q
-1 0 0 1 62.69291 312.6236 cm
+1 0 0 1 62.69291 292.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 258.6236 cm
+1 0 0 1 62.69291 238.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 240.6236 cm
+1 0 0 1 62.69291 220.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 234.6236 cm
+1 0 0 1 62.69291 214.6236 cm
Q
q
-1 0 0 1 62.69291 222.6236 cm
+1 0 0 1 62.69291 202.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3472,17 +3434,17 @@ q
Q
Q
q
-1 0 0 1 62.69291 222.6236 cm
+1 0 0 1 62.69291 202.6236 cm
Q
q
-1 0 0 1 62.69291 204.6236 cm
+1 0 0 1 62.69291 184.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 162.6236 cm
+1 0 0 1 62.69291 142.6236 cm
q
BT 1 0 0 1 0 28.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 (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
@@ -3498,8 +3460,8 @@ Q
endstream
endobj
-% 'R166': class PDFStream
-166 0 obj
+% 'R163': class PDFStream
+163 0 obj
% page stream
<< /Length 6149 >>
stream
@@ -3616,8 +3578,8 @@ Q
endstream
endobj
-% 'R167': class PDFStream
-167 0 obj
+% 'R164': class PDFStream
+164 0 obj
% page stream
<< /Length 5253 >>
stream
@@ -3737,10 +3699,10 @@ Q
endstream
endobj
-% 'R168': class PDFStream
-168 0 obj
+% 'R165': class PDFStream
+165 0 obj
% page stream
-<< /Length 4319 >>
+<< /Length 4316 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -3815,7 +3777,7 @@ n -6 -6 468.6898 252 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 233.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='~/conf.shelve'\):) Tj T* ( self.fname = os.path.expanduser\(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* ( def set\(self, name, value\):) Tj T* ( "set name value") Tj T* ( yield 'setting %s=%s' % \(name, value\)) Tj T* ET
+BT 1 0 0 1 0 233.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* ( def set\(self, name, value\):) Tj T* ( "set name value") Tj T* ET
Q
Q
Q
@@ -3832,14 +3794,14 @@ Q
endstream
endobj
-% 'R169': class PDFStream
-169 0 obj
+% 'R166': class PDFStream
+166 0 obj
% page stream
-<< /Length 4262 >>
+<< /Length 4288 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 487.8236 cm
+1 0 0 1 62.69291 475.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3849,30 +3811,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 276 re B*
+n -6 -6 468.6898 288 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 257.71 Tm /F4 10 Tf 12 TL ( 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
+BT 1 0 0 1 0 269.71 Tm /F4 10 Tf 12 TL ( 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 395.8236 cm
+1 0 0 1 62.69291 383.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 317.8236 cm
+1 0 0 1 62.69291 305.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 299.8236 cm
+1 0 0 1 62.69291 287.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
@@ -3889,10 +3851,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 192 re B*
+n -6 -6 468.6898 180 re B*
Q
q
-BT 1 0 0 1 0 173.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* (delete set show showall) Tj T* T* (i) Tj (>) Tj ( delete) Tj T* ET
+BT 1 0 0 1 0 161.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* (delete set show showall) Tj T* T* ET
Q
Q
Q
@@ -3909,14 +3871,14 @@ Q
endstream
endobj
-% 'R170': class PDFStream
-170 0 obj
+% 'R167': class PDFStream
+167 0 obj
% page stream
-<< /Length 3748 >>
+<< /Length 5042 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 513.3633 cm
+1 0 0 1 62.69291 504.0769 cm
q
q
.773863 0 0 .773863 0 0 cm
@@ -3926,48 +3888,103 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 606 324 re B*
+n -6 -6 606 336 re B*
Q
q
-BT 1 0 0 1 0 305.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (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
+BT 1 0 0 1 0 317.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (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 481.3633 cm
+1 0 0 1 62.69291 472.0769 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 448.3633 cm
+1 0 0 1 62.69291 439.0769 cm
q
-BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Readline support) Tj T* ET
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (plac.Interpreter.call) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 370.3633 cm
+1 0 0 1 62.69291 397.0769 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
+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 106.5859 cm
+1 0 0 1 62.69291 351.8769 cm
q
q
-.96447 0 0 .96447 0 0 cm
+1 0 0 1 0 0 cm
q
-1 0 0 1 6.6 6.843137 cm
+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 295.8769 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 250.6769 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 486 264 re B*
+n -6 -6 468.6898 36 re B*
Q
q
-BT 1 0 0 1 0 245.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* ET
+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 146.6769 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 62.69291 89.47694 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 (# ishelve3.py) Tj T* (from ishelve2 import ShelveInterface as main) Tj T* T* ET
Q
Q
Q
@@ -3984,14 +4001,63 @@ Q
endstream
endobj
-% 'R171': class PDFStream
-171 0 obj
+% 'R168': class PDFStream
+168 0 obj
% page stream
-<< /Length 4503 >>
+<< /Length 4455 >>
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 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 (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 707.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 674.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 557.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4004,21 +4070,75 @@ q
n -6 -6 468.6898 108 re B*
Q
q
-BT 1 0 0 1 0 89.71 Tm 12 TL /F4 10 Tf 0 0 0 rg 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* ( si = plac.call\(SqlInterface\)) Tj T* ( i = plac.Interpreter\(si, split=split_on_first_space\)) Tj T* ( i.interact\(rl_input, prompt='sql) Tj (>) Tj ( '\)) Tj T* ET
+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 635.8236 cm
+1 0 0 1 62.69291 488.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 4.82 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET
+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 578.6236 cm
+1 0 0 1 62.69291 456.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 363.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 319.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 301.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 243.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4031,32 +4151,76 @@ q
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
+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 498.6236 cm
+1 0 0 1 62.69291 163.8236 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
+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 62.69291 420.6236 cm
+1 0 0 1 56.69291 56.69291 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 1.869984 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 1 0 0 rg (pyreadline_) Tj T* 0 Tw .74408 Tw 0 0 0 rg (library \(I do not use Windows, so this part is very little tested: I tried it only once and it worked, but your) Tj T* 0 Tw .441163 Tw (mileage 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) Tj T* 0 Tw .211353 Tw (if 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
+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
+% 'R169': class PDFStream
+169 0 obj
+% page stream
+<< /Length 5082 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 378.6236 cm
+1 0 0 1 62.69291 744.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
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Readline support) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 666.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 321.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 93.42362 cm
+1 0 0 1 62.69291 301.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 244.0307 cm
q
q
1 0 0 1 0 0 cm
@@ -4066,34 +4230,59 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 276 re B*
+n -6 -6 468.6898 48 re B*
Q
q
-BT 1 0 0 1 0 257.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* ET
+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 164.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 98.03071 cm
+q
+BT 1 0 0 1 0 52.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 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
+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
-% 'R172': class PDFStream
-172 0 obj
+% 'R170': class PDFStream
+170 0 obj
% page stream
-<< /Length 6026 >>
+<< /Length 4532 >>
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 753.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (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 62.69291 711.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 401.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4103,35 +4292,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 36 re B*
+n -6 -6 468.6898 300 re B*
Q
q
-BT 1 0 0 1 0 17.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (positional arguments:) Tj T* ( names) Tj T* ET
+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 671.8236 cm
+1 0 0 1 62.69291 345.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 641.8236 cm
+1 0 0 1 62.69291 315.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 623.8236 cm
+1 0 0 1 62.69291 297.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 578.6236 cm
+1 0 0 1 62.69291 252.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4151,25 +4340,42 @@ Q
Q
Q
q
-1 0 0 1 62.69291 545.6236 cm
+1 0 0 1 62.69291 219.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The plac runner) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 479.6236 cm
+1 0 0 1 62.69291 153.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 449.6236 cm
+1 0 0 1 62.69291 123.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 380.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 (12) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R171': class PDFStream
+171 0 obj
+% page stream
+<< /Length 4227 >>
+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
@@ -4190,13 +4396,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 312.4236 cm
+1 0 0 1 62.69291 635.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 223.2505 cm
+1 0 0 1 62.69291 546.6505 cm
q
q
.952737 0 0 .952737 0 0 cm
@@ -4217,24 +4423,24 @@ Q
Q
Q
q
-1 0 0 1 62.69291 191.2505 cm
+1 0 0 1 62.69291 514.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 161.2505 cm
+1 0 0 1 62.69291 484.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 155.2505 cm
+1 0 0 1 62.69291 478.6505 cm
Q
q
-1 0 0 1 62.69291 143.2505 cm
+1 0 0 1 62.69291 466.6505 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -4249,33 +4455,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 143.2505 cm
+1 0 0 1 62.69291 466.6505 cm
Q
q
-1 0 0 1 62.69291 113.2505 cm
+1 0 0 1 62.69291 436.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 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
-% 'R173': class PDFStream
-173 0 obj
-% page stream
-<< /Length 4848 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 595.8236 cm
+1 0 0 1 62.69291 259.4505 cm
q
q
1 0 0 1 0 0 cm
@@ -4295,13 +4484,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 575.8236 cm
+1 0 0 1 62.69291 239.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 446.6236 cm
+1 0 0 1 62.69291 110.2505 cm
q
q
1 0 0 1 0 0 cm
@@ -4321,20 +4510,37 @@ Q
Q
Q
q
-1 0 0 1 62.69291 414.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 235.3849 0 Td (13) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R172': class PDFStream
+172 0 obj
+% page stream
+<< /Length 5347 >>
+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.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 62.69291 396.6236 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 (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 351.4236 cm
+1 0 0 1 62.69291 677.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4355,19 +4561,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 307.4236 cm
+1 0 0 1 62.69291 633.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 277.4236 cm
+1 0 0 1 62.69291 603.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 244.2236 cm
+1 0 0 1 62.69291 570.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4388,23 +4594,23 @@ Q
Q
Q
q
-1 0 0 1 62.69291 212.2236 cm
+1 0 0 1 62.69291 538.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 194.2236 cm
+1 0 0 1 62.69291 520.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 188.2236 cm
+1 0 0 1 62.69291 514.6236 cm
Q
q
-1 0 0 1 62.69291 176.2236 cm
+1 0 0 1 62.69291 502.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -4419,17 +4625,17 @@ q
Q
Q
q
-1 0 0 1 62.69291 176.2236 cm
+1 0 0 1 62.69291 502.6236 cm
Q
q
-1 0 0 1 62.69291 158.2236 cm
+1 0 0 1 62.69291 484.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 89.02362 cm
+1 0 0 1 62.69291 415.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4450,63 +4656,32 @@ 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 (12) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R174': class PDFStream
-174 0 obj
-% page stream
-<< /Length 5041 >>
-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 383.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 735.0236 cm
-Q
-q
-1 0 0 1 62.69291 88.86614 cm
-0 0 0 rg
-BT /F3 10 Tf 12 TL ET
-BT 1 0 0 1 0 2 Tm T* ET
-q
-1 0 0 1 20 618.33 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (Multiline support and Emacs integration) Tj T* ET
-Q
-Q
-q
-1 0 0 1 20 504.33 cm
+1 0 0 1 62.69291 350.4236 cm
q
-BT 1 0 0 1 0 100.82 Tm .36436 Tw 12 TL /F1 10 Tf 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is optimized for the simplest use case and by default it provide support for simple command-line) Tj T* 0 Tw .598409 Tw (languages where a command take a single line. This is the simplest case: it is easy to keep track of) Tj T* 0 Tw 1.096988 Tw (the line number and to print it in the error message, if there is some error in a ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (script. Starting) Tj T* 0 Tw .08561 Tw (from release 0.7 ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (is beginning to support multiline input: it is now possible to define command-line) Tj T* 0 Tw .970697 Tw (languages with commands spanning multiple lines. The topical use case is the implementation of a) Tj T* 0 Tw 2.41061 Tw (tool to interact with a relational database: the tool must be able to send complex SQL queries) Tj T* 0 Tw .636905 Tw (spanning multiple lines to the backend. To support multiline input the ) Tj /F4 10 Tf (Interpreter ) Tj /F1 10 Tf (class provides) Tj T* 0 Tw .678294 Tw (a method ) Tj /F4 10 Tf (multiline\(stdin=sys.stdin, terminator=';', verbose=False\) ) Tj /F1 10 Tf (which reads) Tj T* 0 Tw (input from ) Tj /F4 10 Tf (stdin ) Tj /F1 10 Tf (until the terminator character \(by default a semicolon\) is reached.) Tj T* ET
+BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A non class-based example) Tj T* ET
Q
Q
q
-1 0 0 1 20 426.33 cm
+1 0 0 1 62.69291 308.4236 cm
q
-BT 1 0 0 1 0 64.82 Tm 1.842126 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since the Python readline module does not expose the multiline functionality of the underlying C) Tj T* 0 Tw .244692 Tw (library \(which is there\), ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (multiline mode does not have readline functionality. This is not a big deal) Tj T* 0 Tw 1.210574 Tw (really, because if you are writing multiple line commands you don't really want to type them at the) Tj T* 0 Tw 1.299988 Tw (command-line. It is much better to use a real editor to type them, and to call ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (from the editor.) Tj T* 0 Tw .962927 Tw (Since I use Emacs I will give the recipe to integrate Emacs with ) Tj 0 0 .501961 rg (plac) Tj 0 0 0 rg (: something equivalent can be) Tj T* 0 Tw (done for vi and for other editors/IDEs.) Tj T* ET
+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 20 384.33 cm
+1 0 0 1 62.69291 278.4236 cm
q
-BT 1 0 0 1 0 28.82 Tm .001163 Tw 12 TL /F1 10 Tf 0 0 0 rg (The multiline mode can be enabled by invoking the ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (runner with the ) Tj /F4 10 Tf (-m ) Tj /F1 10 Tf (option. Since the multiline) Tj T* 0 Tw 2.052209 Tw (mode is intended for use with Emacs in inferior mode, it does not print any prompt. Here is an) Tj T* 0 Tw (example of usage:) Tj T* ET
+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 20 303.13 cm
+1 0 0 1 62.69291 89.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -4516,93 +4691,16 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 442.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 -m ishelve2.py) Tj T* (set a 1;) Tj T* (setting a=1) Tj T* (show a;) Tj T* (a = 1) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-1 0 0 1 20 277.13 cm
-q
-BT 1 0 0 1 0 4.82 Tm 12 TL /F1 10 Tf 0 0 0 rg (To integrate ) Tj 0 0 .501961 rg (plac ) Tj 0 0 0 rg (with Emacs, enters the following lines in your .emacs:) Tj T* ET
-Q
-Q
-q
-1 0 0 1 20 0 cm
-q
-q
-.970887 0 0 .970887 0 0 cm
-q
-1 0 0 1 6.6 6.797904 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 456 276 re B*
-Q
-q
-BT 1 0 0 1 0 257.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (;;; Emacs-plac integration: add the following to your .emacs) Tj T* T* (\(define-generic-mode 'plac-mode) Tj T* ( '\("#"\) ; comment chars) Tj T* ( '\(\); highlighted commands) Tj T* ( nil) Tj T* ( '\(".plac\\\\'"\); file extensions) Tj T* ( nil\)) Tj T* ( ) Tj T* (\(add-hook 'plac-mode-hook \(lambda \(\) \(local-set-key [f4] 'plac-start\)\)\)) Tj T* (\(add-hook 'plac-mode-hook \(lambda \(\) \(local-set-key [f5] 'plac-send\)\)\)) Tj T* (\(add-hook 'plac-mode-hook \(lambda \(\) \(local-set-key [f6] 'plac-stop\)\)\)) Tj T* T* (\(defconst terminator 59\); ASCII code for the semicolon) Tj T* (\(defvar *plac-process* nil\)) Tj T* T* (\(defun plac-start \(\)) Tj T* ( "Start an inferior plac process by inferring the script to use from the ) Tj T* ( shebang line") Tj T* ( \(interactive\)) Tj T* ( \(let \(\(shebang-line ) Tj T* ( \(save-excursion) Tj T* ET
-Q
-Q
-Q
-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 (13) Tj T* -235.3849 0 Td ET
-Q
+n -6 -6 468.6898 180 re B*
Q
-
-endstream
-
-endobj
-% 'R175': class PDFStream
-175 0 obj
-% page stream
-<< /Length 3087 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 47.6378 159.1303 cm
0 0 0 rg
-BT /F3 10 Tf 12 TL ET
-BT 1 0 0 1 0 2 Tm T* ET
-q
-1 0 0 1 20 0 cm
-q
-q
-.90002 0 0 .90002 0 0 cm
-q
-1 0 0 1 6.6 7.333172 cm
-q
-.662745 .662745 .662745 RG
-.5 w
-.960784 .960784 .862745 rg
-n -6 -6 492 672 re B*
+BT 1 0 0 1 0 161.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* ET
Q
-q
-BT 1 0 0 1 0 653.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( \(goto-line 1\) \(end-of-line\)) Tj T* ( \(buffer-substring-no-properties 3 \(point\)\)\)\)\)) Tj T* ( \(if *plac-process* \(princ "plac already started"\)) Tj T* ( \(setq *plac-process*) Tj T* ( \(start-process) Tj T* ( "plac" "*plac*" "plac_runner.py" "-m" shebang-line\)\)\)\)) Tj T* ( \(display-buffer "*plac*"\)\)) Tj T* T* (;\(defun plac-send \(\)) Tj T* (; "Send the current region to the inferior plac process") Tj T* (; \(interactive\)) Tj T* (; \(save-excursion \(set-buffer "*plac*"\) \(erase-buffer\)\)) Tj T* (; \(process-send-region *plac-process* \(region-beginning\) \(region-end\)\)\)) Tj T* T* (\(defun current-paragraph-beg-end \(\)) Tj T* ( "Returns the extrema of the current paragraph, delimited by semicolons") Tj T* ( \(interactive\)) Tj T* ( \(save-excursion) Tj T* ( \(let \(\(beg \(save-excursion \(goto-line 2\) \(point\)\)\); skip the shebang) Tj T* ( \(end \(point-max\)\)\)) Tj T* ( ;; go backward) Tj T* ( \(while \() Tj (>) Tj ( \(point\) beg\)) Tj T* ( \(goto-char \(1- \(point\)\)\)) Tj T* ( \(if \(= terminator \(following-char\)\)) Tj T* ( \(setq beg \(point\)\)\)\)) Tj T* ( \(if \(= terminator \(following-char\)\)) Tj T* ( \(setq beg \(1+ beg\)\)\)) Tj T* ( ;; go forward) Tj T* ( \(while \() Tj (<) Tj ( \(point\) end\)) Tj T* ( \(goto-char \(1+ \(point\)\)\)) Tj T* ( \(if \(= 59 \(following-char\)\)) Tj T* ( \(setq end \(point\)\)\)\)) Tj T* ( \(if \(= 59 \(following-char\)\)) Tj T* ( \(setq end \(1+ end\)\)\)) Tj T* ( \(list beg end\)\)\)\)) Tj T* ( ) Tj T* (\(defun plac-send \(\)) Tj T* ( "Send the current region to the inferior plac process") Tj T* ( \(interactive\)) Tj T* ( \(save-excursion \(set-buffer "*plac*"\) \(erase-buffer\)\)) Tj T* ( \(let \(\(p \(apply 'buffer-substring-no-properties \(current-paragraph-beg-end\)\)\)\)) Tj T* ( \(message p\)) Tj T* ( \(process-send-string *plac-process* \(concat p "\\n"\)\)\)\)) Tj T* ( ;\(switch-to-buffer-other-window "*plac*"\)\)\)) Tj T* ( ;\(save-excursion \(set-buffer "*plac*"\) ) Tj T* ( ; \(set-window-start \(selected-window\) 1 nil\)\)\)\)) Tj T* T* (\(defun plac-stop \(\)) Tj T* ( "Stop the inferior plac process by sending to it an EOF") Tj T* ( \(interactive\)) Tj T* ( \(process-send-eof *plac-process*\)) Tj T* ( \(setq *plac-process* nil\)) Tj T* ( "killed *plac-process*"\)) Tj T* T* (\(provide 'plac\)) Tj T* ET
Q
Q
Q
Q
-Q
-q
-Q
-Q
-q
-1 0 0 1 62.69291 159.1303 cm
-Q
q
1 0 0 1 56.69291 56.69291 cm
q
@@ -4614,33 +4712,14 @@ Q
endstream
endobj
-% 'R176': class PDFStream
-176 0 obj
+% 'R173': class PDFStream
+173 0 obj
% page stream
-<< /Length 3684 >>
+<< /Length 3894 >>
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 (A non class-based example) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 702.0236 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 672.0236 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 290.8236 cm
+1 0 0 1 62.69291 559.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4650,30 +4729,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 372 re B*
+n -6 -6 468.6898 204 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 353.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* (@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
+BT 1 0 0 1 0 185.71 Tm /F4 10 Tf 12 TL ( return \('commit ', message\)) Tj T* T* (@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 246.8236 cm
+1 0 0 1 62.69291 515.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 216.8236 cm
+1 0 0 1 62.69291 485.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 99.62362 cm
+1 0 0 1 62.69291 344.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4683,35 +4762,24 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 108 re B*
+n -6 -6 468.6898 132 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 89.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* ET
+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 56.69291 56.69291 cm
+1 0 0 1 62.69291 324.6236 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
+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
-
-endstream
-
-endobj
-% 'R177': class PDFStream
-177 0 obj
-% page stream
-<< /Length 3422 >>
-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 207.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4721,24 +4789,31 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 36 re B*
+n -6 -6 468.6898 108 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 17.71 Tm /F4 10 Tf 12 TL ( {status,commit,checkout}) Tj T* ( -h to get additional help) Tj T* ET
+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 707.8236 cm
+1 0 0 1 62.69291 175.4236 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
+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 590.6236 cm
+1 0 0 1 62.69291 157.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
@@ -4748,31 +4823,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 108 re B*
+n -6 -6 468.6898 48 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
+BT 1 0 0 1 0 29.71 Tm /F4 10 Tf 12 TL ($ plac vcs.py check url) Tj T* (checkout) Tj T* (url) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 558.6236 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 540.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 an example of a non-interactive session:) Tj T* ET
+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
+% 'R174': class PDFStream
+174 0 obj
+% page stream
+<< /Length 5650 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 411.4236 cm
+1 0 0 1 62.69291 679.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4782,25 +4861,25 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 120 re B*
+n -6 -6 468.6898 84 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 101.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* (True) Tj T* ($ plac vcs.py co) Tj T* (commit) Tj T* (None) Tj T* ET
+BT 1 0 0 1 0 65.71 Tm /F4 10 Tf 12 TL ($ plac vcs.py st -q) Tj T* (status) Tj T* (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 391.4236 cm
+1 0 0 1 62.69291 659.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 190.2236 cm
+1 0 0 1 62.69291 458.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4820,55 +4899,38 @@ Q
Q
Q
q
-1 0 0 1 62.69291 158.2236 cm
+1 0 0 1 62.69291 426.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 128.2236 cm
+1 0 0 1 62.69291 396.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 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
-% 'R178': class PDFStream
-178 0 obj
-% page stream
-<< /Length 5984 >>
-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
+1 0 0 1 62.69291 363.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Writing your own plac runner) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 690.0236 cm
+1 0 0 1 62.69291 309.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 684.0236 cm
+1 0 0 1 62.69291 303.6236 cm
Q
q
-1 0 0 1 62.69291 684.0236 cm
+1 0 0 1 62.69291 303.6236 cm
Q
q
-1 0 0 1 62.69291 666.0236 cm
+1 0 0 1 62.69291 285.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -4888,13 +4950,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 666.0236 cm
+1 0 0 1 62.69291 285.6236 cm
Q
q
-1 0 0 1 62.69291 666.0236 cm
+1 0 0 1 62.69291 285.6236 cm
Q
q
-1 0 0 1 62.69291 648.0236 cm
+1 0 0 1 62.69291 267.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -4914,13 +4976,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 648.0236 cm
+1 0 0 1 62.69291 267.6236 cm
Q
q
-1 0 0 1 62.69291 648.0236 cm
+1 0 0 1 62.69291 267.6236 cm
Q
q
-1 0 0 1 62.69291 630.0236 cm
+1 0 0 1 62.69291 249.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -4940,13 +5002,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 630.0236 cm
+1 0 0 1 62.69291 249.6236 cm
Q
q
-1 0 0 1 62.69291 630.0236 cm
+1 0 0 1 62.69291 249.6236 cm
Q
q
-1 0 0 1 62.69291 612.0236 cm
+1 0 0 1 62.69291 231.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -4966,25 +5028,25 @@ q
Q
Q
q
-1 0 0 1 62.69291 612.0236 cm
+1 0 0 1 62.69291 231.6236 cm
Q
q
-1 0 0 1 62.69291 612.0236 cm
+1 0 0 1 62.69291 231.6236 cm
Q
q
-1 0 0 1 62.69291 570.0236 cm
+1 0 0 1 62.69291 189.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 552.0236 cm
+1 0 0 1 62.69291 171.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 458.8236 cm
+1 0 0 1 62.69291 90.42362 cm
q
q
1 0 0 1 0 0 cm
@@ -4994,30 +5056,67 @@ 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
-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
+BT 1 0 0 1 0 53.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* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 426.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
+% 'R175': class PDFStream
+175 0 obj
+% page stream
+<< /Length 5042 >>
+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
+BT 1 0 0 1 0 5.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (SystemExit: unrecognized arguments: .cler) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 707.8236 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 384.8236 cm
+1 0 0 1 62.69291 665.8236 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 147.6236 cm
+1 0 0 1 62.69291 428.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5038,37 +5137,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 115.6236 cm
+1 0 0 1 62.69291 396.6236 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 56.69291 56.69291 cm
+1 0 0 1 62.69291 366.6236 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 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
-
-endstream
-
-endobj
-% 'R179': class PDFStream
-179 0 obj
-% page stream
-<< /Length 4283 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 717.0236 cm
+1 0 0 1 62.69291 312.6236 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 659.8236 cm
+1 0 0 1 62.69291 255.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5089,25 +5177,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 627.8236 cm
+1 0 0 1 62.69291 223.4236 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 594.8236 cm
+1 0 0 1 62.69291 190.4236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Long running commands) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 552.8236 cm
+1 0 0 1 62.69291 148.4236 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 291.6236 cm
+1 0 0 1 62.69291 91.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -5117,24 +5205,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 252 re B*
+n -6 -6 468.6898 48 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 233.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* ( 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\(plac.call\(FakeImporter\)\).interact\(\)) Tj T* ET
+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 62.69291 259.6236 cm
+1 0 0 1 56.69291 56.69291 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
+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
+% 'R176': class PDFStream
+176 0 obj
+% page stream
+<< /Length 4422 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 130.4236 cm
+1 0 0 1 62.69291 547.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5144,63 +5243,66 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 120 re B*
+n -6 -6 468.6898 216 re B*
Q
q
-BT 1 0 0 1 0 101.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* (Imported 100 lines) Tj T* (Imported 200 lines) Tj T* (Imported 300 lines) Tj T* (... ) Tj (<) Tj (wait 3+ minutes) Tj (>) Tj T* (Imported 10000 lines) Tj T* (closing the file) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 197.71 Tm /F4 10 Tf 12 TL (class FakeImporter\(object\):) Tj T* ( "A fake importer with an import_file command") Tj T* ( commands = ['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\(.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 98.42362 cm
+1 0 0 1 62.69291 515.8236 cm
q
-BT 1 0 0 1 0 16.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 ET
+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 56.69291 56.69291 cm
+1 0 0 1 62.69291 374.6236 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
+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
-
-endstream
-
-endobj
-% 'R180': class PDFStream
-180 0 obj
-% page stream
-<< /Length 5339 >>
-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 330.6236 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 4.82 Tm /F1 10 Tf 12 TL (reach this goal: threads and processes.) Tj T* ET
+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 720.0236 cm
+1 0 0 1 62.69291 297.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Threaded commands) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 690.0236 cm
+1 0 0 1 62.69291 267.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 684.0236 cm
+1 0 0 1 62.69291 261.6236 cm
Q
q
-1 0 0 1 62.69291 672.0236 cm
+1 0 0 1 62.69291 249.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -5215,20 +5317,20 @@ q
Q
Q
q
-1 0 0 1 62.69291 672.0236 cm
+1 0 0 1 62.69291 249.6236 cm
Q
q
-1 0 0 1 62.69291 654.0236 cm
+1 0 0 1 62.69291 231.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 648.0236 cm
+1 0 0 1 62.69291 225.6236 cm
Q
q
-1 0 0 1 62.69291 636.0236 cm
+1 0 0 1 62.69291 213.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -5243,16 +5345,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 636.0236 cm
+1 0 0 1 62.69291 213.6236 cm
Q
q
-1 0 0 1 62.69291 606.0236 cm
+1 0 0 1 62.69291 183.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 560.8236 cm
+1 0 0 1 62.69291 138.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5272,13 +5374,30 @@ Q
Q
Q
q
-1 0 0 1 62.69291 528.8236 cm
+1 0 0 1 62.69291 106.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 459.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 235.3849 0 Td (18) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R177': class PDFStream
+177 0 obj
+% page stream
+<< /Length 4933 >>
+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
@@ -5298,14 +5417,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 439.6236 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 (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 346.4236 cm
+1 0 0 1 62.69291 590.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5325,14 +5444,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 326.4236 cm
+1 0 0 1 62.69291 570.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 281.2236 cm
+1 0 0 1 62.69291 525.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5352,20 +5471,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 249.2236 cm
+1 0 0 1 62.69291 493.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 231.2236 cm
+1 0 0 1 62.69291 475.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 162.0236 cm
+1 0 0 1 62.69291 406.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -5385,50 +5504,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 142.0236 cm
+1 0 0 1 62.69291 386.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 96.82362 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 ( .list) Tj T* (<) Tj (ThreadedTask 5 [import_file file2] 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 (19) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R181': class PDFStream
-181 0 obj
-% page stream
-<< /Length 4995 >>
-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 329.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -5438,24 +5520,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 48 re B*
Q
q
-BT 1 0 0 1 0 5.71 Tm 12 TL /F4 10 Tf 0 0 0 rg (<) Tj (ThreadedTask 6 [import_file file3] RUNNING) Tj (>) Tj T* ET
+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 719.8236 cm
+1 0 0 1 62.69291 309.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 626.6236 cm
+1 0 0 1 62.69291 215.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5475,13 +5557,30 @@ Q
Q
Q
q
-1 0 0 1 62.69291 534.6236 cm
+1 0 0 1 62.69291 123.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 249.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 (19) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R178': class PDFStream
+178 0 obj
+% page stream
+<< /Length 4294 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 487.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5495,36 +5594,36 @@ n -6 -6 468.6898 276 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 257.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* ( 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\(plac.call\(FakeImporter\)\).interact\(\)) Tj T* ET
+BT 1 0 0 1 0 257.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* ( 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 216.4236 cm
+1 0 0 1 62.69291 454.8236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Running commands as external processes) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 162.4236 cm
+1 0 0 1 62.69291 400.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 144.4236 cm
+1 0 0 1 62.69291 382.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 138.4236 cm
+1 0 0 1 62.69291 376.8236 cm
Q
q
-1 0 0 1 62.69291 126.4236 cm
+1 0 0 1 62.69291 364.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -5539,20 +5638,20 @@ q
Q
Q
q
-1 0 0 1 62.69291 126.4236 cm
+1 0 0 1 62.69291 364.8236 cm
Q
q
-1 0 0 1 62.69291 108.4236 cm
+1 0 0 1 62.69291 346.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 102.4236 cm
+1 0 0 1 62.69291 340.8236 cm
Q
q
-1 0 0 1 62.69291 90.42362 cm
+1 0 0 1 62.69291 328.8236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -5566,34 +5665,17 @@ q
Q
Q
q
-1 0 0 1 62.69291 90.42362 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 (20) Tj T* -235.3849 0 Td ET
+1 0 0 1 62.69291 328.8236 cm
Q
-Q
-
-endstream
-
-endobj
-% 'R182': class PDFStream
-182 0 obj
-% page stream
-<< /Length 5075 >>
-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 298.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 599.8236 cm
+1 0 0 1 62.69291 157.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5613,46 +5695,63 @@ Q
Q
Q
q
-1 0 0 1 62.69291 543.8236 cm
+1 0 0 1 62.69291 101.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 489.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 (20) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R179': class PDFStream
+179 0 obj
+% page stream
+<< /Length 4183 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
+q
+1 0 0 1 62.69291 717.0236 cm
q
BT 1 0 0 1 0 40.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 /F1 10 Tf (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 459.8236 cm
+1 0 0 1 62.69291 687.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 426.8236 cm
+1 0 0 1 62.69291 654.0236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Managing the output of concurrent commands) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 324.8236 cm
+1 0 0 1 62.69291 552.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 294.8236 cm
+1 0 0 1 62.69291 522.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 93.62362 cm
+1 0 0 1 62.69291 152.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5662,11 +5761,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 192 re B*
+n -6 -6 468.6898 360 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 173.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* ET
+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
@@ -5683,47 +5782,26 @@ Q
endstream
endobj
-% 'R183': class PDFStream
-183 0 obj
+% 'R180': class PDFStream
+180 0 obj
% page stream
-<< /Length 4632 >>
+<< /Length 4670 >>
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 ( 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 62.69291 550.8236 cm
+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 (Parallel computing with plac) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 436.8236 cm
+1 0 0 1 62.69291 630.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 331.6236 cm
+1 0 0 1 62.69291 524.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5743,20 +5821,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 263.6236 cm
+1 0 0 1 62.69291 456.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 233.6236 cm
+1 0 0 1 62.69291 426.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 92.42362 cm
+1 0 0 1 62.69291 93.62362 cm
q
q
1 0 0 1 0 0 cm
@@ -5766,10 +5844,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 132 re B*
+n -6 -6 468.6898 324 re B*
Q
q
-BT 1 0 0 1 0 113.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* ET
+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
@@ -5786,14 +5864,14 @@ Q
endstream
endobj
-% 'R184': class PDFStream
-184 0 obj
+% 'R181': class PDFStream
+181 0 obj
% page stream
-<< /Length 2492 >>
+<< /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 115.8236 cm
+1 0 0 1 62.69291 307.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5803,47 +5881,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 648 re B*
+n -6 -6 468.6898 456 re B*
Q
q
-BT 1 0 0 1 0 629.71 Tm 12 TL /F4 10 Tf 0 0 0 rg ( 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* ( 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
+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
-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
-% 'R185': class PDFStream
-185 0 obj
-% page stream
-<< /Length 4788 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 693.0236 cm
+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 675.0236 cm
+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 581.8236 cm
+1 0 0 1 62.69291 116.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5864,26 +5925,43 @@ Q
Q
Q
q
-1 0 0 1 62.69291 549.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 (23) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R182': class PDFStream
+182 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
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 516.8236 cm
+1 0 0 1 62.69291 708.0236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The plac server) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 402.8236 cm
+1 0 0 1 62.69291 594.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:) Tj T* ET
+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 273.6236 cm
+1 0 0 1 62.69291 464.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -5904,50 +5982,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 253.6236 cm
+1 0 0 1 62.69291 444.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 100.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 144 re B*
-Q
-q
-BT 1 0 0 1 0 125.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* 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 (24) Tj T* -235.3849 0 Td ET
-Q
-Q
-
-endstream
-
-endobj
-% 'R186': class PDFStream
-186 0 obj
-% page stream
-<< /Length 7197 >>
-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 267.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -5957,35 +5998,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 36 re B*
+n -6 -6 468.6898 168 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 ( EOF) Tj T* (Connection closed by foreign host.) Tj T* ET
+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 694.8236 cm
+1 0 0 1 62.69291 234.6236 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Summary) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 652.8236 cm
+1 0 0 1 62.69291 192.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 646.8236 cm
+1 0 0 1 62.69291 186.6236 cm
Q
q
-1 0 0 1 62.69291 646.8236 cm
+1 0 0 1 62.69291 186.6236 cm
Q
q
-1 0 0 1 62.69291 628.8236 cm
+1 0 0 1 62.69291 168.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -6005,13 +6046,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 628.8236 cm
+1 0 0 1 62.69291 168.6236 cm
Q
q
-1 0 0 1 62.69291 628.8236 cm
+1 0 0 1 62.69291 168.6236 cm
Q
q
-1 0 0 1 62.69291 568.8236 cm
+1 0 0 1 62.69291 108.6236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -6089,13 +6130,30 @@ q
Q
Q
q
-1 0 0 1 62.69291 568.8236 cm
+1 0 0 1 62.69291 108.6236 cm
Q
q
-1 0 0 1 62.69291 568.8236 cm
+1 0 0 1 62.69291 108.6236 cm
Q
q
-1 0 0 1 62.69291 538.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 (24) Tj T* -235.3849 0 Td ET
+Q
+Q
+
+endstream
+
+endobj
+% 'R183': class PDFStream
+183 0 obj
+% page stream
+<< /Length 5397 >>
+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
@@ -6115,13 +6173,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 538.8236 cm
+1 0 0 1 62.69291 735.0236 cm
Q
q
-1 0 0 1 62.69291 538.8236 cm
+1 0 0 1 62.69291 735.0236 cm
Q
q
-1 0 0 1 62.69291 508.8236 cm
+1 0 0 1 62.69291 705.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -6141,13 +6199,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 508.8236 cm
+1 0 0 1 62.69291 705.0236 cm
Q
q
-1 0 0 1 62.69291 508.8236 cm
+1 0 0 1 62.69291 705.0236 cm
Q
q
-1 0 0 1 62.69291 478.8236 cm
+1 0 0 1 62.69291 675.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -6167,13 +6225,13 @@ q
Q
Q
q
-1 0 0 1 62.69291 478.8236 cm
+1 0 0 1 62.69291 675.0236 cm
Q
q
-1 0 0 1 62.69291 478.8236 cm
+1 0 0 1 62.69291 675.0236 cm
Q
q
-1 0 0 1 62.69291 448.8236 cm
+1 0 0 1 62.69291 645.0236 cm
0 0 0 rg
BT /F3 10 Tf 12 TL ET
q
@@ -6193,38 +6251,42 @@ q
Q
Q
q
-1 0 0 1 62.69291 448.8236 cm
+1 0 0 1 62.69291 645.0236 cm
Q
q
-1 0 0 1 62.69291 448.8236 cm
+1 0 0 1 62.69291 645.0236 cm
Q
q
-1 0 0 1 62.69291 430.8236 cm
+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 397.8236 cm
+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 565.6772 cm
q
BT 1 0 0 1 0 8.435 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Appendix: custom annotation objects) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 367.8236 cm
+1 0 0 1 62.69291 535.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 337.8236 cm
+1 0 0 1 62.69291 505.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 208.6236 cm
+1 0 0 1 62.69291 376.4772 cm
q
q
1 0 0 1 0 0 cm
@@ -6245,14 +6307,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 188.6236 cm
+1 0 0 1 62.69291 356.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 95.42362 cm
+1 0 0 1 62.69291 179.2772 cm
q
q
1 0 0 1 0 0 cm
@@ -6262,35 +6324,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 168 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 65.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* ET
+BT 1 0 0 1 0 149.71 Tm /F4 10 Tf 12 TL (# example11.py) Tj T* (import plac) Tj T* (from annotations import Positional) Tj T* T* (@plac.annotations\() Tj T* ( i=Positional\("This is an int", int\),) Tj T* ( n=Positional\("This is a float", float\),) Tj T* ( rest=Positional\("Other arguments"\)\)) Tj T* (def main\(i, n, *rest\):) Tj T* ( print\(i, n, rest\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 56.69291 56.69291 cm
+1 0 0 1 62.69291 159.2772 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
+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
-
-endstream
-
-endobj
-% 'R187': class PDFStream
-187 0 obj
-% page stream
-<< /Length 1862 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 667.8236 cm
+1 0 0 1 62.69291 90.07717 cm
q
q
1 0 0 1 0 0 cm
@@ -6300,25 +6352,35 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 96 re B*
+n -6 -6 468.6898 60 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 77.71 Tm /F4 10 Tf 12 TL ( n=Positional\("This is a float", float\),) Tj T* ( rest=Positional\("Other arguments"\)\)) Tj T* (def main\(i, n, *rest\):) Tj T* ( print\(i, n, rest\)) Tj T* T* (if __name__ == '__main__':) Tj T* ( import plac; plac.call\(main\)) Tj T* ET
+BT 1 0 0 1 0 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 62.69291 647.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 (Here is the usage message you get:) Tj T* ET
+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
+% 'R184': class PDFStream
+184 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 518.6236 cm
+1 0 0 1 62.69291 691.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -6328,18 +6390,18 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 120 re B*
+n -6 -6 468.6898 72 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 101.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* ( 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
+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 474.6236 cm
+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
@@ -6355,220 +6417,220 @@ Q
endstream
endobj
-% 'R188': class PDFPageLabels
-188 0 obj
+% 'R185': class PDFPageLabels
+185 0 obj
% Document Root
<< /Nums [ 0
- 189 0 R
+ 186 0 R
1
- 190 0 R
+ 187 0 R
2
- 191 0 R
+ 188 0 R
3
- 192 0 R
+ 189 0 R
4
- 193 0 R
+ 190 0 R
5
- 194 0 R
+ 191 0 R
6
- 195 0 R
+ 192 0 R
7
- 196 0 R
+ 193 0 R
8
- 197 0 R
+ 194 0 R
9
- 198 0 R
+ 195 0 R
10
- 199 0 R
+ 196 0 R
11
- 200 0 R
+ 197 0 R
12
- 201 0 R
+ 198 0 R
13
- 202 0 R
+ 199 0 R
14
- 203 0 R
+ 200 0 R
15
- 204 0 R
+ 201 0 R
16
- 205 0 R
+ 202 0 R
17
- 206 0 R
+ 203 0 R
18
- 207 0 R
+ 204 0 R
19
- 208 0 R
+ 205 0 R
20
- 209 0 R
+ 206 0 R
21
- 210 0 R
+ 207 0 R
22
- 211 0 R
+ 208 0 R
23
- 212 0 R
+ 209 0 R
24
- 213 0 R
+ 210 0 R
25
- 214 0 R ] >>
+ 211 0 R ] >>
+endobj
+% 'R186': class PDFPageLabel
+186 0 obj
+% None
+<< /S /D
+ /St 1 >>
+endobj
+% 'R187': class PDFPageLabel
+187 0 obj
+% None
+<< /S /D
+ /St 2 >>
+endobj
+% 'R188': class PDFPageLabel
+188 0 obj
+% None
+<< /S /D
+ /St 3 >>
endobj
% 'R189': class PDFPageLabel
189 0 obj
% None
<< /S /D
- /St 1 >>
+ /St 4 >>
endobj
% 'R190': class PDFPageLabel
190 0 obj
% None
<< /S /D
- /St 2 >>
+ /St 5 >>
endobj
% 'R191': class PDFPageLabel
191 0 obj
% None
<< /S /D
- /St 3 >>
+ /St 6 >>
endobj
% 'R192': class PDFPageLabel
192 0 obj
% None
<< /S /D
- /St 4 >>
+ /St 7 >>
endobj
% 'R193': class PDFPageLabel
193 0 obj
% None
<< /S /D
- /St 5 >>
+ /St 8 >>
endobj
% 'R194': class PDFPageLabel
194 0 obj
% None
<< /S /D
- /St 6 >>
+ /St 9 >>
endobj
% 'R195': class PDFPageLabel
195 0 obj
% None
<< /S /D
- /St 7 >>
+ /St 10 >>
endobj
% 'R196': class PDFPageLabel
196 0 obj
% None
<< /S /D
- /St 8 >>
+ /St 11 >>
endobj
% 'R197': class PDFPageLabel
197 0 obj
% None
<< /S /D
- /St 9 >>
+ /St 12 >>
endobj
% 'R198': class PDFPageLabel
198 0 obj
% None
<< /S /D
- /St 10 >>
+ /St 13 >>
endobj
% 'R199': class PDFPageLabel
199 0 obj
% None
<< /S /D
- /St 11 >>
+ /St 14 >>
endobj
% 'R200': class PDFPageLabel
200 0 obj
% None
<< /S /D
- /St 12 >>
+ /St 15 >>
endobj
% 'R201': class PDFPageLabel
201 0 obj
% None
<< /S /D
- /St 13 >>
+ /St 16 >>
endobj
% 'R202': class PDFPageLabel
202 0 obj
% None
<< /S /D
- /St 14 >>
+ /St 17 >>
endobj
% 'R203': class PDFPageLabel
203 0 obj
% None
<< /S /D
- /St 15 >>
+ /St 18 >>
endobj
% 'R204': class PDFPageLabel
204 0 obj
% None
<< /S /D
- /St 16 >>
+ /St 19 >>
endobj
% 'R205': class PDFPageLabel
205 0 obj
% None
<< /S /D
- /St 17 >>
+ /St 20 >>
endobj
% 'R206': class PDFPageLabel
206 0 obj
% None
<< /S /D
- /St 18 >>
+ /St 21 >>
endobj
% 'R207': class PDFPageLabel
207 0 obj
% None
<< /S /D
- /St 19 >>
+ /St 22 >>
endobj
% 'R208': class PDFPageLabel
208 0 obj
% None
<< /S /D
- /St 20 >>
+ /St 23 >>
endobj
% 'R209': class PDFPageLabel
209 0 obj
% None
<< /S /D
- /St 21 >>
+ /St 24 >>
endobj
% 'R210': class PDFPageLabel
210 0 obj
% None
<< /S /D
- /St 22 >>
+ /St 25 >>
endobj
% 'R211': class PDFPageLabel
211 0 obj
% None
<< /S /D
- /St 23 >>
-endobj
-% 'R212': class PDFPageLabel
-212 0 obj
-% None
-<< /S /D
- /St 24 >>
-endobj
-% 'R213': class PDFPageLabel
-213 0 obj
-% None
-<< /S /D
- /St 25 >>
-endobj
-% 'R214': class PDFPageLabel
-214 0 obj
-% None
-<< /S /D
/St 26 >>
endobj
xref
-0 215
+0 212
0000000000 65535 f
0000000113 00000 n
0000000257 00000 n
@@ -6594,204 +6656,201 @@ xref
0000004804 00000 n
0000005047 00000 n
0000005290 00000 n
-0000005534 00000 n
-0000005778 00000 n
-0000006022 00000 n
-0000006266 00000 n
-0000006510 00000 n
-0000006754 00000 n
-0000006998 00000 n
-0000007242 00000 n
-0000007486 00000 n
-0000007730 00000 n
-0000007974 00000 n
-0000008218 00000 n
-0000008462 00000 n
-0000008706 00000 n
-0000008950 00000 n
-0000009194 00000 n
-0000009438 00000 n
-0000009682 00000 n
-0000009926 00000 n
-0000010170 00000 n
-0000010414 00000 n
-0000010657 00000 n
-0000010909 00000 n
-0000011146 00000 n
-0000011821 00000 n
-0000012073 00000 n
+0000005533 00000 n
+0000005776 00000 n
+0000006020 00000 n
+0000006264 00000 n
+0000006508 00000 n
+0000006752 00000 n
+0000006996 00000 n
+0000007240 00000 n
+0000007484 00000 n
+0000007728 00000 n
+0000007972 00000 n
+0000008216 00000 n
+0000008460 00000 n
+0000008704 00000 n
+0000008948 00000 n
+0000009192 00000 n
+0000009436 00000 n
+0000009680 00000 n
+0000009924 00000 n
+0000010168 00000 n
+0000010412 00000 n
+0000010656 00000 n
+0000010900 00000 n
+0000011143 00000 n
+0000011395 00000 n
+0000011632 00000 n
0000012325 00000 n
0000012577 00000 n
-0000012820 00000 n
-0000013072 00000 n
+0000012829 00000 n
+0000013081 00000 n
0000013324 00000 n
0000013576 00000 n
0000013828 00000 n
-0000014085 00000 n
-0000014475 00000 n
-0000014712 00000 n
-0000015015 00000 n
-0000015312 00000 n
-0000015564 00000 n
+0000014080 00000 n
+0000014332 00000 n
+0000014589 00000 n
+0000014979 00000 n
+0000015216 00000 n
+0000015519 00000 n
0000015816 00000 n
0000016068 00000 n
-0000016328 00000 n
-0000016580 00000 n
-0000016841 00000 n
-0000017092 00000 n
-0000017353 00000 n
-0000017605 00000 n
-0000017842 00000 n
-0000018241 00000 n
-0000018492 00000 n
-0000018728 00000 n
-0000019055 00000 n
-0000019327 00000 n
-0000019579 00000 n
+0000016320 00000 n
+0000016572 00000 n
+0000016832 00000 n
+0000017084 00000 n
+0000017345 00000 n
+0000017596 00000 n
+0000017857 00000 n
+0000018109 00000 n
+0000018346 00000 n
+0000018745 00000 n
+0000018996 00000 n
+0000019232 00000 n
+0000019559 00000 n
0000019831 00000 n
-0000020068 00000 n
-0000020413 00000 n
-0000020665 00000 n
+0000020083 00000 n
+0000020335 00000 n
+0000020572 00000 n
0000020917 00000 n
-0000021161 00000 n
-0000021497 00000 n
-0000021734 00000 n
-0000022052 00000 n
-0000022308 00000 n
-0000022560 00000 n
-0000022811 00000 n
-0000023063 00000 n
-0000023322 00000 n
-0000023567 00000 n
-0000023930 00000 n
-0000024180 00000 n
-0000024431 00000 n
-0000024681 00000 n
-0000024933 00000 n
-0000025185 00000 n
-0000025437 00000 n
-0000025690 00000 n
-0000025930 00000 n
-0000026314 00000 n
-0000026551 00000 n
-0000026871 00000 n
-0000027124 00000 n
-0000027377 00000 n
-0000027630 00000 n
-0000027883 00000 n
-0000028136 00000 n
-0000028387 00000 n
-0000028640 00000 n
-0000028879 00000 n
-0000029255 00000 n
-0000029553 00000 n
-0000029792 00000 n
-0000030098 00000 n
-0000030396 00000 n
-0000030634 00000 n
-0000030954 00000 n
-0000031226 00000 n
-0000031479 00000 n
-0000031718 00000 n
-0000032059 00000 n
-0000032298 00000 n
-0000032619 00000 n
-0000032873 00000 n
-0000033131 00000 n
-0000033462 00000 n
-0000033701 00000 n
-0000034022 00000 n
-0000034261 00000 n
-0000034567 00000 n
-0000034866 00000 n
-0000035105 00000 n
-0000035426 00000 n
-0000035680 00000 n
-0000035919 00000 n
-0000036235 00000 n
-0000036520 00000 n
-0000036684 00000 n
-0000036938 00000 n
-0000037067 00000 n
-0000037243 00000 n
-0000037463 00000 n
-0000037669 00000 n
-0000037864 00000 n
-0000038062 00000 n
-0000038266 00000 n
-0000038462 00000 n
-0000038658 00000 n
-0000038864 00000 n
-0000039074 00000 n
-0000039277 00000 n
-0000039476 00000 n
-0000039696 00000 n
-0000039920 00000 n
-0000040130 00000 n
-0000040327 00000 n
-0000040516 00000 n
-0000040701 00000 n
-0000041053 00000 n
-0000050435 00000 n
-0000055843 00000 n
-0000060129 00000 n
-0000065526 00000 n
-0000071778 00000 n
-0000077134 00000 n
-0000081556 00000 n
-0000085921 00000 n
-0000089772 00000 n
-0000094378 00000 n
-0000100507 00000 n
-0000105458 00000 n
-0000110602 00000 n
-0000113792 00000 n
-0000117579 00000 n
-0000121104 00000 n
-0000127191 00000 n
-0000131577 00000 n
-0000137019 00000 n
-0000142117 00000 n
-0000147295 00000 n
-0000152030 00000 n
-0000154625 00000 n
-0000159516 00000 n
-0000166816 00000 n
-0000168785 00000 n
-0000169247 00000 n
-0000169326 00000 n
-0000169405 00000 n
-0000169484 00000 n
-0000169563 00000 n
-0000169642 00000 n
-0000169721 00000 n
-0000169800 00000 n
-0000169879 00000 n
-0000169958 00000 n
-0000170038 00000 n
-0000170118 00000 n
-0000170198 00000 n
-0000170278 00000 n
-0000170358 00000 n
-0000170438 00000 n
-0000170518 00000 n
-0000170598 00000 n
-0000170678 00000 n
-0000170758 00000 n
-0000170838 00000 n
-0000170918 00000 n
-0000170998 00000 n
-0000171078 00000 n
-0000171158 00000 n
-0000171238 00000 n
+0000021169 00000 n
+0000021421 00000 n
+0000021665 00000 n
+0000021986 00000 n
+0000022269 00000 n
+0000022566 00000 n
+0000022818 00000 n
+0000023074 00000 n
+0000023326 00000 n
+0000023592 00000 n
+0000023844 00000 n
+0000024082 00000 n
+0000024445 00000 n
+0000024704 00000 n
+0000024963 00000 n
+0000025213 00000 n
+0000025464 00000 n
+0000025715 00000 n
+0000025968 00000 n
+0000026221 00000 n
+0000026474 00000 n
+0000026727 00000 n
+0000026967 00000 n
+0000027359 00000 n
+0000027657 00000 n
+0000027908 00000 n
+0000028147 00000 n
+0000028463 00000 n
+0000028761 00000 n
+0000028999 00000 n
+0000029319 00000 n
+0000029572 00000 n
+0000029844 00000 n
+0000030083 00000 n
+0000030423 00000 n
+0000030676 00000 n
+0000030915 00000 n
+0000031231 00000 n
+0000031529 00000 n
+0000031782 00000 n
+0000032040 00000 n
+0000032370 00000 n
+0000032609 00000 n
+0000032930 00000 n
+0000033169 00000 n
+0000033475 00000 n
+0000033774 00000 n
+0000034028 00000 n
+0000034267 00000 n
+0000034598 00000 n
+0000034837 00000 n
+0000035143 00000 n
+0000035428 00000 n
+0000035592 00000 n
+0000035846 00000 n
+0000035975 00000 n
+0000036151 00000 n
+0000036371 00000 n
+0000036577 00000 n
+0000036772 00000 n
+0000036970 00000 n
+0000037174 00000 n
+0000037375 00000 n
+0000037571 00000 n
+0000037767 00000 n
+0000037974 00000 n
+0000038184 00000 n
+0000038387 00000 n
+0000038586 00000 n
+0000038806 00000 n
+0000039030 00000 n
+0000039240 00000 n
+0000039437 00000 n
+0000039626 00000 n
+0000039811 00000 n
+0000040162 00000 n
+0000049451 00000 n
+0000055004 00000 n
+0000059148 00000 n
+0000064812 00000 n
+0000071064 00000 n
+0000076420 00000 n
+0000080839 00000 n
+0000085230 00000 n
+0000090375 00000 n
+0000094933 00000 n
+0000100118 00000 n
+0000104753 00000 n
+0000109083 00000 n
+0000114533 00000 n
+0000118530 00000 n
+0000124283 00000 n
+0000129428 00000 n
+0000133953 00000 n
+0000138989 00000 n
+0000143386 00000 n
+0000147672 00000 n
+0000152445 00000 n
+0000155907 00000 n
+0000161587 00000 n
+0000167087 00000 n
+0000168297 00000 n
+0000168759 00000 n
+0000168838 00000 n
+0000168917 00000 n
+0000168996 00000 n
+0000169075 00000 n
+0000169154 00000 n
+0000169233 00000 n
+0000169312 00000 n
+0000169391 00000 n
+0000169470 00000 n
+0000169550 00000 n
+0000169630 00000 n
+0000169710 00000 n
+0000169790 00000 n
+0000169870 00000 n
+0000169950 00000 n
+0000170030 00000 n
+0000170110 00000 n
+0000170190 00000 n
+0000170270 00000 n
+0000170350 00000 n
+0000170430 00000 n
+0000170510 00000 n
+0000170590 00000 n
+0000170670 00000 n
+0000170750 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(\373.sKQ\210\237\313\200B\274O\370\202\343\022) (\373.sKQ\210\237\313\200B\274O\370\202\343\022)]
+ [(n\020^\320f\231\256\243,\334=\267N\336b3) (n\020^\320f\231\256\243,\334=\267N\336b3)]
- /Info 141 0 R
- /Root 140 0 R
- /Size 215 >>
+ /Info 137 0 R
+ /Root 136 0 R
+ /Size 212 >>
startxref
-171287
+170799
%%EOF
diff --git a/plac/doc/plac_adv.txt b/plac/doc/plac_adv.txt
index 633c445..719c3a4 100644
--- a/plac/doc/plac_adv.txt
+++ b/plac/doc/plac_adv.txt
@@ -404,6 +404,90 @@ Here is a session of usage on an Unix-like operating system::
Notice that in interactive mode the traceback is hidden, unless
you pass the ``verbose`` flag to the ``Interpreter.interact`` method.
+plac.Interpreter.call
+--------------------------------------------
+
+At the core of ``plac`` there is the ``call`` function which invokes
+a callable with the list of the arguments passed at the command-line
+(``sys.argv[1:]``). Thanks to ``plac.call`` you can launch your module
+by simply adding the lines::
+
+ if __name__ == '__main__':
+ plac.call(main)
+
+Everything works fine if ``main`` is a simple callable performing some
+action; however, in many cases, one has a ``main`` "function" which
+is a actually a factory returning a command container object. For
+instance, in my second shelve example the main function is the class
+``ShelveInterface``, and the two lines needed to run the module are
+a bit ugly::
+
+ if __name__ == '__main__':
+ plac.Interpreter(plac.call(ShelveInterface)).interact()
+
+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 ``__enter__`` and ``__exit__``)
+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 ``plac.Interpreter`` provides
+a classmethod named ``.call`` 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 ``ShelveInterface``
+into a script
+
+.. include:: ishelve3.py
+ :literal:
+
+and here are a few examples of usage::
+
+ $ python ishelve3.py -h
+
+.. include:: ishelve3.help
+ :literal:
+
+::
+
+ $ python ishelve3.py set a 1
+ setting a=1
+ $ python ishelve3.py show a
+ a = 1
+
+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::
+
+ $ python ishelve3.py
+ A minimal interface over a shelve object.
+ Operating on /home/micheles/conf.shelve.
+ .help to see the available commands.
+
+ i>
+
+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 ``shelve_interpreter.py`` example), whereas here I
+have show how to turn an interactive application into a script.
+
+The complete signature of ``plac.Interpreter.call`` is the following::
+
+ call(factory, arglist=sys.argv[1:],
+ commentchar='#', split=shlex.split,
+ stdin=sys.stdin, prompt='i> ', verbose=False)
+
+The factory must have a fixed number of positional arguments (no
+default arguments, no varargs, no kwargs), otherwise a ``TypeError``
+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
+``sys.argv[1:]`` (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.
+
Readline support
---------------------------------------
@@ -600,52 +684,6 @@ Here is an example::
Notice that in non-interactive mode the runner just invokes ``plac.call``
on the ``main`` object of the Python module.
-..
-
- Multiline support and Emacs integration
-
- plac_ is optimized for the simplest use case and by default it provide
- support for simple command-line languages where a command take
- a single line. This is the simplest case: it is easy to keep
- track of the line number and to print it in the error message, if
- there is some error in a plac_ script. Starting from release 0.7
- plac_ is beginning to support multiline input: it is now possible
- to define command-line languages with commands spanning multiple
- lines. The topical use case is the implementation of a tool
- to interact with a relational database: the tool must be able to send
- complex SQL queries spanning multiple lines to the backend.
- To support multiline input the ``Interpreter`` class provides
- a method ``multiline(stdin=sys.stdin, terminator=';', verbose=False)``
- which reads input from ``stdin`` until the terminator character
- (by default a semicolon) is reached.
-
- Since the Python readline module does not expose the
- multiline functionality of the underlying C library (which is there),
- plac_ multiline mode does not have readline functionality. This is
- not a big deal really, because if you are writing multiple line
- commands you don't really want to type them at the command-line. It is
- much better to use a real editor to type them, and to call plac_ from
- the editor. Since I use Emacs I will give the recipe to integrate
- Emacs with plac_: something equivalent can be done for vi and for
- other editors/IDEs.
-
- The multiline mode can be enabled by invoking the plac_ runner with
- the ``-m`` option. Since the multiline mode is intended for use with
- Emacs in inferior mode, it does not print any prompt. Here is an example
- of usage::
-
- $ plac -m ishelve2.py
- set a 1;
- setting a=1
- show a;
- a = 1
-
- To integrate plac_ with Emacs, enters the following lines in your
- .emacs:
-
- .. include:: plac.el
- :literal:
-
A non class-based example
--------------------------------------------------------
@@ -789,6 +827,10 @@ 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.
+An example of GUI program built on top of plac_ is given later on, in the
+paragraph *Managing the output of concurrent commands* (using Tkinter
+for simplicity and portability).
+
There is a final *caveat*: since the plac interpreter loop is
implemented via extended generators, plac interpreters are single threaded: you
will get an error if you ``.send`` commands from separated threads.
@@ -822,10 +864,11 @@ before entering a new command::
$ python importer1.py dsn
A fake importer with an import_file command
i> import_file file1
+ ... <wait 3+ minutes>
Imported 100 lines
Imported 200 lines
Imported 300 lines
- ... <wait 3+ minutes>
+ ...
Imported 10000 lines
closing the file
@@ -1069,7 +1112,8 @@ Since ``asynchat``-based servers are asynchronous, any blocking command
in the interpreter should be run in a separated process or thread.
The default port for the plac_ 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:
+For instance, here is how you could manage remote import on a database
+(say a SQLite db):
.. include:: server_ex.py
:literal:
@@ -1122,6 +1166,8 @@ rules are quite simple:
Moreover, remember that ``plac_runner.py`` is your friend.
+------
+
Appendix: custom annotation objects
--------------------------------------------------------
@@ -1174,3 +1220,4 @@ pretty well for most users.
.. _distutils: http://docs.python.org/distutils/
.. _cmd: http://docs.python.org/library/cmd.html
.. _rlwrap: http://freshmeat.net/projects/rlwrap/
+.. _pyreadline: http://ipython.scipy.org/moin/PyReadline/Intro
diff --git a/plac/doc/sql_interface.py b/plac/doc/sql_interface.py
index 16f0216..34042dd 100644
--- a/plac/doc/sql_interface.py
+++ b/plac/doc/sql_interface.py
@@ -24,6 +24,5 @@ def split_on_first_space(line, commentchar):
return line.strip().split(' ', 1) # ignoring comments
if __name__ == '__main__':
- si = plac.call(SqlInterface)
- i = plac.Interpreter(si, split=split_on_first_space)
- i.interact(rl_input, prompt='sql> ')
+ plac.Interpreter.call(SqlInterface, split=split_on_first_space,
+ stdin=rl_input, prompt='sql> ')
diff --git a/plac/doc/test_plac.py b/plac/doc/test_plac.py
index 86c600b..9759280 100644
--- a/plac/doc/test_plac.py
+++ b/plac/doc/test_plac.py
@@ -24,6 +24,7 @@ def parser_from(f, **kw):
def check_help(name):
sys.argv[0] = name + '.py' # avoid issue with nosetests
+ plac.parser_registry.clear() # makes different imports independent
try:
try:
main = plac.import_main(name + '.py')
diff --git a/plac/doc/test_server.py b/plac/doc/test_server.py
index dd14e5c..a9904ee 100644
--- a/plac/doc/test_server.py
+++ b/plac/doc/test_server.py
@@ -2,7 +2,7 @@ import multiprocessing, subprocess, time, random
import plac
from ishelve2 import ShelveInterface
-i = plac.Interpreter(ShelveInterface())
+i = plac.Interpreter(ShelveInterface(configfile=None))
COMMANDS = ['''\
.help
diff --git a/plac/plac_ext.py b/plac/plac_ext.py
index 2a38c4e..e175514 100644
--- a/plac/plac_ext.py
+++ b/plac/plac_ext.py
@@ -154,7 +154,7 @@ def import_main(path, *args, **pconf):
if os.path.exists(fullpath):
break
else: # no break
- raise ImportError(_('Cannot find %s'), path)
+ raise ImportError(_('Cannot find %s' % path))
else:
fullpath = path
name, ext = os.path.splitext(os.path.basename(fullpath))
@@ -195,7 +195,7 @@ class BaseTask(object):
self.str, self.etype, self.exc, self.tb = '', None, None, None
self.status = 'SUBMITTED'
self.outlist = []
-
+
def _wrap(self, genobj, stringify_tb=False):
"""
Wrap the genobj into a generator managing the exceptions,
@@ -589,6 +589,43 @@ class Interpreter(object):
A context manager with a .send method and a few utility methods:
execute, test and doctest.
"""
+
+ @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"""
+ 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):
+ obj = factory(%s)
+ obj.args = args
+ return obj'''% (required_args, required_args)
+ dic = dict(factory=factory)
+ exec code in dic
+ makeobj = dic['makeobj']
+ if inspect.isclass(factory):
+ makeobj.__annotations__ = getattr(
+ factory.__init__, '__annotations__', {})
+ else:
+ makeobj.__annotations__ = getattr(
+ factory, '__annotations__', {})
+ obj = plac_core.call(makeobj, arglist)
+ i = cls(obj, commentchar, split) # interpreter
+ if obj.args:
+ with i:
+ task = i.send(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: