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
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
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
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
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
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')
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
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)
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