import os
import yaml
from copy import deepcopy
from jsonschema import Draft4Validator, RefResolver, validators
from astropy.units.quantity import Quantity
from tardis.io.util import YAMLLoader
base_dir = os.path.abspath(os.path.dirname(__file__))
schema_dir = os.path.join(base_dir, "schemas")
config_schema_file = os.path.join(schema_dir, "base.yml")
[docs]def extend_with_default(validator_class):
    """
    Extend a `jsonschema.IValidator` to also set default
    values on properties. By default jsonschema ignores
    default values.
    Parameters
    ----------
    validator_class :
        The `jsonschema.IValidator` class to extend
    Returns
    -------
    The extended `jsonschema.IValidator`
    """
    validate_properties = validator_class.VALIDATORS["properties"]
    def set_defaults(validator, properties, instance, schema):
        # This validator also checks if default values
        # are of the correct type and properly sets default
        # values on schemas that use the oneOf keyword
        if not list(
            validate_properties(validator, properties, instance, schema)
        ):
            for property, subschema in properties.items():
                if "default" in subschema:
                    instance.setdefault(property, subschema["default"])
        for error in validate_properties(
            validator,
            properties,
            instance,
            schema,
        ):
            yield error
    return validators.extend(
        validator_class,
        {"properties": set_defaults},
    )
 
DefaultDraft4Validator = extend_with_default(Draft4Validator)
def _yaml_handler(path):
    if not path.startswith("file://"):
        raise Exception(f"Not a file URL: {path}")
    with open(path[len("file://") :]) as f:
        return yaml.load(f, Loader=YAMLLoader)
[docs]def validate_dict(
    config_dict, schemapath=config_schema_file, validator=DefaultDraft4Validator
):
    with open(schemapath) as f:
        schema = yaml.load(f, Loader=YAMLLoader)
    schemaurl = "file://" + schemapath
    handlers = {"file": _yaml_handler}
    resolver = RefResolver(schemaurl, schema, handlers=handlers)
    validated_dict = deepcopy(config_dict)
    validator(
        schema=schema, types={"quantity": (Quantity,)}, resolver=resolver
    ).validate(validated_dict)
    return validated_dict
 
[docs]def validate_yaml(
    configpath, schemapath=config_schema_file, validator=DefaultDraft4Validator
):
    with open(configpath) as f:
        config = yaml.load(f, Loader=YAMLLoader)
    return validate_dict(config, schemapath, validator)