mirror of
https://github.com/correl/openapi-core.git
synced 2025-03-18 17:00:11 -09:00
Parameter with required and allow empty value support
This commit is contained in:
parent
279ace9ed0
commit
a86c49d1be
7 changed files with 88 additions and 20 deletions
|
@ -33,5 +33,9 @@ class InvalidValue(OpenAPIMappingError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EmptyValue(OpenAPIMappingError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UndefinedSchemaProperty(OpenAPIMappingError):
|
class UndefinedSchemaProperty(OpenAPIMappingError):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
"""OpenAPI core parameters module"""
|
"""OpenAPI core parameters module"""
|
||||||
import logging
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from openapi_core.exceptions import EmptyValue
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -8,20 +11,32 @@ class Parameter(object):
|
||||||
"""Represents an OpenAPI operation Parameter."""
|
"""Represents an OpenAPI operation Parameter."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, name, location, schema=None, default=None,
|
self, name, location, schema=None, required=False,
|
||||||
required=False, deprecated=False, allow_empty_value=False,
|
deprecated=False, allow_empty_value=False,
|
||||||
items=None, collection_format=None):
|
items=None, collection_format=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.location = location
|
self.location = location
|
||||||
self.schema = schema
|
self.schema = schema
|
||||||
self.default = default
|
self.required = True if self.location == "path" else required
|
||||||
self.required = required
|
|
||||||
self.deprecated = deprecated
|
self.deprecated = deprecated
|
||||||
self.allow_empty_value = allow_empty_value
|
self.allow_empty_value = (
|
||||||
|
allow_empty_value if self.location == "query" else False
|
||||||
|
)
|
||||||
self.items = items
|
self.items = items
|
||||||
self.collection_format = collection_format
|
self.collection_format = collection_format
|
||||||
|
|
||||||
def unmarshal(self, value):
|
def unmarshal(self, value):
|
||||||
|
if self.deprecated:
|
||||||
|
warnings.warn(
|
||||||
|
"{0} parameter is deprecated".format(self.name),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (self.location == "query" and value == "" and
|
||||||
|
not self.allow_empty_value):
|
||||||
|
raise EmptyValue(
|
||||||
|
"Value of {0} parameter cannot be empty.".format(self.name))
|
||||||
|
|
||||||
if not self.schema:
|
if not self.schema:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -38,7 +53,7 @@ class ParametersGenerator(object):
|
||||||
for parameter in paramters:
|
for parameter in paramters:
|
||||||
parameter_deref = self.dereferencer.dereference(parameter)
|
parameter_deref = self.dereferencer.dereference(parameter)
|
||||||
|
|
||||||
default = parameter_deref.get('default')
|
allow_empty_value = parameter_deref.get('allowEmptyValue')
|
||||||
required = parameter_deref.get('required', False)
|
required = parameter_deref.get('required', False)
|
||||||
|
|
||||||
schema_spec = parameter_deref.get('schema', None)
|
schema_spec = parameter_deref.get('schema', None)
|
||||||
|
@ -50,6 +65,7 @@ class ParametersGenerator(object):
|
||||||
parameter_deref['name'],
|
parameter_deref['name'],
|
||||||
Parameter(
|
Parameter(
|
||||||
parameter_deref['name'], parameter_deref['in'],
|
parameter_deref['name'], parameter_deref['in'],
|
||||||
schema=schema, default=default, required=required,
|
schema=schema, required=required,
|
||||||
|
allow_empty_value=allow_empty_value,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -149,6 +149,7 @@ class SchemaFactory(object):
|
||||||
schema_type = schema_deref['type']
|
schema_type = schema_deref['type']
|
||||||
model = schema_deref.get('x-model', None)
|
model = schema_deref.get('x-model', None)
|
||||||
required = schema_deref.get('required', False)
|
required = schema_deref.get('required', False)
|
||||||
|
default = schema_deref.get('default', None)
|
||||||
properties_spec = schema_deref.get('properties', None)
|
properties_spec = schema_deref.get('properties', None)
|
||||||
items_spec = schema_deref.get('items', None)
|
items_spec = schema_deref.get('items', None)
|
||||||
nullable = schema_deref.get('nullable', False)
|
nullable = schema_deref.get('nullable', False)
|
||||||
|
@ -165,7 +166,7 @@ class SchemaFactory(object):
|
||||||
|
|
||||||
return Schema(
|
return Schema(
|
||||||
schema_type, model=model, properties=properties, items=items,
|
schema_type, model=model, properties=properties, items=items,
|
||||||
required=required, nullable=nullable, enum=enum,
|
required=required, default=default, nullable=nullable, enum=enum,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -64,27 +64,30 @@ class RequestParametersFactory(BaseRequestFactory):
|
||||||
params = RequestParameters()
|
params = RequestParameters()
|
||||||
for param_name, param in iteritems(operation.parameters):
|
for param_name, param in iteritems(operation.parameters):
|
||||||
try:
|
try:
|
||||||
value = self._unmarshal_param(request, param)
|
raw_value = self._get_raw_value(request, param)
|
||||||
except MissingParameterError:
|
except MissingParameterError:
|
||||||
if param.required:
|
if param.required:
|
||||||
raise
|
raise
|
||||||
continue
|
|
||||||
|
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
|
params[param.location][param_name] = value
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def _unmarshal_param(self, request, param):
|
def _get_raw_value(self, request, param):
|
||||||
request_location = self.attr_mapping[param.location]
|
request_location = self.attr_mapping[param.location]
|
||||||
request_attr = getattr(request, request_location)
|
request_attr = getattr(request, request_location)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
raw_value = request_attr[param.name]
|
return request_attr[param.name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MissingParameterError(
|
raise MissingParameterError(
|
||||||
"Missing required `{0}` parameter".format(param.name))
|
"Missing required `{0}` parameter".format(param.name))
|
||||||
|
|
||||||
return param.unmarshal(raw_value)
|
|
||||||
|
|
||||||
|
|
||||||
class RequestBodyFactory(BaseRequestFactory):
|
class RequestBodyFactory(BaseRequestFactory):
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,12 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- pets
|
- pets
|
||||||
parameters:
|
parameters:
|
||||||
|
- name: page
|
||||||
|
in: query
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 1
|
||||||
- name: limit
|
- name: limit
|
||||||
in: query
|
in: query
|
||||||
description: How many items to return at one time (max 100)
|
description: How many items to return at one time (max 100)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from six import iteritems
|
||||||
from openapi_core.exceptions import (
|
from openapi_core.exceptions import (
|
||||||
MissingParameterError, InvalidContentTypeError, InvalidServerError,
|
MissingParameterError, InvalidContentTypeError, InvalidServerError,
|
||||||
InvalidValueType, UndefinedSchemaProperty, MissingPropertyError,
|
InvalidValueType, UndefinedSchemaProperty, MissingPropertyError,
|
||||||
|
EmptyValue,
|
||||||
)
|
)
|
||||||
from openapi_core.media_types import MediaType
|
from openapi_core.media_types import MediaType
|
||||||
from openapi_core.operations import Operation
|
from openapi_core.operations import Operation
|
||||||
|
@ -135,6 +136,7 @@ class TestPetstore(object):
|
||||||
assert parameters == {
|
assert parameters == {
|
||||||
'query': {
|
'query': {
|
||||||
'limit': 20,
|
'limit': 20,
|
||||||
|
'page': 1,
|
||||||
'ids': [12, 13],
|
'ids': [12, 13],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,14 +188,10 @@ class TestPetstore(object):
|
||||||
path_pattern=path_pattern, args=query_params,
|
path_pattern=path_pattern, args=query_params,
|
||||||
)
|
)
|
||||||
|
|
||||||
parameters = request.get_parameters(spec)
|
with pytest.raises(EmptyValue):
|
||||||
|
request.get_parameters(spec)
|
||||||
body = request.get_body(spec)
|
body = request.get_body(spec)
|
||||||
|
|
||||||
assert parameters == {
|
|
||||||
'query': {
|
|
||||||
'limit': None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert body is None
|
assert body is None
|
||||||
|
|
||||||
def test_get_pets_none_value(self, spec):
|
def test_get_pets_none_value(self, spec):
|
||||||
|
@ -213,6 +211,7 @@ class TestPetstore(object):
|
||||||
assert parameters == {
|
assert parameters == {
|
||||||
'query': {
|
'query': {
|
||||||
'limit': None,
|
'limit': None,
|
||||||
|
'page': 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
tests/unit/test_paramters.py
Normal file
39
tests/unit/test_paramters.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openapi_core.exceptions import EmptyValue
|
||||||
|
from openapi_core.parameters import Parameter
|
||||||
|
|
||||||
|
|
||||||
|
class TestParameterUnmarshal(object):
|
||||||
|
|
||||||
|
def test_deprecated(self):
|
||||||
|
param = Parameter('param', 'query', deprecated=True)
|
||||||
|
value = 'test'
|
||||||
|
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
result = param.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
def test_query_valid(self):
|
||||||
|
param = Parameter('param', 'query')
|
||||||
|
value = 'test'
|
||||||
|
|
||||||
|
result = param.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
def test_query_empty(self):
|
||||||
|
param = Parameter('param', 'query')
|
||||||
|
value = ''
|
||||||
|
|
||||||
|
with pytest.raises(EmptyValue):
|
||||||
|
param.unmarshal(value)
|
||||||
|
|
||||||
|
def test_query_allow_empty_value(self):
|
||||||
|
param = Parameter('param', 'query', allow_empty_value=True)
|
||||||
|
value = ''
|
||||||
|
|
||||||
|
result = param.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
Loading…
Add table
Reference in a new issue