"""OpenAPI core wrappers module""" from six import iteritems from six.moves.urllib.parse import urljoin from openapi_core.exceptions import ( OpenAPIMappingError, MissingParameterError, InvalidContentTypeError, InvalidServerError, ) SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING = { 'path': 'view_args', 'query': 'args', 'headers': 'headers', 'cookies': 'cookies', } class RequestParameters(dict): valid_locations = ['path', 'query', 'headers', 'cookies'] def __getitem__(self, location): self.validate_location(location) return self.setdefault(location, {}) def __setitem__(self, location, value): raise NotImplementedError @classmethod def validate_location(cls, location): if location not in cls.valid_locations: raise OpenAPIMappingError( "Unknown parameter location: {0}".format(str(location))) class BaseRequestFactory(object): def get_operation(self, request, spec): server = self._get_server(request, spec) operation_pattern = request.full_url_pattern.replace( server.default_url, '') method = request.method.lower() return spec.get_operation(operation_pattern, method) def _get_server(self, request, spec): for server in spec.servers: if server.default_url in request.full_url_pattern: return server raise InvalidServerError( "Invalid request server {0}".format(request.full_url_pattern)) class RequestParametersFactory(BaseRequestFactory): def __init__(self, attr_mapping=SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING): self.attr_mapping = attr_mapping def create(self, request, spec): operation = self.get_operation(request, spec) params = RequestParameters() for param_name, param in iteritems(operation.parameters): try: raw_value = self._get_raw_value(request, param) except MissingParameterError: if param.required: raise if not param.schema or not param.schema.default: continue raw_value = param.schema.default value = param.unmarshal(raw_value) params[param.location][param_name] = value return params def _get_raw_value(self, request, param): request_location = self.attr_mapping[param.location] request_attr = getattr(request, request_location) try: return request_attr[param.name] except KeyError: raise MissingParameterError( "Missing required `{0}` parameter".format(param.name)) class RequestBodyFactory(BaseRequestFactory): def create(self, request, spec): operation = self.get_operation(request, spec) if operation.request_body is None: return None try: media_type = operation.request_body[request.mimetype] except KeyError: raise InvalidContentTypeError( "Invalid media type `{0}`".format(request.mimetype)) return media_type.unmarshal(request.data) class BaseOpenAPIRequest(object): host_url = NotImplemented path = NotImplemented path_pattern = NotImplemented method = NotImplemented args = NotImplemented view_args = NotImplemented headers = NotImplemented cookies = NotImplemented data = NotImplemented mimetype = NotImplemented @property def full_url_pattern(self): return urljoin(self.host_url, self.path_pattern) def get_parameters(self, spec): return RequestParametersFactory().create(self, spec) def get_body(self, spec): return RequestBodyFactory().create(self, spec)