Package: pth
Note:This is in very alpha state.Simple and brief path traversal and filesystem access library. This library is a bit different that other path manipulation libraries:Path are subclasses of strings. You can use them anyhere you would use a string.Almost everything fromos.pathis available as apropertywith the same name except:os.path.relpathis amethodos.path.getsizebecomes apropertynamedsizeos.path.getatimebecomes apropertynamedatimeos.path.getctimebecomes apropertynamedctimeos.path.getmtimebecomes apropertynamedmtimeos.path.splitbecomes amethodnamesplitpathassplitis already a string methodos.path.joinbecomes amethodnamejoinpathasjoinis already a string methodos.path.commonprefixis not implementedos.path.basenamebecomes apropertynamednameos.path.dirnamebecomes apropertynameddiros.listdirbecomes apropertynamedlistos.walkbecomes apropertynamedtreeCalling aPathobject callsopen()on the path. Takes any argumentopenwould take (except the filename ofcourse).Transparent support for files in .zip files.Basically it is designed for extreme brevity. It sharesUnipath’s
str-subclassing approach and and it has seamless zip support (like Twisted’sZipPath).UsageGetting started:>>> import pth
>>> pth  # the module is a function!
<function pth at ...>
>>> p = pth("a.txt")
>>> p
<Path 'a.txt'>
>>> p
<Path 'a.txt'>API>>> p = pth('tests')
>>> p
<Path 'tests'>Joining paths:>>> p/"a"/"b"/"c"/"d"
<Path 'tests/a/b/c/d'>

>>> p/"/root"
<Path '/root'>Properties:>>> p.abspath
<Path '/.../tests'>

>>> p2 = p/'b.txt'
>>> p2
<Path 'tests/b.txt'>

>>> p.exists
True

>>> p2.isfile
True

>>> p2()
<...'tests/b.txt'...mode...'r'...>

>>> pth('bogus-doesnt-exist')()
Traceback (most recent call last):
  ...
pth.PathMustBeFile: [Errno 2] No such file or directory: ...Looping over children, including files in .zip files:>>> for i in sorted([i for i in p.tree]): print(i)
tests/a
tests/a/a.txt
tests/b.txt
tests/test.zip
tests/test.zip/1
tests/test.zip/1/1.txt
tests/test.zip/B.TXT
tests/test.zip/a.txt

>>> for i in sorted([i for i in p.files]): print(i)
tests/b.txt

>>> for i in sorted([i for i in p.dirs]): print(i)
tests/a
tests/test.zip

>>> for i in sorted([i for i in p.list]): print(i)
tests/a
tests/b.txt
tests/test.zip

>>> list(pth('bogus-doesnt-exist').tree)
Traceback (most recent call last):
  ...
pth.PathMustBeDirectory: <Path 'bogus-doesnt-exist'> is not a directory nor a zip !Trying to access inexisting property:>>> p.bogus
Traceback (most recent call last):
...
AttributeError: 'Path' object has no attribute 'bogus'Automatic wrapping of zips:>>> p/'test.zip'
<ZipPath 'tests/test.zip' / ''>Other properties:>>> p.abspath
<Path '/.../tests'>

>>> p.abs
<Path '/.../tests'>

>>> p.basename
<Path 'tests'>

>>> p.abs.basename
<Path 'tests'>

>>> p.name
<Path 'tests'>

>>> p.dirname
<Path ''>

>>> p.dir
<Path ''>

>>> p.exists
True

>>> pth('~root').expanduser
<Path '/root'>

>>> pth('~/stuff').expanduser
<Path '/home/.../stuff'>

>>> p.expandvars
<Path 'tests'>

>>> type(p.atime)
<... 'float'>

>>> type(p.ctime)
<... 'float'>

>>> type(p.size)
<... 'int'>

>>> p.isabs
False

>>> p.abs.isabs
True

>>> p.isdir
True

>>> p.isfile
False

>>> p.islink
False

>>> p.ismount
False

>>> p.lexists
True

>>> p.normcase
<Path 'tests'>

>>> p.normpath
<Path 'tests'>

>>> p.realpath
<Path '/.../tests'>

>>> p.splitpath
(<Path ''>, <Path 'tests'>)

>>> pth('a/b/c/d').splitpath
(<Path 'a/b/c'>, <Path 'd'>)

>>> pth('a/b/c/d').parts
[<Path 'a'>, <Path 'b'>, <Path 'c'>, <Path 'd'>]

>>> pth('/a/b/c/d').parts
[<Path '/'>, <Path 'a'>, <Path 'b'>, <Path 'c'>, <Path 'd'>]

>>> pth(*pth('/a/b/c/d').parts)
<Path '/a/b/c/d'>

>>> p.splitdrive
('', <Path 'tests'>)

>>> p.drive
''

>>> [i for i in (p/'xxx').tree]
Traceback (most recent call last):
...
pth.PathMustBeDirectory: <Path 'tests/xxx'> is not a directory nor a zip !

>>> (p/'xxx').isfile
False

>>> (p/'xxx')()
Traceback (most recent call last):
...
pth.PathMustBeFile: ... 2...

>>> p()
Traceback (most recent call last):
...
pth.PathMustBeFile: <Path 'tests'> is not a file !

>>> pth('a.txt').splitext
(<Path 'a'>, '.txt')

>>> pth('a.txt').ext
'.txt'Zip stuff:>>> z = pth('tests/test.zip')
>>> z
<ZipPath 'tests/test.zip' / ''>

>>> z.abspath
<ZipPath '/.../tests/test.zip' / ''>

>>> z.abs
<ZipPath '/.../tests/test.zip' / ''>

>>> z.basename # transforms in normal path cauze zip is not accessible in current dir
<Path 'test.zip'>

>>> z.abs.basename # transforms in normal path cauze zip is not accessible in current dir
<Path 'test.zip'>

>>> import os
>>> os.chdir('tests')
>>> z.basename
<ZipPath 'test.zip' / ''>
>>> z.name
<ZipPath 'test.zip' / ''>
>>> os.chdir('..')

>>> z.dirname
<Path 'tests'>

>>> z.abs.dirname
<Path '/.../tests'>

>>> z.dir
<Path 'tests'>

>>> z.exists
True

>>> pth('~root').expanduser
<Path '/root'>

>>> pth('~/stuff').expanduser
<Path '/home/.../stuff'>

>>> z.expandvars
<ZipPath 'tests/test.zip' / ''>

>>> type(z.atime)
Traceback (most recent call last):
...
AttributeError: Not available here.

>>> type(z.ctime)
<... 'float'>

>>> type(z.size)
<... 'int'>

>>> z.isabs
False

>>> z.abs.isabs
True

>>> z.isdir
True

>>> z.isfile
False

>>> z.islink
False

>>> z.ismount
False

>>> z.lexists
Traceback (most recent call last):
...
AttributeError: Not available here.

>>> for i in z.tree: print((str(i), repr(i)))
('tests/test.zip/1',...... "<ZipPath 'tests/test.zip' / '1/'>")
('tests/test.zip/1/1.txt', "<ZipPath 'tests/test.zip' / '1/1.txt'>")
('tests/test.zip/B.TXT',..."<ZipPath 'tests/test.zip' / 'B.TXT'>")
('tests/test.zip/a.txt',..."<ZipPath 'tests/test.zip' / 'a.txt'>")

>>> for i in z.files: print((str(i), repr(i)))
('tests/test.zip/B.TXT',..."<ZipPath 'tests/test.zip' / 'B.TXT'>")
('tests/test.zip/a.txt',..."<ZipPath 'tests/test.zip' / 'a.txt'>")

>>> for i in z.dirs: print((str(i), repr(i)))
('tests/test.zip/1',...... "<ZipPath 'tests/test.zip' / '1/'>")

>>> for i in z.list: print((str(i), repr(i)))
('tests/test.zip/1',...... "<ZipPath 'tests/test.zip' / '1/'>")
('tests/test.zip/B.TXT',..."<ZipPath 'tests/test.zip' / 'B.TXT'>")
('tests/test.zip/a.txt',..."<ZipPath 'tests/test.zip' / 'a.txt'>")

>>> (z/'B.TXT')
<ZipPath 'tests/test.zip' / 'B.TXT'>

>>> str(z/'B.TXT')
'tests/test.zip/B.TXT'

>>> (z/'B.TXT').dirname
<ZipPath 'tests/test.zip' / ''>

>>> (z/'B.TXT').rel(z)
<Path 'B.TXT'>

>>> z.rel(z/'B.TXT')
<Path '..'>

>>> (z/'B.TXT').exists
True

>>> (z/'B.TXT').normcase
<ZipPath 'tests/test.zip' / 'B.TXT'>

>>> (z/'B.TXT').normpath
<ZipPath 'tests/test.zip' / 'B.TXT'>

>>> (z/'B.TXT').name
<Path 'B.TXT'>

>>> (z/'B.TXT').name
<Path 'B.TXT'>

>>> z.normcase
<ZipPath 'tests/test.zip' / ''>

>>> z.normpath
<ZipPath 'tests/test.zip' / ''>

>>> z.realpath
<ZipPath '/.../tests/test.zip' / ''>

>>> z.splitpath
(<Path 'tests'>, <Path 'test.zip'>)

>>> z.splitdrive
('', <ZipPath 'tests/test.zip' / ''>)

>>> z.drive
''

>>> pth('a.txt').splitext
(<Path 'a'>, '.txt')

>>> pth('a.txt').ext
'.txt'Working with files in a .zip:>>> p = z/'B.TXT'
>>> p.abspath
<ZipPath '/.../tests/test.zip' / 'B.TXT'>

>>> p.abs
<ZipPath '/.../tests/test.zip' / 'B.TXT'>

>>> p.basename
<Path 'B.TXT'>

>>> p.abs.basename
<Path 'B.TXT'>

>>> p.name
<Path 'B.TXT'>

>>> p.dirname
<ZipPath 'tests/test.zip' / ''>

>>> p.dir
<ZipPath 'tests/test.zip' / ''>

>>> p.exists
True

>>> type(p.atime)
Traceback (most recent call last):
...
AttributeError: Not available here.

>>> type(p.ctime)
<... 'float'>

>>> type(p.size)
<... 'int'>

>>> p.isabs
False

>>> p.abs.isabs
True

>>> p.isdir
False

>>> p.isfile
True

>>> p.islink
False

>>> p.ismount
False

>>> p.lexists
Traceback (most recent call last):
...
AttributeError: Not available here.

>>> p.normcase
<ZipPath 'tests/test.zip' / 'B.TXT'>

>>> p.normpath
<ZipPath 'tests/test.zip' / 'B.TXT'>

>>> p.realpath
<ZipPath '/.../tests/test.zip' / 'B.TXT'>

>>> p.splitpath
(<ZipPath 'tests/test.zip' / ''>, <Path 'B.TXT'>)

>>> pth.ZipPath.from_string('tests/test.zip/1/1.txt')
<ZipPath 'tests/test.zip' / '1/1.txt'>

>>> p.splitdrive
('', <ZipPath 'tests/test.zip' / 'B.TXT'>)

>>> p.drive
''

>>> p.splitext
(<ZipPath 'tests/test.zip' / 'B'>, '.TXT')

>>> p.ext
'.TXT'

>>> p.joinpath('tete')
<ZipPath 'tests/test.zip' / 'B.TXT/tete'>

>>> p.joinpath('tete').exists
False

>>> p.joinpath('tete').isdir
False

>>> p.joinpath('tete').isfile
False

>>> p.joinpath('tete').ctime
Traceback (most recent call last):
...
pth.PathDoesNotExist: "There is no item named 'B.TXT/tete' in the archive"

>>> p.joinpath('tete').size
Traceback (most recent call last):
...
pth.PathDoesNotExist: "There is no item named 'B.TXT/tete' in the archive"

>>> p.relpath('tests')
<Path 'test.zip/B.TXT'>

>>> p.joinpath('tete')('rb')
Traceback (most recent call last):
...
pth.PathMustBeFile: <ZipPath 'tests/test.zip' / 'B.TXT/tete'> is not a file !

>>> p('r')
<zipfile.ZipExtFile ...>

>>> [i for i in p.tree]
Traceback (most recent call last):
...
pth.PathMustBeDirectory: <ZipPath 'tests/test.zip' / 'B.TXT'> is not a directory !

>>> z('rb')
Traceback (most recent call last):
...
pth.PathMustBeFile: <ZipPath 'tests/test.zip' / ''> is not a file !Iterating though the contents of the zip:>>> [i for i in z.tree]
[<ZipPath 'tests/test.zip' / '1/'>, <ZipPath 'tests/test.zip' / '1/1.txt'>, <ZipPath 'tests/test.zip' / 'B.TXT'>, <ZipPath 'tests/test.zip' / 'a.txt'>]

>>> [i for i in z.files]
[<ZipPath 'tests/test.zip' / 'B.TXT'>, <ZipPath 'tests/test.zip' / 'a.txt'>]

>>> [i for i in z.dirs]
[<ZipPath 'tests/test.zip' / '1/'>]Note that there’s this inconsistency with joining absolute paths:>>> z/pth('/root')
<Path '/root'>Vs:>>> z/'/root'
<ZipPath 'tests/test.zip' / '/root'>TODO: Make this nicer.>>> pth.ZipPath('tests', '', '')
<Path 'tests'>

>>> pth.ZipPath.from_string('/bogus/path/to/stuff/bla/bla/bla')
<Path '/bogus/path/to/stuff/bla/bla/bla'>

>>> pth.ZipPath.from_string('bogus')
<Path 'bogus'>

>>> pth.ZipPath.from_string('tests/test.zip/bogus/path/to/stuff/bla/bla/bla')
<ZipPath 'tests/test.zip' / 'bogus/path/to/stuff/bla/bla/bla'>

>>> pth.ZipPath.from_string('tests/1/bogus/path/to/stuff/bla/bla/bla')
<Path 'tests/1/bogus/path/to/stuff/bla/bla/bla'>

>>> pth.ZipPath.from_string('tests')
<Path 'tests'>

>>> pth.ZipPath.from_string('tests/bogus')
<Path 'tests/bogus'>And there’s atemporary path:>>> t = pth.TempPath()
>>> t
<TempPath '/tmp/...'>

>>> with t:
...     with (t/"booo.txt")('w+') as f:
...         _ = f.write("test")
...     print([i for i in t.tree])
[<Path '/tmp/.../booo.txt'>]

>>> t.exists
FalseChangelog0.1.0 (2014-06-10)First release on PyPI.