class Base(Exception):
class UnsupportedVocabularyError(Base):
class UnsupportedContentTypeError(Base):
class ValidationError(Base):
class HandlerException(Base):
class RequestException(HandlerException):
class ResponseException(HandlerException):
class UnimplementedVerbError(RequestException):
class NoEndpointError(RequestException):
class AuthenticationError(RequestException):
class AuthorizationError(RequestException):
class SerializationFailedError(RequestException):
class DeSerializationFailedError(RequestException):
class AttributeFilterDiffers(RequestException):
class InconsistentPersistentDataError(Base):
class DataValidationException(Base):
class RequiredAttributeError(DataValidationException):
class ParseFailedError(DataValidationException):
class LessThanMinimumError(DataValidationException):
class MoreThanMaximumError(DataValidationException):
class InvalidChoiceError(DataValidationException):
class MinimumLengthError(DataValidationException):
class MaximumLengthError(DataValidationException):
class InvalidTypeError(DataValidationException):
class MissingParameterError(DataValidationException):
class InvalidFormatError(DataValidationException):
class InvalidMetaValueError(DataValidationException):
class UnregisteredAdapterError(DataValidationException):
class ServiceUnavailable(ResponseException):
class BadRequest(ResponseException):
class Conflict(ResponseException):
class NotFound(ResponseException):
class Unauthorized(ResponseException):
class MovedPermanently(ResponseException):
class Redirect(ResponseException):
class TemporaryRedirect(Redirect):
class PermanentRedirect(Redirect):
class PaymentRequired(ResponseException):
class Forbidden(ResponseException):
class InternalServerError(ResponseException):
    def __init__(self, http_status, message):
    def http_status(self):
    def http_status(self, value):
    def stack_trace(self):
    def push_trace(self, trace_object):
    def message(self):
    def __str__(self):
    def __init__(self, accept_header, supported_types):
    def __init__(self, requested_mime_type, content_type):
    def __init__(self, message, attribute_name, value, blueprint):
    def append_validation_trace(self, blueprint):
    def __str__(self):
    def __init__(self, code, message):
    def request(self):
    def request(self, value):
    def log_message(self):
    def __str__(self):
    def __init__(self, code, message):
    def __init__(self, code, message, response_model=None):
    def response_model(self):
    def __init__(self, verb_name):
    def __init__(self):
    def __init__(self, message=None):
    def __init__(self, role_name):
    def __init__(self, format):
    def __init__(self, format):
    def __init__(self, attribute_list):
    def __init__(self, attribute_name, exception_message):
    def __str__(self):
    def __init__(self, message):
    def __init__(self):
    def __init__(self, message="Parser Failed"):
    def __init__(self, value, allowed_min):
    def __init__(self, value, allowed_max):
    def __init__(self, value, allowed_choices):
    def __init__(self, value, minimum):
    def __init__(self, value, maximum):
    def __init__(self, value, type_name):
    def __init__(self):
    def __init__(self, value):
    def __init__(self):
    def __init__(self, model_name):
    def __init__(self, message="Service Unavailable", response_model=None):
    def __init__(self, message="Bad Request", response_model=None):
    def __init__(self, message="Conflict", response_model=None):
    def __init__(self, message="Not Found", response_model=None):
    def __init__(self, message="Unauthorized", response_model=None):
    def __init__(self, message="Moved Permanently", response_model=None):
    def __init__(self, code, url):
    def url(self):
    def __init__(self, url):
    def __init__(self, url):
    def __init__(self, message="Payment Required", response_model=None):
    def __init__(self, message="Forbidden", response_model=None):
    def __init__(self, message="Internal Server Error", response_model=None): class DataCollection(DataType):

    def blueprint(self):
        raise NotImplementedError

    def validate(self, value, attribute_filter=None, minified=False):
        raise NotImplementedError

    def as_serializable(self, attribute_filter=None):
        raise NotImplementedError

    def attribute_rewrite_map(self):
        raise NotImplementedError

    def attribute_rewrite_reverse_map(self):
        raise NotImplementedError

    def get_attribute_filter(self, default_value=False):
        raise NotImplementedError class DataStructure(DataType):
    """
    Wrappers on Python types generally represented as structures e.g DateTime

    as_serializable methods signature for %DataStructure is different to that of DataCollection
    it requires a value to be passed in, this is because the python type of structures is
    difference to what gets serialized.

    E.g DateTime serializes itself as a ISO string
    """

    def blueprint(self):
        raise NotImplementedError

    def validate(self, value):
        raise NotImplementedError

    def as_serializable(self, value):
        raise NotImplementedError class DataType(object):

    def blueprint(self):
        raise NotImplementedError

    def validate(self, value):
        raise NotImplementedError class Boolean(DataType):

    def __init__(self, default=None, required=True, description=None):

        if default is None or \
           isinstance(default, bool):
            self._default = default
        else:
            raise TypeError("default must be of type bool or None")
        self._required = required
        self._description = description

    @property
    def required(self):
        return self._required

    @property
    def default(self):
        return self._default

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'boolean'

        constraints = dict()
        constraints['default'] = self.default
        constraints['required'] = self.required
        constraints['description'] = self.description

        blueprint['constraints'] = constraints
        return blueprint

    def validate(self, value):

        if not self._required and self._default is None and value is None:
            return None
        elif self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif value is None and self.default is not None:
            value = self._default

        if not isinstance(value, bool):
            raise exception.ParseFailedError()

        return value class Float(DataType):

    def __init__(self, default=None, minimum=None, maximum=None, required=True,
                 choices=None, description=None):

        if minimum and maximum and minimum > maximum:
            raise ValueError("maximum cannot be less than minimum")

        self._default = default
        self._minimum = minimum
        self._maximum = maximum
        self._required = required
        self._choices = choices
        self._description = description

    @property
    def default(self):
        return self._default

    @property
    def minimum(self):
        return self._minimum

    @property
    def maximum(self):
        return self._maximum

    @property
    def required(self):
        return self._required

    @property
    def choices(self):
        return self._choices

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'float'

        constraints = dict()
        constraints['default'] = self._default
        constraints['minimum'] = self._minimum
        constraints['maximum'] = self._maximum
        constraints['required'] = self._required
        constraints['choices'] = self._choices
        constraints['description'] = self._description

        blueprint['constraints'] = constraints
        return blueprint

    def validate(self, value):

        if not self._required and self._default is None and value is None:
            return None
        if self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif self._required and value is None:
            value = self._default
        elif not self._required and value is None:
            value = self._default

        try:
            _validated_value = float(value)
        except Exception as exp:
            raise exception.ParseFailedError("float encoding failed %s" % exp)

        if _validated_value is not None and self._minimum is not None and _validated_value < self._minimum:
            raise exception.LessThanMinimumError(value, self._minimum)

        if _validated_value is not None and self._maximum is not None and _validated_value > self._maximum:
            raise exception.MoreThanMaximumError(value, self._maximum)

        if self._choices is not None and _validated_value not in self._choices:
            raise exception.InvalidChoiceError(value, self._choices)

        return _validated_value class Integer(DataType):

    def __init__(self, default=None, minimum=None, maximum=None,
                 required=True, choices=None, description=None):

        if minimum and maximum and minimum > maximum:
            raise ValueError("maximum cannot be less than minimum")

        # todo: check default in choices

        self._default = default
        self._minimum = minimum
        self._maximum = maximum
        self._required = required
        self._choices = choices
        self._description = description

    @property
    def default(self):
        return self._default

    @property
    def minimum(self):
        return self._minimum

    @property
    def maximum(self):
        return self._maximum

    @property
    def required(self):
        return self._required

    @property
    def choices(self):
        return self._choices

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'integer'

        constraints = dict()
        constraints['default'] = self.default
        constraints['minimum'] = self.minimum
        constraints['maximum'] = self.maximum
        constraints['required'] = self.required
        constraints['choices'] = self.choices
        constraints['description'] = self.description

        blueprint['constraints'] = constraints

        return blueprint

    def validate(self, value):

        if not self._required and self._default is None and value is None:
            return None
        elif self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif self._default is not None and value is None:
            value = self._default

        try:
            from prestans.util import integer_types

            if isinstance(value, integer_types):
                _validated_value = value
            else:
                _validated_value = int(value)
        except Exception:
            raise exception.ParseFailedError("encoding failed: value is not an integer or a long")

        if _validated_value is not None and self._minimum is not None and _validated_value < self._minimum:
            raise exception.LessThanMinimumError(value, self._minimum)
        if _validated_value is not None and self._maximum is not None and _validated_value > self._maximum:
            raise exception.MoreThanMaximumError(value, self._maximum)

        if self._choices is not None and not _validated_value in self._choices:
            raise exception.InvalidChoiceError(value, self._choices)

        return _validated_value class String(DataType):

    def __init__(self, default=None, min_length=None, max_length=None,
                 required=True, format=None, choices=None, utf_encoding='utf-8',
                 description=None, trim=True):

        if min_length and max_length and min_length > max_length:
            raise ValueError("max length cannot be less than min length")

        if min_length and min_length < 1:
            raise ValueError("min length must be positive")

        if max_length and max_length < 1:
            raise ValueError("max length must be positive")

        self._default = default
        self._min_length = min_length
        self._max_length = max_length
        self._required = required
        self._format = format
        self._choices = choices
        self._utf_encoding = utf_encoding
        self._description = description
        self._trim = trim

    @property
    def required(self):
        return self._required

    @property
    def max_length(self):
        return self._max_length

    @property
    def min_length(self):
        return self._min_length

    @property
    def default(self):
        return self._default

    @property
    def choices(self):
        return self._choices

    @property
    def format(self):
        return self._format

    @property
    def description(self):
        return self._description

    @property
    def trim(self):
        return self._trim

    @property
    def utf_encoding(self):
        return self._utf_encoding

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'string'

        constraints = dict()
        constraints['default'] = self._default
        constraints['min_length'] = self._min_length
        constraints['max_length'] = self._max_length
        constraints['required'] = self._required
        constraints['format'] = self._format
        constraints['choices'] = self._choices
        constraints['utf_encoding'] = self._utf_encoding
        constraints['description'] = self._description
        constraints['trim'] = self._trim

        blueprint['constraints'] = constraints

        return blueprint

    def validate(self, value):

        _validated_value = None

        if self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif self._required and value is None:
            value = self._default
        elif not self._required and self._default is None and value is None:
            return _validated_value
        elif not self._required and value is None:
            value = self._default

        try:
            from prestans.util import string_types

            if isinstance(value, string_types):
                _validated_value = value
            else:
                _validated_value = str(value)
        except Exception as exp:
            raise exception.ParseFailedError("unicode or string encoding failed, %s" % exp)

        if self._trim:
            _validated_value = _validated_value.strip()

        # check for required and empty string
        if self._required and len(_validated_value) == 0:
            raise exception.RequiredAttributeError()

        if not self._required and len(_validated_value) == 0:
            return _validated_value

        if _validated_value is not None and self._min_length is not None and \
                len(_validated_value) < self._min_length:
            raise exception.MinimumLengthError(value, self._min_length)
        if _validated_value is not None and self._max_length is not None and \
                len(_validated_value) > self._max_length:
            raise exception.MaximumLengthError(value, self._max_length)

        if self._choices is not None and not _validated_value in self._choices:
            raise exception.InvalidChoiceError(value, self._choices)

        if self._format is not None and re.search(self._format, _validated_value) is None:
            raise exception.InvalidFormatError(_validated_value)

        return _validated_value class Date(DataStructure):

    DEFAULT_FORMAT = "%Y-%m-%d"
    TODAY = '_PRESTANS_CONSTANT_MODEL_DATE_TODAY'

    def __init__(self, default=None, required=True, format=DEFAULT_FORMAT, description=None):

        if isinstance(default, date_type) or \
                default == self.TODAY or \
                default is None:
            self._default = default
        else:
            raise TypeError("default must be one of date, Date.TODAY")

        self._required = required
        self._format = format
        self._description = description

    @property
    def default(self):
        return self._default

    @property
    def required(self):
        return self._required

    @property
    def format(self):
        return self._format

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'date'

        constraints = dict()
        constraints['default'] = self._default
        constraints['required'] = self._required
        constraints['format'] = self._format
        constraints['description'] = self._description

        blueprint['constraints'] = constraints
        return blueprint

    def validate(self, value):

        _validated_value = None

        if self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif self._required and value is None:
            if self._default == Date.TODAY:
                value = date.today()
            else:
                value = self._default
        elif not self._required and self._default is None and value is None:
            return _validated_value
        elif not self._required and value is None:
            if self._default == Date.TODAY:
                value = date.today()
            else:
                value = self._default

        from prestans.util import string_types

        if isinstance(value, date_type):
            _validated_value = value
        elif isinstance(value, string_types):
            try:
                _validated_value = datetime.strptime(value, self._format).date()
            except ValueError as exp:
                raise exception.ParseFailedError("date parsing failed %s" % exp)
        else:
            raise exception.ParseFailedError("cannot parse value of type %s" % value.__class__.__name__)

        return _validated_value

    def as_serializable(self, value):

        if not isinstance(value, date_type):
            raise exception.InvalidTypeError(value, 'datetime.date')

        return value.strftime(self._format) class DateTime(DataStructure):

    DEFAULT_FORMAT = "%Y-%m-%d %H:%M:%S"
    NOW = '_PRESTANS_CONSTANT_MODEL_DATETIME_NOW'
    UTC_NOW = '_PRESTANS_CONSTANT_MODEL_DATETIME_UTC_NOW'

    def __init__(self, default=None, required=True, format=DEFAULT_FORMAT,
                 timezone=False, utc=False, description=None):

        if isinstance(default, datetime_type) or \
                default == self.NOW or \
                default == self.UTC_NOW or \
                default is None:
            self._default = default
        else:
            raise TypeError("default must be one of datetime, DateTime.NOW or DateTime.UTC_NOW")

        self._required = required
        self._timezone = timezone
        self._utc = utc
        self._format = format
        self._description = description

    @property
    def default(self):
        return self._default

    @property
    def required(self):
        return self._required

    @property
    def format(self):
        return self._format

    @property
    def timezone(self):
        return self._timezone

    @property
    def utc(self):
        return self._utc

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'datetime'

        constraints = dict()
        constraints['default'] = self._default
        constraints['required'] = self._required
        constraints['format'] = self._format
        constraints['timezone'] = self._timezone
        constraints['utc'] = self._utc
        constraints['description'] = self._description

        blueprint['constraints'] = constraints
        return blueprint

    def validate(self, value):

        _validated_value = None

        if self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif self._required and value is None:
            if self._default == DateTime.NOW:
                value = datetime.now()
            elif self._default == DateTime.UTC_NOW:
                value = datetime.utcnow()
            else:
                value = self._default

        elif not self._required and self._default is None and value is None:
            return _validated_value
        elif not self._required and value is None:
            if self._default == DateTime.NOW:
                value = datetime.now()
            elif self._default == DateTime.UTC_NOW:
                value = datetime.utcnow()
            else:
                value = self._default

        from prestans.util import string_types

        if isinstance(value, datetime_type):
            _validated_value = value
        elif isinstance(value, string_types):
            try:
                _validated_value = datetime.strptime(value, self._format)
            except ValueError as exp:
                raise exception.ParseFailedError("date time parsing failed %s" % exp)
        else:
            raise exception.ParseFailedError("cannot parse value of type %s" % value.__class__.__name__)

        return _validated_value

    def as_serializable(self, value):

        if not type(value) == datetime:
            raise exception.InvalidTypeError(value, 'datetime.datetime')

        return value.strftime(self._format) class Time(DataStructure):

    DEFAULT_FORMAT = "%H:%M:%S"
    NOW = '_PRESTANS_CONSTANT_MODEL_TIME_NOW'
    UTC_NOW = '_PRESTANS_CONSTANT_MODEL_TIME_UTC_NOW'

    def __init__(self, default=None, required=True, format=DEFAULT_FORMAT, description=None):

        if isinstance(default, time) or \
           default == self.NOW or \
           default == self.UTC_NOW or \
           default is None:
            self._default = default
        else:
            raise TypeError("default must be one of time, Time.NOW or Time.UTC_NOW")

        self._required = required
        self._format = format
        self._description = description

    @property
    def default(self):
        return self._default

    @property
    def required(self):
        """
        :return:
        :rtype: bool
        """
        return self._required

    @property
    def format(self):
        return self._format

    @property
    def description(self):
        return self._description

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'time'

        constraints = dict()
        constraints['default'] = self.default
        constraints['required'] = self.required
        constraints['format'] = self.format
        constraints['description'] = self.description

        blueprint['constraints'] = constraints
        return blueprint

    def validate(self, value):
        from prestans.util import string_types

        _validated_value = None

        # no need to do any validation if None, not required and default provided
        if not self._required and self._default is None and value is None:
            return value
        elif self._required and self._default is None and value is None:
            raise exception.RequiredAttributeError()
        elif value is None and self._default is not None:
            if self._default == Time.NOW:
                value = datetime.now()
            elif self._default == Time.UTC_NOW:
                value = datetime.utcnow()
            else:
                value = self._default

        if isinstance(value, time):
            _validated_value = value
        elif isinstance(value, string_types):
            try:
                _validated_value = datetime.strptime(value, self._format).time()
            except ValueError as exp:
                raise exception.ParseFailedError("time parsing failed %s" % exp)
        else:
            raise exception.ParseFailedError("cannot parse value of type %s" % value.__class__.__name__)

        return _validated_value

    def as_serializable(self, value):

        if not type(value) == time:
            raise exception.InvalidTypeError(value, 'datetime.time')

        return value.strftime(self._format)
from prestans import exception
from prestans.types import DataCollection
from prestans.types import DataStructure
from prestans.types import DataType
from prestans.types import Boolean
from prestans.types import Float
from prestans.types import Integer
from prestans.types import String
from prestans.types import Date
from prestans.types import DateTime
from prestans.types import Time
        from prestans.parser import AttributeFilter

    def __len__(self):
        return len(self._array_elements)

    def __iter__(self):
        """"
        With a little help from:
        http://johnmc.co/llum/the-easiest-way-to-implement-__iter__-for-a-python-object
        """
        for element in self._array_elements:
            yield element

    def __getitem__(self, index):
        return self._array_elements[index]

    def __contains__(self, item):
        return item in self._array_elements

    @property
    def max_length(self):
        return self._max_length

    @property
    def min_length(self):
        return self._min_length

    @property
    def description(self):
        return self._description

    @property
    def is_scalar(self):
        """
        :return:
        :rtype: bool
        """
        return \
            isinstance(self._element_template, Boolean) or \
            isinstance(self._element_template, Float) or  \
            isinstance(self._element_template, Integer) or \
            isinstance(self._element_template, String)

    @property
    def element_template(self):
        return self._element_template

    @element_template.setter
    def element_template(self, value):
        self._element_template = value

    def blueprint(self):

        blueprint = dict()
        blueprint['type'] = 'array'

        constraints = dict()
        constraints['required'] = self._required
        constraints['min_length'] = self._min_length
        constraints['max_length'] = self._max_length
        constraints['element_template'] = self._element_template.blueprint()
        constraints['description'] = self._description

        blueprint['constraints'] = constraints
        return blueprint

    def remove(self, value):
        self._array_elements.remove(value)

    def validate(self, value, attribute_filter=None, minified=False):
        """
        :param value:
        :type value: list | None
        :param attribute_filter:
        :type attribute_filter: prestans.parser.AttributeFilter
        :param minified:
        :type minified: bool
        :return:
        """

        if not self._required and value is None:
            return None
        elif self._required and value is None:
            raise exception.RequiredAttributeError()

        _validated_value = self.__class__(
            element_template=self._element_template,
            min_length=self._min_length,
            max_length=self._max_length
        )

        if not isinstance(value, (list, tuple)):
            raise TypeError(value)

        for array_element in value:

            if isinstance(self._element_template, DataCollection):
                validated_array_element = self._element_template.validate(array_element, attribute_filter, minified)
            else:
                validated_array_element = self._element_template.validate(array_element)

            _validated_value.append(validated_array_element)

        if self._min_length is not None and len(_validated_value) < self._min_length:
            raise exception.LessThanMinimumError(value, self._min_length)

        if self._max_length is not None and len(_validated_value) > self._max_length:
            raise exception.MoreThanMaximumError(value, self._max_length)

        return _validated_value

    def append(self, value):

        if isinstance(value, (list, tuple)):

            for element in value:
                self.append(element)
            return

        # check for basic types supported by array
        if isinstance(self._element_template, Boolean) or \

           isinstance(self._element_template, Float) or \