classification
Title: Make tempfiles subclass IOBase
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.9
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: Dutcho, asvetlov, martin.panter, sergiitk, serhiy.storchaka, terry.reedy, wumpus
Priority: normal Keywords:

Created on 2018-06-03 20:53 by Dutcho, last changed 2019-12-11 20:46 by terry.reedy. This issue is now closed.

Messages (12)
msg318585 - (view) Author: (Dutcho) Date: 2018-06-03 20:53
I'd expect isinstance(tempfile.TemporaryFile(), io.IOBase) to be True as you can read() from and write() to the temp file.

However, on Python 3.6.5 64 bit on Windows 7 above isinstance() == False and and type(tempfile.TemporaryFile()) == tempfile._TemporaryFileWrapper, which has no super class (other than object).
Whereas, on Python 3.6.1 on iOS 11.4 (Pythonista 3.2) above isinstance() == True and type(tempfile.TemporaryFile()) == io.BufferedRandom, which has io.IOBase as its (indirect) super class.
The difference is likely caused by tempfile line 565 that equals TemporaryFile = NamedTemporaryFile in case of Windows.

This may be somewhat related to issue 26175, but isn't a duplicate as 26175 is on a temp file's attributes, and this issue is on its type
msg319090 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-08 17:57
Martin, I added you because this Tempfile issue is related to #26175.
msg319193 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2018-06-10 01:43
I think it is an implementation detail whether the result subclasses IOBase or just implements its API. Why do you want to check the base class, and why IOBase in particular, rather than BufferedIOBase, RawIOBase, or TextIOBase?
msg344599 - (view) Author: Greg Lindahl (wumpus) Date: 2019-06-04 16:18
This is breaking aiohttp client file multipart uploads from temporary files. I'd be willing to bet that a lot of libraries do isinstance(foo, io.IOBase) deep in their guts.
msg358211 - (view) Author: Sergii Tkachenko (sergiitk) Date: 2019-12-10 18:44
Confirming this to be a thing on Python 3.7.5 / OS X 10.15.1.

In [31]: f = tempfile.NamedTemporaryFile()
In [32]: isinstance(f, io.IOBase)
Out[32]: False
msg358212 - (view) Author: Sergii Tkachenko (sergiitk) Date: 2019-12-10 18:50
Affected as well:
Python 3.8.0 (default, Nov  3 2019, 10:55:54)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
msg358214 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-12-10 19:07
Even if make TemporaryFile a subclass of IOBase (I am not sure we should do this) you could only use this in Python 3.9 and newer. I think it is better to fix this issue on the aiohttp side. aiohttp already registers payload types for a bunch of file-like types. You can also register it yourself:

aiohttp.payload.PAYLOAD_REGISTRY.register(aiohttp.payload.IOBasePayload, tempfile.TemporaryFile)

Seems IOBasePayload needs only read() and close() methods.
msg358218 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2019-12-10 19:44
Agree, aiohttp can be fixed easily.

If somebody wants to make a pull request -- you are welcome!
https://github.com/aio-libs/aiohttp/issues/4432
msg358220 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-12-10 20:05
Actually things are more complex. TemporaryFile is not a class, it is a function, so it does not make sense to use it with isinstance(). And if add support for TemporaryFile, NamedTemporaryFile and SpooledTemporaryFile should be supported too.

It may be easier to use a virtual subclassing: register IOBasePayload with a class which has an __instancecheck__() method which checks the existence of attributes "read" and "close".
msg358230 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-12-10 22:50
TemporaryFile() returns an instance of _TemporaryFileWrapper.  isinstance(TemporaryFile(), io.IOBase) is a sensible thing to do and would be True if _TemporaryFileWrapper subclassed the appropriate io base file.

The base class for IDLE's stdxxx pseudofiles does this and hence, for instance,

>>> sys.stdout
<idlelib.run.StdOutputFile object at 0x0000023BEB515F70>
>>> isinstance(sys.stdout, io.IOBase)
True

I believe that tempfile long predates io, added in 2.6.  Since the IO base classes are not 'abstract base classes' in the sense of subclassing abc.ABCMeta, the tempfile classes cannot just be registered as implementing them.  And tempfile has never been re-written to be based on io, by subclassing io base classes.

Doing so would fix this issue.  It *might* result in simpler tempfile code (but I would not be sure until it is done).  It would also address (but not automatically fix) #26175. I think SpooledTemporaryFile would likely be the hardest.  Martin and Serhiy are correct that a change would be an enhancement, not a bugfix.
msg358253 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-12-11 07:03
I have doubts that making _TemporaryFileWrapper a subclass of IOBase can make it simpler. It can make it more complex. _TemporaryFileWrapper is a proxy class with the __getattr__ method which not just return attributes of the underlying file, but wraps methods so they have references to the _TemporaryFileWrapper instance. If subclass IOBase you will need to write implementations of all methods of IOBase and its subclasses. You could also to reproduce the hierarhy of io classes to support binary and text, buffered and unbuffered files.

IDLE's pseudofiles are simpler because they represent only text files.
msg358278 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-12-11 20:46
Looking at the tempfile code more, I agree with Serhiy that changing it should be rejected.  Python is a duck-typed language (essentially what Martin said). People should not be over-zealous in using instance checks.
 
The doc specifically says that TemporaryFile returns a *file-like object*
https://docs.python.org/3/glossary.html#term-file-like-object
which only require implementing the interface.
History
Date User Action Args
2019-12-11 20:46:17terry.reedysetstatus: open -> closed
resolution: rejected
messages: + msg358278

stage: test needed -> resolved
2019-12-11 07:03:01serhiy.storchakasetmessages: + msg358253
2019-12-10 22:50:55terry.reedysetversions: - Python 3.7, Python 3.8
title: temp file isn't IOBase -> Make tempfiles subclass IOBase
messages: + msg358230

type: behavior -> enhancement
stage: test needed
2019-12-10 20:05:51serhiy.storchakasetmessages: + msg358220
2019-12-10 19:44:22asvetlovsetmessages: + msg358218
2019-12-10 19:37:50terry.reedysetversions: + Python 3.7, Python 3.9
2019-12-10 19:08:00serhiy.storchakasetnosy: + serhiy.storchaka, asvetlov
messages: + msg358214
2019-12-10 18:50:12sergiitksetmessages: + msg358212
versions: + Python 3.8, - Python 3.7
2019-12-10 18:44:53sergiitksetnosy: + sergiitk

messages: + msg358211
versions: + Python 3.7, - Python 3.6
2019-06-04 16:18:15wumpussetnosy: + wumpus
messages: + msg344599
2018-06-10 01:43:55martin.pantersetmessages: + msg319193
2018-06-08 17:57:20terry.reedysetnosy: + terry.reedy, martin.panter
messages: + msg319090
2018-06-03 20:53:05Dutchocreate