Commit 9457a3c9 by willmcgugan

Work in progress

parent d5fb43e5
...@@ -27,8 +27,19 @@ error_codes = error_msgs.keys() ...@@ -27,8 +27,19 @@ error_codes = error_msgs.keys()
class FSError(Exception): class FSError(Exception):
"""A catch all exception for FS objects."""
def __init__(self, code, path=None, msg=None, details=None): def __init__(self, code, path=None, msg=None, details=None):
"""
code -- A short identifier for the error
path -- A path associated with the error
msg -- An textual description of the error
details -- Any additional details associated with the error
"""
self.code = code self.code = code
self.msg = msg or error_msgs.get(code, error_msgs['UNKNOWN_ERROR']) self.msg = msg or error_msgs.get(code, error_msgs['UNKNOWN_ERROR'])
self.path = path self.path = path
...@@ -49,7 +60,14 @@ class PathError(Exception): ...@@ -49,7 +60,14 @@ class PathError(Exception):
return self.msg return self.msg
class NullFile: class NullFile(object):
"""A NullFile is a file object that has no functionality. Null files are
returned by the 'safeopen' method in FS objects when the file does not exist.
This can simplify code by negating the need to check if a file exists,
or handling exceptions.
"""
def __init__(self): def __init__(self):
self.closed = False self.closed = False
...@@ -91,20 +109,24 @@ class NullFile: ...@@ -91,20 +109,24 @@ class NullFile:
pass pass
def isabsolutepath(path): def isabsolutepath(path):
"""Returns True if a given path is absolute."""
if path: if path:
return path[0] in '\\/' return path[0] in '\\/'
return False return False
def normpath(path): def normpath(path):
"""Normalizes a path to be in the formated expected by FS objects.
Returns a new path string."""
return path.replace('\\', '/') return path.replace('\\', '/')
def pathjoin(*paths): def pathjoin(*paths):
"""Joins any number of paths together. Returns a new path string.
paths -- An iterable of path strings
"""
absolute = False absolute = False
relpaths = [] relpaths = []
...@@ -134,10 +156,21 @@ def pathjoin(*paths): ...@@ -134,10 +156,21 @@ def pathjoin(*paths):
def pathsplit(path): def pathsplit(path):
"""Splits a path on a path separator. Returns a tuple containing the path up
to that last separator and the remaining path component.
>>> pathsplit("foo/bar")
('foo', 'bar')
>>> pathsplit("foo/bar/baz")
('foo/bar', 'bar')
"""
split = normpath(path).rsplit('/', 1) split = normpath(path).rsplit('/', 1)
if len(split) == 1: if len(split) == 1:
return ('', split[0]) return ('', split[0])
return split return tuple(split)
def resolvepath(path): def resolvepath(path):
return pathjoin(path) return pathjoin(path)
......
...@@ -24,27 +24,29 @@ class TestHelpers(unittest.TestCase): ...@@ -24,27 +24,29 @@ class TestHelpers(unittest.TestCase):
self.assertEqual(fs.normpath(path), result) self.assertEqual(fs.normpath(path), result)
def test_pathjon(self): def test_pathjon(self):
tests = [ ("", "a", "a"), tests = [ ("", "a", "a"),
("a", "a", "a/a"), ("a", "a", "a/a"),
("a/b", "../c", "a/c"), ("a/b", "../c", "a/c"),
("a/b/../c", "d", "a/c/d"), ("a/b/../c", "d", "a/c/d"),
("/a/b/c", "d", "/a/b/c/d"), ("/a/b/c", "d", "/a/b/c/d"),
("/a/b/c", "../../../d", "/d"), ("/a/b/c", "../../../d", "/d"),
("a", "b", "c", "a/b/c"), ("a", "b", "c", "a/b/c"),
("a/b/c", "../d", "c", "a/b/d/c"), ("a/b/c", "../d", "c", "a/b/d/c"),
("a/b/c", "../d", "/a", "/a"), ("a/b/c", "../d", "/a", "/a"),
("aaa", "bbb/ccc", "aaa/bbb/ccc"), ("aaa", "bbb/ccc", "aaa/bbb/ccc"),
("aaa", "bbb\ccc", "aaa/bbb/ccc"), ("aaa", "bbb\ccc", "aaa/bbb/ccc"),
("aaa", "bbb", "ccc", "/aaa", "eee", "/aaa/eee"), ("aaa", "bbb", "ccc", "/aaa", "eee", "/aaa/eee"),
("a/b", "./d", "e", "a/b/d/e"), ("a/b", "./d", "e", "a/b/d/e"),
("/", "/", "/"), ("/", "/", "/"),
("/", "", "/"), ("/", "", "/"),
] ]
for testpaths in tests: for testpaths in tests:
paths = testpaths[:-1] paths = testpaths[:-1]
result = testpaths[-1] result = testpaths[-1]
self.assertEqual(fs.pathjoin(*paths), result) self.assertEqual(fs.pathjoin(*paths), result)
self.assertRaises(fs.PathError, fs.pathjoin, "../")
self.assertRaises(fs.PathError, fs.pathjoin, "./../")
self.assertRaises(fs.PathError, fs.pathjoin, "a/b", "../../..") self.assertRaises(fs.PathError, fs.pathjoin, "a/b", "../../..")
self.assertRaises(fs.PathError, fs.pathjoin, "a/b/../../../d") self.assertRaises(fs.PathError, fs.pathjoin, "a/b/../../../d")
...@@ -53,6 +55,7 @@ class TestHelpers(unittest.TestCase): ...@@ -53,6 +55,7 @@ class TestHelpers(unittest.TestCase):
tests = [ ("/a/b", "a/b"), tests = [ ("/a/b", "a/b"),
("a/b", "a/b"), ("a/b", "a/b"),
("/", "") ] ("/", "") ]
for path, result in tests: for path, result in tests:
print path, result print path, result
self.assertEqual(fs.makerelative(path), result) self.assertEqual(fs.makerelative(path), result)
...@@ -62,6 +65,7 @@ class TestHelpers(unittest.TestCase): ...@@ -62,6 +65,7 @@ class TestHelpers(unittest.TestCase):
tests = [ ("/a/b", "/a/b"), tests = [ ("/a/b", "/a/b"),
("a/b", "/a/b"), ("a/b", "/a/b"),
("/", "/") ] ("/", "/") ]
for path, result in tests: for path, result in tests:
self.assertEqual(fs.makeabsolute(path), result) self.assertEqual(fs.makeabsolute(path), result)
...@@ -80,6 +84,19 @@ class TestHelpers(unittest.TestCase): ...@@ -80,6 +84,19 @@ class TestHelpers(unittest.TestCase):
self.assertEqual(list(fs._iteratepath("a/b/c/d", 1)), ["a", "b/c/d"]) self.assertEqual(list(fs._iteratepath("a/b/c/d", 1)), ["a", "b/c/d"])
self.assertEqual(list(fs._iteratepath("a/b/c/d", 2)), ["a", "b", "c/d"]) self.assertEqual(list(fs._iteratepath("a/b/c/d", 2)), ["a", "b", "c/d"])
def test_pathsplit(self):
tests = [ ("a/b", ("a", "b")),
("a/b/c", ("a/b", "c")),
("a", ("", "a")),
("", ("", "")),
("/", ("", "")),
("foo/bar", ("foo", "bar")),
("foo/bar/baz", ("foo/bar", "baz")),
]
for path, result in tests:
self.assertEqual(fs.pathsplit(path), result)
if __name__ == "__main__": if __name__ == "__main__":
import nose import nose
nose.run() nose.run()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment