Skip to content

Instantly share code, notes, and snippets.

@bluele
Created January 26, 2013 20:10
Show Gist options
  • Save bluele/4644340 to your computer and use it in GitHub Desktop.
Save bluele/4644340 to your computer and use it in GitHub Desktop.
Path module provide the utility accessors for File path.
#-*- coding:utf-8 -*-
__author__ = 'bluele'
from os.path import exists as op_exists, join as op_join, dirname as op_dirname, basename as op_basename,\
normpath as op_normpath, split as op_split, normcase as op_normcase, splitext as op_splittext
class Path(object):
def __init__(self, path, is_relative=False):
self.set_path(path, is_relative=is_relative)
def __eq__(self, other):
return self.to_str() == self.normpath(str(other))
def __add__(self, other):
other = other if not isinstance(other, self.__class__) else other.to_str()
return self.__class__(op_join(self.to_str(), other))
def __str__(self):
return self.path
def __unicode__(self):
return unicode(self.path)
def __repr__(self):
return self.__unicode__()
@property
def basename(self):
return op_basename(self.to_str())
@property
def dirname(self):
""" Path's directory name. """
return op_dirname(self.to_str())
@property
def name(self):
return op_splittext(self.basename)[0]
@property
def ext(self):
return op_splittext(self.basename)[1]
@property
def tree(self):
""" Traverse directory tree. """
if self.__tree is not None:
return self.__tree
_tree, head, tail = list(), self.to_str(), None
while head != '':
head, tail = op_split(head)
if tail == '':
_tree.append(head)
break
_tree.append(tail)
_tree.reverse()
self.__tree = tuple(_tree)
return self.__tree
def to_str(self):
return self.__str__()
def set_path(self, path, is_relative=False):
if not is_relative and not path.startswith("/"):
raise ValueError('Path: "%s" is not absolute path.' % path)
self.path = self.normpath(path)
self.__tree = None
self.is_relative = is_relative
def move(self, target):
self.set_path(op_join(self.path, target))
return self
def exists(self):
return op_exists(self.to_str())
def join(self, *args):
self.set_path(op_join(self.to_str(), *args), is_relative=self.is_relative)
return self
def get_parent(self):
return self.__class__(self.dirname)
def get_common_path(self, other):
""" Get a common path between two path. """
from itertools import takewhile, izip
if not isinstance(other, self.__class__):
other = Path(other)
return op_join(*[ pair[0] for pair in takewhile(lambda x:x[0]==x[1], izip(self.tree, other.tree)) ])
@classmethod
def from_strings(cls, paths, is_relative=False):
return cls(paths[0], is_relative).join(*paths[1:])
@staticmethod
def normpath(path):
return op_normpath(op_normcase(path))
if __name__ == '__main__':
import unittest
class TestSimple(unittest.TestCase):
def setUp(self):
self.base_path = '/tmp'
self.path = Path(self.base_path)
def tearDown(self):
pass
def test_path(self):
path = Path('/tmp/path.txt')
self.assertEqual(path.name, 'path')
self.assertEqual(path.ext, '.txt')
other = Path.from_strings(['/tmp', 'python', 'is', 'great'])
self.assertEqual(other, '/tmp/python/is/great')
other = Path.from_strings(['/tmp', '/python', 'is', 'great'])
self.assertEqual(other, '/python/is/great')
self.assertEqual(path + other, other)
def test_relative(self):
path = Path('path/', is_relative=True)
self.assertEqual(path, 'path/')
path.join('python')
self.assertEqual(path, 'path/python')
def test_move(self):
self.path.move('path/')
self.assertEqual(self.path, '/tmp/path')
self.path.move('..')
self.assertEqual(self.path, '/tmp')
self.path.move('/tmp').move('path/')
self.assertEqual(self.path, '/tmp/path')
def test_parent(self):
self.path.move('default')
self.assertEqual(self.path.dirname, self.base_path)
self.path.move('..')
self.assertEqual(self.path.dirname, '/')
self.path.move('.')
self.assertEqual(self.path.dirname, '/')
def test_interface(self):
self.assertEqual(self.path, self.path)
self.assertEqual(self.path, Path('/tmp'))
self.assertEqual(self.path + "python/is/great", "/tmp/python/is/great")
self.path += "python/is/great"
self.assertEqual(self.path, "/tmp/python/is/great/./.")
self.assertEqual(self.path, "/tmp/python/is/great/../great")
def test_tree(self):
self.assertEqual(self.path, '/tmp')
self.assertEqual(self.path.tree, ('/', 'tmp'))
self.path.move('..')
self.assertEqual(self.path.tree, ('/',))
def test_common_path(self):
other = Path('/tmp/path/dir/file')
self.assertEqual(self.path.get_common_path(other), '/tmp')
def test_invalid(self):
path = '/python/dummy'
other = Path(path)
other.move('..')
self.assertEqual(other, '/python')
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment