Example #1
0
class LogGame(types.Type):
    season: int = validators.Number(
        1, 11, description="Overwatch season from 1 to 11.")
    sr: int = validators.Number(
        0, 5000, description="You SR at the end of the game from 0 to 5000.")
    map: str = validators.String(
        enum=MAP_CHOICES,
        allow_null=True,
        description=f"Name of the map the game was played.",
    )
    heroes: List[str] = validators.Array(
        items=validators.String(enum=HERO_CHOICES),
        unique_items=True,
        allow_null=True,
        description=f"List of heroes name that you played for that game.",
    )
    comment: str = validators.String(
        allow_null=True,
        description="Free text field to leave a comment for that game.")
    thrower_team: bool = validators.Boolean(
        allow_null=True, description="If there was a thrower in your team.")
    thrower_enemy_team: bool = validators.Boolean(
        allow_null=True,
        description="If there was a thrower in the enemy team.")
    leaver_team: bool = validators.Boolean(
        allow_null=True, description="If there was a leaver on your team.")
    leaver_enemy_team: bool = validators.Boolean(
        allow_null=True,
        description="If there was a leaver on the enemy team.")
    group_with: List[str] = validators.Array(
        items=validators.String(),
        allow_null=True,
        unique_items=True,
        description="List of people of you grouped with for this game.",
    )
Example #2
0
class GameType(types.Type):
    name = validators.String()
    platform = validators.String()
    score = validators.Number()
    resolution_tested = validators.String(pattern="^\d+x\d+$")
    genre = validators.Array()
    players = validators.Array()
    language = validators.Number()
    awesome_city = CityType
class UserType(types.Type):
    _id = validators.String(allow_null=True)
    username = validators.String(min_length=3, max_length=30)
    email = validators.String(allow_null=True, pattern=EMAIL_REGEX)
    names = validators.Array(items=validators.String(), allow_null=True)
    lastnames = validators.Array(items=validators.String(), allow_null=True)
    groups = validators.Array(unique_items=True,
                              items=validators.String(enum=['admin',
                                                            'developer',
                                                            'basic']))
Example #4
0
class GetResponse(types.Type):
    """ default type for get request responses """

    count = validators.Integer(description="The number of objects matching this query.", allow_null=True)
    next = validators.String(description="The url for the next page of data.", allow_null=True)
    previous = validators.String(description="The url for the previous page of data.", allow_null=True)
    results = validators.Array(description="The list of objects returned by the query.", allow_null=True)
Example #5
0
 def coerce_generics(self, annotation):
     origin = getattr(annotation, '__origin__', annotation)
     if (isinstance(origin, type) and issubclass(origin, typing.List)
             and getattr(annotation, '__args__', None)
             and issubclass(annotation.__args__[0], types.Type)):
         return validators.Array(items=annotation.__args__[0])
     return annotation
Example #6
0
class DescriptionEvent(BaseBlock):
    BLOCK_TYPE = "event_description"

    description = validators.String(allow_null=True)
    free_text = validators.String(allow_null=True)
    price = validators.String(allow_null=True)
    tags = validators.Array(allow_null=True)

    @classmethod
    def from_es(cls, es_poi, lang):
        if es_poi.PLACE_TYPE != 'event':
            return None

        description = es_poi.get('description')
        free_text =  es_poi.get('free_text')
        price = es_poi.get('pricing_info')
        tags = es_poi.get('tags', [])

        if isinstance(tags, str):
            tags = tags.split(';')

        if not description:
            return None

        return cls(
            description=description,
            free_text=free_text,
            price=price,
            tags=tags
        )
Example #7
0
class CuisineBlock(BaseBlock):
    BLOCK_TYPE = "cuisine"
    SUPPORTED_DIETS = ("vegetarian", "vegan", "gluten_free")
    STATUS_YES = "yes"
    STATUS_NO = "no"
    STATUS_ONLY = "only"
    STATUS_UNKNOWN = "unknown"

    cuisines = validators.Array(items=Cuisine)
    vegetarian = validators.String()
    vegan = validators.String()
    gluten_free = validators.String()

    @classmethod
    def from_es(cls, es_poi, lang):
        cuisine = es_poi.get("properties", {}).get("cuisine")

        vegetarian = get_diet_status("vegetarian", es_poi)
        vegan = get_diet_status("vegan", es_poi)
        gluten_free = get_diet_status("gluten_free", es_poi)

        cuisines = []
        if cuisine is not None:
            cuisines = [Cuisine(name=b) for b in cuisine.split(";")]
        elif (vegetarian == cls.STATUS_UNKNOWN and vegan == cls.STATUS_UNKNOWN
              and gluten_free == cls.STATUS_UNKNOWN):
            return None

        return cls(cuisines=cuisines,
                   vegetarian=vegetarian,
                   vegan=vegan,
                   gluten_free=gluten_free)
Example #8
0
class BaseExtractionJSONParams(CoercingType):
    """Common extraction parameters validator"""
    domains = validators.Array(
        items=DomainValidator(enum=list(TAG_DOMAINS.keys())),
        unique_items=True,
        description=
        'List of domains to search, if not provided ALL domains will be included',
        allow_null=True,
    )
    offset = validators.Integer(minimum=0,
                                allow_null=True,
                                description='The paging offset')
    limit = validators.Integer(
        minimum=1,
        maximum=10000,
        default=10,
        allow_null=True,
        description='The paging limit.',
    )
    min_score = validators.Number(
        minimum=0.1,
        allow_null=True,
        description=
        'The minimum search score required. No default is applied when not provided. '
        'Ignored when `constant_score` is on.',
    )
    constant_score = validators.Boolean(
        default=True,
        allow_null=False,
        description=
        'Disables relevance scoring when `True`. All results will have score `1`.',
    )
Example #9
0
 def coerce_generics(self, annotation):
     if (
         isinstance(annotation, type) and
         issubclass(annotation, typing.List) and
         annotation.__args__ and
         issubclass(annotation.__args__[0], types.Type)
     ):
         return validators.Array(items=annotation.__args__[0])
     return annotation
Example #10
0
class Basket(types.Type):
    """Represent the item that was added to a basket."""
    id = validators.String(max_length=48, allow_null=True)
    products = validators.Array(items=Product, allow_null=True)

    @classmethod
    def from_model(cls, obj):
        return cls(id=str(obj.id),
                   products=[Product.from_model(p) for p in obj.products])
Example #11
0
    def create_get_response_class(self, model_name, response_object_class=validators.Object):

        return type(
            model_name,  # name of the class
            # (eval('types.Type'),),  # super class as tuple
            (self.get_response_class,),  # super classes at a tuple
            {
                'results': validators.Array(allow_null=True, items=response_object_class)
            }
        )
Example #12
0
class Anime(types.Type):
    id = validators.Integer(allow_null=True)
    title = validators.String(max_length=2500)
    year = validators.Integer(minimum=1900, maximum=2050)
    episodes = validators.Integer(maximum=9999)
    status = validators.String(enum=list(ANIME_VALID_STATUS))
    type = validators.String(allow_null=True)
    animeSeason = validators.Object(allow_null=True)
    picture = validators.String(allow_null=True)
    sources = validators.Array(allow_null=True)
Example #13
0
class Movie(types.Type):
    id = validators.Integer(allow_null=True)  # assign in POST
    genre = validators.Array(items=validators.String(enum=list(VALID_GENRES)))
    director_name = validators.String(max_length=100)
    year = validators.Integer(minimum=1900, maximum=2050)
    language = validators.String(max_length=100,
                                 enum=list(VALID_LANGUAGES),
                                 allow_null=True)
    title = validators.String(max_length=200)
    rating = validators.Number(minimum=0, maximum=10)
Example #14
0
class CsrfSettings(types.Type):
    CSRF_COOKIE_NAME = validators.String(default='csrftoken')
    CSRF_COOKIE_AGE = validators.Integer(default=60 * 60 * 24 * 7 * 52)
    CSRF_COOKIE_DOMAIN = validators.String(allow_null=True)
    CSRF_COOKIE_PATH = validators.String(default='/')
    CSRF_COOKIE_SECURE = validators.Boolean(default=False)
    CSRF_COOKIE_HTTPONLY = validators.Boolean(default=False)
    CSRF_HEADER_NAME = validators.String(default='HTTP_X_CSRFTOKEN')
    CSRF_TOKEN_FIELD_NAME = validators.String(default='csrf_token')
    CSRF_TRUSTED_ORIGINS = validators.Array(default=[])
Example #15
0
class Block(PickleType):
    height = validators.Integer()
    timestamp = validators.DateTime()
    txns = validators.Array(items=Transaction, allow_null=True, default=[])
    mined_hash = validators.String(max_length=100)
    previous_hash = validators.String(max_length=100, allow_null=True)
    nonce = validators.Integer()

    @property
    def previous_block(self):
        return get_block(self.previous_hash)
Example #16
0
class FeatureUpdate(types.Type):

    version = validators.String(description="The feature number version.")
    enabled = validators.Boolean()
    deny = validators.Boolean()

    services = validators.Array(
        unique_items=True,
        items=validators.Integer(),
        allow_null=True,
        description="Array with services allowed to access the feature.",
    )
Example #17
0
class AuthenticatedUserData(types.Type):
    id = validators.Integer()
    email = validators.String(description="Email address",
                              pattern="[^@]+@[^@]+\.[^@]+",
                              allow_null=True)
    phone = validators.String(description="Phone number",
                              pattern="\D*",
                              allow_null=True)
    first_name = validators.String()
    last_name = validators.String()
    language = validators.Integer()
    groups = validators.Array()
    location = validators.Integer()
    picture = validators.String(allow_null=True)
Example #18
0
class BreweryBlock(BaseBlock):
    BLOCK_TYPE = "brewery"

    beers = validators.Array(items=Beer)

    @classmethod
    def from_es(cls, es_poi, lang):
        brewery = es_poi.get("properties", {}).get("brewery")

        if brewery is None:
            return None

        beers = [Beer(name=b) for b in brewery.split(";")]

        return cls(beers=beers)
Example #19
0
class HappyHourBlock(BaseBlock):
    BLOCK_TYPE = 'happy_hours'
    STATUSES = ['yes', 'no']

    status = validators.String(enum=STATUSES)
    next_transition_datetime = validators.String(allow_null=True)
    seconds_before_next_transition = validators.Integer(allow_null=True)
    raw = validators.String()
    days = validators.Array(items=DaysType)

    @classmethod
    def init_class(cls, status, next_transition_datetime, time_before_next, oh, poi_dt, raw):
        return cls(
            status=status,
            next_transition_datetime=next_transition_datetime,
            seconds_before_next_transition=time_before_next,
            raw=oh.field,
            days=get_days(cls, oh, poi_dt)
        )

    @classmethod
    def from_es(cls, es_poi, lang):
        return parse_time_block(cls, es_poi, lang, es_poi.get_raw_happy_hours())
Example #20
0
class OpeningHourBlock(BaseBlock):
    BLOCK_TYPE = 'opening_hours'
    STATUSES = ['open', 'closed']

    status = validators.String(enum=STATUSES)
    next_transition_datetime = validators.String(allow_null=True)
    seconds_before_next_transition = validators.Integer(allow_null=True)
    is_24_7 = validators.Boolean()
    raw = validators.String()
    days = validators.Array(items=DaysType)

    @classmethod
    def init_class(cls, status, next_transition_datetime, time_before_next, oh,
                   poi_dt, raw):
        if raw == '24/7' or oh.is_24_7:
            return cls(status=status,
                       next_transition_datetime=None,
                       seconds_before_next_transition=None,
                       is_24_7=True,
                       raw=oh.field,
                       days=get_days(cls, oh, poi_dt))

        if all(r.status == 'closed' for r in oh.rules):
            # Ignore opening_hours such as "Apr 1-Sep 30: off", causing overflow
            return None

        return cls(status=status,
                   next_transition_datetime=next_transition_datetime,
                   seconds_before_next_transition=time_before_next,
                   is_24_7=oh.is_24_7,
                   raw=oh.field,
                   days=get_days(cls, oh, poi_dt))

    @classmethod
    def from_es(cls, es_poi, lang):
        return parse_time_block(cls, es_poi, lang,
                                es_poi.get_raw_opening_hours())
Example #21
0
class OpeningDayEvent(BaseBlock):
    BLOCK_TYPE = "event_opening_dates"

    date_start = validators.DateTime()
    date_end = validators.DateTime()
    space_time_info = validators.String(allow_null=True)
    timetable = validators.Array(items=TimeTableItem)

    @classmethod
    def from_es(cls, es_poi, lang):
        if es_poi.PLACE_TYPE != 'event':
            return None

        date_start = es_poi.get('date_start')
        date_end = es_poi.get('date_end')
        space_time_info= es_poi.get('space_time_info')
        timetable = es_poi.get('timetable') or ''

        if not date_start or not date_end:
            return None

        timetable = timetable.split(';')
        new_format_timetable = []
        for tt in filter(None, timetable):
            date_start_end = tt.split(' ')
            new_format_timetable.append(
                TimeTableItem(beginning=date_start_end[0], end=date_start_end[1])
            )

        timetable = new_format_timetable

        return cls(
            date_start=date_start,
            date_end=date_end,
            space_time_info=space_time_info,
            timetable=timetable
        )
Example #22
0
def load_type(typename, struct, allow_null):
    attrs = {'allow_null': True} if allow_null else {}

    if typename == 'string':
        if 'minLength' in struct:
            attrs['min_length'] = struct['minLength']
        if 'maxLength' in struct:
            attrs['max_length'] = struct['maxLength']
        if 'pattern' in struct:
            attrs['pattern'] = struct['pattern']
        if 'format' in struct:
            attrs['format'] = struct['format']
        return validators.String(**attrs)

    if typename in ['number', 'integer']:
        if 'minimum' in struct:
            attrs['minimum'] = struct['minimum']
        if 'maximum' in struct:
            attrs['maximum'] = struct['maximum']
        if 'exclusiveMinimum' in struct:
            attrs['exclusive_minimum'] = struct['exclusiveMinimum']
        if 'exclusiveMaximum' in struct:
            attrs['exclusive_maximum'] = struct['exclusiveMaximum']
        if 'multipleOf' in struct:
            attrs['multiple_of'] = struct['multipleOf']
        if 'format' in struct:
            attrs['format'] = struct['format']
        if typename == 'integer':
            return validators.Integer(**attrs)
        return validators.Number(**attrs)

    if typename == 'boolean':
        return validators.Boolean(**attrs)

    if typename == 'object':
        if 'properties' in struct:
            attrs['properties'] = dict_type([
                (key, decode(value))
                for key, value in struct['properties'].items()
            ])
        if 'required' in struct:
            attrs['required'] = struct['required']
        if 'minProperties' in struct:
            attrs['min_properties'] = struct['minProperties']
        if 'maxProperties' in struct:
            attrs['max_properties'] = struct['maxProperties']
        if 'required' in struct:
            attrs['required'] = struct['required']
        if 'patternProperties' in struct:
            attrs['pattern_properties'] = dict_type([
                (key, decode(value))
                for key, value in struct['patternProperties'].items()
            ])
        if 'additionalProperties' in struct:
            if isinstance(struct['additionalProperties'], bool):
                attrs['additional_properties'] = struct['additionalProperties']
            else:
                attrs['additional_properties'] = decode(
                    struct['additionalProperties'])
        return validators.Object(**attrs)

    if typename == 'array':
        if 'items' in struct:
            if isinstance(struct['items'], list):
                attrs['items'] = [decode(item) for item in struct['items']]
            else:
                attrs['items'] = decode(struct['items'])
        if 'additionalItems' in struct:
            if isinstance(struct['additionalItems'], bool):
                attrs['additional_items'] = struct['additionalItems']
            else:
                attrs['additional_items'] = decode(struct['additionalItems'])
        if 'minItems' in struct:
            attrs['min_items'] = struct['minItems']
        if 'maxItems' in struct:
            attrs['max_items'] = struct['maxItems']
        if 'uniqueItems' in struct:
            attrs['unique_items'] = struct['uniqueItems']
        return validators.Array(**attrs)

    assert False
Example #23
0
class DaysType(types.Type):
    dayofweek = validators.Integer(minimum=1, maximum=7)
    local_date = validators.Date()
    status = validators.String(enum=['open', 'closed'])
    opening_hours = validators.Array(items=OpeningHoursType)
Example #24
0
import json

from apistar import types, validators
from apistar.codecs.base import BaseCodec
from apistar.compat import dict_type
from apistar.exceptions import ParseError

JSON_SCHEMA = validators.Object(
    def_name='JSONSchema',
    properties=[
        ('$ref', validators.String()),
        ('type',
         validators.String() | validators.Array(items=validators.String())),
        ('enum', validators.Array(unique_items=True, min_items=1)),
        ('definitions',
         validators.Object(
             additional_properties=validators.Ref('JSONSchema'))),

        # String
        ('minLength', validators.Integer(minimum=0)),
        ('maxLength', validators.Integer(minimum=0)),
        ('pattern', validators.String(format='regex')),
        ('format', validators.String()),

        # Numeric
        ('minimum', validators.Number()),
        ('maximum', validators.Number()),
        ('exclusiveMinimum', validators.Boolean()),
        ('exclusiveMaximum', validators.Boolean()),
        ('multipleOf', validators.Number(minimum=0.0, exclusive_minimum=True)),
Example #25
0
class OpeningHourBlock(BaseBlock):
    BLOCK_TYPE = 'opening_hours'

    status = validators.String(enum=['open', 'closed'])
    next_transition_datetime = validators.String(allow_null=True)
    seconds_before_next_transition = validators.Integer(allow_null=True)
    is_24_7 = validators.Boolean()
    raw = validators.String()
    days = validators.Array(items=DaysType)

    @classmethod
    def from_es(cls, es_poi, lang):
        raw = es_poi.get('properties', {}).get('opening_hours')
        if raw is None:
            return None

        poi_coord = get_coord(es_poi)
        poi_lat = poi_coord[0]
        poi_lon = poi_coord[1]

        is247 = raw == '24/7'

        poi_tzname = tz.tzNameAt(poi_lat, poi_lon, forceTZ=True)
        poi_tz = get_tz(poi_tzname, poi_lat, poi_lon)
        poi_location = (poi_lat, poi_lon, poi_tzname, 24)

        if poi_tz is None:
            logger.info("No timezone found for poi %s", es_poi.get('id'))
            return None

        try:
            oh = hoh.OHParser(raw, location=poi_location)
        except HOHError:
            logger.info("Failed to parse OSM opening_hour field",
                        exc_info=True)
            return None

        poi_dt = UTC.localize(datetime.utcnow()).astimezone(poi_tz)

        if oh.is_open(poi_dt.replace(tzinfo=None)):
            status = 'open'
        else:
            status = 'closed'

        if is247:
            return cls(status=status,
                       next_transition_datetime=None,
                       seconds_before_next_transition=None,
                       is_24_7=is247,
                       raw=oh.field,
                       days=cls.get_days(oh, dt=poi_dt))

        # The current version of the hoh lib doesn't allow to use the next_change() function
        # with an offset aware datetime.
        # This is why we replace the timezone info until this problem is fixed in the library.
        try:
            nt = oh.next_change(dt=poi_dt.replace(tzinfo=None))
        except HOHError:
            logger.info(
                "HOHError: Failed to compute next transition for poi %s",
                es_poi.get('id'),
                exc_info=True)
            return None

        # Then we localize the next_change transition datetime in the local POI timezone.
        next_transition = poi_tz.localize(nt.replace(tzinfo=None))
        next_transition = cls.round_dt_to_minute(next_transition)

        next_transition_datetime = next_transition.isoformat()
        delta = next_transition - poi_dt
        time_before_next = int(delta.total_seconds())

        return cls(status=status,
                   next_transition_datetime=next_transition_datetime,
                   seconds_before_next_transition=time_before_next,
                   is_24_7=is247,
                   raw=oh.field,
                   days=cls.get_days(oh, dt=poi_dt))

    @staticmethod
    def round_dt_to_minute(dt):
        dt += timedelta(seconds=30)
        return dt.replace(second=0, microsecond=0)

    @staticmethod
    def round_time_to_minute(t):
        dt = datetime.combine(date(2000, 1, 1), t)
        rounded = OpeningHourBlock.round_dt_to_minute(dt)
        return rounded.time()

    @classmethod
    def get_days(cls, oh_parser, dt):
        last_monday = dt.date() - timedelta(days=dt.weekday())
        days = []
        for x in range(0, 7):
            day = last_monday + timedelta(days=x)
            oh_day = oh_parser.get_day(day)
            periods = oh_day.opening_periods()
            day_value = {
                'dayofweek': day.isoweekday(),
                'local_date': day.isoformat(),
                'status': 'open' if len(periods) > 0 else 'closed',
                'opening_hours': []
            }
            for beginning_dt, end_dt in periods:
                if beginning_dt.date() < day:
                    continue
                beginning = cls.round_time_to_minute(beginning_dt.time())
                end = cls.round_time_to_minute(end_dt.time())
                day_value['opening_hours'].append({
                    'beginning':
                    beginning.strftime('%H:%M'),
                    'end':
                    end.strftime('%H:%M')
                })
            days.append(day_value)
        return days
Example #26
0
from apistar.compat import dict_type
from apistar.document import Document, Field, Link, Section
from apistar.exceptions import ParseError

SCHEMA_REF = validators.Object(
    properties={'$ref': validators.String(pattern='^#/components/schemas/')})
RESPONSE_REF = validators.Object(
    properties={'$ref': validators.String(pattern='^#/components/responses/')})

OPEN_API = validators.Object(
    def_name='OpenAPI',
    title='OpenAPI',
    properties=[
        ('openapi', validators.String()),
        ('info', validators.Ref('Info')),
        ('servers', validators.Array(items=validators.Ref('Server'))),
        ('paths', validators.Ref('Paths')),
        ('components', validators.Ref('Components')),
        ('security', validators.Ref('SecurityRequirement')),
        ('tags', validators.Array(items=validators.Ref('Tag'))),
        ('externalDocs', validators.Ref('ExternalDocumentation')),
    ],
    pattern_properties={
        '^x-': validators.Any(),
    },
    additional_properties=False,
    required=['openapi', 'info', 'paths'],
    definitions={
        'Info':
        validators.Object(properties=[
            ('title', validators.String()),
Example #27
0
    properties={'$ref': validators.String(pattern='^#/components/schemas/')}
)
RESPONSE_REF = validators.Object(
    properties={'$ref': validators.String(pattern='^#/components/responses/')}
)

SWAGGER = validators.Object(
    def_name='Swagger',
    title='Swagger',
    properties=[
        ('swagger', validators.String()),
        ('info', validators.Ref('Info')),
        ('paths', validators.Ref('Paths')),
        ('host', validators.String()),
        ('basePath', validators.String()),
        ('schemes', validators.Array(items=validators.String())),
        ('consumes', validators.Array(items=validators.String())),
        ('produces', validators.Array(items=validators.String())),
        ('definitions', validators.Object(additional_properties=validators.Any())),
        ('parameters', validators.Object(additional_properties=validators.Ref('Parameters'))),
        ('responses', validators.Object(additional_properties=validators.Ref('Responses'))),
        ('securityDefinitions', validators.Object(additional_properties=validators.Ref('SecurityScheme'))),
        ('security', validators.Ref('SecurityRequirement')),
        ('tags', validators.Array(items=validators.Ref('Tag'))),
        ('externalDocs', validators.Ref('ExternalDocumentation')),
    ],
    pattern_properties={
        '^x-': validators.Any(),
    },
    additional_properties=False,
    required=['swagger', 'info', 'paths'],
import json

from apistar import types, validators
from apistar.codecs.base import BaseCodec
from apistar.compat import dict_type
from apistar.exceptions import ParseError

JSON_SCHEMA = validators.Object(
    def_name="JSONSchema",
    properties=[
        ("$ref", validators.String()),
        ("type", validators.String() | validators.Array(items=validators.String())),
        ("enum", validators.Array(unique_items=True, min_items=1)),
        (
            "definitions",
            validators.Object(additional_properties=validators.Ref("JSONSchema")),
        ),
        # String
        ("minLength", validators.Integer(minimum=0)),
        ("maxLength", validators.Integer(minimum=0)),
        ("pattern", validators.String(format="regex")),
        ("format", validators.String()),
        # Numeric
        ("minimum", validators.Number()),
        ("maximum", validators.Number()),
        ("exclusiveMinimum", validators.Boolean()),
        ("exclusiveMaximum", validators.Boolean()),
        ("multipleOf", validators.Number(minimum=0.0, exclusive_minimum=True)),
        # Object
        (
            "properties",
Example #29
0
SCHEMA_REF = validators.Object(
    properties={'$ref': validators.String(pattern='^#/components/schemas/')})
RESPONSE_REF = validators.Object(
    properties={'$ref': validators.String(pattern='^#/components/responses/')})

SWAGGER = validators.Object(
    def_name='Swagger',
    title='Swagger',
    properties=[
        ('swagger', validators.String()),
        ('info', validators.Ref('Info')),
        ('paths', validators.Ref('Paths')),
        ('host', validators.String()),
        ('basePath', validators.String()),
        ('schemes', validators.Array(items=validators.String())),
        ('consumes', validators.Array(items=validators.String())),
        ('produces', validators.Array(items=validators.String())),
        ('definitions',
         validators.Object(additional_properties=validators.Any())),
        ('parameters',
         validators.Object(
             additional_properties=validators.Ref('Parameters'))),
        ('responses',
         validators.Object(additional_properties=validators.Ref('Responses'))),
        ('securityDefinitions',
         validators.Object(
             additional_properties=validators.Ref('SecurityScheme'))),
        ('security',
         validators.Array(items=validators.Ref('SecurityRequirement'))),
        ('tags', validators.Array(items=validators.Ref('Tag'))),
def load_type(typename, struct, allow_null):
    attrs = {"allow_null": True} if allow_null else {}

    if typename == "string":
        if "minLength" in struct:
            attrs["min_length"] = struct["minLength"]
        if "maxLength" in struct:
            attrs["max_length"] = struct["maxLength"]
        if "pattern" in struct:
            attrs["pattern"] = struct["pattern"]
        if "format" in struct:
            attrs["format"] = struct["format"]
        return validators.String(**attrs)

    if typename in ["number", "integer"]:
        if "minimum" in struct:
            attrs["minimum"] = struct["minimum"]
        if "maximum" in struct:
            attrs["maximum"] = struct["maximum"]
        if "exclusiveMinimum" in struct:
            attrs["exclusive_minimum"] = struct["exclusiveMinimum"]
        if "exclusiveMaximum" in struct:
            attrs["exclusive_maximum"] = struct["exclusiveMaximum"]
        if "multipleOf" in struct:
            attrs["multiple_of"] = struct["multipleOf"]
        if "format" in struct:
            attrs["format"] = struct["format"]
        if typename == "integer":
            return validators.Integer(**attrs)
        return validators.Number(**attrs)

    if typename == "boolean":
        return validators.Boolean(**attrs)

    if typename == "object":
        if "properties" in struct:
            attrs["properties"] = dict_type(
                [(key, decode(value)) for key, value in struct["properties"].items()]
            )
        if "required" in struct:
            attrs["required"] = struct["required"]
        if "minProperties" in struct:
            attrs["min_properties"] = struct["minProperties"]
        if "maxProperties" in struct:
            attrs["max_properties"] = struct["maxProperties"]
        if "required" in struct:
            attrs["required"] = struct["required"]
        if "patternProperties" in struct:
            attrs["pattern_properties"] = dict_type(
                [
                    (key, decode(value))
                    for key, value in struct["patternProperties"].items()
                ]
            )
        if "additionalProperties" in struct:
            if isinstance(struct["additionalProperties"], bool):
                attrs["additional_properties"] = struct["additionalProperties"]
            else:
                attrs["additional_properties"] = decode(struct["additionalProperties"])
        return validators.Object(**attrs)

    if typename == "array":
        if "items" in struct:
            if isinstance(struct["items"], list):
                attrs["items"] = [decode(item) for item in struct["items"]]
            else:
                attrs["items"] = decode(struct["items"])
        if "additionalItems" in struct:
            if isinstance(struct["additionalItems"], bool):
                attrs["additional_items"] = struct["additionalItems"]
            else:
                attrs["additional_items"] = decode(struct["additionalItems"])
        if "minItems" in struct:
            attrs["min_items"] = struct["minItems"]
        if "maxItems" in struct:
            attrs["max_items"] = struct["maxItems"]
        if "uniqueItems" in struct:
            attrs["unique_items"] = struct["uniqueItems"]
        return validators.Array(**attrs)

    assert False