import copy
from collections import OrderedDict
[docs]class Schema:
'''
A schema is a thing.
'''
def __init__(self, *args, **kwargs):
self.fields = OrderedDict()
for field in args:
self.fields[field.name] = field
for name, field in kwargs.items():
field.name = name
self.fields[name] = field
def __getitem__(self, key):
if isinstance(key, list):
return Schema(**{self[k].name: self[k] for k in key})
return self.fields[key]
def keys(self):
return list(self.fields.keys())
def values(self):
return list(self.fields.values())
def items(self):
return self.fields.items()
def coercions(self):
return {f.name: f.coerce for f in self.fields.values()}
def __str__(self):
return "\n".join(
['{} -> {}'.format(name, meta.__str__()) for name, meta in self.fields.items()]
)
def __repr__(self):
return '<{}({}):\n{}\n>'.format(self.__class__.__name__, id(self), self.__str__())
def __eq__(self, other):
return self.fields == other.fields
def __contains__(self, key):
return key in self.fields
def __len__(self):
return len(self.fields)
def merge(self, other):
merged_fields = {**self.fields, **other.fields}
for name, field in merged_fields.items():
if name in self.fields:
self_meta = copy.deepcopy(self.fields[name].metadata)
else:
self_meta = {}
if name in other.fields:
other_meta = copy.deepcopy(other.fields[name].metadata)
else:
other_meta = {}
merged_field_metadata = {**self_meta, **other_meta}
merged_fields[name] = type(field)(**merged_field_metadata)
return Schema(**merged_fields)
def copy(self):
return copy.deepcopy(self)
def rename(self, mapper):
new_fields = []
for field in self.fields.values():
new_field = copy.deepcopy(field)
new_field.name = mapper.get(field.name, field.name)
new_fields.append(new_field)
return Schema(*new_fields)
[docs] def select(self, func):
'Returns a new schema with the fields selected via a function (func) of the field'
return Schema(**{name:copy.deepcopy(field) for name, field in self.items() if func(field)})