[svn r63539] moving py/doc to doc/ and removing some more files
--HG-- branch : trunk
This commit is contained in:
+259
@@ -0,0 +1,259 @@
|
||||
=======
|
||||
py.path
|
||||
=======
|
||||
|
||||
The 'py' lib provides a uniform high-level api to deal with filesystems
|
||||
and filesystem-like interfaces: :api:`py.path`. It aims to offer a central
|
||||
object to fs-like object trees (reading from and writing to files, adding
|
||||
files/directories, examining the types and structure, etc.), and out-of-the-box
|
||||
provides a number of implementations of this API.
|
||||
|
||||
Path implementations provided by :api:`py.path`
|
||||
===============================================
|
||||
|
||||
:api:`py.path.local`
|
||||
--------------------
|
||||
|
||||
The first and most obvious of the implementations is a wrapper around a local
|
||||
filesystem. It's just a bit nicer in usage than the regular Python APIs, and
|
||||
of course all the functionality is bundled together rather than spread over a
|
||||
number of modules.
|
||||
|
||||
Example usage, here we use the :api:`py.test.ensuretemp()` function to create
|
||||
a :api:`py.path.local` object for us (which wraps a directory)::
|
||||
|
||||
>>> import py
|
||||
>>> temppath = py.test.ensuretemp('py.path_documentation')
|
||||
>>> foopath = temppath.join('foo') # get child 'foo' (lazily)
|
||||
>>> foopath.check() # check if child 'foo' exists
|
||||
False
|
||||
>>> foopath.write('bar') # write some data to it
|
||||
>>> foopath.check()
|
||||
True
|
||||
>>> foopath.read()
|
||||
'bar'
|
||||
>>> foofile = foopath.open() # return a 'real' file object
|
||||
>>> foofile.read(1)
|
||||
'b'
|
||||
|
||||
:api:`py.path.svnurl` and :api:`py.path.svnwc`
|
||||
----------------------------------------------
|
||||
|
||||
Two other :api:`py.path` implementations that the py lib provides wrap the
|
||||
popular `Subversion`_ revision control system: the first (called 'svnurl')
|
||||
by interfacing with a remote server, the second by wrapping a local checkout.
|
||||
Both allow you to access relatively advanced features such as metadata and
|
||||
versioning, and both in a way more user-friendly manner than existing other
|
||||
solutions.
|
||||
|
||||
Some example usage of :api:`py.path.svnurl`::
|
||||
|
||||
.. >>> import py
|
||||
.. >>> if not py.test.config.option.urlcheck: raise ValueError('skipchunk')
|
||||
>>> url = py.path.svnurl('http://codespeak.net/svn/py')
|
||||
>>> info = url.info()
|
||||
>>> info.kind
|
||||
'dir'
|
||||
>>> firstentry = url.log()[-1]
|
||||
>>> import time
|
||||
>>> time.strftime('%Y-%m-%d', time.gmtime(firstentry.date))
|
||||
'2004-10-02'
|
||||
|
||||
Example usage of :api:`py.path.svnwc`::
|
||||
|
||||
.. >>> if not py.test.config.option.urlcheck: raise ValueError('skipchunk')
|
||||
>>> temp = py.test.ensuretemp('py.path_documentation')
|
||||
>>> wc = py.path.svnwc(temp.join('svnwc'))
|
||||
>>> wc.checkout('http://codespeak.net/svn/py/dist/py/path/local')
|
||||
>>> wc.join('local.py').check()
|
||||
True
|
||||
|
||||
.. _`Subversion`: http://subversion.tigris.org/
|
||||
|
||||
Common vs. specific API
|
||||
=======================
|
||||
|
||||
All Path objects support a common set of operations, suitable
|
||||
for many use cases and allowing to transparently switch the
|
||||
path object within an application (e.g. from "local" to "svnwc").
|
||||
The common set includes functions such as `path.read()` to read all data
|
||||
from a file, `path.write()` to write data, `path.listdir()` to get a list
|
||||
of directory entries, `path.check()` to check if a node exists
|
||||
and is of a particular type, `path.join()` to get
|
||||
to a (grand)child, `path.visit()` to recursively walk through a node's
|
||||
children, etc. Only things that are not common on 'normal' filesystems (yet),
|
||||
such as handling metadata (e.g. the Subversion "properties") require
|
||||
using specific APIs.
|
||||
|
||||
Examples
|
||||
---------------------------------
|
||||
|
||||
A quick 'cookbook' of small examples that will be useful 'in real life',
|
||||
which also presents parts of the 'common' API, and shows some non-common
|
||||
methods:
|
||||
|
||||
Searching `.txt` files
|
||||
..........................
|
||||
|
||||
Search for a particular string inside all files with a .txt extension in a
|
||||
specific directory.
|
||||
|
||||
::
|
||||
|
||||
>>> dirpath = temppath.ensure('testdir', dir=True)
|
||||
>>> dirpath.join('textfile1.txt').write('foo bar baz')
|
||||
>>> dirpath.join('textfile2.txt').write('frob bar spam eggs')
|
||||
>>> subdir = dirpath.ensure('subdir', dir=True)
|
||||
>>> subdir.join('textfile1.txt').write('foo baz')
|
||||
>>> subdir.join('textfile2.txt').write('spam eggs spam foo bar spam')
|
||||
>>> results = []
|
||||
>>> for fpath in dirpath.visit('*.txt'):
|
||||
... if 'bar' in fpath.read():
|
||||
... results.append(fpath.basename)
|
||||
>>> results.sort()
|
||||
>>> results
|
||||
['textfile1.txt', 'textfile2.txt', 'textfile2.txt']
|
||||
|
||||
Working with Paths
|
||||
.......................
|
||||
|
||||
This example shows the :api:`py.path` features to deal with
|
||||
filesystem paths Note that the filesystem is never touched,
|
||||
all operations are performed on a string level (so the paths
|
||||
don't have to exist, either)::
|
||||
|
||||
>>> p1 = py.path.local('/foo/bar')
|
||||
>>> p2 = p1.join('baz/qux')
|
||||
>>> p2 == py.path.local('/foo/bar/baz/qux')
|
||||
True
|
||||
>>> sep = py.path.local.sep
|
||||
>>> p2.relto(p1).replace(sep, '/') # os-specific path sep in the string
|
||||
'baz/qux'
|
||||
>>> p2.bestrelpath(p1).replace(sep, '/')
|
||||
'../..'
|
||||
>>> p2.join(p2.bestrelpath(p1)) == p1
|
||||
True
|
||||
>>> p3 = p1 / 'baz/qux' # the / operator allows joining, too
|
||||
>>> p2 == p3
|
||||
True
|
||||
>>> p4 = p1 + ".py"
|
||||
>>> p4.basename == "bar.py"
|
||||
True
|
||||
>>> p4.ext == ".py"
|
||||
True
|
||||
>>> p4.purebasename == "bar"
|
||||
True
|
||||
|
||||
This should be possible on every implementation of :api:`py.path`, so
|
||||
regardless of whether the implementation wraps a UNIX filesystem, a Windows
|
||||
one, or a database or object tree, these functions should be available (each
|
||||
with their own notion of path seperators and dealing with conversions, etc.).
|
||||
|
||||
Checking path types
|
||||
.......................
|
||||
|
||||
Now we will show a bit about the powerful 'check()' method on paths, which
|
||||
allows you to check whether a file exists, what type it is, etc.::
|
||||
|
||||
>>> file1 = temppath.join('file1')
|
||||
>>> file1.check() # does it exist?
|
||||
False
|
||||
>>> file1 = file1.ensure(file=True) # 'touch' the file
|
||||
>>> file1.check()
|
||||
True
|
||||
>>> file1.check(dir=True) # is it a dir?
|
||||
False
|
||||
>>> file1.check(file=True) # or a file?
|
||||
True
|
||||
>>> file1.check(ext='.txt') # check the extension
|
||||
False
|
||||
>>> textfile = temppath.ensure('text.txt', file=True)
|
||||
>>> textfile.check(ext='.txt')
|
||||
True
|
||||
>>> file1.check(basename='file1') # we can use all the path's properties here
|
||||
True
|
||||
|
||||
Setting svn-properties
|
||||
.......................
|
||||
|
||||
As an example of 'uncommon' methods, we'll show how to read and write
|
||||
properties in an :api:`py.path.svnwc` instance::
|
||||
|
||||
.. >>> if not py.test.config.option.urlcheck: raise ValueError('skipchunk')
|
||||
>>> wc.propget('foo')
|
||||
''
|
||||
>>> wc.propset('foo', 'bar')
|
||||
>>> wc.propget('foo')
|
||||
'bar'
|
||||
>>> len(wc.status().prop_modified) # our own props
|
||||
1
|
||||
>>> msg = wc.revert() # roll back our changes
|
||||
>>> len(wc.status().prop_modified)
|
||||
0
|
||||
|
||||
SVN authentication
|
||||
.......................
|
||||
|
||||
Some uncommon functionality can also be provided as extensions, such as SVN
|
||||
authentication::
|
||||
|
||||
.. >>> if not py.test.config.option.urlcheck: raise ValueError('skipchunk')
|
||||
>>> auth = py.path.SvnAuth('anonymous', 'user', cache_auth=False,
|
||||
... interactive=False)
|
||||
>>> wc.auth = auth
|
||||
>>> wc.update() # this should work
|
||||
>>> path = wc.ensure('thisshouldnotexist.txt')
|
||||
>>> try:
|
||||
... path.commit('testing')
|
||||
... except py.process.cmdexec.Error, e:
|
||||
... pass
|
||||
>>> 'authorization failed' in str(e)
|
||||
True
|
||||
|
||||
Known problems / limitations
|
||||
===================================
|
||||
|
||||
* The SVN path objects require the "svn" command line,
|
||||
there is currently no support for python bindings.
|
||||
Parsing the svn output can lead to problems, particularly
|
||||
regarding if you have a non-english "locales" setting.
|
||||
|
||||
* While the path objects basically work on windows,
|
||||
there is no attention yet on making unicode paths
|
||||
work or deal with the famous "8.3" filename issues.
|
||||
|
||||
Future plans
|
||||
============
|
||||
|
||||
The Subversion path implementations are based
|
||||
on the `svn` command line, not on the bindings.
|
||||
It makes sense now to directly use the bindings.
|
||||
|
||||
Moreover, it would be good, also considering
|
||||
`py.execnet`_ distribution of programs, to
|
||||
be able to manipulate Windows Paths on Linux
|
||||
and vice versa. So we'd like to consider
|
||||
refactoring the path implementations
|
||||
to provide this choice (and getting rid
|
||||
of platform-dependencies as much as possible).
|
||||
|
||||
There is some experimental small approach
|
||||
(:source:`py/path/gateway/`) aiming at having
|
||||
a convenient Remote Path implementation
|
||||
and some considerations about future
|
||||
works in the according :source:`py/path/gateway/TODO.txt`
|
||||
|
||||
There are various hacks out there to have
|
||||
Memory-Filesystems and even path objects
|
||||
being directly mountable under Linux (via `fuse`).
|
||||
However, the Path object implementations
|
||||
do not internally have a clean abstraction
|
||||
of going to the filesystem - so with some
|
||||
refactoring it should become easier to
|
||||
have very custom Path objects, still offering
|
||||
the quite full interface without requiring
|
||||
to know about all details of the full path
|
||||
implementation.
|
||||
|
||||
.. _`py.execnet`: execnet.html
|
||||
|
||||
Reference in New Issue
Block a user