1import os 2 3 4class Path: 5 # cache for better performance 6 __cached_existing_dir = None 7 _path = None # type: str 8 9 def __init__(self, path): 10 self._path = os.path.expandvars(os.path.expanduser(path.lstrip())) 11 12 def get_abs_path(self) -> str: 13 return self._path 14 15 def exists(self) -> bool: 16 return os.path.exists(self._path) 17 18 def get_basename(self) -> str: 19 return os.path.basename(self._path.rstrip('/')) 20 21 def get_dirname(self) -> str: 22 return os.path.dirname(self.get_user_path()) 23 24 def is_dir(self) -> bool: 25 return os.path.isdir(self._path) 26 27 def is_exe(self) -> bool: 28 return os.access(self._path, os.X_OK) 29 30 def get_ext(self) -> str: 31 return os.path.splitext(self._path)[1].lower()[1:] 32 33 def get_user_path(self) -> str: 34 result = self._path.rstrip('/') 35 36 user_dir = os.path.expanduser('~') 37 if result.startswith(user_dir): 38 return result.replace(user_dir, '~', 1) 39 40 return result 41 42 def get_existing_dir(self) -> str: 43 """ 44 Example (assuming foo & bar do not exist): 45 46 >>> p = Path('/home/aleksandr/projects/foo/bar') 47 >>> p.get_existing_dir() == '/home/aleksandr/projects' 48 49 :returns: path to the last dir that exists in the user's query 50 """ 51 if self.__cached_existing_dir: 52 return self.__cached_existing_dir 53 54 result = self._path 55 while result and (not os.path.exists(result) or not os.path.isdir(result)): 56 result = os.path.dirname(result) 57 58 # special case when dir ends with "/." 59 # we want to return path without . 60 # example: /bin/env/. -> /bin/env 61 if result.endswith('/.'): 62 result = result[:-2] 63 64 if not result: 65 raise InvalidPathError('Invalid path "%s"' % self._path) 66 67 self.__cached_existing_dir = result 68 return result 69 70 def get_search_part(self) -> str: 71 """ 72 :returns: remaining part of the query that goes after :meth:`get_existing_dir` 73 """ 74 return self._path[len(self.get_existing_dir()):].strip('/') 75 76 77class InvalidPathError(RuntimeError): 78 pass 79