Fastapi: [FEATURE] Correctly typed file upload handlers

Created on 13 May 2019  路  4Comments  路  Source: tiangolo/fastapi

I see no way of implementing a file upload handler that passes type checking:

@app.post("/api/uploadone")
async def upload_file(
    file: UploadFile = File(...)  # Incompatible default for argument "file" (default has type "File", argument has type "UploadFile") mypy(error)
) -> Dict[str, str]:
    return {"filename": file.filename}

@app.post("/api/upload")
async def upload_files(
    files: List[UploadFile] = File(...)  # Incompatible default for argument "files" (default has type "File", argument has type "List[UploadFile]") mypy(error)
) -> Dict[str, List[str]]:
    return {"filenames": [file.filename for file in files]}

Describe the solution you'd like
Use the special types UploadFile and List[UploadFile] to be treated specially the same way as any subclass of BaseModel is treated specially to mean "read data from the body" without the need for a default value.

@app.post("/api/uploadone")
async def upload_file(file: UploadFile) -> Dict[str, str]:
    return {"filename": file.filename}

@app.post("/api/upload")
async def upload_files(files: List[UploadFile]) -> Dict[str, List[str]]:
    return {"filenames": [file.filename for file in files]}

Describe alternatives you've considered

  1. Make File(...) compatible with UploadFile and List[UploadFile].
    While satisfying the type-level compatibility may not be very difficult with some gratuitous multiple inheritance, File(...) would end up with a pretty much nonsense implementation. That might not be so bad if File(...) were only used as a token.
  2. Use default values of the correct type:
    python file: UploadFile = UploadFile(...)
    and
    python file: List[UploadFile] = [UploadFile(...)]
    This may work (with help from the library interpreting these values as mere indicators that the files should be parsed from the body) but I am afraid it is still surprising for a regular python user.

Other clarifications
Not sure if this qualifies as a clarification, but the reason I am asking is mainly because FastAPI is so amazingly awesome! Using the new type annotations in Python to create such an elegant web framework is nothing short of brilliant!
There are frameworks that do something similar in other languages (check out Rocket in Rust), but I was really not expecting such features to land in a Python framework any time soon. Great job, @tiangolo !

enhancement

Most helpful comment

Thanks @Victor-Savu ! :smile:

This is available/fixed now, with FastAPI version 0.22.0. :tada:

@sbv-trueenergy And it's also fixed for Depends, Security, etc.


I'll close this issue now, but feel free to add more comments or create new issues.

All 4 comments

And same thing with for example Depends:

 error: Incompatible default for argument "token" (default has type "Depends", argument has type "str")

Thanks for the report!

I tried to "check it quickly" to see if I could solve it with just a bit of mypy-foo... and here I am now, after several hours (:joy: )... But I have a solution in PR #226.

I'll leave it until tomorrow to see if anyone finds any use case that could be affected, and then I'll merge it tomorrow.

It fixes the mypy errors for all these parameter utils, including File, Query, Depends, Security, etc.


FastAPI is so amazingly awesome! Using the new type annotations in Python to create such an elegant web framework is nothing short of brilliant!
There are frameworks that do something similar in other languages (check out Rocket in Rust), but I was really not expecting such features to land in a Python framework any time soon. Great job, @tiangolo !

Thanks a lot! I'm glad to hear you're liking it :smile: :tada: :rocket:

@tiangolo Thank you for looking into this! You found a very elegant solution.

Thanks @Victor-Savu ! :smile:

This is available/fixed now, with FastAPI version 0.22.0. :tada:

@sbv-trueenergy And it's also fixed for Depends, Security, etc.


I'll close this issue now, but feel free to add more comments or create new issues.

Was this page helpful?
0 / 5 - 0 ratings