Skip to content

Instantly share code, notes, and snippets.

@rmorshea
Created October 9, 2018 00:00
Show Gist options
  • Save rmorshea/1e8d00dbd9f583f763837c47d3910c25 to your computer and use it in GitHub Desktop.
Save rmorshea/1e8d00dbd9f583f763837c47d3910c25 to your computer and use it in GitHub Desktop.
Compose two or more schemas into one - see https://github.com/keleshev/schema/pull/169 for details.
from schema import Schema, _priority, DICT, Optional
def compose(*schemas, **kwargs):
"""Compose two or more schemas into one.
See https://github.com/keleshev/schema/pull/169 for details.
"""
reduce = kwargs.pop("reduce", lambda schemas: schemas[0])
if not callable(reduce):
if callable(getattr(reduce, "validate", None)):
reduce = reduce.validate
else:
msg = "Expected a callabled or validator, not %r"
raise TypeError(msg % reduce)
schemas = [s._schema if isinstance(s, Schema) else s for s in schemas]
priorities = set(map(_priority, schemas))
if priorities == {DICT}:
optionals = set()
to_compose = {}
for s in schemas:
for k, v in ((k, s[k]) for k in s):
if isinstance(k, Optional):
if k.key in to_compose:
continue
else:
optionals.add(k.key)
elif k not in optionals:
comp = to_compose.setdefault(k, [])
comp.append(v)
new = {}
for k, v in to_compose.items():
if len(v) > 1:
new[k] = compose(*v, reduce=reduce)
else:
new[k] = v[0]
return Schema(new, **kwargs)
else:
return Schema(reduce(schemas), **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment