Why doesn't tempfile.SpooledTemporaryFile impl

2020-07-11 05:15发布

问题:

In Python 3.6.1, I've tried wrapping a tempfile.SpooledTemporaryFile in an io.TextIOWrapper:

with tempfile.SpooledTemporaryFile() as tfh:
    do_some_download(tfh)
    tfh.seek(0)
    wrapper = io.TextIOWrapper(tfh, encoding='utf-8')
    yield from do_some_text_formatting(wrapper)

The line wrapper = io.TextIOWrapper(tfh, encoding='utf-8') gives me an error:

AttributeError: 'SpooledTemporaryFile' object has no attribute 'readable'

If I create a simple class like this, I can bypass the error (I get similar errors for writable and seekable):

class MySpooledTempfile(tempfile.SpooledTemporaryFile):                                                                                
    @property                                                                                                                          
    def readable(self):                                                                                                                
        return self._file.readable                                                                                                     

    @property                                                                                                                          
    def writable(self):                                                                                                                
        return self._file.writable                                                                                                     

    @property                                                                                                                          
    def seekable(self):                                                                                                                
        return self._file.seekable 

Is there a good reason why tempfile.SpooledTemporaryFile doesn't already have these attributes?

回答1:

SpooledTemporaryFile actually uses 2 different _file implementations under the hood - initially an io Buffer (StringIO or BytesIO), until it rolls over and creates a "file-like object" via tempfile.TemporaryFile() (for example, when max_size is exceeded).

io.TextIOWrapper requires a BufferedIOBase base class/interface, which is provided by io.StringIO and io.BytesIO, but not necessarily by the object returned by TemporaryFile() (though in my testing on OSX, TemporaryFile() returned an _io.BufferedRandom object, which had the desired interface, my theory is this may depend on platform).

So, I would expect your MySpooledTempfile wrapper to possibly fail on some platforms after rollover.