2016-08-09 08:33:36 +00:00
|
|
|
import glob
|
|
|
|
import os
|
|
|
|
class Path:
|
|
|
|
'''
|
|
|
|
I started to use pathlib.Path, but it was too much of a pain.
|
|
|
|
'''
|
|
|
|
def __init__(self, path):
|
|
|
|
path = os.path.normpath(path)
|
|
|
|
path = os.path.abspath(path)
|
|
|
|
self.absolute_path = path
|
|
|
|
|
|
|
|
def __contains__(self, other):
|
2016-11-08 04:48:43 +00:00
|
|
|
this = os.path.normcase(self.absolute_path)
|
|
|
|
that = os.path.normcase(other.absolute_path)
|
|
|
|
return that.startswith(this)
|
2016-08-09 08:33:36 +00:00
|
|
|
|
2016-08-13 00:26:12 +00:00
|
|
|
def __eq__(self, other):
|
2016-11-08 04:48:43 +00:00
|
|
|
if not hasattr(other, 'absolute_path'):
|
|
|
|
return False
|
|
|
|
this = os.path.normcase(self.absolute_path)
|
|
|
|
that = os.path.normcase(other.absolute_path)
|
|
|
|
return this == that
|
2016-08-13 00:26:12 +00:00
|
|
|
|
2016-08-09 08:33:36 +00:00
|
|
|
def __hash__(self):
|
2016-11-08 04:48:43 +00:00
|
|
|
return hash(os.path.normcase(self.absolute_path))
|
2016-08-09 08:33:36 +00:00
|
|
|
|
2016-09-05 23:37:07 +00:00
|
|
|
def __repr__(self):
|
2016-09-24 00:35:58 +00:00
|
|
|
return '{c}({path})'.format(c=self.__class__.__name__, path=repr(self.absolute_path))
|
2016-09-05 23:37:07 +00:00
|
|
|
|
2016-08-09 08:33:36 +00:00
|
|
|
@property
|
|
|
|
def basename(self):
|
|
|
|
return os.path.basename(self.absolute_path)
|
|
|
|
|
2016-08-18 01:24:38 +00:00
|
|
|
def correct_case(self):
|
|
|
|
self.absolute_path = get_path_casing(self.absolute_path)
|
|
|
|
return self.absolute_path
|
|
|
|
|
2016-08-09 08:33:36 +00:00
|
|
|
@property
|
|
|
|
def exists(self):
|
|
|
|
return os.path.exists(self.absolute_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_dir(self):
|
|
|
|
return os.path.isdir(self.absolute_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_file(self):
|
|
|
|
return os.path.isfile(self.absolute_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_link(self):
|
|
|
|
return os.path.islink(self.absolute_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def parent(self):
|
|
|
|
parent = os.path.dirname(self.absolute_path)
|
|
|
|
parent = self.__class__(parent)
|
|
|
|
return parent
|
|
|
|
|
|
|
|
@property
|
|
|
|
def relative_path(self):
|
|
|
|
relative = self.absolute_path
|
|
|
|
relative = relative.replace(os.getcwd(), '')
|
|
|
|
relative = relative.lstrip(os.sep)
|
|
|
|
return relative
|
|
|
|
|
|
|
|
@property
|
|
|
|
def size(self):
|
|
|
|
if self.is_file:
|
|
|
|
return os.path.getsize(self.absolute_path)
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def stat(self):
|
|
|
|
return os.stat(self.absolute_path)
|
|
|
|
|
2016-11-11 23:52:25 +00:00
|
|
|
def with_child(self, basename):
|
|
|
|
basename = os.path.basename(basename)
|
|
|
|
return Path(os.path.join(self.absolute_path, basename))
|
|
|
|
|
|
|
|
|
2016-08-09 08:33:36 +00:00
|
|
|
def get_path_casing(path):
|
|
|
|
'''
|
|
|
|
Take what is perhaps incorrectly cased input and get the path's actual
|
|
|
|
casing according to the filesystem.
|
|
|
|
|
|
|
|
Thank you:
|
|
|
|
Ethan Furman http://stackoverflow.com/a/7133137/5430534
|
|
|
|
xvorsx http://stackoverflow.com/a/14742779/5430534
|
|
|
|
'''
|
|
|
|
if isinstance(path, Path):
|
|
|
|
path = path.absolute_path
|
|
|
|
|
|
|
|
(drive, subpath) = os.path.splitdrive(path)
|
2016-09-05 23:37:07 +00:00
|
|
|
drive = drive.upper()
|
2016-08-09 08:33:36 +00:00
|
|
|
subpath = subpath.lstrip(os.sep)
|
|
|
|
|
2016-08-13 00:26:12 +00:00
|
|
|
pattern = [glob_patternize(piece) for piece in subpath.split(os.sep)]
|
2016-08-09 08:33:36 +00:00
|
|
|
pattern = os.sep.join(pattern)
|
2016-09-05 23:37:07 +00:00
|
|
|
pattern = drive + os.sep + pattern
|
2016-08-09 08:33:36 +00:00
|
|
|
#print(pattern)
|
|
|
|
try:
|
|
|
|
return glob.glob(pattern)[0]
|
|
|
|
except IndexError:
|
2016-08-13 00:26:12 +00:00
|
|
|
return path
|
|
|
|
|
|
|
|
def glob_patternize(piece):
|
|
|
|
'''
|
|
|
|
Create a pattern like "[u]ser" from "user", forcing glob to look up the
|
|
|
|
correct path name, while guaranteeing that the only result will be the correct path.
|
|
|
|
|
|
|
|
Special cases are:
|
|
|
|
!, because in glob syntax, [!x] tells glob to look for paths that don't contain
|
|
|
|
"x". [!] is invalid syntax, so we pick the first non-! character to put
|
|
|
|
in the brackets.
|
|
|
|
[, because this starts a capture group
|
|
|
|
'''
|
|
|
|
piece = glob.escape(piece)
|
|
|
|
for character in piece:
|
|
|
|
if character not in '![]':
|
|
|
|
replacement = '[%s]' % character
|
|
|
|
#print(piece, character, replacement)
|
|
|
|
piece = piece.replace(character, replacement, 1)
|
|
|
|
break
|
|
|
|
return piece
|