<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>[misc] </title> <meta content="text/html;charset=ISO-8859-1" name="Content-Type"/> <link href="style.css" media="screen" rel="stylesheet" type="text/css"/></head> <body> <div><a href="http://codespeak.net"><img alt="py lib" height="114" id="pyimg" src="http://codespeak.net/img/pylib.png" width="154"/></a></div> <div id="metaspace"> <div class="project_title">[misc] </div> <div id="menubar"><a class="menu" href="index.html">index</a> <a class="menu" href="../../apigen/api/index.html">api</a> <a class="menu" href="../../apigen/source/index.html">source</a> <a class="menu" href="contact.html">contact</a> <a class="menu" href="download.html">download</a></div></div> <div id="contentspace"> <div id="docinfoline"> <div style="float: right; font-style: italic;"> </div></div> <div class="document" id="miscellaneous-features-of-the-py-lib"> <h1 class="title">Miscellaneous features of the py lib</h1> <div class="contents topic" id="contents"> <p class="topic-title first">Contents</p> <ul class="auto-toc simple"> <li><a class="reference internal" href="#mapping-the-standard-python-library-into-py" id="id1">1 Mapping the standard python library into py</a><ul class="auto-toc"> <li><a class="reference internal" href="#the-py-std-hook" id="id2">1.1 The py.std hook</a></li> <li><a class="reference internal" href="#automagically-accessing-sub-packages-doesn-t-work-yet" id="id3">1.2 Automagically accessing sub packages doesn't work (yet?)</a></li> <li><a class="reference internal" href="#note-you-get-an-attributeerror-not-an-importerror" id="id4">1.3 Note: you get an AttributeError, not an ImportError</a></li> </ul> </li> <li><a class="reference internal" href="#support-for-interaction-with-system-utilities-binaries" id="id5">2 Support for interaction with system utilities/binaries</a><ul class="auto-toc"> <li><a class="reference internal" href="#the-shell-based-approach" id="id6">2.1 The shell based approach</a></li> <li><a class="reference internal" href="#local-paths-have-sysexec" id="id7">2.2 local paths have <tt class="docutils literal"><span class="pre">sysexec</span></tt></a></li> <li><a class="reference internal" href="#finding-an-executable-local-path" id="id8">2.3 finding an executable local path</a></li> </ul> </li> <li><a class="reference internal" href="#cross-python-version-compatibility-helpers" id="id9">3 Cross-Python Version compatibility helpers</a><ul class="auto-toc"> <li><a class="reference internal" href="#py-compat" id="id10">3.1 py.compat</a></li> <li><a class="reference internal" href="#py-builtin" id="id11">3.2 py.builtin</a></li> </ul> </li> </ul> </div> <div class="section" id="mapping-the-standard-python-library-into-py"> <h1><a class="toc-backref" href="#id1">1 Mapping the standard python library into py</a></h1> <blockquote> Warning: This feature is very young and thus experimental. Be prepared to adapt your code later if you use it.</blockquote> <p>After you have worked with the py lib a bit, you might enjoy the lazy importing, i.e. you only have to do <tt class="docutils literal"><span class="pre">import</span> <span class="pre">py</span></tt> and work your way to your desired object. Using the full path also ensures that there remains a focus on getting short paths to objects.</p> <div class="section" id="the-py-std-hook"> <h2>1.1 The <a class="reference external" href="../../apigen/api/std.html">py.std</a> hook</h2> <p>Of course, no matter what, everybody will continue to use the python standard library because it is a very usable code base. However, to properly support lazyness the py lib offers a way to get to many standard modules without requiring "import" statements. For example, to get to the print-exception functionality of the standard library you can write:</p> <pre class="literal-block"> py.std.traceback.print_exc() </pre> <p>without having to do anything else than the usual <tt class="docutils literal"><span class="pre">import</span> <span class="pre">py</span></tt> at the beginning. Note that not having imports for the <span class="incremental">python standard library</span> obviously gets rid of the <em>unused import</em> problem. Modules only get imported when you actually need them.</p> <p>Moreover, this approach resolves some of the issues stated in <a class="reference external" href="http://www.python.org/peps/pep-0328.html">the relative/absolute import PEP-328</a>, as with the above approach you never have ambiguity problems. The above traceback-usage is an absolute path that will not be accidentally get confused with local names. (Well, never put a file <tt class="docutils literal"><span class="pre">py.py</span></tt> in an importable path, btw, mind you :-)</p> </div> <div class="section" id="automagically-accessing-sub-packages-doesn-t-work-yet"> <h2><a class="toc-backref" href="#id3">1.2 Automagically accessing sub packages doesn't work (yet?)</a></h2> <p>If you use the <a class="reference external" href="../../apigen/api/std.html">py.std</a> hook you currently cannot magically import nested packages which otherwise need explicit imports of their sub-packages. For example, the suversion bindings require you to do something like:</p> <pre class="literal-block"> import svn.client </pre> <p>If you just do the naive thing with the py lib, i.e. write <tt class="docutils literal"><span class="pre">py.std.svn.client</span></tt> it will not work unless you previously imported it already. The py lib currently doesn't try to magically make this work. The <a class="reference external" href="../../apigen/api/std.html">py.std</a> hook really is intended for Python standard modules which very seldomly (if at all) provide such nested packages.</p> <p><strong>Note that you may never rely</strong> on module identity, i.e. that <tt class="docutils literal"><span class="pre">X</span> <span class="pre">is</span> <span class="pre">py.std.X</span></tt> for any <tt class="docutils literal"><span class="pre">X</span></tt>. This is to allow us later to lazyly import nested packages. Yes, lazyness is hard to resist :-)</p> </div> <div class="section" id="note-you-get-an-attributeerror-not-an-importerror"> <h2><a class="toc-backref" href="#id4">1.3 Note: you get an AttributeError, not an ImportError</a></h2> <p>If you say <tt class="docutils literal"><span class="pre">py.std.XYZ</span></tt> and importing <tt class="docutils literal"><span class="pre">XYZ</span></tt> produces an <tt class="docutils literal"><span class="pre">ImportError</span></tt> , it will actually show up as an <tt class="docutils literal"><span class="pre">AttributeError</span></tt>. It is deemed more important to adhere to the standard <tt class="docutils literal"><span class="pre">__getattr__</span></tt> protocol than to let the <tt class="docutils literal"><span class="pre">ImportError</span></tt> pass through. For example, you might want to do:</p> <pre class="literal-block"> getattr(py.std.cStringIO, 'StringIO', py.std.StringIO.StringIO) </pre> <p>and you would expect that it works. It does work although it will take away some lazyness because <tt class="docutils literal"><span class="pre">py.std.StringIO.StringIO</span></tt> will be imported in any case.</p> </div> </div> <div class="section" id="support-for-interaction-with-system-utilities-binaries"> <h1><a class="toc-backref" href="#id5">2 Support for interaction with system utilities/binaries</a></h1> <p>sources:</p> <blockquote> <ul class="simple"> <li><a class="reference external" href="../../apigen/source/process/index.html">py/process/</a></li> <li><a class="reference external" href="../../apigen/source/path/local/index.html">py/path/local/</a></li> </ul> </blockquote> <p>Currently, the py lib offers two ways to interact with system executables. <a class="reference external" href="../../apigen/api/process.cmdexec.html">py.process.cmdexec()</a> invokes the shell in order to execute a string. The other one, <a class="reference external" href="../../apigen/api/path.local.html">py.path.local</a>'s 'sysexec()' method lets you directly execute a binary.</p> <p>Both approaches will raise an exception in case of a return- code other than 0 and otherwise return the stdout-output of the child process.</p> <div class="section" id="the-shell-based-approach"> <h2><a class="toc-backref" href="#id6">2.1 The shell based approach</a></h2> <p>You can execute a command via your system shell by doing something like:</p> <pre class="literal-block"> out = py.process.cmdexec('ls -v') </pre> <p>However, the <tt class="docutils literal"><span class="pre">cmdexec</span></tt> approach has a few shortcomings:</p> <ul class="simple"> <li>it relies on the underlying system shell</li> <li>it neccessitates shell-escaping for expressing arguments</li> <li>it does not easily allow to "fix" the binary you want to run.</li> <li>it only allows to execute executables from the local filesystem</li> </ul> </div> <div class="section" id="local-paths-have-sysexec"> <span id="sysexec"></span><h2><a class="toc-backref" href="#id7">2.2 local paths have <tt class="docutils literal"><span class="pre">sysexec</span></tt></a></h2> <p>The py lib currently offers a stripped down functionality of what the new <a class="reference external" href="http://www.python.org/peps/pep-0324.html">PEP-324 subprocess module</a> offers. The main functionality of synchronously executing a system executable has a straightforward API:</p> <pre class="literal-block"> binsvn.sysexec('ls', 'http://codespeak.net/svn') </pre> <p>where <tt class="docutils literal"><span class="pre">binsvn</span></tt> is a path that points to the <tt class="docutils literal"><span class="pre">svn</span></tt> commandline binary. Note that this function would not offer any shell-escaping so you really have to pass in separated arguments. This idea fits nicely into <a class="reference external" href="future.html#general-path">a more general view on path objects</a>.</p> <p>For a first go, we are just reusing the existing <a class="reference external" href="http://www.lysator.liu.se/~astrand/popen5/">subprocess implementation</a> but don't expose any of its API apart from the above <tt class="docutils literal"><span class="pre">sysexec()</span></tt> method.</p> <p>Note, however, that currently the support for the <tt class="docutils literal"><span class="pre">sysexec</span></tt> interface on win32 is not thoroughly tested. If you run into problems with it, we are interested to hear about them. If you are running a Python older than 2.4 you will have to install the <a class="reference external" href="http://pywin32.sourceforge.net/">pywin32 package</a>.</p> </div> <div class="section" id="finding-an-executable-local-path"> <h2><a class="toc-backref" href="#id8">2.3 finding an executable local path</a></h2> <p>Finding an executable is quite different on multiple platforms. Currently, the <tt class="docutils literal"><span class="pre">PATH</span></tt> environment variable based search on unix platforms is supported:</p> <pre class="literal-block"> py.path.local.sysfind('svn') </pre> <p>which returns the first path whose <tt class="docutils literal"><span class="pre">basename</span></tt> matches <tt class="docutils literal"><span class="pre">svn</span></tt>. In principle, <span class="incremental">sysfind</span> deploys platform specific algorithms to perform the search. On Windows, for example, it may look at the registry (XXX).</p> <p>To make the story complete, we allow to pass in a second <tt class="docutils literal"><span class="pre">checker</span></tt> argument that is called for each found executable. For example, if you have multiple binaries available you may want to select the right version:</p> <pre class="literal-block"> def mysvn(p): """ check that the given svn binary has version 1.1. """ line = p.execute('--version'').readlines()[0] if line.find('version 1.1'): return p binsvn = py.path.local.sysfind('svn', checker=mysvn) </pre> </div> </div> <div class="section" id="cross-python-version-compatibility-helpers"> <h1><a class="toc-backref" href="#id9">3 Cross-Python Version compatibility helpers</a></h1> <p>sources:</p> <blockquote> <ul class="simple"> <li><a class="reference external" href="../../apigen/source/compat/index.html">py/compat/</a></li> <li><a class="reference external" href="../../apigen/source/builtin/index.html">py/builtin/</a></li> </ul> </blockquote> <p>The py-lib contains some helpers that make writing scripts that work on various Python versions easier.</p> <div class="section" id="py-compat"> <h2>3.1 <a class="reference external" href="../../apigen/api/compat.html">py.compat</a></h2> <p><a class="reference external" href="../../apigen/api/compat.html">py.compat</a> provides fixed versions (currently from Python 2.4.4) of various newer modules to be able to use them in various Python versions. Currently these are:</p> <blockquote> <ul class="simple"> <li>doctest</li> <li>optparse</li> <li>subprocess</li> <li>textwrap</li> </ul> </blockquote> <p>They are used by replacing the normal <tt class="docutils literal"><span class="pre">import</span> <span class="pre">...</span></tt> byr <tt class="docutils literal"><span class="pre">from</span> <span class="pre">py.compat</span> <span class="pre">import</span> <span class="pre">...</span></tt>.</p> </div> <div class="section" id="py-builtin"> <h2>3.2 <a class="reference external" href="../../apigen/api/builtin.html">py.builtin</a></h2> <p><a class="reference external" href="../../apigen/api/builtin.html">py.builtin</a> provides various builtins that were added in later Python versions. If the used Python version used does not provide these builtins, they are pure-Python reimplementations. These currently are:</p> <blockquote> <ul class="simple"> <li>enumerate</li> <li>reversed</li> <li>sorted</li> <li>BaseException</li> <li>set and frozenset (using either the builtin, if available, or the sets module)</li> </ul> </blockquote> <p><a class="reference external" href="../../apigen/api/builtin.BaseException.html">py.builtin.BaseException</a> is just <tt class="docutils literal"><span class="pre">Exception</span></tt> before Python 2.5.</p> </div> </div> </div> </div></body></html>