Advertisement
SyberiaK

JsonSerializable

May 2nd, 2023 (edited)
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.28 KB | Source Code | 0 0
  1. import dataclasses
  2. import inspect
  3. from pathlib import Path
  4. import json
  5.  
  6.  
  7. class JsonSerializable:
  8.     @classmethod
  9.     def from_json(cls, path: Path | str, post_init_setattr: bool = False):
  10.         """
  11.        Loads a JSON file and creates an object with loaded data.
  12.  
  13.        Works fine with typing.NamedTuple / typing.TypedDict / dataclasses.dataclass.
  14.  
  15.        The object's `__init__` method must accept ALL the object attributes as keyword-possible arguments.
  16.         """
  17.  
  18.         if cls == JsonSerializable:
  19.             raise TypeError('Cannot load to JsonSerializable itself.'
  20.                             ' Maybe you want to inherit your class from JsonSerializable to load from JSON?')
  21.  
  22.         with open(path) as f:
  23.             attrs = json.load(f)
  24.             if not post_init_setattr:
  25.                 return cls(**attrs)
  26.  
  27.             sig = inspect.signature(cls.__init__)
  28.             init_attrs = {k: v for k, v in attrs.items() if sig.parameters.get(k)}
  29.             other_attrs = dict(set(attrs.items()) - set(init_attrs.items()))
  30.  
  31.             obj = cls(**init_attrs)
  32.             for name, value in other_attrs.items():
  33.                 setattr(obj, name, value)
  34.             return obj
  35.  
  36.     def to_json(self, path: Path | str):
  37.         """
  38.        Saves the object attributes to JSON file.
  39.  
  40.        Be aware that ALL the attributes will be saved.
  41.  
  42.        Works fine with typing.NamedTuple / typing.TypedDict / dataclasses.dataclass.
  43.        """
  44.         if self.__class__ == JsonSerializable:
  45.             raise TypeError('Cannot save from JsonSerializable itself.'
  46.                             ' Maybe you want to inherit your class from JsonSerializable to save to JSON?')
  47.  
  48.         with open(path, 'w+') as f:
  49.             json.dump(vars(self), f)
  50.  
  51.  
  52. def main():
  53.     # example class
  54.     @dataclasses.dataclass
  55.     class Data(JsonSerializable):
  56.         field1: int
  57.         field2: float
  58.         field3: str
  59.  
  60.     # loading
  61.     data = Data.from_json('initial.json')
  62.     # doing some data manipulations
  63.     assert data.field3 == 'pending', f'Expected "pending" status, got {data.field3}'
  64.     data.field1 = int(data.field2 % 3)
  65.     data.field2 = .0
  66.     data.field3 = 'success'
  67.     # saving
  68.     data.to_json('result.json')
  69.  
  70.  
  71. if __name__ == '__main__':
  72.     main()
  73.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement