[pypy-svn] r38737 - in pypy/dist/pypy: interpreter module/_file module/_file/test module/sys rlib
arigo at codespeak.net
arigo at codespeak.net
Tue Feb 13 18:55:49 CET 2007
Author: arigo
Date: Tue Feb 13 18:55:44 2007
New Revision: 38737
Modified:
pypy/dist/pypy/interpreter/baseobjspace.py
pypy/dist/pypy/interpreter/mixedmodule.py
pypy/dist/pypy/module/_file/app_file.py
pypy/dist/pypy/module/_file/test/test_file.py
pypy/dist/pypy/module/_file/test/test_file_extra.py
pypy/dist/pypy/module/sys/__init__.py
pypy/dist/pypy/module/sys/app.py
pypy/dist/pypy/rlib/streamio.py
Log:
Add flush-on-exit capability to all our file objects.
Done with a new internal dict sys.pypy__exithandlers__. In
space.finish(), we pop key/value pairs from this dictionary and just
call the value, as long as the dict is not empty. This is probably
generally useful for situations where a number of small things must be
"finished" in any order, but finishing them might possibly create more
stuff that must itself be "finished" too. The fact that it's a
dictionary means that it's cheap to add and remove many things from it.
Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py (original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py Tue Feb 13 18:55:44 2007
@@ -201,6 +201,12 @@
w_exitfunc = self.sys.getdictvalue_w(self, 'exitfunc')
if w_exitfunc is not None:
self.call_function(w_exitfunc)
+ w_exithandlers = self.sys.getdictvalue_w(self, 'pypy__exithandlers__')
+ if w_exithandlers is not None:
+ while self.is_true(w_exithandlers):
+ w_key_value = self.call_method(w_exithandlers, 'popitem')
+ w_key, w_value = self.unpacktuple(w_key_value, 2)
+ self.call_function(w_value)
if self.config.objspace.std.withdictmeasurement:
from pypy.objspace.std.dictmultiobject import report
report()
Modified: pypy/dist/pypy/interpreter/mixedmodule.py
==============================================================================
--- pypy/dist/pypy/interpreter/mixedmodule.py (original)
+++ pypy/dist/pypy/interpreter/mixedmodule.py Tue Feb 13 18:55:44 2007
@@ -216,10 +216,10 @@
else:
appname = name
mod = Module(space, space.wrap(appname))
- moddict = space.unwrap(mod.getdict())
res = new.module(appname)
- res.__dict__.update(moddict)
sys.modules[appname] = res
+ moddict = space.unwrap(mod.getdict())
+ res.__dict__.update(moddict)
return res
def compilemodule(name, interactive=False):
Modified: pypy/dist/pypy/module/_file/app_file.py
==============================================================================
--- pypy/dist/pypy/module/_file/app_file.py (original)
+++ pypy/dist/pypy/module/_file/app_file.py Tue Feb 13 18:55:44 2007
@@ -1,5 +1,9 @@
"""NOT_RPYTHON"""
+import sys
+import _file
+
+
class file(object):
"""file(name[, mode[, buffering]]) -> file object
@@ -22,32 +26,29 @@
_closed = True # Until the file is successfully opened
def __init__(self, name, mode='r', buffering=-1):
- import _file
- self._name = name
- self.softspace = 0 # Required according to file object docs
- self.encoding = None # This is not used internally by file objects
- self._closed = False
- self.stream = _file.open_file_as_stream(self._name, mode, buffering)
- self._mode = mode
- self.fd = self.stream.try_to_find_file_descriptor()
- assert self.fd != -1
-
+ stream = _file.open_file_as_stream(name, mode, buffering)
+ fd = stream.try_to_find_file_descriptor()
+ assert fd != -1
+ self._fdopenstream(fd, mode, buffering, name, stream)
+
def fdopen(cls, fd, mode='r', buffering=-1):
f = cls.__new__(cls)
- f._fdopen(fd, mode, buffering, '<fdopen>')
+ stream = _file.fdopen_as_stream(fd, mode, buffering)
+ f._fdopenstream(fd, mode, buffering, '<fdopen>', stream)
return f
fdopen = classmethod(fdopen)
- def _fdopen(self, fd, mode, buffering, name):
- import _file
+ def _fdopenstream(self, fd, mode, buffering, name, stream):
self.fd = fd
self._name = name
self.softspace = 0 # Required according to file object docs
self.encoding = None # This is not used internally by file objects
self._closed = False
- self.stream = _file.fdopen_as_stream(fd, mode, buffering)
+ self.stream = stream
self._mode = mode
-
+ if stream.flushable():
+ sys.pypy__exithandlers__[stream] = stream.flush
+
def getnewlines(self):
"end-of-line convention used in this file"
@@ -227,6 +228,7 @@
may return an exit status upon closing."""
if not self._closed and hasattr(self, 'stream'):
self._closed = True
+ sys.pypy__exithandlers__.pop(self.stream, None)
self.stream.close()
__del__ = close
Modified: pypy/dist/pypy/module/_file/test/test_file.py
==============================================================================
--- pypy/dist/pypy/module/_file/test/test_file.py (original)
+++ pypy/dist/pypy/module/_file/test/test_file.py Tue Feb 13 18:55:44 2007
@@ -116,3 +116,21 @@
assert res == "hello\n"
assert type(res) is str
f.close()
+
+
+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):
+ f = open(tmpfile, 'w')
+ f.write('42')
+ # no flush() and no close()
+ import sys; sys._keepalivesomewhereobscure = f
+ """)
+ space.finish()
+ assert tmpfile.read() == '42'
Modified: pypy/dist/pypy/module/_file/test/test_file_extra.py
==============================================================================
--- pypy/dist/pypy/module/_file/test/test_file_extra.py (original)
+++ pypy/dist/pypy/module/_file/test/test_file_extra.py Tue Feb 13 18:55:44 2007
@@ -1,4 +1,4 @@
-import os, random
+import os, random, sys
from pypy.tool.udir import udir
import py
from pypy.interpreter.mixedmodule import testmodule
@@ -14,6 +14,9 @@
def setup_module(mod):
mod._file = testmodule("_file")
udir.join('sample').write(SAMPLE)
+ # workaround for testing _file on top of CPython
+ if not hasattr(sys, 'pypy_objspaceclass'):
+ sys.pypy__exithandlers__ = {}
class BaseROTests:
Modified: pypy/dist/pypy/module/sys/__init__.py
==============================================================================
--- pypy/dist/pypy/module/sys/__init__.py (original)
+++ pypy/dist/pypy/module/sys/__init__.py Tue Feb 13 18:55:44 2007
@@ -72,6 +72,7 @@
'__excepthook__' : 'app.excepthook',
'exit' : 'app.exit',
'exitfunc' : 'app.exitfunc',
+ 'pypy__exithandlers__' : 'app.pypy__exithandlers__', # internal
'getfilesystemencoding' : 'app.getfilesystemencoding',
'callstats' : 'app.callstats',
'getdefaultencoding' : 'app.getdefaultencoding',
Modified: pypy/dist/pypy/module/sys/app.py
==============================================================================
--- pypy/dist/pypy/module/sys/app.py (original)
+++ pypy/dist/pypy/module/sys/app.py Tue Feb 13 18:55:44 2007
@@ -26,6 +26,8 @@
def exitfunc():
"""Placeholder for sys.exitfunc(), which is called when PyPy exits."""
+pypy__exithandlers__ = {}
+
#import __builtin__
def getfilesystemencoding():
Modified: pypy/dist/pypy/rlib/streamio.py
==============================================================================
--- pypy/dist/pypy/rlib/streamio.py (original)
+++ pypy/dist/pypy/rlib/streamio.py Tue Feb 13 18:55:44 2007
@@ -4,7 +4,8 @@
- This module contains various stream classes which provide a subset of the
classic Python I/O API: read(n), write(s), tell(), seek(offset, whence=0),
- readall(), readline(), truncate(size), flush(), close(), peek().
+ readall(), readline(), truncate(size), flush(), close(), peek(),
+ flushable(), try_to_find_file_descriptor().
- This is not for general usage:
* read(n) may return less than n bytes, just like os.read().
@@ -13,6 +14,7 @@
there is no __del__() closing the stream for you.
* some methods may raise NotImplementedError.
* peek() returns some (or no) characters that have already been read ahead.
+ * flushable() returns True/False if flushing that stream is useful/pointless.
- A 'basis stream' provides I/O using a low-level API, like the os, mmap or
socket modules.
@@ -197,6 +199,9 @@
def flush(self):
pass
+ def flushable(self):
+ return False
+
def close(self):
pass
@@ -338,6 +343,10 @@
def flush(self):
self.mm.flush()
+ def flushable(self):
+ import mmap
+ return self.access == mmap.ACCESS_WRITE
+
def try_to_find_file_descriptor(self):
return self.fd
@@ -352,6 +361,7 @@
("readline", []),
("truncate", [int]),
("flush", []),
+ ("flushable", []),
("close", []),
("peek", []),
("try_to_find_file_descriptor", []),
@@ -613,10 +623,10 @@
write = PassThrough("write", flush_buffers=True)
truncate = PassThrough("truncate", flush_buffers=True)
flush = PassThrough("flush", flush_buffers=True)
+ flushable = PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
class BufferingOutputStream(Stream):
@@ -669,9 +679,11 @@
truncate = PassThrough("truncate", flush_buffers=True)
flush = PassThrough("flush", flush_buffers=True)
close = PassThrough("close", flush_buffers=True)
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ def flushable(self):
+ return True
class LineBufferingOutputStream(BufferingOutputStream):
@@ -688,9 +700,6 @@
self.do_write(self.buf[:p])
self.buf = self.buf[p:]
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
-
# ____________________________________________________________
@@ -720,10 +729,10 @@
return data
flush = PassThrough("flush", flush_buffers=False)
+ flushable= PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
class TextInputFilter(Stream):
@@ -853,10 +862,10 @@
write = PassThrough("write", flush_buffers=True)
truncate = PassThrough("truncate", flush_buffers=True)
flush = PassThrough("flush", flush_buffers=True)
+ flushable = PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
class TextOutputFilter(Stream):
@@ -879,10 +888,10 @@
readline = PassThrough("readline", flush_buffers=False)
truncate = PassThrough("truncate", flush_buffers=False)
flush = PassThrough("flush", flush_buffers=False)
+ flushable = PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
# _________________________________________________
@@ -930,10 +939,10 @@
write = PassThrough("write", flush_buffers=False)
truncate = PassThrough("truncate", flush_buffers=False)
flush = PassThrough("flush", flush_buffers=False)
+ flushable = PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
class EncodingOutputFilter(Stream):
@@ -958,8 +967,7 @@
readline = PassThrough("readline", flush_buffers=False)
truncate = PassThrough("truncate", flush_buffers=False)
flush = PassThrough("flush", flush_buffers=False)
+ flushable = PassThrough("flushable", flush_buffers=False)
close = PassThrough("close", flush_buffers=False)
-
- def try_to_find_file_descriptor(self):
- return self.base.try_to_find_file_descriptor()
-
+ try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor",
+ flush_buffers=False)
More information about the Pypy-commit
mailing list