class AbsPath: _components = None def __init__(self, path = None, components = None): if path is not None and components is not None: raise ValueError('Both path and components provided') if path is not None: if isinstance(path, str): path = path.encode('utf-8') if len(path) < 1 or not path.startswith(b'/'): raise ValueError('Path does not look like valid absolute path', path) components = list(filter(lambda x: len(x) > 0 and x != b'.', path[1:].split(b'/'))) if b'..' in components: raise ValueError('Parent references are not allowed', path) self._components = components def __bytes__(self): return self.path def __repr__(self): return self.path.decode('utf-8', errors = 'backslashreplace') def __contains__(self, item): c = self.components ci = item.components if len(ci) >= len(c) and ci[:len(c)] == c: return True return False def __eq__(self, other): return self.components == other.components def __len__(self): return len(self.components) @property def path(self): return b'/' + b'/'.join(self.components) @property def components(self): """ Return a list of path components. Note that root does not count as a component, so a path of b'/' returns an empty list. """ return self._components def reparent(self, src, dst): if not self in src: raise ValueError('Path not in parent', self, src) tail = self.components[len(src):] return AbsPath(components = dst.components + tail) ROOT = AbsPath('/')