======= py.path ======= .. contents:: .. sectnum:: 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`:: >>> 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`:: >>> 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.relto(dirpath)) >>> results ['textfile1.txt', 'textfile2.txt', 'subdir/textfile2.txt'] Joining path types ++++++++++++++++++++ This example shows the :api:`py.path` features to deal with actual paths (strings). 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.strpath '/foo/bar/baz/qux' >>> p2.relto(p1) 'baz/qux' >>> p3 = p1 / 'baz/qux' # the / operator allows joining, too >>> p2 == p3 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:: >>> 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 XXX more examples (look at API) +++++++++++++++++++++++++++++++++++++++ XXX Known problems / limitations =================================== There are some known issues, most importantly that using the Subversion Paths requires the command line `svn` binary and parsing its output is a bit fragile across versions and locales (it basically only works with an english locale!). XXX note more here 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