mirror of https://github.com/tiangolo/fastapi.git
tests passing for freeform queries
This commit is contained in:
parent
0e835695f1
commit
32f2db3fac
|
|
@ -45,7 +45,6 @@ sequence_types = tuple(sequence_annotation_to_type.keys())
|
||||||
|
|
||||||
mapping_annotation_to_type = {
|
mapping_annotation_to_type = {
|
||||||
Mapping: list,
|
Mapping: list,
|
||||||
List: list,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping_types = tuple(mapping_annotation_to_type.keys())
|
mapping_types = tuple(mapping_annotation_to_type.keys())
|
||||||
|
|
@ -567,16 +566,19 @@ def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
|
||||||
get_origin(annotation)
|
get_origin(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _annotation_is_mapping(annotation: Union[Type[Any], None]) -> bool:
|
def _annotation_is_mapping(annotation: Union[Type[Any], None]) -> bool:
|
||||||
if lenient_issubclass(annotation, (str, bytes)):
|
if lenient_issubclass(annotation, (str, bytes)):
|
||||||
return False
|
return False
|
||||||
return lenient_issubclass(annotation, mapping_types)
|
return lenient_issubclass(annotation, mapping_types)
|
||||||
|
|
||||||
|
|
||||||
def field_annotation_is_mapping(annotation: Union[Type[Any], None]) -> bool:
|
def field_annotation_is_mapping(annotation: Union[Type[Any], None]) -> bool:
|
||||||
return _annotation_is_mapping(annotation) or _annotation_is_sequence(
|
return _annotation_is_mapping(annotation) or _annotation_is_mapping(
|
||||||
get_origin(annotation)
|
get_origin(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def value_is_sequence(value: Any) -> bool:
|
def value_is_sequence(value: Any) -> bool:
|
||||||
return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
|
return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
@ -585,6 +587,7 @@ def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
|
||||||
return (
|
return (
|
||||||
lenient_issubclass(annotation, (BaseModel, UploadFile))
|
lenient_issubclass(annotation, (BaseModel, UploadFile))
|
||||||
or _annotation_is_sequence(annotation)
|
or _annotation_is_sequence(annotation)
|
||||||
|
or _annotation_is_mapping(annotation)
|
||||||
or is_dataclass(annotation)
|
or is_dataclass(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -623,6 +626,7 @@ def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> b
|
||||||
for sub_annotation in get_args(annotation)
|
for sub_annotation in get_args(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def field_annotation_is_scalar_mapping(annotation: Union[Type[Any], None]) -> bool:
|
def field_annotation_is_scalar_mapping(annotation: Union[Type[Any], None]) -> bool:
|
||||||
origin = get_origin(annotation)
|
origin = get_origin(annotation)
|
||||||
if origin is Union or origin is UnionType:
|
if origin is Union or origin is UnionType:
|
||||||
|
|
@ -639,7 +643,10 @@ def field_annotation_is_scalar_mapping(annotation: Union[Type[Any], None]) -> bo
|
||||||
for sub_annotation in get_args(annotation)
|
for sub_annotation in get_args(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
def field_annotation_is_scalar_sequence_mapping(annotation: Union[Type[Any], None]) -> bool:
|
|
||||||
|
def field_annotation_is_scalar_sequence_mapping(
|
||||||
|
annotation: Union[Type[Any], None]
|
||||||
|
) -> bool:
|
||||||
origin = get_origin(annotation)
|
origin = get_origin(annotation)
|
||||||
if origin is Union or origin is UnionType:
|
if origin is Union or origin is UnionType:
|
||||||
at_least_one_scalar_mapping = False
|
at_least_one_scalar_mapping = False
|
||||||
|
|
@ -651,10 +658,14 @@ def field_annotation_is_scalar_sequence_mapping(annotation: Union[Type[Any], Non
|
||||||
return False
|
return False
|
||||||
return at_least_one_scalar_mapping
|
return at_least_one_scalar_mapping
|
||||||
return field_annotation_is_mapping(annotation) and all(
|
return field_annotation_is_mapping(annotation) and all(
|
||||||
(field_annotation_is_scalar_sequence(sub_annotation) or field_annotation_is_scalar(sub_annotation))
|
(
|
||||||
|
field_annotation_is_scalar_sequence(sub_annotation)
|
||||||
|
or field_annotation_is_scalar(sub_annotation)
|
||||||
|
)
|
||||||
for sub_annotation in get_args(annotation)
|
for sub_annotation in get_args(annotation)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
|
def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
|
||||||
if lenient_issubclass(annotation, bytes):
|
if lenient_issubclass(annotation, bytes):
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
|
|
@ -652,7 +652,7 @@ def request_params_to_args(
|
||||||
received_params, (QueryParams, Headers)
|
received_params, (QueryParams, Headers)
|
||||||
):
|
):
|
||||||
value = received_params.getlist(field.alias) or field.default
|
value = received_params.getlist(field.alias) or field.default
|
||||||
if is_scalar_mapping_field(field) and isinstance(
|
elif is_scalar_mapping_field(field) and isinstance(
|
||||||
received_params, (QueryParams, Headers)
|
received_params, (QueryParams, Headers)
|
||||||
):
|
):
|
||||||
value = dict(received_params.multi_items()) or field.default
|
value = dict(received_params.multi_items()) or field.default
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -184,16 +184,21 @@ def get_query_param_required_type(query: int = Query()):
|
||||||
return f"foo bar {query}"
|
return f"foo bar {query}"
|
||||||
|
|
||||||
|
|
||||||
@app.get("/query/params")
|
|
||||||
def get_query_params(query: Mapping[str, int] = Query({})):
|
|
||||||
return f"foo bar {query}"
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/query/sequence-params")
|
@app.get("/query/sequence-params")
|
||||||
def get_sequence_query_params(query: Mapping[str, List[int]] = Query({})):
|
def get_sequence_query_params(query: Mapping[str, List[int]] = Query({})):
|
||||||
return f"foo bar {query}"
|
return f"foo bar {query}"
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/query/mapping-params")
|
||||||
|
def get_mapping_query_params(queries: Mapping[str, str] = Query({})):
|
||||||
|
return f"foo bar {queries['foo']} {queries['bar']}"
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/query/mapping-sequence-params")
|
||||||
|
def get_sequence_mapping_query_params(queries: Mapping[str, List[int]] = Query({})):
|
||||||
|
return f"foo bar {queries}"
|
||||||
|
|
||||||
|
|
||||||
@app.get("/enum-status-code", status_code=http.HTTPStatus.CREATED)
|
@app.get("/enum-status-code", status_code=http.HTTPStatus.CREATED)
|
||||||
def get_enum_status_code():
|
def get_enum_status_code():
|
||||||
return "foo bar"
|
return "foo bar"
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -408,3 +408,9 @@ def test_query_frozenset_query_1_query_1_query_2():
|
||||||
response = client.get("/query/frozenset/?query=1&query=1&query=2")
|
response = client.get("/query/frozenset/?query=1&query=1&query=2")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == "1,2"
|
assert response.json() == "1,2"
|
||||||
|
|
||||||
|
|
||||||
|
def test_mapping_query():
|
||||||
|
response = client.get("/query/mapping-params/?foo=fuzz&bar=buzz")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == "foo bar fuzz buzz"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue