Source code for qudi.core.config.validator

# -*- coding: utf-8 -*-

"""
JSON (draft v7) validator for qudi YAML configurations that also fills in default values.
The corresponding JSON schema is defined in :file:`.__schema.py`.

.. Copyright (c) 2021, the qudi developers. See the AUTHORS.md file at the top-level directory of this
.. distribution and on <https://github.com/Ulm-IQO/qudi-core/>
..
.. This file is part of qudi.
..
.. Qudi is free software: you can redistribute it and/or modify it under the terms of
.. the GNU Lesser General Public License as published by the Free Software Foundation,
.. either version 3 of the License, or (at your option) any later version.
..
.. Qudi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
.. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.. See the GNU Lesser General Public License for more details.
..
.. You should have received a copy of the GNU Lesser General Public License along with qudi.
.. If not, see <https://www.gnu.org/licenses/>.
"""

__all__ = [
    'ValidationError',
    'validate_config',
    'validate_local_module_config',
    'validate_remote_module_config',
    'validate_module_name',
]

import re
from typing import Mapping, Any
from jsonschema import ValidationError
from jsonschema import validators as __validators
from jsonschema import Draft7Validator as __BaseValidator

from .schema import (
    config_schema,
    remote_module_config_schema,
    local_module_config_schema,
)


def __set_defaults(validator, properties, instance, schema):
    # Only insert default values of current schema into instance if validation passses
    try:
        __BaseValidator(schema).validate(instance)
    except ValidationError:
        pass
    else:
        for property, subschema in properties.items():
            if 'default' in subschema:
                try:
                    instance.setdefault(property, subschema['default'])
                except AttributeError:
                    pass

    for error in __BaseValidator.VALIDATORS['properties'](
        validator, properties, instance, schema
    ):
        yield error


def __is_iterable(checker, instance):
    return __BaseValidator.TYPE_CHECKER.is_type(instance, 'array') or isinstance(
        instance, (set, frozenset, tuple)
    )


# Add custom JSON schema (draft v7) validator that accepts all Python builtin sequences as "array"
# type
DefaultInsertionValidator = __validators.extend(
    validator=__BaseValidator,
    validators={'properties': __set_defaults},
    type_checker=__BaseValidator.TYPE_CHECKER.redefine('array', __is_iterable),
)


[docs] def validate_config(config: Mapping[str, Any]) -> None: """JSON schema (draft v7) validator for qudi configuration. Raises jsonschema.ValidationError if invalid. """ DefaultInsertionValidator(config_schema()).validate(config)
[docs] def validate_local_module_config(config: Mapping[str, Any]) -> None: """JSON schema (draft v7) validator for single qudi local module configuration. Raises jsonschema.ValidationError if invalid. """ DefaultInsertionValidator(local_module_config_schema()).validate(config)
[docs] def validate_remote_module_config(config: Mapping[str, Any]) -> None: """JSON schema (draft v7) validator for single qudi remote module configuration. Raises jsonschema.ValidationError if invalid. """ DefaultInsertionValidator(remote_module_config_schema()).validate(config)
[docs] def validate_module_name(name: str) -> None: """Regular expression validator for qudi module names. Raises jsonschema.ValidationError if invalid. WARNING: The jsonschema.ValidationError raised does not contain any JSON schema information. """ if re.match(r'^[a-zA-Z_]+[a-zA-Z0-9_]*$', name) is None: raise ValidationError( 'Module names must only contain word characters [a-zA-Z0-9_] and not start on a number.' )