221 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| ====================================
 | |
| Miscellaneous features of the py lib 
 | |
| ====================================
 | |
| 
 | |
| .. contents::
 | |
| .. sectnum::
 | |
| 
 | |
| Mapping the standard python library into py 
 | |
| ===========================================
 | |
| 
 | |
|     Warning: This feature is very young and thus experimental.
 | |
|     Be prepared to adapt your code later if you use it. 
 | |
| 
 | |
| After you have worked with the py lib a bit, you might enjoy
 | |
| the lazy importing, i.e. you only have to do ``import py`` 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. 
 | |
| 
 | |
| The :api:`py.std` hook
 | |
| ----------------------
 | |
| 
 | |
| 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:: 
 | |
| 
 | |
|     py.std.traceback.print_exc()
 | |
| 
 | |
| without having to do anything else than the usual ``import py`` 
 | |
| at the beginning.  Note that not having imports for the 
 | |
| `python standard library` obviously gets rid of the *unused 
 | |
| import* problem. Modules only get imported when you actually
 | |
| need them. 
 | |
| 
 | |
| Moreover, this approach resolves some of the issues stated in
 | |
| `the relative/absolute import PEP-328`_, 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 ``py.py`` in an importable path, btw, mind you :-) 
 | |
| 
 | |
| Automagically accessing sub packages doesn't work (yet?) 
 | |
| --------------------------------------------------------
 | |
| 
 | |
| If you use the :api:`py.std` 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:: 
 | |
| 
 | |
|     import svn.client 
 | |
| 
 | |
| If you just do the naive thing with the py lib, i.e. write
 | |
| ``py.std.svn.client`` it will not work unless you previously
 | |
| imported it already.  The py lib currently doesn't try to
 | |
| magically make this work.  The :api:`py.std` hook really is
 | |
| intended for Python standard modules which very seldomly (if
 | |
| at all) provide such nested packages. 
 | |
| 
 | |
| **Note that you may never rely** on module identity, i.e. 
 | |
| that ``X is py.std.X`` for any ``X``. This is to allow
 | |
| us later to lazyly import nested packages. Yes, lazyness
 | |
| is hard to resist :-) 
 | |
| 
 | |
| Note: you get an AttributeError, not an ImportError
 | |
| ---------------------------------------------------
 | |
| 
 | |
| If you say ``py.std.XYZ`` and importing ``XYZ`` produces an
 | |
| ``ImportError`` , it will actually show up as an
 | |
| ``AttributeError``. It is deemed more important to adhere to
 | |
| the standard ``__getattr__`` protocol than to let the
 | |
| ``ImportError`` pass through.  For example, you might want to
 | |
| do::
 | |
| 
 | |
|     getattr(py.std.cStringIO, 'StringIO', py.std.StringIO.StringIO) 
 | |
| 
 | |
| and you would expect that it works. It does work although it will 
 | |
| take away some lazyness because ``py.std.StringIO.StringIO`` will
 | |
| be imported in any case. 
 | |
| 
 | |
| .. _`the relative/absolute import PEP-328`: http://www.python.org/peps/pep-0328.html
 | |
| 
 | |
| Support for interaction with system utilities/binaries
 | |
| ======================================================
 | |
| 
 | |
| sources:
 | |
| 
 | |
|   * :source:`py/process/`
 | |
|   * :source:`py/path/local/`
 | |
| 
 | |
| Currently, the py lib offers two ways to interact with
 | |
| system executables. :api:`py.process.cmdexec()` invokes
 | |
| the shell in order to execute a string.  The other
 | |
| one, :api:`py.path.local`'s 'sysexec()' method lets you 
 | |
| directly execute a binary. 
 | |
| 
 | |
| 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.
 | |
| 
 | |
| The shell based approach 
 | |
| ------------------------
 | |
| 
 | |
| You can execute a command via your system shell 
 | |
| by doing something like:: 
 | |
| 
 | |
|     out = py.process.cmdexec('ls -v')
 | |
| 
 | |
| However, the ``cmdexec`` approach has a few shortcomings: 
 | |
| 
 | |
| - it relies on the underlying system shell
 | |
| - it neccessitates shell-escaping for expressing arguments
 | |
| - it does not easily allow to "fix" the binary you want to run.  
 | |
| - it only allows to execute executables from the local 
 | |
|   filesystem 
 | |
| 
 | |
| .. _sysexec: 
 | |
| 
 | |
| local paths have ``sysexec``
 | |
| ---------------------------- 
 | |
| 
 | |
| The py lib currently offers a stripped down functionality of what
 | |
| the new `PEP-324 subprocess module`_ offers.  The main functionality 
 | |
| of synchronously executing a system executable has a straightforward API:: 
 | |
| 
 | |
|     binsvn.sysexec('ls', 'http://codespeak.net/svn') 
 | |
| 
 | |
| where ``binsvn`` is a path that points to the ``svn`` 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 more general view on path objects`_. 
 | |
| 
 | |
| For a first go, we are just reusing the existing `subprocess
 | |
| implementation`_ but don't expose any of its API apart
 | |
| from the above ``sysexec()`` method. 
 | |
| 
 | |
| Note, however, that currently the support for the ``sysexec`` 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 `pywin32 package`_.
 | |
| 
 | |
| 
 | |
| .. _`future book`: future.html 
 | |
| .. _`PEP-324 subprocess module`: http://www.python.org/peps/pep-0324.html
 | |
| .. _`subprocess implementation`: http://www.lysator.liu.se/~astrand/popen5/
 | |
| .. _`a more general view on path objects`: future.html#general-path
 | |
| .. _`pywin32 package`: http://pywin32.sourceforge.net/
 | |
| 
 | |
| finding an executable local path
 | |
| --------------------------------
 | |
| 
 | |
| Finding an executable is quite different on multiple platforms. 
 | |
| Currently, the ``PATH`` environment variable based search on
 | |
| unix platforms is supported:: 
 | |
| 
 | |
|     py.path.local.sysfind('svn')
 | |
| 
 | |
| which returns the first path whose ``basename`` matches ``svn``. 
 | |
| In principle, `sysfind` deploys platform specific algorithms
 | |
| to perform the search.  On Windows, for example, it may look
 | |
| at the registry (XXX). 
 | |
| 
 | |
| To make the story complete, we allow to pass in a second ``checker`` 
 | |
| argument that is called for each found executable.  For example, if 
 | |
| you have multiple binaries available you may want to select the
 | |
| right version:: 
 | |
| 
 | |
|     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) 
 | |
| 
 | |
| 
 | |
| 
 | |
| Cross-Python Version compatibility helpers
 | |
| =============================================
 | |
| 
 | |
| sources: 
 | |
| 
 | |
|   * :source:`py/compat/`
 | |
|   * :source:`py/builtin/`
 | |
| 
 | |
| The py-lib contains some helpers that make writing scripts that work on various
 | |
| Python versions easier.
 | |
| 
 | |
| :api:`py.compat`
 | |
| ----------------
 | |
| 
 | |
| :api:`py.compat` 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:
 | |
| 
 | |
|  * doctest
 | |
|  * optparse
 | |
|  * subprocess
 | |
|  * textwrap
 | |
| 
 | |
| They are used by replacing the normal ``import ...`` byr
 | |
| ``from py.compat import ...``.
 | |
| 
 | |
| :api:`py.builtin`
 | |
| -----------------
 | |
| 
 | |
| :api:`py.builtin` 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:
 | |
| 
 | |
|  * enumerate
 | |
|  * reversed
 | |
|  * sorted
 | |
|  * BaseException
 | |
|  * set and frozenset (using either the builtin, if available, or the sets
 | |
|    module)
 | |
| 
 | |
| :api:`py.builtin.BaseException` is just ``Exception`` before Python 2.5.
 | |
| 
 |