Replies: 4 comments 1 reply
-
I'm not sure how you're encountering an error. This works just fine for me: from starlette.applications import Starlette
from starlette.responses import JSONResponse, PlainTextResponse
from starlette.requests import Request
from starlette.routing import Route
async def homepage(request: Request) -> JSONResponse | PlainTextResponse:
return JSONResponse({"hello": "world"})
app = Starlette(routes=[Route("/", homepage)]) No errors from the latest version of mypy or pyright. |
Beta Was this translation helpful? Give feedback.
0 replies
-
Repo: https://github.com/zackees/torrent-worker-coordinator problematic function signature @app.get("/torrent/{name}/download")
async def route_torrent_download(
name: str, api_key: str = ApiKeyHeader
) -> FileResponse | JSONResponse:
"""Download a torrent by name."""
if not is_authenticated(api_key):
return JSONResponse({"error": "Not authenticated"}, status_code=401) # type: ignore
db = get_db()
torrent = TorrentManager.get_torrent(db, name)
if torrent is None:
return JSONResponse({"error": "Torrent not found"}, status_code=404) # type: ignore
torrent_path = TORRENTS_PATH / name
if not os.path.exists(torrent_path):
return JSONResponse( # type: ignore
{"error": "Torrent file not found, even though it should exist"},
status_code=500,
)
return FileResponse(
torrent_path, media_type="application/x-bittorrent", filename=torrent_path.name
) error output $ ./prod
2024-12-09 18:19:18,458 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2024-12-09 18:19:18,458 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("torrents")
2024-12-09 18:19:18,459 INFO sqlalchemy.engine.Engine [raw sql] ()
2024-12-09 18:19:18,460 INFO sqlalchemy.engine.Engine COMMIT
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Scripts\uvicorn.exe\__main__.py", line 8, in <module>
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\click\core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\click\core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\click\core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\main.py", line 410, in main
run(
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\main.py", line 578, in run
server.run()
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\server.py", line 61, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\AppData\Roaming\uv\python\cpython-3.11.5-windows-x86_64-none\Lib\asyncio\runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "C:\Users\niteris\AppData\Roaming\uv\python\cpython-3.11.5-windows-x86_64-none\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\AppData\Roaming\uv\python\cpython-3.11.5-windows-x86_64-none\Lib\asyncio\base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\server.py", line 68, in serve
config.load()
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\config.py", line 473, in load
self.loaded_app = import_from_string(self.app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\uvicorn\importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\AppData\Roaming\uv\python\cpython-3.11.5-windows-x86_64-none\Lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\src\torrent_worker_coordinator\app.py", line 186, in <module>
@app.get("/torrent/{name}/download")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\fastapi\routing.py", line 704, in decorator
self.add_api_route(
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\fastapi\routing.py", line 643, in add_api_route
route = route_class(
^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\fastapi\routing.py", line 448, in __init__
self.response_field = create_response_field(
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\niteris\dev\mikeadams\torrent-worker-coordinator\.venv\Lib\site-packages\fastapi\utils.py", line 101, in create_response_field
raise fastapi.exceptions.FastAPIError(
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that starlette.responses.FileResponse | starlette.responses.JSONResponse is a valid Pydantic field type. If you are using a return type annotation that is not a valid Pydantic field (e.g. Union[Response, dict, None]) you can disable generating the response model from the type annotation with the path operation decorator parameter response_model=None. Read more: https://fastapi.tiangolo.com/tutorial/response-model/
Cleaning up background processes... requirements.txt
|
Beta Was this translation helpful? Give feedback.
1 reply
-
Maybe this is FastAPI's interaction with pydantic and I need to file there? |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Currently FastAPI does not allow definitions of the form:
This is useful for using Json for errors but allowing the FileResponse to succeed in the valid path. Right now starlette says it can't form a pedantic object from the return type of FileResponse | JSONResponse.
My humble request is that this be allowed. Right now I'm working around the issue using
mypy
#type ignore
to return it anyway. It would be super duper awesome for dx to be able to declare the response as this | that without having to tell mypy to shutup.However, this is a super low priority thing as there is a clear work-around, so I just wanted to offer this suggestion in case others have mentioned it as well.
Feel free to archive this request for any reason.
Beta Was this translation helpful? Give feedback.
All reactions