From 40294a7c9e68f2355bc71e2ccb9be1473c11b533 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Thu, 13 Feb 2025 13:36:59 -0800 Subject: [PATCH] standarize filename from upload (#4734) * standarize filename from upload * all my friends hate fast api upload file * make deprecated filename private * lstrip the "/" Co-authored-by: Masen Furer --------- Co-authored-by: Masen Furer --- reflex/app.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index 67d4f5b91..2c8e889fc 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -22,6 +22,7 @@ from typing import ( TYPE_CHECKING, Any, AsyncIterator, + BinaryIO, Callable, Coroutine, Dict, @@ -35,12 +36,15 @@ from typing import ( get_type_hints, ) -from fastapi import FastAPI, HTTPException, Request, UploadFile +from fastapi import FastAPI, HTTPException, Request +from fastapi import UploadFile as FastAPIUploadFile from fastapi.middleware import cors from fastapi.responses import JSONResponse, StreamingResponse from fastapi.staticfiles import StaticFiles from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn from socketio import ASGIApp, AsyncNamespace, AsyncServer +from starlette.datastructures import Headers +from starlette.datastructures import UploadFile as StarletteUploadFile from starlette_admin.contrib.sqla.admin import Admin from starlette_admin.contrib.sqla.view import ModelView @@ -231,6 +235,53 @@ class OverlayFragment(Fragment): pass +@dataclasses.dataclass(frozen=True) +class UploadFile(StarletteUploadFile): + """A file uploaded to the server. + + Args: + file: The standard Python file object (non-async). + filename: The original file name. + size: The size of the file in bytes. + headers: The headers of the request. + """ + + file: BinaryIO + + path: Optional[Path] = dataclasses.field(default=None) + + _deprecated_filename: Optional[str] = dataclasses.field(default=None) + + size: Optional[int] = dataclasses.field(default=None) + + headers: Headers = dataclasses.field(default_factory=Headers) + + @property + def name(self) -> Optional[str]: + """Get the name of the uploaded file. + + Returns: + The name of the uploaded file. + """ + if self.path: + return self.path.name + + @property + def filename(self) -> Optional[str]: + """Get the filename of the uploaded file. + + Returns: + The filename of the uploaded file. + """ + console.deprecate( + feature_name="UploadFile.filename", + reason="Use UploadFile.name instead.", + deprecation_version="0.7.1", + removal_version="0.8.0", + ) + return self._deprecated_filename + + @dataclasses.dataclass( frozen=True, ) @@ -1585,7 +1636,7 @@ def upload(app: App): The upload function. """ - async def upload_file(request: Request, files: List[UploadFile]): + async def upload_file(request: Request, files: List[FastAPIUploadFile]): """Upload a file. Args: @@ -1661,7 +1712,8 @@ def upload(app: App): file_copies.append( UploadFile( file=content_copy, - filename=file.filename, + path=Path(file.filename.lstrip("/")) if file.filename else None, + _deprecated_filename=file.filename, size=file.size, headers=file.headers, )