Skip to content

Instantly share code, notes, and snippets.

@jimkring
Last active September 4, 2024 18:14
Show Gist options
  • Save jimkring/6b6a7c22cacca311b1f05b71f4139971 to your computer and use it in GitHub Desktop.
Save jimkring/6b6a7c22cacca311b1f05b71f4139971 to your computer and use it in GitHub Desktop.
Working around an issue with Nuitka-commercial's handling of embedded file and it's incompatibility with anyio/asyncio async file IO, which is used by Starlette's FileResponse class.
import os
import stat
from fastapi.responses import FileResponse
from starlette.types import Receive, Scope, Send
class FileResponseSynchronous(FileResponse):
"""
This works around an issue building with `Nuitka-commercial` and embedding files
(so they are not present on disk), since that doesn't work with anyio/asyncio.
See issue: https://github.com/Nuitka/Nuitka-commercial/issues/159
"""
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
"""This is identical to FileResponse's `__call__()` method, but with a conversion to synchronous file IO."""
if self.stat_result is None:
try:
stat_result = os.stat(self.path)
self.set_stat_headers(stat_result)
except FileNotFoundError:
raise RuntimeError(f"File at path {self.path} does not exist.")
else:
mode = stat_result.st_mode
if not stat.S_ISREG(mode):
raise RuntimeError(f"File at path {self.path} is not a file.")
await send(
{
"type": "http.response.start",
"status": self.status_code,
"headers": self.raw_headers,
}
)
if scope["method"].upper() == "HEAD":
await send({"type": "http.response.body", "body": b"", "more_body": False})
elif "extensions" in scope and "http.response.pathsend" in scope["extensions"]:
await send({"type": "http.response.pathsend", "path": str(self.path)})
else:
with open(self.path, mode="rb") as file:
more_body = True
while more_body:
chunk = file.read(self.chunk_size)
more_body = len(chunk) == self.chunk_size
await send(
{
"type": "http.response.body",
"body": chunk,
"more_body": more_body,
}
)
if self.background is not None:
await self.background()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment