Skip to content

Instantly share code, notes, and snippets.

@rnag
Last active April 6, 2024 11:37
Show Gist options
  • Save rnag/ddd678b42af0ed97193c8b763d216d58 to your computer and use it in GitHub Desktop.
Save rnag/ddd678b42af0ed97193c8b763d216d58 to your computer and use it in GitHub Desktop.
field/key remapping
from dataclasses import dataclass
from .remappers import Alias, remapper # see module `remappers.py` below
@dataclass
class DiveSpot(metaclass=remapper):
id: str = Alias('_id')
name: str = Alias('divespot')
# stub to satisfy external linters and type checkers
def __init__(self, **kwargs): ...
ds = DiveSpot()
print(ds) # DiveSpot(id=None, name=None)
data = {'_id': '5719fdf6edf5136d37aaf562', 'divespot': 'The Tugs', 'divesite': 'Fathom Five National Park', 'region': 'Ontario', 'country': 'Canada'}
ds = DiveSpot(**data)
print(ds) # DiveSpot(id='5719fdf6edf5136d37aaf562', name='The Tugs')
ds = DiveSpot(id='test', name='my name')
print(ds) # DiveSpot(id='test', name='my name')
from dataclasses import _create_fn
def remapper(name, bases, cls_dict):
def __init__(self, **kwargs):
cls = self.__class__
# create a sentinel "missing" type, as `dataclasses` also does
class _MISSING_TYPE:
...
lines = ['_get = kwargs.get']
lines.extend(f'r = _get("{other_key}", _MISSING); '
f'self.{attr} = _get("{attr}") if r is _MISSING else r'
for other_key, attr in cls.__remapping__.items())
init_fn = cls.__init__ = _create_fn('__init__', ('self', '**kwargs'), lines,
locals={'_MISSING': _MISSING_TYPE()})
return init_fn(self, **kwargs)
cls_dict.update(
__init__=__init__,
__remapping__={},
)
cls = type(name, bases, cls_dict)
return cls
class Alias:
__slots__ = ('_other_name', )
def __init__(self, other_name: str):
self._other_name = other_name
def __set_name__(self, owner, name):
owner.__remapping__[self._other_name] = name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment