Created
November 3, 2016 15:28
-
-
Save jomido/c6faf65152e9ad78950305a94e92924a to your computer and use it in GitHub Desktop.
Auto create classes from arbitrarily nested dicts, preserving list context
This file contains hidden or 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
| from collections import defaultdict | |
| class AutoClass(object): | |
| pass | |
| def inflate(data, class_from_fields): | |
| """ | |
| Given arbitarily nested :data limited to dict and list container types, | |
| and a mapping of fields -> class name, automatically generate classes from | |
| dicts, preserving any list context from :data. | |
| Return this as :objects, along with :instances. :instances is a dictionary | |
| mapping class names to instances. | |
| """ | |
| def __init__(self, kwargs): | |
| self.kwargs = kwargs | |
| self.fields = make_key(kwargs) | |
| self.__dict__.update(kwargs) | |
| def __getitem__(self, name): | |
| return self.__dict__[name] | |
| def __setitem__(self, name, value): | |
| self.__dict__[name] = value | |
| class_definition = { | |
| '__init__': __init__, | |
| '__getitem__': __getitem__, | |
| '__setitem__': __setitem__, | |
| } | |
| make_key = lambda d: tuple(sorted([str(k) for k in d.keys()])) | |
| make_class = lambda key: type( | |
| class_from_fields[key], | |
| (AutoClass,), | |
| class_definition | |
| ) | |
| registries = {'classes': {}, 'instances': defaultdict(list)} | |
| def inflate(data): | |
| if isinstance(data, list): | |
| return [inflate(elem) for elem in data] | |
| elif isinstance(data, dict): | |
| key = make_key(data) | |
| try: | |
| name = class_from_fields[key] | |
| except KeyError: | |
| msg = "Please add a class name entry for the following: {}" | |
| raise Exception(msg.format( | |
| key | |
| )) | |
| cls = registries['classes'].get(name) or make_class(key) | |
| registries['classes'][name] = cls | |
| kwargs = {k: inflate(v) for k, v in data.items()} | |
| instance = cls(kwargs) | |
| registries['instances'][name].append(instance) | |
| return instance | |
| else: | |
| return data | |
| return inflate(data), registries['instances'] | |
| indent = 2 | |
| def print_walk(objects, indent=4): | |
| def print_walk(objects, depth=0, name=''): | |
| tab = depth * ' ' * indent | |
| if isinstance(objects, list): | |
| if objects: | |
| print('{}['.format(tab)) | |
| [print_walk(o, depth + 1) for o in objects] | |
| print('{}]'.format(tab)) | |
| else: | |
| print('{}[]'.format(tab)) | |
| elif isinstance(objects, AutoClass): | |
| if objects.fields: | |
| print('{}{} {{'.format(tab, objects.__class__.__name__)) | |
| [print_walk(getattr(objects, f), depth + 1, name=f) | |
| for f in objects.fields] | |
| print('{}}}'.format(tab)) | |
| else: | |
| print('{}{{}}'.format(tab)) | |
| else: | |
| if name: | |
| print('{}{}: {}'.format(tab, name, str(objects))) | |
| else: | |
| print('{}{}'.format(tab, str(objects))) | |
| print_walk(objects) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment