[pypy-svn] pypy default: file.writelines() should release the stream lock between two lines

amauryfa commits-noreply at bitbucket.org
Thu Feb 10 17:10:59 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r41789:f95db44eb35a
Date: 2011-02-10 15:45 +0100
http://bitbucket.org/pypy/pypy/changeset/f95db44eb35a/

Log:	file.writelines() should release the stream lock between two lines

diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -216,20 +216,6 @@
         self.softspace = 0
         self.getstream().write(data)
 
-    def direct_writelines(self, w_lines):    # note: a wrapped list!
-        stream = self.getstream()
-        space = self.space
-        w_iterator = space.iter(w_lines)
-        self.softspace = 0
-        while True:
-            try:
-                w_line = space.next(w_iterator)
-            except OperationError, e:
-                if not e.match(space, space.w_StopIteration):
-                    raise
-                break  # done
-            stream.write(space.str_w(w_line))
-
     def direct___iter__(self):
         self.getstream()
         return self
@@ -374,12 +360,6 @@
 Note that due to buffering, flush() or close() may be needed before
 the file on disk reflects the data written.""")
 
-    _decl(locals(), "writelines", ['self', W_Root],
-        """writelines(sequence_of_strings) -> None.  Write the strings to the file.
-
-Note that newlines are not added.  The sequence can be any iterable object
-producing strings. This is equivalent to calling write() for each string.""")
-
     _decl(locals(), "__iter__", ['self'],
         """Iterating over files, as in 'for line in f:', returns each line of
 the file one by one.""")
@@ -412,6 +392,24 @@
         else:
             return self.space.str_w(self.space.repr(w_name))
 
+    def file_writelines(self, w_lines):
+        """writelines(sequence_of_strings) -> None.  Write the strings to the file.
+
+Note that newlines are not added.  The sequence can be any iterable object
+producing strings. This is equivalent to calling write() for each string."""
+
+        space = self.space
+        w_iterator = space.iter(w_lines)
+        while True:
+            try:
+                w_line = space.next(w_iterator)
+            except OperationError, e:
+                if not e.match(space, space.w_StopIteration):
+                    raise
+                break  # done
+            self.file_write(space.str_w(w_line))
+    file_writelines.unwrap_spec = ['self', W_Root]
+
     def file_readinto(self, w_rwbuffer):
         """readinto() -> Undocumented.  Don't use this; it may go away."""
         # XXX not the most efficient solution as it doesn't avoid the copying
@@ -509,6 +507,7 @@
                               doc="Support for 'print'."),
     __repr__ = interp2app(W_File.file__repr__),
     readinto = interp2app(W_File.file_readinto),
+    writelines = interp2app(W_File.file_writelines),
     __weakref__ = make_weakref_descr(W_File),
     **dict([(name, interp2app(getattr(W_File, 'file_' + name)))
                 for name in W_File._exposed_method_names])

diff --git a/pypy/module/_file/test/test_file_extra.py b/pypy/module/_file/test/test_file_extra.py
--- a/pypy/module/_file/test/test_file_extra.py
+++ b/pypy/module/_file/test/test_file_extra.py
@@ -382,6 +382,20 @@
         assert len(somelines) > 200
         assert somelines == lines[:len(somelines)]
 
+    def test_nasty_writelines(self):
+        # The stream lock should be released between writes
+        fn = self.temptestfile
+        f = file(fn, 'w')
+        def nasty():
+            for i in range(5):
+                if i == 3:
+                    # should not raise because of acquired lock
+                    f.close()
+                yield str(i)
+        exc = raises(ValueError, f.writelines, nasty())
+        assert exc.value.message == "I/O operation on closed file"
+        f.close()
+
     def test_rw_bin(self):
         import random
         flags = 'w+b'


More information about the Pypy-commit mailing list