Author: Antonio Cuni <anto.c...@gmail.com> Branch: Changeset: r52808:599b70ca76ec Date: 2012-02-23 16:26 +0100 http://bitbucket.org/pypy/pypy/changeset/599b70ca76ec/
Log: merge heads diff --git a/pypy/module/_io/__init__.py b/pypy/module/_io/__init__.py --- a/pypy/module/_io/__init__.py +++ b/pypy/module/_io/__init__.py @@ -28,6 +28,7 @@ } def init(self, space): + MixedModule.init(self, space) w_UnsupportedOperation = space.call_function( space.w_type, space.wrap('UnsupportedOperation'), @@ -35,3 +36,9 @@ space.newdict()) space.setattr(self, space.wrap('UnsupportedOperation'), w_UnsupportedOperation) + + def shutdown(self, space): + # at shutdown, flush all open streams. Ignore I/O errors. + from pypy.module._io.interp_iobase import get_autoflushher + get_autoflushher(space).flush_all(space) + diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -5,6 +5,8 @@ from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError, operationerrfmt from pypy.rlib.rstring import StringBuilder +from pypy.rlib import rweakref + DEFAULT_BUFFER_SIZE = 8192 @@ -43,6 +45,8 @@ self.space = space self.w_dict = space.newdict() self.__IOBase_closed = False + self.streamholder = None # needed by AutoFlusher + get_autoflushher(space).add(self) def getdict(self, space): return self.w_dict @@ -98,6 +102,7 @@ space.call_method(self, "flush") finally: self.__IOBase_closed = True + get_autoflushher(space).remove(self) def flush_w(self, space): if self._CLOSED(): @@ -303,3 +308,52 @@ read = interp2app(W_RawIOBase.read_w), readall = interp2app(W_RawIOBase.readall_w), ) + + +# ------------------------------------------------------------ +# functions to make sure that all streams are flushed on exit +# ------------------------------------------------------------ + +class StreamHolder(object): + + def __init__(self, w_iobase): + self.w_iobase_ref = rweakref.ref(w_iobase) + w_iobase.autoflusher = self + + def autoflush(self, space): + w_iobase = self.w_iobase_ref() + if w_iobase is not None: + space.call_method(w_iobase, 'flush') # XXX: ignore IOErrors? + + +class AutoFlusher(object): + + def __init__(self, space): + self.streams = {} + + def add(self, w_iobase): + assert w_iobase.streamholder is None + holder = StreamHolder(w_iobase) + w_iobase.streamholder = holder + self.streams[holder] = None + + def remove(self, w_iobase): + holder = w_iobase.streamholder + if holder is not None: + del self.streams[holder] + + def flush_all(self, space): + while self.streams: + for streamholder in self.streams.keys(): + try: + del self.streams[streamholder] + except KeyError: + pass # key was removed in the meantime + else: + streamholder.autoflush(space) + + +def get_autoflushher(space): + return space.fromcache(AutoFlusher) + + diff --git a/pypy/module/_io/test/test_fileio.py b/pypy/module/_io/test/test_fileio.py --- a/pypy/module/_io/test/test_fileio.py +++ b/pypy/module/_io/test/test_fileio.py @@ -160,3 +160,20 @@ f.close() assert repr(f) == "<_io.FileIO [closed]>" +def test_flush_at_exit(): + from pypy import conftest + from pypy.tool.option import make_config, make_objspace + from pypy.tool.udir import udir + + tmpfile = udir.join('test_flush_at_exit') + config = make_config(conftest.option) + space = make_objspace(config) + space.appexec([space.wrap(str(tmpfile))], """(tmpfile): + import io + f = io.open(tmpfile, 'w') + f.write('42') + # no flush() and no close() + import sys; sys._keepalivesomewhereobscure = f + """) + space.finish() + assert tmpfile.read() == '42' _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit