Source code for topchef_client.models.validator

"""
Describes a JSON schema validator
"""
from ..exceptions import NetworkError, ProcessingError
import requests
from abc import ABCMeta, abstractmethod
from six import add_metaclass


[docs]class Validator(object): """ Validates schemas """ _JSON_header = {'Content-Type': 'application/json'} HTTP_STATUS_CODE_OK = 200 HTTP_STATUS_CODE_BAD_REQUEST = 400
[docs] def __init__(self, topchef_url, http_library=requests): """ :param topchef_url: The URL for the TopChef API :param http_library: The library to use for HTTP calls """ self._topchef_url = topchef_url self._http_library = http_library
[docs] def assert_instance_matches_schema(self, instance, schema, validator=None): """ :param dict instance: The instance to validate :param dict schema: The schema against which the instance is to be validated :param AbstractValidator validator: The validator to use. If this is None, a RemoteSchemaValidator will be constructed :return: True if the instance matches the schema :raises: NetworkError if an unexpected status code is received """ if validator is None: validator = self.RemoteSchemaValidator( self._topchef_url, self._http_library ) result = validator.does_instance_match_schema(instance, schema) if not result: raise ProcessingError("The instance does not match the schema")
@add_metaclass(ABCMeta)
[docs] class AbstractValidator(object): """ Describes the interface for an object capable of validating JSON schemas. This object does the heavy lifting for validating JSON. It also helps with testing as the validation procedure can be stubbed out more efficiently. """ @abstractmethod
[docs] def does_instance_match_schema(self, instance, schema): """ :param dict instance: The instance to validate :param dict schema: The schema against which the instance is to be validated """ raise NotImplementedError()
[docs] class RemoteSchemaValidator(AbstractValidator): """ Perfoms validation remotely using the TopChef API """ _JSON_header = {'Content-Type': 'application/json'} HTTP_STATUS_CODE_OK = 200 HTTP_STATUS_CODE_BAD_REQUEST = 400
[docs] def __init__(self, topchef_url, http_library=requests): """ :param str topchef_url: The URL for the TopChef API :param mod http_library: The library to use for HTTP requests """ self.topchef_url = topchef_url self._http_library = http_library
@property def _validator_endpoint(self): """ :return: The URL for the JSON schema validator """ return '{0}/validator'.format(self.topchef_url)
[docs] def does_instance_match_schema(self, instance, schema): """ :param dict instance: The instance to validate :param dict schema: The schema against which the instance is to be validated :return: True if the instance matches the schema :raises: NetworkError if an unexpected status code is received """ request_body = self._get_request_body(instance, schema) response = self._http_library.post( self._validator_endpoint, headers=self._JSON_header, json=request_body ) return self._analyze_validation_response(response)
[docs] def _analyze_validation_response(self, response): """ Analyze whether the validation request was successful or not based on the status code of the response :param requests.Response response: The response to analyze :return: True if the status code is correct, and False if otherwise :raises: NetworkError if an unexpected status code is received """ status_code = response.status_code if status_code == self.HTTP_STATUS_CODE_OK: return True elif status_code == self.HTTP_STATUS_CODE_BAD_REQUEST: return False else: raise NetworkError( 'Unable to contact validator. Status code %s', status_code )
@staticmethod
[docs] def _get_request_body(instance, schema): """ Format a request for the body of the POST request for the TopChef JSON Schema validator :param dict instance: The instance to validate :param dict schema: The schema against which the instance is to be validated """ return {'object': instance, 'schema': schema}