diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | fs/base.py | 1 | ||||
-rw-r--r-- | fs/filelike.py | 2 | ||||
-rw-r--r-- | fs/mountfs.py | 43 | ||||
-rw-r--r-- | fs/objecttree.py | 105 | ||||
-rw-r--r-- | fs/path.py | 44 | ||||
-rw-r--r-- | fs/tests/test_objecttree.py | 47 | ||||
-rw-r--r-- | fs/wrapfs/__init__.py | 47 |
8 files changed, 128 insertions, 162 deletions
@@ -70,4 +70,5 @@ * Added copyfile_non_atomic and movefile_non_atomic for improved performance of multi-threaded copies * Added ilistdir() and ilistdirinfo() methods, which are generator-based variants of listdir() and listdirinfo(). + * Removed obsolute module fs.objectree; use fs.path.PathMap instead. @@ -224,6 +224,7 @@ class FS(object): The following are less common: * *free_space* The free space (in bytes) available on the file system + * *total_space* The total space (in bytes) available on the file system FS implementations may expose non-generic meta data through a self-named namespace. e.g. 'somefs.some_meta' diff --git a/fs/filelike.py b/fs/filelike.py index cbf71d2..476d1eb 100644 --- a/fs/filelike.py +++ b/fs/filelike.py @@ -32,7 +32,7 @@ import tempfile as _tempfile try: from cStringIO import StringIO as _StringIO except ImportError: - from StrimgIO import StringIO as _StringIO + from StringIO import StringIO as _StringIO import fs diff --git a/fs/mountfs.py b/fs/mountfs.py index 48131a6..662da85 100644 --- a/fs/mountfs.py +++ b/fs/mountfs.py @@ -218,6 +218,49 @@ class MountFS(FS): return paths @synchronize + def ilistdir(self, path="/", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False): + fs, mount_path, delegate_path = self._delegate(path) + + if fs is None: + raise ResourceNotFoundError(path) + + if fs is self: + paths = self.mount_tree.names(path) + for path in self._listdir_helper(path,wildcard,full,absolute,dirs_only,files_only): + yield path + else: + paths = fs.ilistdir(delegate_path, + wildcard=wildcard, + full=False, + absolute=False, + dirs_only=dirs_only) + extra_paths = set(self.mount_tree.names(path)) + if full: + pathhead = relpath(normpath(path)) + def mkpath(p): + return pathjoin(pathhead,p) + elif absolute: + pathhead = abspath(normpath(path)) + def mkpath(p): + return pathjoin(pathhead,p) + else: + def mkpath(p): + return p + for p in paths: + if p not in extra_paths: + yield mkpath(p) + for p in extra_paths: + if dirs_only: + if self.isdir(pathjoin(path,p)): + yield mkpath(p) + elif files_only: + if self.isfile(pathjoin(path,nm)): + yield mkpath(p) + else: + yield mkpath(p) + + + @synchronize def makedir(self, path, recursive=False, allow_recreate=False): fs, mount_path, delegate_path = self._delegate(path) if fs is self or fs is None: diff --git a/fs/objecttree.py b/fs/objecttree.py deleted file mode 100644 index 2f04d90..0000000 --- a/fs/objecttree.py +++ /dev/null @@ -1,105 +0,0 @@ - - -class _ObjectDict(dict): - pass - - -class ObjectTree(object): - """A class to facilitate the creation of tree structures.""" - - def __init__(self): - self.root = _ObjectDict() - - def _split(self, path): - if '/' not in path: - return "", path - else: - return path.rsplit('/', 1) - - def _splitpath(self, path): - return [p for p in path.split('/') if p] - - def _locate(self, path): - current = self.root - for path_component in self._splitpath(path): - if type(current) is not _ObjectDict: - return None - node = current.get(path_component, None) - if node is None: - return None - current = node - return current - - def __setitem__(self, path, object): - if not path: - raise IndexError("No path supplied") - current = self.root - path, name = self._split(path) - for path_component in self._splitpath(path): - node = current.get(path_component, None) - if type(node) is not _ObjectDict: - new_dict = _ObjectDict() - current[path_component] = new_dict - current = new_dict - else: - current = node - current[name] = object - - def __getitem__(self, path): - node = self._locate(path) - if node is None: - raise IndexError("Path does not exist") - return node - - def __delitem__(self, path): - path, name = self._split(path) - node = self._locate(path) - if node is None or type(node) is not _ObjectDict: - raise IndexError("Path does not exist") - del node[name] - - def get(self, path, default): - node = self._locate(path) - if node is None: - return default - return node - - def partialget(self, path, default=None): - current = self.root - partial_path = [] - remaining_path = self._splitpath(path) - for path_component in remaining_path[:]: - if type(current) is not _ObjectDict: - return "/".join(partial_path), current, "/".join(remaining_path) - partial_path.append(path_component) - remaining_path.pop(0) - node = current.get(path_component, None) - if node is None: - return None, default, None - current = node - return path, current, "" - - def isobject(self, path): - node = self._locate(path) - return type(node) is not _ObjectDict - - def __contains__(self, path): - node = self._locate(path) - return node is not None - - def __iter__(self): - return iter(self.root) - - def keys(self): - return self.root.keys() - - def iterkeys(self): - return self.root.iterkeys() - - def items(self): - return self.root.items() - - def iteritems(self): - return self.root.iteritems() - - @@ -17,7 +17,7 @@ def normpath(path): """Normalizes a path to be in the format expected by FS objects. This function remove any leading or trailing slashes, collapses - duplicate slashes, replaces forward with backward slashes, and generally + duplicate slashes, replaces backward with forward slashes, and generally tries very hard to return a new path string the canonical FS format. If the path is invalid, ValueError will be raised. @@ -162,8 +162,16 @@ def pathjoin(*paths): path = abspath(path) return path -# Allow pathjoin() to be used as fs.path.join() -join = pathjoin + +def join(*paths): + """Joins any number of paths together, returning a new path string. + + This is a simple alias for the ``pathjoin`` function, allowing it to be + used as ``fs.path.join`` in direct correspondance with ``os.path.join``. + + :param paths: Paths to join are given in positional arguments + """ + return pathjoin(*paths) def pathsplit(path): @@ -189,8 +197,17 @@ def pathsplit(path): split = path.rsplit('/', 1) return (split[0] or '/', split[1]) -# Allow pathsplit() to be used as fs.path.split() -split = pathsplit + +def split(path): + """Splits a path into (head, tail) pair. + + This is a simple alias for the ``pathsplit`` function, allowing it to be + used as ``fs.path.split`` in direct correspondance with ``os.path.split``. + + :param path: Path to split + """ + return pathsplit(path) + def splitext(path): """Splits the extension from the path, and returns the path (up to the last @@ -337,9 +354,18 @@ def frombase(path1, path2): class PathMap(object): """Dict-like object with paths for keys. - A PathMap is like a dictionary where the keys are all FS paths. It allows - various dictionary operations (e.g. listing values, clearing values) to - be performed on a subset of the keys sharing some common prefix, e.g.:: + A PathMap is like a dictionary where the keys are all FS paths. It has + two main advantages over a standard dictionary. First, keys are normalised + automatically:: + + >>> pm = PathMap() + >>> pm["hello/world"] = 42 + >>> print pm["/hello/there/../world"] + 42 + + Second, various dictionary operations (e.g. listing or clearing values) + can be efficiently performed on a subset of keys sharing some common + prefix:: # list all values in the map pm.values() @@ -547,4 +573,4 @@ def iswildcard(path): return not base_chars.isdisjoint(_wild_chars) if __name__ == "__main__": - print recursepath('a/b/c')
\ No newline at end of file + print recursepath('a/b/c') diff --git a/fs/tests/test_objecttree.py b/fs/tests/test_objecttree.py deleted file mode 100644 index b8d9a12..0000000 --- a/fs/tests/test_objecttree.py +++ /dev/null @@ -1,47 +0,0 @@ -""" - - fs.tests.test_objectree: testcases for the fs objecttree module - -""" - - -import unittest - -import fs.tests -from fs import objecttree - -class TestObjectTree(unittest.TestCase): - """Testcases for the ObjectTree class.""" - - def test_getset(self): - ot = objecttree.ObjectTree() - ot['foo'] = "bar" - self.assertEqual(ot['foo'], 'bar') - - ot = objecttree.ObjectTree() - ot['foo/bar'] = "baz" - self.assertEqual(ot['foo'], {'bar':'baz'}) - self.assertEqual(ot['foo/bar'], 'baz') - - del ot['foo/bar'] - self.assertEqual(ot['foo'], {}) - - ot = objecttree.ObjectTree() - ot['a/b/c'] = "A" - ot['a/b/d'] = "B" - ot['a/b/e'] = "C" - ot['a/b/f'] = "D" - self.assertEqual(sorted(ot['a/b'].values()), ['A', 'B', 'C', 'D']) - self.assert_(ot.get('a/b/x', -1) == -1) - - self.assert_('a/b/c' in ot) - self.assert_('a/b/x' not in ot) - self.assert_(ot.isobject('a/b/c')) - self.assert_(ot.isobject('a/b/d')) - self.assert_(not ot.isobject('a/b')) - - left, object, right = ot.partialget('a/b/e/f/g') - self.assertEqual(left, "a/b/e") - self.assertEqual(object, "C") - self.assertEqual(right, "f/g") - diff --git a/fs/wrapfs/__init__.py b/fs/wrapfs/__init__.py index 760a601..9b02aeb 100644 --- a/fs/wrapfs/__init__.py +++ b/fs/wrapfs/__init__.py @@ -192,6 +192,32 @@ class WrapFS(FS): return entries @rewrite_errors + def ilistdir(self, path="", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False): + kwds = dict(wildcard=wildcard, + full=full, + absolute=absolute, + dirs_only=dirs_only, + files_only=files_only) + full = kwds.pop("full",False) + absolute = kwds.pop("absolute",False) + wildcard = kwds.pop("wildcard",None) + if wildcard is None: + wildcard = lambda fn:True + elif not callable(wildcard): + wildcard_re = re.compile(fnmatch.translate(wildcard)) + wildcard = lambda fn:bool (wildcard_re.match(fn)) + enc_path = self._encode(path) + for e in self.wrapped_fs.ilistdir(enc_path,**kwds): + e = basename(self._decode(pathjoin(enc_path,e))) + if not wildcard(e): + continue + if full: + e = pathjoin(path,e) + elif absolute: + e = abspath(pathjoin(path,e)) + yield e + + @rewrite_errors def listdirinfo(self, path="", **kwds): full = kwds.pop("full",False) absolute = kwds.pop("absolute",False) @@ -215,6 +241,27 @@ class WrapFS(FS): return entries @rewrite_errors + def ilistdirinfo(self, path="", **kwds): + full = kwds.pop("full",False) + absolute = kwds.pop("absolute",False) + wildcard = kwds.pop("wildcard",None) + if wildcard is None: + wildcard = lambda fn:True + elif not callable(wildcard): + wildcard_re = re.compile(fnmatch.translate(wildcard)) + wildcard = lambda fn:bool (wildcard_re.match(fn)) + enc_path = self._encode(path) + for (nm,info) in self.wrapped_fs.ilistdirinfo(enc_path,**kwds): + nm = basename(self._decode(pathjoin(enc_path,nm))) + if not wildcard(nm): + continue + if full: + nm = pathjoin(path,nm) + elif absolute: + nm = abspath(pathjoin(path,nm)) + yield (nm,info) + + @rewrite_errors def makedir(self, path, *args, **kwds): return self.wrapped_fs.makedir(self._encode(path),*args,**kwds) |