Module hug.types

hug/types.py

Defines hugs built-in supported types / validators

Copyright (C) 2016 Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View Source
"""hug/types.py

Defines hugs built-in supported types / validators

Copyright (C) 2016  Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated

documentation files (the "Software"), to deal in the Software without restriction, including without limitation

the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and

to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or

substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED

TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR

OTHER DEALINGS IN THE SOFTWARE.

"""

from __future__ import absolute_import

import uuid as native_uuid

from decimal import Decimal

from distutils.version import LooseVersion

import hug._empty as empty

from hug import introspect

from hug.exceptions import InvalidTypeData

from hug.json_module import json as json_converter

MARSHMALLOW_MAJOR_VERSION = None

try:

    import marshmallow

    from marshmallow import ValidationError

    MARSHMALLOW_MAJOR_VERSION = getattr(

        marshmallow, "__version_info__", LooseVersion(marshmallow.__version__).version

    )[0]

except ImportError:

    # Just define the error that is never raised so that Python does not complain.

    class ValidationError(Exception):

        pass

class Type(object):

    """Defines the base hug concept of a type for use in function annotation.

       Override `__call__` to define how the type should be transformed and validated

    """

    _hug_type = True

    _sub_type = None

    _accept_context = False

    def __init__(self):

        pass

    def __call__(self, value):

        raise NotImplementedError("To implement a new type __call__ must be defined")

def create(

    doc=None,

    error_text=None,

    exception_handlers=empty.dict,

    extend=Type,

    chain=True,

    auto_instance=True,

    accept_context=False,

):

    """Creates a new type handler with the specified type-casting handler"""

    extend = extend if type(extend) == type else type(extend)

    def new_type_handler(function):

        class NewType(extend):

            __slots__ = ()

            _accept_context = accept_context

            if chain and extend != Type:

                if error_text or exception_handlers:

                    if not accept_context:

                        def __call__(self, value):

                            try:

                                value = super(NewType, self).__call__(value)

                                return function(value)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        if extend._accept_context:

                            def __call__(self, value, context):

                                try:

                                    value = super(NewType, self).__call__(value, context)

                                    return function(value, context)

                                except Exception as exception:

                                    for take_exception, rewrite in exception_handlers.items():

                                        if isinstance(exception, take_exception):

                                            if isinstance(rewrite, str):

                                                raise ValueError(rewrite)

                                            else:

                                                raise rewrite(value)

                                    if error_text:

                                        raise ValueError(error_text)

                                    raise exception

                        else:

                            def __call__(self, value, context):

                                try:

                                    value = super(NewType, self).__call__(value)

                                    return function(value, context)

                                except Exception as exception:

                                    for take_exception, rewrite in exception_handlers.items():

                                        if isinstance(exception, take_exception):

                                            if isinstance(rewrite, str):

                                                raise ValueError(rewrite)

                                            else:

                                                raise rewrite(value)

                                    if error_text:

                                        raise ValueError(error_text)

                                    raise exception

                else:

                    if not accept_context:

                        def __call__(self, value):

                            value = super(NewType, self).__call__(value)

                            return function(value)

                    else:

                        if extend._accept_context:

                            def __call__(self, value, context):

                                value = super(NewType, self).__call__(value, context)

                                return function(value, context)

                        else:

                            def __call__(self, value, context):

                                value = super(NewType, self).__call__(value)

                                return function(value, context)

            else:

                if not accept_context:

                    if error_text or exception_handlers:

                        def __call__(self, value):

                            try:

                                return function(value)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        def __call__(self, value):

                            return function(value)

                else:

                    if error_text or exception_handlers:

                        def __call__(self, value, context):

                            try:

                                return function(value, context)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        def __call__(self, value, context):

                            return function(value, context)

        NewType.__doc__ = function.__doc__ if doc is None else doc

        if auto_instance and not (

            introspect.arguments(NewType.__init__, -1)

            or introspect.takes_kwargs(NewType.__init__)

            or introspect.takes_args(NewType.__init__)

        ):

            return NewType()

        return NewType

    return new_type_handler

def accept(kind, doc=None, error_text=None, exception_handlers=empty.dict, accept_context=False):

    """Allows quick wrapping of any Python type cast function for use as a hug type annotation"""

    return create(

        doc,

        error_text,

        exception_handlers=exception_handlers,

        chain=False,

        accept_context=accept_context,

    )(kind)

number = accept(int, "A whole number", "Invalid whole number provided")

float_number = accept(float, "A float number", "Invalid float number provided")

decimal = accept(Decimal, "A decimal number", "Invalid decimal number provided")

boolean = accept(

    bool, "Providing any value will set this to true", "Invalid boolean value provided"

)

uuid = accept(native_uuid.UUID, "A Universally Unique IDentifier", "Invalid UUID provided")

class Text(Type):

    """Basic text / string value"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) in (list, tuple) or value is None:

            raise ValueError("Invalid text value provided")

        return str(value)

text = Text()

class SubTyped(type):

    def __getitem__(cls, sub_type):

        class TypedSubclass(cls):

            _sub_type = sub_type

        return TypedSubclass

class Multiple(Type, metaclass=SubTyped):

    """Multiple Values"""

    __slots__ = ()

    def __call__(self, value):

        as_multiple = value if isinstance(value, list) else [value]

        if self._sub_type:

            return [self._sub_type(item) for item in as_multiple]

        return as_multiple

class DelimitedList(Type, metaclass=SubTyped):

    """Defines a list type that is formed by delimiting a list with a certain character or set of characters"""

    def __init__(self, using=","):

        super().__init__()

        self.using = using

    @property

    def __doc__(self):

        return '''Multiple values, separated by "{0}"'''.format(self.using)

    def __call__(self, value):

        value_list = value if type(value) in (list, tuple) else value.split(self.using)

        if self._sub_type:

            value_list = [self._sub_type(val) for val in value_list]

        return value_list

class SmartBoolean(type(boolean)):

    """Accepts a true or false value"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) == bool or value in (None, 1, 0):

            return bool(value)

        value = value.lower()

        if value in ("true", "t", "1"):

            return True

        elif value in ("false", "f", "0", ""):

            return False

        raise KeyError("Invalid value passed in for true/false field")

class InlineDictionary(Type, metaclass=SubTyped):

    """A single line dictionary, where items are separted by commas and key:value are separated by a pipe"""

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.key_type = self.value_type = None

        if self._sub_type:

            if type(self._sub_type) in (tuple, list):

                if len(self._sub_type) >= 2:

                    self.key_type, self.value_type = self._sub_type[:2]

            else:

                self.key_type = self._sub_type

    def __call__(self, string):

        dictionary = {}

        for key, value in (item.split(":") for item in string.split("|")):

            key, value = key.strip(), value.strip()

            dictionary[self.key_type(key) if self.key_type else key] = (

                self.value_type(value) if self.value_type else value

            )

        return dictionary

class OneOf(Type):

    """Ensures the value is within a set of acceptable values"""

    __slots__ = ("values",)

    def __init__(self, values):

        self.values = values

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return value

class Mapping(OneOf):

    """Ensures the value is one of an acceptable set of values mapping those values to a Python equivelent"""

    __slots__ = ("value_map",)

    def __init__(self, value_map):

        self.value_map = value_map

        self.values = value_map.keys()

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return self.value_map[value]

class JSON(Type):

    """Accepts a JSON formatted data structure"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) in (str, bytes):

            try:

                return json_converter.loads(value)

            except Exception:

                raise ValueError("Incorrectly formatted JSON provided")

        if type(value) is list:

            # If Falcon is set to comma-separate entries, this segment joins them again.

            try:

                fixed_value = ",".join(value)

                return json_converter.loads(fixed_value)

            except Exception:

                raise ValueError("Incorrectly formatted JSON provided")

        else:

            return value

class Multi(Type):

    """Enables accepting one of multiple type methods"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    @property

    def __doc__(self):

        type_strings = (type_method.__doc__ for type_method in self.types)

        return "Accepts any of the following value types:{0}\n".format("\n  - ".join(type_strings))

    def __call__(self, value):

        for type_method in self.types:

            try:

                return type_method(value)

            except BaseException:

                pass

        raise ValueError(self.__doc__)

class InRange(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=number):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater or equal to {1} and less than {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        if value < self.lower:

            raise ValueError("'{0}' is less than the lower limit {1}".format(value, self.lower))

        if value >= self.upper:

            raise ValueError("'{0}' reaches the limit of {1}".format(value, self.upper))

        return value

class LessThan(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=number):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is less than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        if not value < self.limit:

            raise ValueError("'{0}' must be less than {1}".format(value, self.limit))

        return value

class GreaterThan(Type):

    """Accepts a value above a given minimum"""

    __slots__ = ("minimum", "convert")

    def __init__(self, minimum, convert=number):

        self.minimum = minimum

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater than {1}".format(self.convert.__doc__, self.minimum)

    def __call__(self, value):

        value = self.convert(value)

        if not value > self.minimum:

            raise ValueError("'{0}' must be greater than {1}".format(value, self.minimum))

        return value

class Length(Type):

    """Accepts a a value that is within a specific length limit"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=text):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that has a length longer or equal to {1} and less then {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if length < self.lower:

            raise ValueError(

                "'{0}' is shorter than the lower limit of {1}".format(value, self.lower)

            )

        if length >= self.upper:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.upper)

            )

        return value

class ShorterThan(Type):

    """Accepts a text value shorter than the specified length limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length of no more than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length < self.limit:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.limit)

            )

        return value

class LongerThan(Type):

    """Accepts a value up to the specified limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length longer than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length > self.limit:

            raise ValueError("'{0}' must be longer than {1}".format(value, self.limit))

        return value

class CutOff(Type):

    """Cuts off the provided value at the specified index"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "'{0}' with anything over the length of {1} being ignored".format(

            self.convert.__doc__, self.limit

        )

    def __call__(self, value):

        return self.convert(value)[: self.limit]

class Chain(Type):

    """type for chaining multiple types together"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    def __call__(self, value):

        for type_function in self.types:

            value = type_function(value)

        return value

class Nullable(Chain):

    """A Chain types that Allows None values"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    def __call__(self, value):

        if value is None:

            return None

        else:

            return super(Nullable, self).__call__(value)

class TypedProperty(object):

    """class for building property objects for schema objects"""

    __slots__ = ("name", "type_func")

    def __init__(self, name, type_func):

        self.name = "_" + name

        self.type_func = type_func

    def __get__(self, instance, cls):

        return getattr(instance, self.name, None)

    def __set__(self, instance, value):

        setattr(instance, self.name, self.type_func(value))

    def __delete__(self, instance):

        raise AttributeError("Can't delete attribute")

class NewTypeMeta(type):

    """Meta class to turn Schema objects into format usable by hug"""

    __slots__ = ()

    def __init__(cls, name, bases, nmspc):

        cls._types = {

            attr: getattr(cls, attr)

            for attr in dir(cls)

            if getattr(getattr(cls, attr), "_hug_type", False)

        }

        slots = getattr(cls, "__slots__", ())

        slots = set(slots)

        for attr, type_func in cls._types.items():

            slots.add("_" + attr)

            slots.add(attr)

            prop = TypedProperty(attr, type_func)

            setattr(cls, attr, prop)

        cls.__slots__ = tuple(slots)

        super(NewTypeMeta, cls).__init__(name, bases, nmspc)

class Schema(object, metaclass=NewTypeMeta):

    """Schema for creating complex types using hug types"""

    __slots__ = ()

    def __new__(cls, json, *args, **kwargs):

        if json.__class__ == cls:

            return json

        else:

            return super(Schema, cls).__new__(cls)

    def __init__(self, json, force=False):

        if self != json:

            for (key, value) in json.items():

                if force:

                    key = "_" + key

                setattr(self, key, value)

json = JSON()

class MarshmallowInputSchema(Type):

    """Allows using a Marshmallow Schema directly in a hug input type annotation"""

    __slots__ = "schema"

    def __init__(self, schema):

        self.schema = schema

    @property

    def __doc__(self):

        return self.schema.__doc__ or self.schema.__class__.__name__

    def __call__(self, value, context):

        self.schema.context = context

        # In marshmallow 2 schemas return tuple (`data`, `errors`) upon loading. They might also raise on invalid data

        # if configured so, but will still return a tuple.

        # In marshmallow 3 schemas always raise Validation error on load if input data is invalid and a single

        # value `data` is returned.

        if MARSHMALLOW_MAJOR_VERSION is None or MARSHMALLOW_MAJOR_VERSION == 2:

            value, errors = (

                self.schema.loads(value) if isinstance(value, str) else self.schema.load(value)

            )

        else:

            errors = {}

            try:

                value = (

                    self.schema.loads(value) if isinstance(value, str) else self.schema.load(value)

                )

            except ValidationError as e:

                errors = e.messages

        if errors:

            raise InvalidTypeData(

                "Invalid {0} passed in".format(self.schema.__class__.__name__), errors

            )

        return value

class MarshmallowReturnSchema(Type):

    """Allows using a Marshmallow Schema directly in a hug return type annotation"""

    __slots__ = ("schema",)

    def __init__(self, schema):

        self.schema = schema

    @property

    def context(self):

        return self.schema.context

    @context.setter

    def context(self, context):

        self.schema.context = context

    @property

    def __doc__(self):

        return self.schema.__doc__ or self.schema.__class__.__name__

    def __call__(self, value):

        # In marshmallow 2 schemas return tuple (`data`, `errors`) upon loading. They might also raise on invalid data

        # if configured so, but will still return a tuple.

        # In marshmallow 3 schemas always raise Validation error on load if input data is invalid and a single

        # value `data` is returned.

        if MARSHMALLOW_MAJOR_VERSION is None or MARSHMALLOW_MAJOR_VERSION == 2:

            value, errors = self.schema.dump(value)

        else:

            errors = {}

            try:

                value = self.schema.dump(value)

            except ValidationError as e:

                errors = e.messages

        if errors:

            raise InvalidTypeData(

                "Invalid {0} passed in".format(self.schema.__class__.__name__), errors

            )

        return value

multiple = Multiple()

smart_boolean = SmartBoolean()

inline_dictionary = InlineDictionary()

comma_separated_list = DelimitedList(using=",")

# NOTE: These forms are going to be DEPRECATED, here for backwards compatibility only

delimited_list = DelimitedList

one_of = OneOf

mapping = Mapping

multi = Multi

in_range = InRange

less_than = LessThan

greater_than = GreaterThan

length = Length

shorter_than = ShorterThan

longer_than = LongerThan

cut_off = CutOff

Variables

MARSHMALLOW_MAJOR_VERSION
boolean
comma_separated_list
decimal
float_number
inline_dictionary
json
multiple
number
smart_boolean
text
uuid

Functions

accept

def accept(
    kind,
    doc=None,
    error_text=None,
    exception_handlers=mappingproxy({}),
    accept_context=False
)

Allows quick wrapping of any Python type cast function for use as a hug type annotation

View Source
def accept(kind, doc=None, error_text=None, exception_handlers=empty.dict, accept_context=False):

    """Allows quick wrapping of any Python type cast function for use as a hug type annotation"""

    return create(

        doc,

        error_text,

        exception_handlers=exception_handlers,

        chain=False,

        accept_context=accept_context,

    )(kind)

create

def create(
    doc=None,
    error_text=None,
    exception_handlers=mappingproxy({}),
    extend=<class 'hug.types.Type'>,
    chain=True,
    auto_instance=True,
    accept_context=False
)

Creates a new type handler with the specified type-casting handler

View Source
def create(

    doc=None,

    error_text=None,

    exception_handlers=empty.dict,

    extend=Type,

    chain=True,

    auto_instance=True,

    accept_context=False,

):

    """Creates a new type handler with the specified type-casting handler"""

    extend = extend if type(extend) == type else type(extend)

    def new_type_handler(function):

        class NewType(extend):

            __slots__ = ()

            _accept_context = accept_context

            if chain and extend != Type:

                if error_text or exception_handlers:

                    if not accept_context:

                        def __call__(self, value):

                            try:

                                value = super(NewType, self).__call__(value)

                                return function(value)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        if extend._accept_context:

                            def __call__(self, value, context):

                                try:

                                    value = super(NewType, self).__call__(value, context)

                                    return function(value, context)

                                except Exception as exception:

                                    for take_exception, rewrite in exception_handlers.items():

                                        if isinstance(exception, take_exception):

                                            if isinstance(rewrite, str):

                                                raise ValueError(rewrite)

                                            else:

                                                raise rewrite(value)

                                    if error_text:

                                        raise ValueError(error_text)

                                    raise exception

                        else:

                            def __call__(self, value, context):

                                try:

                                    value = super(NewType, self).__call__(value)

                                    return function(value, context)

                                except Exception as exception:

                                    for take_exception, rewrite in exception_handlers.items():

                                        if isinstance(exception, take_exception):

                                            if isinstance(rewrite, str):

                                                raise ValueError(rewrite)

                                            else:

                                                raise rewrite(value)

                                    if error_text:

                                        raise ValueError(error_text)

                                    raise exception

                else:

                    if not accept_context:

                        def __call__(self, value):

                            value = super(NewType, self).__call__(value)

                            return function(value)

                    else:

                        if extend._accept_context:

                            def __call__(self, value, context):

                                value = super(NewType, self).__call__(value, context)

                                return function(value, context)

                        else:

                            def __call__(self, value, context):

                                value = super(NewType, self).__call__(value)

                                return function(value, context)

            else:

                if not accept_context:

                    if error_text or exception_handlers:

                        def __call__(self, value):

                            try:

                                return function(value)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        def __call__(self, value):

                            return function(value)

                else:

                    if error_text or exception_handlers:

                        def __call__(self, value, context):

                            try:

                                return function(value, context)

                            except Exception as exception:

                                for take_exception, rewrite in exception_handlers.items():

                                    if isinstance(exception, take_exception):

                                        if isinstance(rewrite, str):

                                            raise ValueError(rewrite)

                                        else:

                                            raise rewrite(value)

                                if error_text:

                                    raise ValueError(error_text)

                                raise exception

                    else:

                        def __call__(self, value, context):

                            return function(value, context)

        NewType.__doc__ = function.__doc__ if doc is None else doc

        if auto_instance and not (

            introspect.arguments(NewType.__init__, -1)

            or introspect.takes_kwargs(NewType.__init__)

            or introspect.takes_args(NewType.__init__)

        ):

            return NewType()

        return NewType

    return new_type_handler

Classes

Chain

class Chain(
    *types
)

type for chaining multiple types together

View Source
class Chain(Type):

    """type for chaining multiple types together"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    def __call__(self, value):

        for type_function in self.types:

            value = type_function(value)

        return value

Ancestors (in MRO)

  • hug.types.Type

Descendants

  • hug.types.Nullable

Instance variables

types

CutOff

class CutOff(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class CutOff(Type):

    """Cuts off the provided value at the specified index"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "'{0}' with anything over the length of {1} being ignored".format(

            self.convert.__doc__, self.limit

        )

    def __call__(self, value):

        return self.convert(value)[: self.limit]

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

DelimitedList

class DelimitedList(
    using=','
)
View Source
class DelimitedList(Type, metaclass=SubTyped):

    """Defines a list type that is formed by delimiting a list with a certain character or set of characters"""

    def __init__(self, using=","):

        super().__init__()

        self.using = using

    @property

    def __doc__(self):

        return '''Multiple values, separated by "{0}"'''.format(self.using)

    def __call__(self, value):

        value_list = value if type(value) in (list, tuple) else value.split(self.using)

        if self._sub_type:

            value_list = [self._sub_type(val) for val in value_list]

        return value_list

Ancestors (in MRO)

  • hug.types.Type

GreaterThan

class GreaterThan(
    minimum,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class GreaterThan(Type):

    """Accepts a value above a given minimum"""

    __slots__ = ("minimum", "convert")

    def __init__(self, minimum, convert=number):

        self.minimum = minimum

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater than {1}".format(self.convert.__doc__, self.minimum)

    def __call__(self, value):

        value = self.convert(value)

        if not value > self.minimum:

            raise ValueError("'{0}' must be greater than {1}".format(value, self.minimum))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
minimum

InRange

class InRange(
    lower,
    upper,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class InRange(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=number):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater or equal to {1} and less than {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        if value < self.lower:

            raise ValueError("'{0}' is less than the lower limit {1}".format(value, self.lower))

        if value >= self.upper:

            raise ValueError("'{0}' reaches the limit of {1}".format(value, self.upper))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
lower
upper

InlineDictionary

class InlineDictionary(
    *args,
    **kwargs
)

A single line dictionary, where items are separted by commas and key:value are separated by a pipe

View Source
class InlineDictionary(Type, metaclass=SubTyped):

    """A single line dictionary, where items are separted by commas and key:value are separated by a pipe"""

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.key_type = self.value_type = None

        if self._sub_type:

            if type(self._sub_type) in (tuple, list):

                if len(self._sub_type) >= 2:

                    self.key_type, self.value_type = self._sub_type[:2]

            else:

                self.key_type = self._sub_type

    def __call__(self, string):

        dictionary = {}

        for key, value in (item.split(":") for item in string.split("|")):

            key, value = key.strip(), value.strip()

            dictionary[self.key_type(key) if self.key_type else key] = (

                self.value_type(value) if self.value_type else value

            )

        return dictionary

Ancestors (in MRO)

  • hug.types.Type

JSON

class JSON(

)

Accepts a JSON formatted data structure

View Source
class JSON(Type):

    """Accepts a JSON formatted data structure"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) in (str, bytes):

            try:

                return json_converter.loads(value)

            except Exception:

                raise ValueError("Incorrectly formatted JSON provided")

        if type(value) is list:

            # If Falcon is set to comma-separate entries, this segment joins them again.

            try:

                fixed_value = ",".join(value)

                return json_converter.loads(fixed_value)

            except Exception:

                raise ValueError("Incorrectly formatted JSON provided")

        else:

            return value

Ancestors (in MRO)

  • hug.types.Type

Length

class Length(
    lower,
    upper,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class Length(Type):

    """Accepts a a value that is within a specific length limit"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=text):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that has a length longer or equal to {1} and less then {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if length < self.lower:

            raise ValueError(

                "'{0}' is shorter than the lower limit of {1}".format(value, self.lower)

            )

        if length >= self.upper:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.upper)

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
lower
upper

LessThan

class LessThan(
    limit,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class LessThan(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=number):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is less than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        if not value < self.limit:

            raise ValueError("'{0}' must be less than {1}".format(value, self.limit))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

LongerThan

class LongerThan(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class LongerThan(Type):

    """Accepts a value up to the specified limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length longer than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length > self.limit:

            raise ValueError("'{0}' must be longer than {1}".format(value, self.limit))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

Mapping

class Mapping(
    value_map
)
View Source
class Mapping(OneOf):

    """Ensures the value is one of an acceptable set of values mapping those values to a Python equivelent"""

    __slots__ = ("value_map",)

    def __init__(self, value_map):

        self.value_map = value_map

        self.values = value_map.keys()

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return self.value_map[value]

Ancestors (in MRO)

  • hug.types.OneOf
  • hug.types.Type

Class variables

values

Instance variables

value_map
values

MarshmallowInputSchema

class MarshmallowInputSchema(
    schema
)
View Source
class MarshmallowInputSchema(Type):

    """Allows using a Marshmallow Schema directly in a hug input type annotation"""

    __slots__ = "schema"

    def __init__(self, schema):

        self.schema = schema

    @property

    def __doc__(self):

        return self.schema.__doc__ or self.schema.__class__.__name__

    def __call__(self, value, context):

        self.schema.context = context

        # In marshmallow 2 schemas return tuple (`data`, `errors`) upon loading. They might also raise on invalid data

        # if configured so, but will still return a tuple.

        # In marshmallow 3 schemas always raise Validation error on load if input data is invalid and a single

        # value `data` is returned.

        if MARSHMALLOW_MAJOR_VERSION is None or MARSHMALLOW_MAJOR_VERSION == 2:

            value, errors = (

                self.schema.loads(value) if isinstance(value, str) else self.schema.load(value)

            )

        else:

            errors = {}

            try:

                value = (

                    self.schema.loads(value) if isinstance(value, str) else self.schema.load(value)

                )

            except ValidationError as e:

                errors = e.messages

        if errors:

            raise InvalidTypeData(

                "Invalid {0} passed in".format(self.schema.__class__.__name__), errors

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

schema

MarshmallowReturnSchema

class MarshmallowReturnSchema(
    schema
)
View Source
class MarshmallowReturnSchema(Type):

    """Allows using a Marshmallow Schema directly in a hug return type annotation"""

    __slots__ = ("schema",)

    def __init__(self, schema):

        self.schema = schema

    @property

    def context(self):

        return self.schema.context

    @context.setter

    def context(self, context):

        self.schema.context = context

    @property

    def __doc__(self):

        return self.schema.__doc__ or self.schema.__class__.__name__

    def __call__(self, value):

        # In marshmallow 2 schemas return tuple (`data`, `errors`) upon loading. They might also raise on invalid data

        # if configured so, but will still return a tuple.

        # In marshmallow 3 schemas always raise Validation error on load if input data is invalid and a single

        # value `data` is returned.

        if MARSHMALLOW_MAJOR_VERSION is None or MARSHMALLOW_MAJOR_VERSION == 2:

            value, errors = self.schema.dump(value)

        else:

            errors = {}

            try:

                value = self.schema.dump(value)

            except ValidationError as e:

                errors = e.messages

        if errors:

            raise InvalidTypeData(

                "Invalid {0} passed in".format(self.schema.__class__.__name__), errors

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

context
schema

Multi

class Multi(
    *types
)
View Source
class Multi(Type):

    """Enables accepting one of multiple type methods"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    @property

    def __doc__(self):

        type_strings = (type_method.__doc__ for type_method in self.types)

        return "Accepts any of the following value types:{0}\n".format("\n  - ".join(type_strings))

    def __call__(self, value):

        for type_method in self.types:

            try:

                return type_method(value)

            except BaseException:

                pass

        raise ValueError(self.__doc__)

Ancestors (in MRO)

  • hug.types.Type

Instance variables

types

Multiple

class Multiple(

)

Multiple Values

View Source
class Multiple(Type, metaclass=SubTyped):

    """Multiple Values"""

    __slots__ = ()

    def __call__(self, value):

        as_multiple = value if isinstance(value, list) else [value]

        if self._sub_type:

            return [self._sub_type(item) for item in as_multiple]

        return as_multiple

Ancestors (in MRO)

  • hug.types.Type

NewTypeMeta

class NewTypeMeta(
    cls,
    name,
    bases,
    nmspc
)

Meta class to turn Schema objects into format usable by hug

View Source
class NewTypeMeta(type):

    """Meta class to turn Schema objects into format usable by hug"""

    __slots__ = ()

    def __init__(cls, name, bases, nmspc):

        cls._types = {

            attr: getattr(cls, attr)

            for attr in dir(cls)

            if getattr(getattr(cls, attr), "_hug_type", False)

        }

        slots = getattr(cls, "__slots__", ())

        slots = set(slots)

        for attr, type_func in cls._types.items():

            slots.add("_" + attr)

            slots.add(attr)

            prop = TypedProperty(attr, type_func)

            setattr(cls, attr, prop)

        cls.__slots__ = tuple(slots)

        super(NewTypeMeta, cls).__init__(name, bases, nmspc)

Ancestors (in MRO)

  • builtins.type

Methods

mro
def mro(
    self,
    /
)

Return a type's method resolution order.

Nullable

class Nullable(
    *types
)

A Chain types that Allows None values

View Source
class Nullable(Chain):

    """A Chain types that Allows None values"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    def __call__(self, value):

        if value is None:

            return None

        else:

            return super(Nullable, self).__call__(value)

Ancestors (in MRO)

  • hug.types.Chain
  • hug.types.Type

Instance variables

types

OneOf

class OneOf(
    values
)
View Source
class OneOf(Type):

    """Ensures the value is within a set of acceptable values"""

    __slots__ = ("values",)

    def __init__(self, values):

        self.values = values

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Descendants

  • hug.types.Mapping

Instance variables

values

Schema

class Schema(
    json,
    force=False
)

Schema for creating complex types using hug types

View Source
class Schema(object, metaclass=NewTypeMeta):

    """Schema for creating complex types using hug types"""

    __slots__ = ()

    def __new__(cls, json, *args, **kwargs):

        if json.__class__ == cls:

            return json

        else:

            return super(Schema, cls).__new__(cls)

    def __init__(self, json, force=False):

        if self != json:

            for (key, value) in json.items():

                if force:

                    key = "_" + key

                setattr(self, key, value)

ShorterThan

class ShorterThan(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class ShorterThan(Type):

    """Accepts a text value shorter than the specified length limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length of no more than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length < self.limit:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.limit)

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

SmartBoolean

class SmartBoolean(

)

Accepts a true or false value

View Source
class SmartBoolean(type(boolean)):

    """Accepts a true or false value"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) == bool or value in (None, 1, 0):

            return bool(value)

        value = value.lower()

        if value in ("true", "t", "1"):

            return True

        elif value in ("false", "f", "0", ""):

            return False

        raise KeyError("Invalid value passed in for true/false field")

Ancestors (in MRO)

  • hug.types.NewType
  • hug.types.Type

SubTyped

class SubTyped(
    /,
    *args,
    **kwargs
)

type(object_or_name, bases, dict) type(object) -> the object's type type(name, bases, dict) -> a new type

View Source
class SubTyped(type):

    def __getitem__(cls, sub_type):

        class TypedSubclass(cls):

            _sub_type = sub_type

        return TypedSubclass

Ancestors (in MRO)

  • builtins.type

Methods

mro
def mro(
    self,
    /
)

Return a type's method resolution order.

Text

class Text(

)

Basic text / string value

View Source
class Text(Type):

    """Basic text / string value"""

    __slots__ = ()

    def __call__(self, value):

        if type(value) in (list, tuple) or value is None:

            raise ValueError("Invalid text value provided")

        return str(value)

Ancestors (in MRO)

  • hug.types.Type

Type

class Type(

)

Defines the base hug concept of a type for use in function annotation. Override __call__ to define how the type should be transformed and validated

View Source
class Type(object):

    """Defines the base hug concept of a type for use in function annotation.

       Override `__call__` to define how the type should be transformed and validated

    """

    _hug_type = True

    _sub_type = None

    _accept_context = False

    def __init__(self):

        pass

    def __call__(self, value):

        raise NotImplementedError("To implement a new type __call__ must be defined")

Descendants

  • hug.types.NewType
  • hug.types.NewType
  • hug.types.NewType
  • hug.types.NewType
  • hug.types.NewType
  • hug.types.Text
  • hug.types.Multiple
  • hug.types.DelimitedList
  • hug.types.InlineDictionary
  • hug.types.OneOf
  • hug.types.JSON
  • hug.types.Multi
  • hug.types.InRange
  • hug.types.LessThan
  • hug.types.GreaterThan
  • hug.types.Length
  • hug.types.ShorterThan
  • hug.types.LongerThan
  • hug.types.CutOff
  • hug.types.Chain
  • hug.types.MarshmallowInputSchema
  • hug.types.MarshmallowReturnSchema

TypedProperty

class TypedProperty(
    name,
    type_func
)

class for building property objects for schema objects

View Source
class TypedProperty(object):

    """class for building property objects for schema objects"""

    __slots__ = ("name", "type_func")

    def __init__(self, name, type_func):

        self.name = "_" + name

        self.type_func = type_func

    def __get__(self, instance, cls):

        return getattr(instance, self.name, None)

    def __set__(self, instance, value):

        setattr(instance, self.name, self.type_func(value))

    def __delete__(self, instance):

        raise AttributeError("Can't delete attribute")

Instance variables

name
type_func

cut_off

class cut_off(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class CutOff(Type):

    """Cuts off the provided value at the specified index"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "'{0}' with anything over the length of {1} being ignored".format(

            self.convert.__doc__, self.limit

        )

    def __call__(self, value):

        return self.convert(value)[: self.limit]

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

delimited_list

class delimited_list(
    using=','
)
View Source
class DelimitedList(Type, metaclass=SubTyped):

    """Defines a list type that is formed by delimiting a list with a certain character or set of characters"""

    def __init__(self, using=","):

        super().__init__()

        self.using = using

    @property

    def __doc__(self):

        return '''Multiple values, separated by "{0}"'''.format(self.using)

    def __call__(self, value):

        value_list = value if type(value) in (list, tuple) else value.split(self.using)

        if self._sub_type:

            value_list = [self._sub_type(val) for val in value_list]

        return value_list

Ancestors (in MRO)

  • hug.types.Type

greater_than

class greater_than(
    minimum,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class GreaterThan(Type):

    """Accepts a value above a given minimum"""

    __slots__ = ("minimum", "convert")

    def __init__(self, minimum, convert=number):

        self.minimum = minimum

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater than {1}".format(self.convert.__doc__, self.minimum)

    def __call__(self, value):

        value = self.convert(value)

        if not value > self.minimum:

            raise ValueError("'{0}' must be greater than {1}".format(value, self.minimum))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
minimum

in_range

class in_range(
    lower,
    upper,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class InRange(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=number):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is greater or equal to {1} and less than {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        if value < self.lower:

            raise ValueError("'{0}' is less than the lower limit {1}".format(value, self.lower))

        if value >= self.upper:

            raise ValueError("'{0}' reaches the limit of {1}".format(value, self.upper))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
lower
upper

length

class length(
    lower,
    upper,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class Length(Type):

    """Accepts a a value that is within a specific length limit"""

    __slots__ = ("lower", "upper", "convert")

    def __init__(self, lower, upper, convert=text):

        self.lower = lower

        self.upper = upper

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that has a length longer or equal to {1} and less then {2}".format(

            self.convert.__doc__, self.lower, self.upper

        )

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if length < self.lower:

            raise ValueError(

                "'{0}' is shorter than the lower limit of {1}".format(value, self.lower)

            )

        if length >= self.upper:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.upper)

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
lower
upper

less_than

class less_than(
    limit,
    convert=<hug.types.create.<locals>.new_type_handler.<locals>.NewType object at 0x7f7ee2ebceb8>
)
View Source
class LessThan(Type):

    """Accepts a number within a lower and upper bound of acceptable values"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=number):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} that is less than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        if not value < self.limit:

            raise ValueError("'{0}' must be less than {1}".format(value, self.limit))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

longer_than

class longer_than(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class LongerThan(Type):

    """Accepts a value up to the specified limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length longer than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length > self.limit:

            raise ValueError("'{0}' must be longer than {1}".format(value, self.limit))

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit

mapping

class mapping(
    value_map
)
View Source
class Mapping(OneOf):

    """Ensures the value is one of an acceptable set of values mapping those values to a Python equivelent"""

    __slots__ = ("value_map",)

    def __init__(self, value_map):

        self.value_map = value_map

        self.values = value_map.keys()

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return self.value_map[value]

Ancestors (in MRO)

  • hug.types.OneOf
  • hug.types.Type

Class variables

values

Instance variables

value_map
values

multi

class multi(
    *types
)
View Source
class Multi(Type):

    """Enables accepting one of multiple type methods"""

    __slots__ = ("types",)

    def __init__(self, *types):

        self.types = types

    @property

    def __doc__(self):

        type_strings = (type_method.__doc__ for type_method in self.types)

        return "Accepts any of the following value types:{0}\n".format("\n  - ".join(type_strings))

    def __call__(self, value):

        for type_method in self.types:

            try:

                return type_method(value)

            except BaseException:

                pass

        raise ValueError(self.__doc__)

Ancestors (in MRO)

  • hug.types.Type

Instance variables

types

one_of

class one_of(
    values
)
View Source
class OneOf(Type):

    """Ensures the value is within a set of acceptable values"""

    __slots__ = ("values",)

    def __init__(self, values):

        self.values = values

    @property

    def __doc__(self):

        return "Accepts one of the following values: ({0})".format("|".join(self.values))

    def __call__(self, value):

        if not value in self.values:

            raise KeyError(

                "Invalid value passed. The accepted values are: ({0})".format("|".join(self.values))

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Descendants

  • hug.types.Mapping

Instance variables

values

shorter_than

class shorter_than(
    limit,
    convert=<hug.types.Text object at 0x7f7ee2ec57f0>
)
View Source
class ShorterThan(Type):

    """Accepts a text value shorter than the specified length limit"""

    __slots__ = ("limit", "convert")

    def __init__(self, limit, convert=text):

        self.limit = limit

        self.convert = convert

    @property

    def __doc__(self):

        return "{0} with a length of no more than {1}".format(self.convert.__doc__, self.limit)

    def __call__(self, value):

        value = self.convert(value)

        length = len(value)

        if not length < self.limit:

            raise ValueError(

                "'{0}' is longer then the allowed limit of {1}".format(value, self.limit)

            )

        return value

Ancestors (in MRO)

  • hug.types.Type

Instance variables

convert
limit