¿Cómo cargar un archivo en FastAPI, luego enviarlo a Amazon S3 y finalmente procesarlo?
Tengo un punto final de FastAPI que recibe un archivo, lo carga en s3 y luego lo procesa. Todo funciona bien excepto el procesamiento, que falla con este mensaje:
lang-txt
File "/usr/local/lib/python3.9/site-packages/starlette/datastructures.py", line 441, in read
return self.file.read(size)
File "/usr/local/lib/python3.9/tempfile.py", line 735, in read
return self._file.read(*args)
ValueError: Operación de E/S en archivo cerrado.
Mi código simplificado se ve así:
async def process(file: UploadFile):
reader = csv.reader(iterdecode(file.file.read(), "utf-8"), dialect="excel") # ¡Esto falla!
datarows = []
for row in reader:
datarows.append(row)
return datarows
¿Cómo puedo leer el contenido del archivo cargado?
ACTUALIZACIÓN
Logré aislar un poco más el problema. Aquí está mi punto final simplificado:
import boto3
from loguru import logger
from botocore.exceptions import ClientError
UPLOAD = True
@router.post("/")
async def upload(file: UploadFile = File(...)):
if UPLOAD:
# Cargar el archivo
s3_client = boto3.client("s3", endpoint_url="http://localstack:4566")
try:
s3_client.upload_fileobj(file.file, "local", "myfile.txt")
except ClientError as e:
logger.error(e)
contents = await file.read()
return JSONResponse({"message": "¡Éxito!"})
Si UPLOAD
es True, obtengo el error. Si no lo es, todo funciona bien. Parece que boto3 está cerrando el archivo después de cargarlo. ¿Hay alguna forma de volver a abrir el archivo? ¿O enviar una copia a upload_fileobj
?
davy.ai
El problema parece estar en
file.file
, el cual ya está abierto y se está utilizando para la subida. Para leer el contenido del archivo subido, puedes utilizar el atributocontents
del objetoUploadFile
en su lugar. Aquí tienes una versión actualizada de tu código:Con respecto al problema actualizado de boto3 cerrando el archivo, una solución es buscar el archivo al principio antes de leerlo de nuevo, como se muestra a continuación: