strictyaml
strictyaml copied to clipboard
New Mapping Type
Create a new kind of mapping validator where it looks for one key and then once it sees that key it expects several others (some may be optional).
Primary use case is here : https://github.com/hitchdev/seleniumdirector/blob/master/seleniumdirector/webdirector.py where the following groups of keys in the mapping are acceptable:
- id, in iframe, which, but parent, subelements (in iframe, which, but parent, subelements) all optional
- class, in iframe, which, but parent, subelements (ditto, all optional)
- attribute, in iframe, which, but parent, subelements (ditto, all optional)
- text is, in iframe, which, but parent, subelements (ditto, all optional)
- text contains, in iframe, which, but parent, subelements (ditto, all optional)
However id, class, attribute, text is and text contains should never be seen together, however - using the current validator, every key is optional.
I'm interested in something similar: some sort of Map() | Map()
. The use case:
We have a sequence of building blocks (taken together, they specify a training process for a particular topic model). There is a small list of building blocks available (at the moment, only two: CubeCreator
and RegularizerModifierCube
), but each takes a lot of input parameters. Different blocks require different parameters, however.
For now, I'm handling the situation like this:
base_schema = Map({
'stages': Seq(Any()),
...
})
SUPPORTED_CUBES = [CubeCreator, RegularizersModifierCube]
def build_schema_for_cubes():
"""
Returns
-------
dict
each element is str -> strictyaml.Map
where key is name of cube,
value is a schema used for validation and type-coercion
"""
schemas = {}
for class_of_object in SUPPORTED_CUBES:
res = build_schema_from_signature(class_of_object)
res = Map(res)
specific_schema = Map({class_of_object.__name__: res})
schemas[class_of_object.__name__] = specific_schema
return schemas
parsed = load(yaml_string, base_schema)
schemas = build_schema_for_cubes()
for i, stage in enumerate(parsed['stages']):
assert len(stage) == 1
name = list(stage.data)[0]
if name not in schemas:
raise ValueError(f"Unsupported stage ID: {name} at line {stage.start_line}")
local_schema = schemas[name]
stage.revalidate(local_schema)
Is there a better way?
No, that looks pretty much exactly how I'd do it.