Metadata#

Validators in Koda Validate naturally forms into graph structures, usually trees (a notable exception would be the use of Lazy, which can create cycles). It is an aim of this library to facilitate the re-purposing of such validation structures for other purposes, such as schemas, HTML, documentation, customized error types, and so on.

Because it’s easy to branch on the type of a Validator, it’s straightforward to write functions that transform arbitrary Validators into other structures. Some examples of this exist within Koda Validate:

  • to_json_schema converts Validators into JSON Schema objects

  • to_serializable_errs converts Invalid objects in human-readable serializable structures (discussed in Errors)

  • koda_validate.signature._get_arg_fail_message converts Invalid objects to human-readable traceback messages.

Pattern Matching#

The recommended approach to branching on validation graphs is to use pattern matching against the type of Validator. For example, if you wanted to generate a markdown description from a Validator, you could start with something like this:

from typing import Union, Any
from koda_validate import (Validator, Predicate, PredicateAsync,
                           ListValidator, StringValidator)

def to_markdown_description(obj: Union[Validator[Any],
                                       Predicate[Any],
                                       PredicateAsync[Any]]) -> str:
    match obj:
        case StringValidator():
            return "string validator"
        case ListValidator(item_validator):
            return f"list validator\n- {to_markdown_description(item_validator)}"
        case _:
            ...

print(to_markdown_description(ListValidator(StringValidator())))

Outputs:

list validator
- string validator

Here we generated a very simple output with code that supports a tiny subset of Validators, but it’s easy to expand the same approach to produce arbitrary outputs for a wide range of validators.