Source code for sciunit.validators

"""Cerberus validator classes for SciUnit."""

import inspect

import quantities as pq
from cerberus import TypeDefinition, Validator


[docs]def register_type(cls, name): """Register `name` as a type to validate as an instance of class `cls`.""" x = TypeDefinition(name, (cls,), ()) Validator.types_mapping[name] = x
[docs]def register_quantity(quantity, name): """Register `name` as a type to validate as an instance of class `cls`.""" x = TypeDefinition(name, (quantity.__class__,), ()) Validator.types_mapping[name] = x
[docs]class ObservationValidator(Validator): """Cerberus validator class for observations."""
[docs] def __init__(self, *args, **kwargs): """Must pass `test` as a keyword argument. Cannot be a positional argument without modifications to cerberus """ try: self.test = kwargs['test'] except AttributeError: raise Exception(("Observation validator constructor must have " "a `test` keyword argument")) super(ObservationValidator, self).__init__(*args, **kwargs) register_type(pq.quantity.Quantity, 'quantity')
[docs] def _validate_iterable(self, is_iterable, key, value): """Validate fields with `iterable` key in schema set to True The rule's arguments are validated against this schema: {'type': 'boolean'} """ if is_iterable: try: iter(value) except TypeError: self._error(key, "Must be iterable (e.g. a list or array)")
[docs] def _validate_units(self, has_units, key, value): """Validate fields with `units` key in schema set to True. The rule's arguments are validated against this schema: {'type': 'boolean'} """ if has_units: if isinstance(self.test.units, dict): required_units = self.test.units[key] else: required_units = self.test.units if not isinstance(value, pq.quantity.Quantity): self._error(key, "Must be a python quantity") if not isinstance(value, pq.quantity.Quantity): self._error(key, "Must be a python quantity") provided_units = value.simplified.units if not isinstance(required_units, pq.Dimensionless): required_units = required_units.simplified.units if not required_units == provided_units: self._error(key, "Must have units of '%s'" % self.test.units.name)
[docs]class ParametersValidator(Validator): """Cerberus validator class for observations.""" units_map = {'time': 's', 'voltage': 'V', 'current': 'A'}
[docs] def validate_quantity(self, value): """Validate that the value is of the `Quantity` type.""" if not isinstance(value, pq.quantity.Quantity): self._error('%s' % value, "Must be a Python quantity.")
[docs] def validate_units(self, value): """Validate units, assuming that it was called by _validate_type_*.""" self.validate_quantity(value) self.units_type = inspect.stack()[1][3].split('_')[-1] assert self.units_type, ("`validate_units` should not be called " "directly. It should be called by a " "_validate_type_* methods that sets " "`units_type`") units = getattr(pq, self.units_map[self.units_type]) if not value.simplified.units == units: self._error('%s' % value, "Must have dimensions of %s." % self.units_type) return True
[docs] def _validate_type_time(self, value): """Validate fields requiring `units` of seconds.""" return self.validate_units(value)
[docs] def _validate_type_voltage(self, value): """Validate fields requiring `units` of volts.""" return self.validate_units(value)
[docs] def _validate_type_current(self, value): """Validate fields requiring `units` of amps.""" return self.validate_units(value)