[Python-Dev] smarter temporary file object (SF #415692)

dustin at v.igoro.us dustin at v.igoro.us
Wed Jan 3 06:27:40 CET 2007


I came across a complaint that PEP 0042 had become a graveyard of
neglected ideas, and decided to have a look through and implement
something.  Creating a smarter temporary file object seemed simple
enough.

Oddly, even after GvR re-opened it, I can't post an attachment to that
tracker item (it's under "Feature Requests" -- does it need to get moved
to "Patches" first?), but the implementation is short, so it's included
below.  This is intended to be appended to Lib/tempfile.py (and thus
assumes that module's globals are present).

I would appreciate it if the gurus of python-dev could take a peek and
let me know if this is unsuitable or incorrect for any reason.  It's not
the most straightforward implementatio -- I used the optimization
techniques I found in TemporaryFile.

If this looks good, I'll prepare a patch against trunk, including an
additional chunk of documentation and a unit test.

Dustin

                     -----cut-here-----

try:
  from cStringIO import StringIO
except:
  from StringIO import StringIO

class SpooledTemporaryFile:
    """Temporary file wrapper, specialized to switch from
    StringIO to a real file when it exceeds a certain size or
    when a fileno is needed.
    """
    _rolled = False

    def __init__(self, max_size=0, mode='w+b', bufsize=-1,
                 suffix="", prefix=template, dir=None):
        self._file = StringIO()
        self._max_size = max_size
        self._TemporaryFileArgs = (mode, bufsize, suffix, prefix, dir)

    def _check(self, file):
        if self._rolled: return
        if file.tell() > self.__dict__['_max_size']:
            self._rollover(file)

    def _rollover(self, file):
        args = self.__dict__['_TemporaryFileArgs']
        self.__dict__.clear() # clear attributes cached by __getattr__
        newfile = self._file = TemporaryFile(*args)
        newfile.write(file.getvalue())
        newfile.seek(file.tell(), 0)
        self._rolled = True
        
        # replace patched functions with the new file's methods
        self.write = newfile.write
        self.writelines = newfile.writelines
        self.fileno = newfile.fileno

    def write(self, s):
        file = self.__dict__['_file']
        rv = file.write(s)
        self._check(file)
        return rv

    def writelines(self, iterable):
        file = self.__dict__['_file']
        rv = file.writelines(iterable)
        self._check(file)
        return rv

    def fileno(self):
        self._rollover(self.__dict__['_file'])
        return self.fileno()

    def __getattr__(self, name):
        file = self.__dict__['_file']
        a = getattr(file, name)
        if type(a) != type(0):
            setattr(self, name, a)
        return a


More information about the Python-Dev mailing list