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 get_content(self, swagger, 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 swagger.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 __init__(self, title='', description='', default=NO_DEFAULT, allow_null=False, 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()) if allow_null and default is NO_DEFAULT: default = None if default is not NO_DEFAULT: self.default = default self.title = title self.description = description self.allow_null = allow_null 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
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_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 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 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 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 = {} for key in value.keys(): if not isinstance(key, str): errors[key] = [self.error_message('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', field_name=key)] # 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.messages # Pattern properties if self.pattern_properties: for key in list(value.keys()): for pattern, child_schema in self.pattern_properties.items(): if isinstance(key, str) and 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.messages # Additional properties remaining = [ key for key in value.keys() if key not in set(validated.keys()) | set(errors.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('invalid_property')] 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.messages if errors: error_messages = [] for key, messages in errors.items(): for message in messages: index = [key] if message.index is None else [key] + message.index error_message = ErrorMessage(message.text, message.code, index) error_messages.append(error_message) raise ValidationError(error_messages) 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: 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
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: 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