Skip to content

Instantly share code, notes, and snippets.

@dillonhicks
Created March 21, 2017 17:07
Show Gist options
  • Select an option

  • Save dillonhicks/7fdba3453969590028f3ca9f569bab03 to your computer and use it in GitHub Desktop.

Select an option

Save dillonhicks/7fdba3453969590028f3ca9f569bab03 to your computer and use it in GitHub Desktop.
Package safe serialization
import abc
from modulefinder import Module
import ruamel.yaml as _yaml
import six
from ruamel.yaml.nodes import Node, ScalarNode
from typing import Generic, TypeVar
from typing import Type
T = TypeVar('T')
N = TypeVar('N', covariant=Node)
class _BlinkLoader(_yaml.Loader):
pass
class _BlinkDumper(_yaml.Dumper):
pass
class YAMLType(Generic[T]):
@abc.abstractmethod
def name(self):
# type: () -> str
pass
@abc.abstractmethod
def python_type(self):
# type: () -> type
pass
@abc.abstractmethod
def representer(self, tag, data):
# type: (six.string_types, T) -> N
pass
@abc.abstractmethod
def constructor(self, tag_suffix, node):
# type: (six.string_types, N) -> six.string_types
pass
def tag(self):
return '!custom/type/{}'.format(self.name())
# noinspection PyUnresolvedReferences
def register(self, yaml_module=_yaml):
# type: (Module) -> None
yaml_module.add_constructor(self.tag(), self.constructor, Loader=_BlinkLoader)
yaml_module.add_representer(self.python_type(), self.representer, Dumper=_BlinkDumper)
#
# Test
#
from decimal import Decimal
class DecimalYAMLType(YAMLType[Decimal]):
def name(self):
# type: () -> str
return Decimal.__name__
def python_type(self):
# type: () -> Type[Decimal]
return Decimal
def representer(self, tag, data):
# type: (Decimal) -> ScalarNode
return ScalarNode(self.tag(), str(data))
def constructor(self, tag_suffix, node):
# type: (six.string_types, ScalarNode) -> Decimal
return Decimal(node.value)
def load(string):
return _yaml.load(string, Loader=_BlinkLoader)
def dump(obj):
return _yaml.dump(obj, default_flow_style=False, Dumper=_BlinkDumper)
# In some common place you'd register your extensions
DecimalYAMLType().register()
from datetime import datetime
data = dict(ts=datetime.now(), cost=Decimal('123.45'))
string = dump(data)
print(string)
data2 = load(string)
print(data2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment