Example #1
0
    def __init__(self, properties=None, pattern_properties=None,
                 additional_properties=True, min_properties=None,
                 max_properties=None, required=None, allow_null=False,
                 **kwargs):
        super().__init__(**kwargs)

        properties = {} if (properties is None) else dict_type(properties)
        pattern_properties = {} if (pattern_properties is None) else dict_type(pattern_properties)
        required = list(required) if isinstance(required, (list, tuple)) else required
        required = [] if (required is None) else required

        assert all(isinstance(k, str) for k in properties.keys())
        assert all(isinstance(v, Validator) for v in properties.values())
        assert all(isinstance(k, str) for k in pattern_properties.keys())
        assert all(isinstance(v, Validator) for v in pattern_properties.values())
        assert additional_properties is None or isinstance(additional_properties, (bool, Validator))
        assert min_properties is None or isinstance(min_properties, int)
        assert max_properties is None or isinstance(max_properties, int)
        assert all(isinstance(i, str) for i in required)

        self.properties = properties
        self.pattern_properties = pattern_properties
        self.additional_properties = additional_properties
        self.min_properties = min_properties
        self.max_properties = max_properties
        self.required = required
        self.allow_null = allow_null
Example #2
0
    def __init__(self, routes):
        rules = []
        name_lookups = {}

        for path, name, route in self.walk_routes(routes):
            path_params = [
                item.strip('{}') for item in re.findall('{[^}]*}', path)
            ]
            args = inspect.signature(route.handler).parameters
            for path_param in path_params:
                if path_param.startswith('+'):
                    path = path.replace('{%s}' % path_param,
                                        "<path:%s>" % path_param.lstrip('+'))
                elif path_param in args and args[path_param].annotation is int:
                    path = path.replace('{%s}' % path_param,
                                        "<int:%s>" % path_param)
                elif path_param in args and args[
                        path_param].annotation is float:
                    path = path.replace('{%s}' % path_param,
                                        "<float:%s>" % path_param)
                else:
                    path = path.replace('{%s}' % path_param,
                                        "<string:%s>" % path_param)

            rule = Rule(path, methods=[route.method], endpoint=name)
            rules.append(rule)
            name_lookups[name] = route

        self.adapter = Map(rules).bind('')
        self.name_lookups = name_lookups

        # Use an MRU cache for router lookups.
        self._lookup_cache = dict_type()
        self._lookup_cache_size = 10000
Example #3
0
    def get_content(self, openapi, base_url, schema_definitions):
        """
        Return all the links in the document, layed out by tag and operationId.
        """
        links_by_tag = dict_type()
        links = []

        for path, path_info in openapi.get('paths', {}).items():
            operations = {
                key: path_info[key] for key in path_info
                if key in METHODS
            }
            for operation, operation_info in operations.items():
                tag = lookup(operation_info, ['tags', 0])
                link = self.get_link(base_url, path, path_info, operation, operation_info, schema_definitions)
                if link is None:
                    continue

                if tag is None:
                    links.append(link)
                elif tag not in links_by_tag:
                    links_by_tag[tag] = [link]
                else:
                    links_by_tag[tag].append(link)

        sections = [
            Section(name=_simple_slugify(tag), title=tag.title(), content=links)
            for tag, links in links_by_tag.items()
        ]
        return links + sections
Example #4
0
    def get_paths(self, document, schema_defs=None):
        paths = dict_type()

        for link, name, sections in document.walk_links():
            path = urlparse(link.url).path
            operation_id = link.name
            tag = sections[0].name if sections else None
            method = link.method.lower()

            if path not in paths:
                paths[path] = {}
            paths[path][method] = self.get_operation(link, operation_id, tag=tag, schema_defs=schema_defs)

        return paths
Example #5
0
    def __init__(self, title='', description='', default=NO_DEFAULT, definitions=None, def_name=None):
        definitions = {} if (definitions is None) else dict_type(definitions)

        assert isinstance(title, str)
        assert isinstance(description, str)
        assert isinstance(definitions, dict)
        assert all(isinstance(k, str) for k in definitions.keys())
        assert all(isinstance(v, Validator) for v in definitions.values())

        self.title = title
        self.description = description
        self.definitions = definitions
        self.def_name = def_name

        # We need this global counter to determine what order fields have
        # been declared in when used with `Type`.
        self._creation_counter = Validator._creation_counter
        Validator._creation_counter += 1

        if default is not NO_DEFAULT:
            self.default = default
Example #6
0
    def encode(self, item, **options):
        defs = dict_type()
        struct = self.encode_to_data_structure(item,
                                               defs=defs,
                                               def_prefix='#/definitions/')
        struct['definitions'] = defs
        if options.get('to_data_structure'):
            return struct

        indent = options.get('indent')
        if indent:
            kwargs = {
                'ensure_ascii': False,
                'indent': 4,
                'separators': (',', ': ')
            }
        else:
            kwargs = {
                'ensure_ascii': False,
                'indent': None,
                'separators': (',', ':')
            }
        return json.dumps(struct, **kwargs).encode('utf-8')
Example #7
0
    def validate(self, value, definitions=None, allow_coerce=False):
        if value is None and self.allow_null:
            return None
        elif value is None:
            self.error('null')
        elif not isinstance(value, (dict, typing.Mapping)):
            self.error('type')

        definitions = self.get_definitions(definitions)
        validated = dict_type()

        # Ensure all property keys are strings.
        errors = {}
        if any(not isinstance(key, str) for key in value.keys()):
            self.error('invalid_key')

        # Min/Max properties
        if self.min_properties is not None:
            if len(value) < self.min_properties:
                if self.min_properties == 1:
                    self.error('empty')
                else:
                    self.error('min_properties')
        if self.max_properties is not None:
            if len(value) > self.max_properties:
                self.error('max_properties')

        # Required properties
        for key in self.required:
            if key not in value:
                errors[key] = self.error_message('required')

        # Properties
        for key, child_schema in self.properties.items():
            if key not in value:
                if child_schema.has_default():
                    validated[key] = child_schema.default
                continue
            item = value[key]
            try:
                validated[key] = child_schema.validate(
                    item,
                    definitions=definitions,
                    allow_coerce=allow_coerce
                )
            except ValidationError as exc:
                errors[key] = exc.detail

        # Pattern properties
        if self.pattern_properties:
            for key in list(value.keys()):
                for pattern, child_schema in self.pattern_properties.items():
                    if re.search(pattern, key):
                        item = value[key]
                        try:
                            validated[key] = child_schema.validate(
                                item, definitions=definitions,
                                allow_coerce=allow_coerce
                            )
                        except ValidationError as exc:
                            errors[key] = exc.detail

        # Additional properties
        remaining = [
            key for key in value.keys()
            if key not in set(validated.keys())
        ]

        if self.additional_properties is True:
            for key in remaining:
                validated[key] = value[key]
        elif self.additional_properties is False:
            for key in remaining:
                errors[key] = self.error_message('no_additional_properties')
        elif self.additional_properties is not None:
            child_schema = self.additional_properties
            for key in remaining:
                item = value[key]
                try:
                    validated[key] = child_schema.validate(
                        item,
                        definitions=definitions,
                        allow_coerce=allow_coerce
                    )
                except ValidationError as exc:
                    errors[key] = exc.detail

        if errors:
            raise ValidationError(errors)

        return validated
Example #8
0
    def encode_to_data_structure(self,
                                 item,
                                 defs=None,
                                 def_prefix=None,
                                 is_def=False):
        if issubclass(item, types.Type):
            item = item.validator

        if defs is not None and item.def_name and not is_def:
            defs[item.def_name] = self.encode_to_data_structure(item,
                                                                defs,
                                                                def_prefix,
                                                                is_def=True)
            return {'$ref': def_prefix + item.def_name}

        value = dict_type()
        if item.title:
            value['title'] = item.title
        if item.description:
            value['description'] = item.description
        if item.has_default():
            value['default'] = item.default
        if getattr(item, 'allow_null') is True:
            value['nullable'] = True

        if isinstance(item, validators.String):
            value['type'] = 'string'
            if item.max_length is not None:
                value['maxLength'] = item.max_length
            if item.min_length is not None:
                value['minLength'] = item.min_length
            if item.pattern is not None:
                value['pattern'] = item.pattern
            if item.format is not None:
                value['format'] = item.format
            return value

        elif isinstance(item, validators.NumericType):
            if isinstance(item, validators.Integer):
                value['type'] = 'integer'
            else:
                value['type'] = 'number'

            if item.minimum is not None:
                value['minimum'] = item.minimum
            if item.maximum is not None:
                value['maximum'] = item.maximum
            if item.exclusive_minimum:
                value['exclusiveMinimum'] = item.exclusive_minimum
            if item.exclusive_maximum:
                value['exclusiveMaximum'] = item.exclusive_maximum
            if item.multiple_of is not None:
                value['multipleOf'] = item.multiple_of
            if item.format is not None:
                value['format'] = item.format
            return value

        elif isinstance(item, validators.Boolean):
            value['type'] = 'boolean'
            return value

        elif isinstance(item, validators.Object):
            value['type'] = 'object'
            if item.properties:
                value['properties'] = dict_type([
                    (key,
                     self.encode_to_data_structure(value, defs, def_prefix))
                    for key, value in item.properties.items()
                ])
            if item.required:
                value['required'] = item.required
            return value

        elif isinstance(item, validators.Array):
            value['type'] = 'array'
            if item.items is not None:
                value['items'] = self.encode_to_data_structure(
                    item.items, defs, def_prefix)
            if item.additional_items:
                value['additionalItems'] = item.additional_items
            if item.min_items is not None:
                value['minItems'] = item.min_items
            if item.max_items is not None:
                value['maxItems'] = item.max_items
            if item.unique_items is not None:
                value['uniqueItems'] = item.unique_items
            return value

        raise Exception('Cannot encode item %s' % item)
Example #9
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