From f1341cab2f8787be55970161836b93aefb035b09 Mon Sep 17 00:00:00 2001 From: Istvan Bozso Date: Wed, 12 Feb 2020 19:07:14 +0100 Subject: [PATCH] added json serialization --- utils/path.py | 6 +++- utils/simpledoc.py | 40 +++++++++++++++++---- utils/utils.py | 90 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/utils/path.py b/utils/path.py index d15a360..14b79d2 100644 --- a/utils/path.py +++ b/utils/path.py @@ -34,7 +34,11 @@ def call(cls, cmd, *args, **kwargs): class Path(object): - __slots__ = ("path",) + json_serialize = ( + "path", + ) + + __slots__ = json_serialize def __init__(self, path): self.path = path diff --git a/utils/simpledoc.py b/utils/simpledoc.py index 53ef06b..f5b1f69 100644 --- a/utils/simpledoc.py +++ b/utils/simpledoc.py @@ -4,6 +4,7 @@ import re import os.path as path +import base64 class DocError(Exception): pass @@ -646,7 +647,7 @@ def inner(self, *args, **kwargs): return inner stags = { - "meta", "link", "img", "source", "iframe", + "meta", "link", "source", "iframe", } for stag in stags: @@ -677,7 +678,8 @@ class ImagePaths(object): __slots__ = ("paths", "doc", "width",) def __init__(self, doc, width, *paths): - self.doc, self.width, self.paths = doc, width, frozenset(paths) + self.doc, self.width, self.paths, self.bundle = \ + doc, width, frozenset(paths), doc.bundle def search(self, name): m = map(lambda p: path.join(p, name), self.paths) @@ -731,11 +733,16 @@ def img(self, name, *args, **kwargs): class HTML(SimpleDoc): - @classmethod - def new(cls, *args, **kwargs): - kwargs.setdefault("stag_end", ">") - return cls(*args, **kwargs) + __slots__ = ( + "bundle", + ) + def __init__(self, *args, **kwargs): + kwargs.setdefault("stag_end", ">") + self.bundle = bool(kwargs.get("bundle", False)) + + SimpleDoc.__init__(self, *args, **kwargs) + @staticmethod def presentation(*args, **kwargs): @@ -744,6 +751,27 @@ def presentation(*args, **kwargs): def use(self, lib): lib.add(self) + + def img(self, *args, **kwargs): + path = kwargs.pop("src") + + if self.bundle: + ext = path.splitext(path)[1] + + with open(path, "rb") as f: + enc = base64.b64encode(f.read()) + + src = "data:image/%s;base64,%s" % ( + ext, enc + ) + + else: + src = path + + kwargs["src"] = path + + self.stag("img", *args, **kwargs) + def image_paths(self, width, *paths): return ImagePaths(self, width, *paths) diff --git a/utils/utils.py b/utils/utils.py index 53b9c70..fb8b7e4 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,10 +1,11 @@ import sys import functools as ft +import json __all__ = ( "Seq", "flat", "new_type", "str_t", "isiter", "all_same", "make_object", "cat", "compose", "fs", "load", "Enum", "namespace", - "export", + "export", "JSONSave" ) py3 = sys.version_info[0] == 3 @@ -279,3 +280,90 @@ def enum(self, **kwargs): def load(name, path): return SourceFileLoader(name, path).load_module() + + +class JSONSave(object): + + class Encoder(json.JSONEncoder): + def default(self, obj): + try: + return { + key: getattr(obj, key) + for key in obj.json_serialize + } + except AttributeError: + return json.JSONEncoder.default(self, obj) + + + json_options = { + "indent": 4, + "cls": Encoder, + } + + def save_to(self, path, **kwargs): + with open(path, "w") as f: + self.save(f) + + @staticmethod + def save_any(obj, writable, **kwargs): + try: + kwargs.update(obj.json_options) + except AttributeError: + kwargs.update(JSONSave.json_options) + + json.dump(obj, writable, **kwargs) + + + def save(self, writable, **kwargs): + self.save_any(self, writable, **kwargs) + + @classmethod + def from_dict(cls, d, *args, **kwargs): + ret = cls(*args, **kwargs) + + for key in cls.json_serialize: + try: + val = d[key] + except KeyError: + val = None + + setattr(ret, key, val) + + return ret + + @classmethod + def load_from(cls, path, *args, **kwargs): + ret = cls(*args, **kwargs) + + with open(path, "r") as f: + ret.load(f, **kwargs) + + return ret + + def load(self, readable, **kwargs): + kwargs.update(self.json_options) + + self = json.load(self, readable, **kwargs) + + @classmethod + def tree_from(cls, path, *args, **kwargs): + with open(path, "r") as f: + return cls.load_tree(f, *args, **kwargs) + + @classmethod + def load_tree(cls, readable, *args, **kwargs): + d = json.load(readable, **kwargs, **self.json_options) + + dd = {} + for key, val in d.items(): + if isinstance(val, dict): + dd[key] = cls.from_dict(val, *args, **kwargs) + else: + dd[key] = tuple( + cls.from_dict(elem, *args, **kwargs) + for elem in val + ) + + return namespace(**dd) + +