pythonfilewerkzeug

How to read a jpeg from disk and instantiate it as 'werkzeug.datastructures.FileStorage'?


python  3.10.11
werkzeug  2.3.7

I have a jpeg in /mnt/dragon.jpeg

I want to write unit test for a method, which has werkzeug.datastructures.FileStorage as input, and behavior is save it to a path.

I try to instantiate it with codes below:

import os
from werkzeug.datastructures import FileStorage

PATH = "/mnt/dragon.jpeg"

def get_file(filepath: str) -> FileStorage:
    filename = os.path.basename(filepath)
    with open(filepath, 'rb') as file:
        return FileStorage(file, name=filename)

file = get_file(PATH)

The ipython instance output are:

In [8]: file
Out[8]: <FileStorage: '/mnt/dragon.jpeg' (None)>

In [9]: file.save("/mnt/saved.jpeg")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 1
----> 1 file.save("/mnt/saved.jpeg")

File ~/.local/lib/python3.10/site-packages/werkzeug/datastructures/file_storage.py:129, in FileStorage.save(self, dst, buffer_size)
    126     close_dst = True
    128 try:
--> 129     copyfileobj(self.stream, dst, buffer_size)
    130 finally:
    131     if close_dst:

File ~/miniconda3/lib/python3.10/shutil.py:195, in copyfileobj(fsrc, fdst, length)
    193 fdst_write = fdst.write
    194 while True:
--> 195     buf = fsrc_read(length)
    196     if not buf:
    197         break

ValueError: read of closed file

How to make the werkzeug.datastructures.FileStorage file can be saved outside the scope of open?


Solution

  • You can use in-memory bytes buffer(io.BytesIO). The current problem with your code is that python closes the underlying file as soon as the with block completes its execution.

    import os
    import io
    from werkzeug.datastructures import FileStorage
    
    PATH = "/mnt/dragon.jpeg"
    
    def get_file(filepath: str) -> FileStorage:
        filename = os.path.basename(filepath)
        with open(filepath, 'rb') as file:
            return FileStorage(io.BytesIO(file.read()), name=filename)
    
    file = get_file(PATH)