blob: c714c6b31e1a1ebd4d75f874bb4575878203c750 [file] [log] [blame]
Guido van Rossum28524c72007-02-27 05:47:44 +00001# Copyright 2006 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""New I/O library.
5
6See PEP XXX; for now: http://docs.google.com/Doc?id=dfksfvqd_1cn5g5m
7"""
8
9__author__ = "Guido van Rossum <guido@python.org>"
10
11__all__ = ["open", "RawIOBase", "FileIO", "SocketIO", "BytesIO"]
12
13import os
14
15def open(filename, mode="r", buffering=None, *, encoding=None):
16 """Replacement for the built-in open function, with encoding parameter."""
17 assert isinstance(filename, str)
18 assert isinstance(mode, str)
19 assert buffering is None or isinstance(buffering, int)
20 assert encoding is None or isinstance(encoding, str)
21 modes = set(mode)
22 if modes - set("arwb+t") or len(mode) > len(modes):
23 raise ValueError("invalid mode: %r" % mode)
24 reading = "r" in modes
25 writing = "w" in modes or "a" in modes
26 binary = "b" in modes
27 appending = "a" in modes
28 updating = "+" in modes
29 text = "t" in modes or not binary
30 if text and binary:
31 raise ValueError("can't have text and binary mode at once")
32 if reading + writing + appending > 1:
33 raise ValueError("can't have read/write/append mode at once")
34 if not (reading or writing or appending):
35 raise ValueError("must have exactly one of read/write/append mode")
36 if binary and encoding is not None:
37 raise ValueError("binary mode doesn't take an encoding")
38 raw = FileIO(filename,
39 (reading and "r" or "") +
40 (writing and "w" or "") +
41 (appending and "a" or "") +
42 (updating and "+" or ""))
43 if buffering is None:
44 buffering = 8*1024 # International standard buffer size
45 if buffering < 0:
46 raise ValueError("invalid buffering size")
47 if buffering == 0:
48 if binary:
49 return raw
50 raise ValueError("can't have unbuffered text I/O")
51 if updating:
52 buffer = BufferedRandom(raw, buffering)
53 elif writing:
54 buffer = BufferedWriter(raw, buffering)
55 else:
56 assert reading
57 buffer = BufferedReader(raw, buffering)
58 if binary:
59 return buffer
60 assert text
61 textio = TextIOWrapper(buffer) # Universal newlines default to on
62 return textio
63
64
65class RawIOBase:
66
67 """Base class for raw binary I/O."""
68
69 def read(self, n):
70 b = bytes(n.__index__())
71 self.readinto(b)
72 return b
73
74 def readinto(self, b):
75 raise IOError(".readinto() not supported")
76
77 def write(self, b):
78 raise IOError(".write() not supported")
79
80 def seek(self, pos, whence=0):
81 raise IOError(".seek() not supported")
82
83 def tell(self):
84 raise IOError(".tell() not supported")
85
86 def truncate(self, pos=None):
87 raise IOError(".truncate() not supported")
88
89 def close(self):
90 pass
91
92 def seekable(self):
93 return False
94
95 def readable(self):
96 return False
97
98 def writable(self):
99 return False
100
101 def __enter__(self):
102 return self
103
104 def __exit__(self, *args):
105 self.close()
106
107 def fileno(self):
108 raise IOError(".fileno() not supported")
109
110
111class FileIO(RawIOBase):
112
113 """Raw I/O implementation for OS files."""
114
115 def __init__(self, filename, mode):
116 self._seekable = None
117 self._mode = mode
118 if mode == "r":
119 flags = os.O_RDONLY
120 elif mode == "w":
121 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
122 self._writable = True
123 elif mode == "r+":
124 flags = os.O_RDWR
125 else:
126 assert 0, "unsupported mode %r (for now)" % mode
127 if hasattr(os, "O_BINARY"):
128 flags |= os.O_BINARY
129 self._fd = os.open(filename, flags)
130
131 def readinto(self, b):
132 # XXX We really should have os.readinto()
133 b[:] = os.read(self._fd, len(b))
134 return len(b)
135
136 def write(self, b):
137 return os.write(self._fd, b)
138
139 def seek(self, pos, whence=0):
140 os.lseek(self._fd, pos, whence)
141
142 def tell(self):
143 return os.lseek(self._fd, 0, 1)
144
145 def truncate(self, pos=None):
146 if pos is None:
147 pos = self.tell()
148 os.ftruncate(self._fd, pos)
149
150 def close(self):
151 os.close(self._fd)
152
153 def readable(self):
154 return "r" in self._mode or "+" in self._mode
155
156 def writable(self):
157 return "w" in self._mode or "+" in self._mode or "a" in self._mode
158
159 def seekable(self):
160 if self._seekable is None:
161 try:
162 os.lseek(self._fd, 0, 1)
163 except os.error:
164 self._seekable = False
165 else:
166 self._seekable = True
167 return self._seekable
168
169 def __enter__(self):
170 return self
171
172 def __exit__(self, *args):
173 self.close()
174
175 def fileno(self):
176 return self._fd
177
178
179class SocketIO(RawIOBase):
180
181 """Raw I/O implementation for stream sockets."""
182
183 def __init__(self, sock, mode):
184 assert mode in ("r", "w", "rw")
185 self._sock = sock
186 self._mode = mode
187 self._readable = "r" in mode
188 self._writable = "w" in mode
189 self._seekable = False
190
191 def readinto(self, b):
192 return self._sock.recv_into(b)
193
194 def write(self, b):
195 return self._sock.send(b)
196
197 def close(self):
198 self._sock.close()
199
200 def readable(self):
201 return "r" in self._mode
202
203 def writable(self):
204 return "w" in self._mode
205
206
207class BytesIO(RawIOBase):
208
209 """Raw I/O implementation for bytes, like StringIO."""
210
211 def __init__(self, inital_bytes=None):
212 self._buffer = b""
213 self._pos = 0
214 if inital_bytes is not None:
215 self._buffer += inital_bytes
216
217 def getvalue(self):
218 return self._buffer
219
220 def read(self, n):
221 assert n >= 0
222 newpos = min(len(self._buffer), self._pos + n)
223 b = self._buffer[self._pos : newpos]
224 self._pos = newpos
225 return b
226
227 def readinto(self, b):
228 b[:] = self.read(len(b))
229
230 def write(self, b):
231 n = len(b)
232 newpos = self._pos + n
233 self._buffer[self._pos:newpos] = b
234 self._pos = newpos
235 return n
236
237 def seek(self, pos, whence=0):
238 if whence == 0:
239 self._pos = max(0, pos)
240 elif whence == 1:
241 self._pos = max(0, self._pos + pos)
242 elif whence == 2:
243 self._pos = max(0, len(self._buffer) + pos)
244 else:
245 raise IOError("invalid whence value")
246
247 def tell(self):
248 return self._pos
249
250 def truncate(self, pos=None):
251 if pos is None:
252 pos = self._pos
253 else:
254 self._pos = max(0, pos)
255 del self._buffer[pos:]
256
257 def readable(self):
258 return True
259
260 def writable(self):
261 return True
262
263 def seekable(self):
264 return True