strictyaml icon indicating copy to clipboard operation
strictyaml copied to clipboard

New Mapping Type

Open crdoconnor opened this issue 6 years ago • 2 comments

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.

crdoconnor avatar Oct 07 '18 11:10 crdoconnor

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?

bt2901 avatar Sep 29 '19 19:09 bt2901

No, that looks pretty much exactly how I'd do it.

crdoconnor avatar Sep 29 '19 19:09 crdoconnor