Created
February 11, 2020 08:42
-
-
Save aodag/3c8facc9ffcf51f1c56bd144cd112682 to your computer and use it in GitHub Desktop.
extension to convert dataclasses with cattrs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dataclasses | |
from .converters import Converter | |
def _is_dataclasses_class(obj): | |
return dataclasses.is_dataclass(obj) | |
class DataclassesConverter(Converter): | |
def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
self.register_unstructure_hook_func( | |
_is_dataclasses_class, self._unstructure_dataclasses) | |
self.register_structure_hook_func( | |
_is_dataclasses_class, self._structure_dataclasses) | |
def _unstructure_dataclasses(self, obj): | |
"""Our version of `attrs.asdict`, so we can call back to us.""" | |
fields = dataclasses.fields(obj) | |
dispatch = self._unstructure_func.dispatch | |
rv = self._dict_factory() | |
for f in fields: | |
name = f.name | |
v = getattr(obj, name) | |
rv[name] = dispatch(v.__class__)(v) | |
return rv | |
def _structure_dataclasses(self, obj, cl): | |
"""Instantiate an attrs class from a mapping (dict).""" | |
# For public use. | |
conv_obj = {} # Start with a fresh dict, to ignore extra keys. | |
dispatch = self._structure_func.dispatch | |
for f in dataclasses.fields(cl): # type: ignore | |
# We detect the type by metadata. | |
type_ = f.type | |
name = f.name | |
try: | |
val = obj[name] | |
except KeyError: | |
continue | |
if name[0] == "_": | |
name = name[1:] | |
conv_obj[name] = ( | |
dispatch(type_)(val, type_) if type_ is not None else val | |
) | |
return cl(**conv_obj) # type: ignore |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment