【问题标题】:AttributeError: 'UploadFile' object has no attribute 'tell' - FastAPIAttributeError: 'UploadFile' 对象没有属性 'tell' - FastAPI
【发布时间】:2021-08-03 15:14:41
【问题描述】:

所以我正在尝试使用 FastAPI 构建一个 API,它获取图像并将图像保存在文件夹中。问题是,当我尝试使用 Pillow 执行此操作时,即使我使用的是 await,我也会收到 AttributeError: 'UploadFile' object has no attribute 'tell' 错误。

我的代码示例如下:

from fastapi import FastAPI, File, UploadFile
from PIL import Image

app = FastAPI()

@app.post('/upload')
async def create_upload_file(file: UploadFile = File(...)):
    picture = await Image.open(file)
    filePath = '/absolute/path/to/folder/',
    await picture.save(filePath, "PNG")
    return {"success": file.filename}

完整的错误:

File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 369, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 59, in __call__
    return await self.app(scope, receive, send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\fastapi\applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc from None
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc from None
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\starlette\routing.py", line 52, in app
    response = await func(request)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\fastapi\routing.py", line 216, in app
    raw_response = await run_endpoint_function(
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\fastapi\routing.py", line 149, in run_endpoint_function
    return await dependant.call(**values)
  File "C:\Users\User\Desktop\Folder\FastAPI\APITwo\core\.\main.py", line 8, in create_upload_file
    picture = await Image.open(file)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\PIL\Image.py", line 3013, in open
    im = _open_core(fp, filename, prefix, formats)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\PIL\Image.py", line 2995, in _open_core
    im = factory(fp, filename)
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\PIL\ImageFile.py", line 121, in __init__
    self._open()
  File "c:\users\User\miniconda3\envs\fastapi\lib\site-packages\PIL\IptcImagePlugin.py", line 88, in _open
    offset = self.fp.tell()
AttributeError: 'UploadFile' object has no attribute 'tell'
c:\users\User\miniconda3\envs\fastapi\lib\site-packages\uvicorn\protocols\http\h11_impl.py:376: RuntimeWarning: coroutine 'UploadFile.read' was never awaited       
  self.transport.close()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

【问题讨论】:

  • 使用“await Image.open(file.file)”

标签: python python-imaging-library fastapi


【解决方案1】:

使用shutil 进行实验。我可以让它像这样工作:

from fastapi import FastAPI, File, UploadFile
import shutil

app = FastAPI()

@app.post('/upload')
async def create_upload_file(file: UploadFile = File(...)):
    path: Path = Path("/absolute/apth/to/file.png")
    try:
        with path.open("wb") as buffer:
            shutil.copyfileobj(file.file, buffer)
    finally:
        image.file.close()

【讨论】:

    【解决方案2】:

    您可以使用aiofiles逐块保存文件异步块,这将避免阻塞您的应用程序的大文件事件循环。

    from fastapi import FastAPI, File, UploadFile
    import aiofiles
    from pathlib import Path
    
    CHUNK_SIZE = 1024
    
    app = FastAPI()
    
    @app.post('/upload')
    async def create_upload_file(file: UploadFile = File(...)):
        fp = Path('/absolute/path/to/folder/') / file.filename
        async with aiofiles.open(fp, 'wb') as fh:
            while True:
                chunk = await file.read(CHUNK_SIZE)
                if not chunk:
                    break
                await fh.write(chunk)
        return {"success": file.filename}
    

    【讨论】:

      猜你喜欢
      • 2014-04-15
      • 2021-09-20
      • 1970-01-01
      • 2021-07-05
      • 2021-09-23
      • 1970-01-01
      • 2012-12-01
      • 2021-04-19
      • 2021-11-22
      相关资源
      最近更新 更多