Settings Bases#
Read the API Reference on these base classes to learn about their design and purpose.
I’ll make a “the works” example of an object inheriting from SlotSettings
and making use of as many of the features I can manage.
from grave_settings.base import SlotSettings
from grave_settings.conversion_manager import ConversionManager
from grave_settings.formatter_settings import FormatterContext
from grave_settings.semantics import AutoPreserveReferences
class Graph(SlotSettings):
VERSION = '1'
P_TITLE = 'title'
P_LEGEND = 'legend'
__slots__ = P_TITLE, P_LEGEND, 'data'
_slot_rems = 'data',
def __init__(self, data):
super().__init__()
self.title = None
self.legend = None
self.data = data
@classmethod
def check_in_serialization_context(cls, context: FormatterContext):
context.add_semantics(AutoPreserveReferences(False))
class Graph3D(Graph):
VERSION = '2'
P_THETA = 'theta'
P_Z = 'z'
__slots__ = P_THETA, P_Z, 'renderer'
_slot_rems = 'renderer',
def __init__(self, data):
super().__init__(data)
self.theta = 0
self.z = 0
@classmethod
def get_conversion_manager(cls) -> ConversionManager:
cm = super().get_conversion_manager()
cm.add_converter('1', Graph3D, convert_1_to_2, '2')
return cm
def convert_1_to_2(state_obj: dict):
theta = state_obj.pop('thetha')
state_obj[Graph3D.P_THETA] = theta
return state_obj
from grave_settings.formatters.json import JsonFormatter
formatter = JsonFormatter()
print(formatter.dumps(Graph3D([])))
old_str = '''
{
"__class__": "__main__.Graph3D",
"__version__": {
"__main__.Graph": "1",
"__main__.Graph3D": "1"
},
"title": null,
"legend": null,
"thetha": 5,
"z": 0
}
'''
graph = formatter.loads(old_str)
print('The deserialized value is: ', graph.theta)
{
"__class__": "__main__.Graph3D",
"__version__": {
"__main__.Graph": "1",
"__main__.Graph3D": "2"
},
"title": null,
"legend": null,
"theta": 0,
"z": 0
}
The deserialized value is: 5
Note
The json string that is output is NOT the same as the string that is deserialized in the code. I changed it on purpose.
I’m not exactly sure what these data structures are supposed to represent. I’ll call this poetry, but anyway, we see two classes; one inherits from the other. We see that they are defining their own __slots__
and _slot_rems
and this effects which attributes are serialized. We see that they are defining their version with the VERSION
attribute and the version object in the output string records the version of the child class and the super class. We see that the super class is adding a semantic to the FrameContext for absolutely no reason. We see that the child class is installing a converter to it’s ConversionManager that fixes a spelling error in version 1. We see that supplying a string that has the spelling error in it and the string "1"
as its version information for that classes triggers the automatic conversion when the string is deserialized.
The convention of making the __slots__
attribute names class level variables is by no means required, that is just a convention of mine as I like to have statically defined paths for static data.