class FileResource: """resource handles kept unique per path""" pathMap: dict[Path, FileResource] = {} def __init__(self, path: (str, Path)): self.path = Path(path) self.pathMap[self.path] = self def exists(self) -> bool: return self.path.is_file() def load(self) -> str: with open(self.path, "r") as f: return f.read() def save(self, data: str): with open(self.path, "w") as f: f.write(data) @classmethod def get(cls, path: (str, Path)) -> FileResource: return cls.pathMap.get(Path(path)) or cls(path)
def parseAddressTokens(cls, tokenArgs): baseTokens = Tree.parseAddressTokens(tokenArgs) return Path(baseTokens).parts
def path(self) -> Path: basePath = self.pathRoot return basePath / Path(*self.address(includeSelf=True))
def __init__(self, nameOrPath: (str, PurePath)): name = Path(nameOrPath).parts[-1] super(FileTree, self).__init__(name)
class FileTree(Tree): """tree manipulations on files and directories values of tree correspond to full file paths""" uidInstanceMap = {} pathRoot: Path = Tree.TreePropertyDescriptor( "pathRoot", default=Path(), inherited=True, desc="Base folder path to add above root of tree", cacheInherited=True) branchesInheritType = True @classmethod def pathInstanceMap(cls): """soft singleton behaviour""" return {i.path(): i for i in cls.uidInstanceMap.values()} def __init__(self, nameOrPath: (str, PurePath)): name = Path(nameOrPath).parts[-1] super(FileTree, self).__init__(name) @classmethod def defaultBranchCls(cls): return FileTree @property def root(self) -> TreeType: return def path(self) -> Path: basePath = self.pathRoot return basePath / Path(*self.address(includeSelf=True)) def __fspath__(self): return str(self.path()) """calling tree looks up child files lazily""" @classmethod def parseAddressTokens(cls, tokenArgs): baseTokens = Tree.parseAddressTokens(tokenArgs) return Path(baseTokens).parts def branchMap(self) -> dict[str, TreeType]: """return map of currently existing files and trees""" if self.path().is_file(): return {} return os.listdir(self.path()) def setName(self, name, allowMerging=False, emitDelta=None): """rename this folder to the given name""" path = self.path() super(FileTree, self).setName(name) oldName = self.name if name == oldName: return name path.rename(self.path().parent / name) def _createChildBranch(self, name, kwargs): if self.path().suffix: raise RuntimeError("cannot add child to leaf file {}".format( self.path())) newPath = self.path() / name if newPath.suffix: if not newPath.exists(): newPath.write_text("") else: newPath.mkdir(parents=True, exist_ok=True) return super(FileTree, self)._createChildBranch(name, kwargs) def _setParent( self, parent=None, ): path = self.path() super(FileTree, self)._setParent(parent) shutil.move(path, self.path())
# def __init__(self): # super(SerialisableJsonEncoder, self).__init__(default=self.default) def default(self, o: Any) -> Any: if isinstance(o, Serialisable): return SerialiseVisitor.serialise(o) return super().default(o) class SerialisableJsonDecoder(json.JSONDecoder): def __init__(self, localTypes=(), *args, **kwargs): super().__init__(*args, object_hook=self.objectHook, **kwargs) self.localTypes = localTypes self.localTypeMap = {i.__name__: i for i in localTypes} def objectHook(self, obj: dict): return SerialiseVisitor.deserialise(obj) if __name__ == '__main__': print(getattr(Path(__file__), "__fspath__")) baseObj = {"a": ["list"], "b": ("tuple", ), "c": Path(__file__)} sata = SerialiseVisitor.serialise(baseObj) pprint.pprint(sata) print(json.dumps(sata)) regen = SerialiseVisitor.deserialise(sata) pprint.pprint(regen)
def get(cls, path: (str, Path)) -> FileResource: return cls.pathMap.get(Path(path)) or cls(path)
def __init__(self, path: (str, Path)): self.path = Path(path) self.pathMap[self.path] = self
def atomValue(self): return Path(self.line.text())