[pypy-commit] pypy default: make sure to flush all _io streams when we exit the interpreter
antocuni
noreply at buildbot.pypy.org
Thu Feb 23 16:27:10 CET 2012
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch:
Changeset: r52806:d4dee87e47cc
Date: 2012-02-23 12:06 +0100
http://bitbucket.org/pypy/pypy/changeset/d4dee87e47cc/
Log: make sure to flush all _io streams when we exit the interpreter
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,8 @@
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 flush_all_streams
+ flush_all_streams(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
@@ -43,6 +43,7 @@
self.space = space
self.w_dict = space.newdict()
self.__IOBase_closed = False
+ register_flushable_stream(space, self)
def getdict(self, space):
return self.w_dict
@@ -98,6 +99,8 @@
space.call_method(self, "flush")
finally:
self.__IOBase_closed = True
+ flushable_streams = get_flushable_streams(space)
+ del flushable_streams[self]
def flush_w(self, space):
if self._CLOSED():
@@ -303,3 +306,32 @@
read = interp2app(W_RawIOBase.read_w),
readall = interp2app(W_RawIOBase.readall_w),
)
+
+
+# ------------------------------------------------------------
+# functions to make sure that all streams are flushed on exit
+# ------------------------------------------------------------
+
+class IoState:
+ def __init__(self, space):
+ self.flushable_streams = {}
+
+def get_flushable_streams(space):
+ return space.fromcache(IoState).flushable_streams
+
+def register_flushable_stream(space, w_stream):
+ streams = get_flushable_streams(space)
+ streams[w_stream] = None
+
+def flush_all_streams(space):
+ flushable_streams = get_flushable_streams(space)
+ while flushable_streams:
+ for w_stream in flushable_streams.keys():
+ assert isinstance(w_stream, W_IOBase)
+ try:
+ del flushable_streams[w_stream]
+ except KeyError:
+ pass # key was removed in the meantime
+ else:
+ space.call_method(w_stream, 'flush') # XXX: ignore IOErrors?
+
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'
More information about the pypy-commit
mailing list