Not quite clear to me if this is a bug or a feature request as I may be doing something out of the ordinary.
Using class based views, my tests return errors using methods (inside cbv) that have multiple path decorators attached to them. When using vanilla FastAPI without cbv the tests pass.
To Reproduce
Credit to @smparekh for the demo below, which I modified slightly to show the issue.
Simple main.py app:
fromfastapiimportFastAPI, APIRouterfromfastapi_utils.cbvimportcbvrouter=APIRouter()
fake_items_db= [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
@cbv(router)classRootHandler:
@router.get("/items/?")@router.get("/items/{item_path:path}")@router.get("/database/{item_path:path}")defroot(self, item_path: str=None, item_query: str=None):
ifitem_path:
return {"item_path": item_path}
elifitem_query:
return {"item_query": item_query}
else:
returnfake_items_dbapp=FastAPI()
app.include_router(router)simple test_main.py
from .mainimportrouterfromstarlette.testclientimportTestClientfrom .mainimportfake_items_dbclient=TestClient(router)
deftest_item_path():
resp=client.get("items/Bar")
assertresp.status_code==200assertresp.json() == {"item_path": "Bar"}
deftest_item_query():
resp=client.get("items/?item_query=Bar")
assertresp.status_code==200assertresp.json() == {"item_query": "Bar"}
deftest_list():
resp=client.get("items/")
assertresp.status_code==200assertresp.json() ==fake_items_dbdeftest_database():
resp=client.get("database/")
assertresp.status_code==200assertresp.json() ==fake_items_dbtraceback
traceback from the first test (others are the same)
===================================FAILURES===================================________________________________test_item_path________________________________deftest_item_path():
>resp=client.get("items/Bar")
app/test_main_mult_decorators.py:11: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/requests/sessions.py:546: ingetreturnself.request('GET', url, **kwargs)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/testclient.py:413: inrequestreturnsuper().request(
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/requests/sessions.py:533: inrequestresp=self.send(prep, **send_kwargs)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/requests/sessions.py:646: insendr=adapter.send(request, **kwargs)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/testclient.py:243: insendraiseexcfromNone
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/testclient.py:240: insendloop.run_until_complete(self.app(scope, receive, send))
../../../miniconda3/envs/web-server-eval/lib/python3.8/asyncio/base_events.py:612: inrun_until_completereturnfuture.result()
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/routing.py:550: in__call__awaitroute.handle(scope, receive, send)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/routing.py:227: inhandleawaitself.app(scope, receive, send)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/starlette/routing.py:41: inappresponse=awaitfunc(request)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ request=<starlette.requests.Requestobjectat0x118cd3670>asyncdefapp(request: Request) ->Response:
try:
body=Noneifbody_field:
ifis_body_form:
body=awaitrequest.form()
else:
body_bytes=awaitrequest.body()
ifbody_bytes:
body=awaitrequest.json()
exceptExceptionase:
logger.error(f"Error getting request body: {e}")
raiseHTTPException(
status_code=400, detail="There was an error parsing the body"
) fromesolved_result=awaitsolve_dependencies(
request=request,
dependant=dependant,
body=body,
dependency_overrides_provider=dependency_overrides_provider,
)
values, errors, background_tasks, sub_response, _ =solved_resultiferrors:
>raiseRequestValidationError(errors, body=body)
Efastapi.exceptions.RequestValidationError: 1validationerrorforRequestEquery->selfEfieldrequired (type=value_error.missing)
../../../miniconda3/envs/web-server-eval/lib/python3.8/site-packages/fastapi/routing.py:145: RequestValidationErrorExpected behavior
Ideally tests work as in vanilla FastAPI without cbv.
Environment:
- OS: tested on macOS and Linux
>>>importfastapi_utils>>>importfastapi>>>importpydantic.utils>>>importpytest>>>>>>print(fastapi_utils.__version__)
0.2.0>>>print(fastapi.__version__)
0.52.0>>>print(pydantic.utils.version_info())
pydanticversion: 1.4pydanticcompiled: Falseinstallpath: /Users/bfalk/miniconda3/envs/web-server-eval/lib/python3.8/site-packages/pydanticpythonversion: 3.8.1 (default, Jan82020, 16:15:59) [Clang4.0.1 (tags/RELEASE_401/final)]
platform: macOS-10.14.6-x86_64-i386-64bitoptionaldeps. installed: ['typing-extensions']
>>>print(pytest.__version__)
5.3.5
Not quite clear to me if this is a bug or a feature request as I may be doing something out of the ordinary.
Using class based views, my tests return errors using methods (inside
cbv) that have multiple path decorators attached to them. When using vanilla FastAPI withoutcbvthe tests pass.To Reproduce
Credit to @smparekh for the demo below, which I modified slightly to show the issue.
Simple
main.pyapp:simple
test_main.pytraceback
traceback from the first test (others are the same)
Expected behavior
Ideally tests work as in vanilla FastAPI without cbv.
Environment: