Skip to content

dp3.bin.check

Load and check configuration from given directory, print any errors, and exit.

TODO
  • refactor to simplify the code, some error path matching must be done to counteract the AttrSpec function magic where Pydantic fails, but otherwise it is not required

ConfigEncoder

Bases: JSONEncoder

JSONEncoder to encode parsed configuration.

locate_attribs_error

locate_attribs_error(data: dict, sought_err: str) -> tuple[list[tuple], list[dict]]

Locate source of an error in a dict of AttrSpecs. Returns all sources of the same kind of error.

Source code in dp3/bin/check.py
def locate_attribs_error(data: dict, sought_err: str) -> tuple[list[tuple], list[dict]]:
    """
    Locate source of an error in a dict of AttrSpecs.
    Returns all sources of the same kind of error.
    """
    paths = []
    sources = []

    for attr, attr_spec in data.items():
        try:
            AttrSpec(attr, attr_spec)
        except ValidationError as exception:
            for err_dict in exception.errors():
                if err_dict["msg"] == sought_err:
                    paths.append((attr, *err_dict["loc"]))
                    sources.append(attr_spec)
        except (ValueError, AssertionError) as exception:
            if sought_err.endswith(exception.args[0]):
                paths.append((attr,))
                sources.append(attr_spec)

    return paths, sources

get_error_sources

get_error_sources(data: dict, error: dict) -> tuple[list, list]

Locate source of an error in validated data using Pydantic error path.

Source code in dp3/bin/check.py
def get_error_sources(data: dict, error: dict) -> tuple[list, list]:
    """Locate source of an error in validated data using Pydantic error path."""
    err_path = error["loc"]

    # Kickstart the model exploration
    curr_model_dict = get_type_hints(ModelSpec)["config"]
    curr_model_origin = get_origin(curr_model_dict)
    curr_model = get_args(curr_model_dict)[1]

    for key in err_path[1:]:
        if curr_model_origin != dict and curr_model_origin is not None:
            return [err_path], [data]

        if key in data:
            prev_data = data
            data = data[key]

            if (curr_model, key) in special_model_cases:
                curr_model = special_model_cases[curr_model, key]
                curr_model_dict = get_type_hints(curr_model)
                curr_model_origin = get_origin(curr_model_dict)

                if curr_model == AttrSpec:
                    return get_all_attribs_errors(data, error)
                continue

            if isinstance(curr_model_dict, dict):
                if key in curr_model_dict:
                    curr_model = curr_model_dict[key]
                else:
                    return [err_path], [prev_data]

            curr_model_dict = get_type_hints(curr_model)
            curr_model_origin = get_origin(curr_model_dict)
            if curr_model_origin == dict:
                curr_model = get_args(curr_model_dict)[1]
        else:
            return [err_path], [data]

    if curr_model == AttrSpec:
        return get_all_attribs_errors(data, error)

    return [], locate_basemodel_error(data, curr_model)

locate_errors

locate_errors(exc: ValidationError, data: dict)

Locate errors (i.e.: get the paths and sources) in a ValidationError object.

Source code in dp3/bin/check.py
def locate_errors(exc: ValidationError, data: dict):
    """Locate errors (i.e.: get the paths and sources) in a ValidationError object."""
    paths = []
    sources = []
    errors = []

    for error in exc.errors():
        if error["loc"] == ():
            paths.append(())
            sources.append(None)
            errors.append(error["msg"])
            continue

        message = f'{error["msg"]} (type={error["type"]})'
        e_paths, e_sources = get_error_sources(data, error)

        paths.extend(e_paths)
        sources.extend(e_sources)
        errors.extend(message for _ in range(len(e_paths)))

    return paths, sources, errors