According the docs for the tempfile module, SpooledTemporaryFile() should operate "exactly as TemporaryFile() does". However, while playing around trying to learn the module I found a couple of places where this is not the case: import tempfile hello = bytes('Hello World!', encoding='utf-8') tf = tempfile.TemporaryFile() stf = tempfile.SpooledTemporaryFile() tf.write(hello) stf.write(hello) # (1) Read after write behaviour differs... >>> print(tf.read()) b'Hello World' >>> print(stf.read()) b'' # ...unless you seek first >>> tf.seek(0) >>> stf.seek(0) >>> print(tf.read()) b'Hello World' >>> print(stf.read()) b'Hello World' # (2) Name attribute is fragile... >>> print(tf.name) 3 print(stf.name) AttributeError: '_io.BytesIO' object has no attribute 'name' # ...until StringIO object replaced stf.rollover() print(stf.name) # 4 I'm not sure if this should be categorised as a documentation or code issue. In either case please be gentle -- I'm still just learning Python (evaluating it as a [now likely] replacement for PHP for web application development in our company). I'm filing this bug because, as a beginner, I was confused by the inconsistency between the docs and the actual behaviour. I'd be happy to try and write documentation and/or unit tests about this, if somebody would be willing to review them for me... :-)
I've attached a patch to SpooledTemporaryFile (and its test class) to remove the suprising exceptions. SpooledTemporaryFile uses a io.StringIO for storage (in self._file) until it reaches a certain size (or rollover() is called), at which point it switches to a file object (or _TemporaryFileWrapper on non-posix platforms). This implementation detail should be abstracted away from the user. The interface mismatch there which caused an AttributeError to be thrown -- but only if the file size was new, or below a certain size.
Some properties seem to be broken no matter if the underlying storage system is file or StringIO. Properties: encoding, newlines, and softspace And the method: xreadlines() I'm not sure what the correct behaviour should be (although I'm pretty sure xreadlines() should just be deleted -- but when?), so I haven't tried to patch the code. The attached patch is a just (a beginners idea of a) test to confirm the problem.