[pypy-commit] pypy py3.3: Implement 'x' flag on io.open() / io.FileIO.

mjacob noreply at buildbot.pypy.org
Fri Feb 27 17:32:33 CET 2015


Author: Manuel Jacob <me at manueljacob.de>
Branch: py3.3
Changeset: r76173:7f15f2e2ab69
Date: 2015-02-27 16:15 +0100
http://bitbucket.org/pypy/pypy/changeset/7f15f2e2ab69/

Log:	Implement 'x' flag on io.open() / io.FileIO.

diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py
--- a/pypy/module/_io/interp_fileio.py
+++ b/pypy/module/_io/interp_fileio.py
@@ -4,7 +4,7 @@
 from pypy.interpreter.error import wrap_oserror, wrap_oserror2
 from rpython.rlib.rarithmetic import r_longlong
 from rpython.rlib.rstring import StringBuilder
-from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC
+from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_EXCL
 import sys, os, stat, errno
 from pypy.module._io.interp_iobase import W_RawIOBase, convert_size
 
@@ -34,13 +34,14 @@
 
 def _bad_mode(space):
     raise OperationError(space.w_ValueError, space.wrap(
-        "Must have exactly one of read/write/append mode"))
+        "Must have exactly one of read/write/create/append mode"))
 
 def decode_mode(space, mode):
     flags = 0
     rwa = False
     readable = False
     writable = False
+    created = False
     append = False
     plus = False
 
@@ -56,6 +57,13 @@
             rwa = True
             writable = True
             flags |= O_CREAT | O_TRUNC
+        elif s == 'x':
+            if rwa:
+                _bad_mode(space)
+            rwa = True
+            created = True
+            writable = True
+            flags |= O_EXCL | O_CREAT
         elif s == 'a':
             if rwa:
                 _bad_mode(space)
@@ -86,7 +94,7 @@
 
     flags |= O_BINARY
 
-    return readable, writable, append, flags
+    return readable, writable, created, append, flags
 
 SMALLCHUNK = 8 * 1024
 BIGCHUNK = 512 * 1024
@@ -121,6 +129,7 @@
         self.fd = -1
         self.readable = False
         self.writable = False
+        self.created = False
         self.appending = False
         self.seekable = -1
         self.closefd = True
@@ -147,7 +156,7 @@
                 raise OperationError(space.w_ValueError, space.wrap(
                     "negative file descriptor"))
 
-        self.readable, self.writable, self.appending, flags = decode_mode(space, mode)
+        self.readable, self.writable, self.created, self.appending, flags = decode_mode(space, mode)
 
         fd_is_own = False
         try:
@@ -204,6 +213,11 @@
             raise
 
     def _mode(self):
+        if self.created:
+            if self.readable:
+                return 'xb+'
+            else:
+                return 'xb'
         if self.appending:
             if self.readable:
                 return 'ab+'
diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -30,7 +30,7 @@
             space.isinstance_w(w_file, space.w_int)):
         raise oefmt(space.w_TypeError, "invalid file: %R", w_file)
 
-    reading = writing = appending = updating = text = binary = universal = False
+    reading = writing = creating = appending = updating = text = binary = universal = False
 
     uniq_mode = {}
     for flag in mode:
@@ -42,6 +42,8 @@
             reading = True
         elif flag == "w":
             writing = True
+        elif flag == "x":
+            creating = True
         elif flag == "a":
             appending = True
         elif flag == "+":
@@ -61,6 +63,8 @@
         rawmode += "r"
     if writing:
         rawmode += "w"
+    if creating:
+        rawmode += "x"
     if appending:
         rawmode += "a"
     if updating:
@@ -74,9 +78,9 @@
         raise OperationError(space.w_ValueError,
             space.wrap("can't have text and binary mode at once")
         )
-    if reading + writing + appending > 1:
+    if reading + writing + creating + appending > 1:
         raise OperationError(space.w_ValueError,
-            space.wrap("must have exactly one of read/write/append mode")
+            space.wrap("must have exactly one of read/write/create/append mode")
         )
     if binary and encoding is not None:
         raise OperationError(space.w_ValueError,
@@ -123,7 +127,7 @@
 
     if updating:
         buffer_cls = W_BufferedRandom
-    elif writing or appending:
+    elif writing or creating or appending:
         buffer_cls = W_BufferedWriter
     elif reading:
         buffer_cls = W_BufferedReader
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
@@ -222,6 +222,17 @@
             if os.path.exists(self.tmpfile):
                 os.unlink(self.tmpfile)
 
+    def test_open_exclusive(self):
+        # XXX: should raise FileExistsError
+        FileExistsError = OSError
+
+        import _io
+        filename = self.tmpfile + '_x'
+        raises(ValueError, _io.FileIO, filename, 'xw')
+        with _io.FileIO(filename, 'x') as f:
+            assert f.mode == 'xb'
+        raises(FileExistsError, _io.FileIO, filename, 'x')
+
 
 def test_flush_at_exit():
     from pypy import conftest
diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py
--- a/pypy/module/_io/test/test_io.py
+++ b/pypy/module/_io/test/test_io.py
@@ -439,3 +439,14 @@
             f.seek(1, 0)
             f.read(buffer_size * 2)
             assert f.tell() == 1 + buffer_size * 2
+
+    def test_open_exclusive(self):
+        # XXX: should raise FileExistsError
+        FileExistsError = OSError
+
+        import _io
+        filename = self.tmpfile + '_x'
+        raises(ValueError, _io.open, filename, 'xw')
+        with _io.open(filename, 'x') as f:
+            assert f.mode == 'x'
+        raises(FileExistsError, _io.open, filename, 'x')


More information about the pypy-commit mailing list