blob: 8abdcb419a0605ba92fb7d856abd0e73c1309b4c [file] [log] [blame]
Guido van Rossum28524c72007-02-27 05:47:44 +00001"""New I/O library.
2
Guido van Rossum17e43e52007-02-27 15:45:13 +00003This is an early prototype; eventually some of this will be
4reimplemented in C and the rest may be turned into a package.
5
Guido van Rossum78892e42007-04-06 17:31:18 +00006See PEP 3116.
Guido van Rossumc819dea2007-03-15 18:59:31 +00007
8XXX need to default buffer size to 1 if isatty()
9XXX need to support 1 meaning line-buffered
10XXX change behavior of blocking I/O
Guido van Rossum76c5d4d2007-04-06 19:10:29 +000011XXX don't use assert to validate input requirements
Guido van Rossum28524c72007-02-27 05:47:44 +000012"""
13
Guido van Rossum68bbcd22007-02-27 17:19:33 +000014__author__ = ("Guido van Rossum <guido@python.org>, "
Guido van Rossum78892e42007-04-06 17:31:18 +000015 "Mike Verdone <mike.verdone@gmail.com>, "
16 "Mark Russell <mark.russell@zen.co.uk>")
Guido van Rossum28524c72007-02-27 05:47:44 +000017
Guido van Rossum68bbcd22007-02-27 17:19:33 +000018__all__ = ["open", "RawIOBase", "FileIO", "SocketIO", "BytesIO",
Guido van Rossum01a27522007-03-07 01:00:12 +000019 "BufferedReader", "BufferedWriter", "BufferedRWPair",
Guido van Rossum78892e42007-04-06 17:31:18 +000020 "BufferedRandom"]
Guido van Rossum28524c72007-02-27 05:47:44 +000021
22import os
Guido van Rossum78892e42007-04-06 17:31:18 +000023import sys
24import codecs
25import warnings
Guido van Rossum28524c72007-02-27 05:47:44 +000026
Guido van Rossum68bbcd22007-02-27 17:19:33 +000027DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes
Guido van Rossum01a27522007-03-07 01:00:12 +000028DEFAULT_MAX_BUFFER_SIZE = 16 * 1024 # bytes
Guido van Rossum01a27522007-03-07 01:00:12 +000029
30
31class BlockingIO(IOError):
Guido van Rossum78892e42007-04-06 17:31:18 +000032
Guido van Rossum01a27522007-03-07 01:00:12 +000033 def __init__(self, errno, strerror, characters_written):
34 IOError.__init__(self, errno, strerror)
35 self.characters_written = characters_written
36
Guido van Rossum68bbcd22007-02-27 17:19:33 +000037
Guido van Rossum28524c72007-02-27 05:47:44 +000038def open(filename, mode="r", buffering=None, *, encoding=None):
Guido van Rossum17e43e52007-02-27 15:45:13 +000039 """Replacement for the built-in open function.
40
41 Args:
42 filename: string giving the name of the file to be opened
43 mode: optional mode string; see below
44 buffering: optional int >= 0 giving the buffer size; values
45 can be: 0 = unbuffered, 1 = line buffered,
46 larger = fully buffered
47 encoding: optional string giving the text encoding (*must* be given
48 as a keyword argument)
49
50 Mode strings characters:
51 'r': open for reading (default)
52 'w': open for writing, truncating the file first
53 'a': open for writing, appending to the end if the file exists
54 'b': binary mode
55 't': text mode (default)
56 '+': open a disk file for updating (implies reading and writing)
Guido van Rossum9be55972007-04-07 02:59:27 +000057 'U': universal newline mode (for backwards compatibility)
Guido van Rossum17e43e52007-02-27 15:45:13 +000058
59 Constraints:
60 - encoding must not be given when a binary mode is given
61 - buffering must not be zero when a text mode is given
62
63 Returns:
64 Depending on the mode and buffering arguments, either a raw
65 binary stream, a buffered binary stream, or a buffered text
66 stream, open for reading and/or writing.
67 """
Guido van Rossum9be55972007-04-07 02:59:27 +000068 assert isinstance(filename, basestring)
69 assert isinstance(mode, basestring)
Guido van Rossum28524c72007-02-27 05:47:44 +000070 assert buffering is None or isinstance(buffering, int)
Guido van Rossum9be55972007-04-07 02:59:27 +000071 assert encoding is None or isinstance(encoding, basestring)
Guido van Rossum28524c72007-02-27 05:47:44 +000072 modes = set(mode)
Guido van Rossum9be55972007-04-07 02:59:27 +000073 if modes - set("arwb+tU") or len(mode) > len(modes):
Guido van Rossum28524c72007-02-27 05:47:44 +000074 raise ValueError("invalid mode: %r" % mode)
75 reading = "r" in modes
Guido van Rossum17e43e52007-02-27 15:45:13 +000076 writing = "w" in modes
Guido van Rossum28524c72007-02-27 05:47:44 +000077 appending = "a" in modes
78 updating = "+" in modes
Guido van Rossum17e43e52007-02-27 15:45:13 +000079 text = "t" in modes
80 binary = "b" in modes
Guido van Rossum9be55972007-04-07 02:59:27 +000081 if not reading and not writing and not appending and "U" in modes:
82 reading = True
Guido van Rossum28524c72007-02-27 05:47:44 +000083 if text and binary:
84 raise ValueError("can't have text and binary mode at once")
85 if reading + writing + appending > 1:
86 raise ValueError("can't have read/write/append mode at once")
87 if not (reading or writing or appending):
88 raise ValueError("must have exactly one of read/write/append mode")
89 if binary and encoding is not None:
90 raise ValueError("binary mode doesn't take an encoding")
91 raw = FileIO(filename,
92 (reading and "r" or "") +
93 (writing and "w" or "") +
94 (appending and "a" or "") +
95 (updating and "+" or ""))
96 if buffering is None:
Guido van Rossum68bbcd22007-02-27 17:19:33 +000097 buffering = DEFAULT_BUFFER_SIZE
98 # XXX Should default to line buffering if os.isatty(raw.fileno())
Guido van Rossum17e43e52007-02-27 15:45:13 +000099 try:
100 bs = os.fstat(raw.fileno()).st_blksize
101 except (os.error, AttributeError):
Guido van Rossumbb09b212007-03-18 03:36:28 +0000102 pass
103 else:
Guido van Rossum17e43e52007-02-27 15:45:13 +0000104 if bs > 1:
105 buffering = bs
Guido van Rossum28524c72007-02-27 05:47:44 +0000106 if buffering < 0:
107 raise ValueError("invalid buffering size")
108 if buffering == 0:
109 if binary:
110 return raw
111 raise ValueError("can't have unbuffered text I/O")
112 if updating:
113 buffer = BufferedRandom(raw, buffering)
Guido van Rossum17e43e52007-02-27 15:45:13 +0000114 elif writing or appending:
Guido van Rossum28524c72007-02-27 05:47:44 +0000115 buffer = BufferedWriter(raw, buffering)
116 else:
117 assert reading
118 buffer = BufferedReader(raw, buffering)
119 if binary:
120 return buffer
Guido van Rossum17e43e52007-02-27 15:45:13 +0000121 # XXX What about newline conventions?
122 textio = TextIOWrapper(buffer, encoding)
Guido van Rossum28524c72007-02-27 05:47:44 +0000123 return textio
124
125
126class RawIOBase:
127
Guido van Rossum17e43e52007-02-27 15:45:13 +0000128 """Base class for raw binary I/O.
129
130 This class provides dummy implementations for all methods that
131 derived classes can override selectively; the default
132 implementations represent a file that cannot be read, written or
133 seeked.
134
135 The read() method is implemented by calling readinto(); derived
Guido van Rossum78892e42007-04-06 17:31:18 +0000136 classes that want to support read() only need to implement
Guido van Rossum17e43e52007-02-27 15:45:13 +0000137 readinto() as a primitive operation.
138 """
139
Guido van Rossum28524c72007-02-27 05:47:44 +0000140 def read(self, n):
Guido van Rossum78892e42007-04-06 17:31:18 +0000141 """read(n: int) -> bytes. Read and return up to n bytes.
Guido van Rossum01a27522007-03-07 01:00:12 +0000142
143 Returns an empty bytes array on EOF, or None if the object is
144 set not to block and has no data to read.
145 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000146 b = bytes(n.__index__())
Guido van Rossum00efead2007-03-07 05:23:25 +0000147 n = self.readinto(b)
148 del b[n:]
Guido van Rossum28524c72007-02-27 05:47:44 +0000149 return b
150
151 def readinto(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000152 """readinto(b: bytes) -> None. Read up to len(b) bytes into b.
153
154 Returns number of bytes read (0 for EOF), or None if the object
155 is set not to block as has no data to read.
156 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000157 raise IOError(".readinto() not supported")
158
159 def write(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000160 """write(b: bytes) -> int. Write the given buffer to the IO stream.
Guido van Rossum01a27522007-03-07 01:00:12 +0000161
Guido van Rossum78892e42007-04-06 17:31:18 +0000162 Returns the number of bytes written, which may be less than len(b).
Guido van Rossum01a27522007-03-07 01:00:12 +0000163 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000164 raise IOError(".write() not supported")
165
166 def seek(self, pos, whence=0):
Guido van Rossum78892e42007-04-06 17:31:18 +0000167 """seek(pos: int, whence: int = 0) -> None. Change stream position.
168
169 Seek to byte offset pos relative to position indicated by whence:
170 0 Start of stream (the default). pos should be >= 0;
171 1 Current position - whence may be negative;
172 2 End of stream - whence usually negative.
173 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000174 raise IOError(".seek() not supported")
175
176 def tell(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000177 """tell() -> int. Return current stream position."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000178 raise IOError(".tell() not supported")
179
180 def truncate(self, pos=None):
Guido van Rossum78892e42007-04-06 17:31:18 +0000181 """truncate(size: int = None) -> None. Truncate file to size bytes.
182
183 Size defaults to the current IO position as reported by tell().
184 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000185 raise IOError(".truncate() not supported")
186
187 def close(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000188 """close() -> None. Close IO object."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000189 pass
190
191 def seekable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000192 """seekable() -> bool. Return whether object supports random access.
193
194 If False, seek(), tell() and truncate() will raise IOError.
195 This method may need to do a test seek().
196 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000197 return False
198
199 def readable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000200 """readable() -> bool. Return whether object was opened for reading.
201
202 If False, read() will raise IOError.
203 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000204 return False
205
206 def writable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000207 """writable() -> bool. Return whether object was opened for writing.
208
209 If False, write() and truncate() will raise IOError.
210 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000211 return False
212
213 def __enter__(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000214 """Context management protocol. Returns self."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000215 return self
216
217 def __exit__(self, *args):
Guido van Rossum78892e42007-04-06 17:31:18 +0000218 """Context management protocol. Same as close()"""
Guido van Rossum28524c72007-02-27 05:47:44 +0000219 self.close()
220
221 def fileno(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000222 """fileno() -> int. Return underlying file descriptor if there is one.
223
224 Raises IOError if the IO object does not use a file descriptor.
225 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000226 raise IOError(".fileno() not supported")
227
228
Guido van Rossuma9e20242007-03-08 00:43:48 +0000229class _PyFileIO(RawIOBase):
Guido van Rossum28524c72007-02-27 05:47:44 +0000230
231 """Raw I/O implementation for OS files."""
232
Guido van Rossum17e43e52007-02-27 15:45:13 +0000233 # XXX More docs
234
Guido van Rossum28524c72007-02-27 05:47:44 +0000235 def __init__(self, filename, mode):
236 self._seekable = None
237 self._mode = mode
238 if mode == "r":
239 flags = os.O_RDONLY
240 elif mode == "w":
241 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
Guido van Rossum28524c72007-02-27 05:47:44 +0000242 elif mode == "r+":
243 flags = os.O_RDWR
244 else:
245 assert 0, "unsupported mode %r (for now)" % mode
246 if hasattr(os, "O_BINARY"):
247 flags |= os.O_BINARY
248 self._fd = os.open(filename, flags)
249
250 def readinto(self, b):
251 # XXX We really should have os.readinto()
Guido van Rossum00efead2007-03-07 05:23:25 +0000252 tmp = os.read(self._fd, len(b))
253 n = len(tmp)
254 b[:n] = tmp
255 return n
Guido van Rossum28524c72007-02-27 05:47:44 +0000256
257 def write(self, b):
258 return os.write(self._fd, b)
259
260 def seek(self, pos, whence=0):
261 os.lseek(self._fd, pos, whence)
262
263 def tell(self):
264 return os.lseek(self._fd, 0, 1)
265
266 def truncate(self, pos=None):
267 if pos is None:
268 pos = self.tell()
269 os.ftruncate(self._fd, pos)
270
271 def close(self):
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000272 # Must be idempotent
273 # XXX But what about thread-safe?
274 fd = self._fd
275 self._fd = -1
276 if fd >= 0:
277 os.close(fd)
Guido van Rossum28524c72007-02-27 05:47:44 +0000278
279 def readable(self):
280 return "r" in self._mode or "+" in self._mode
281
282 def writable(self):
283 return "w" in self._mode or "+" in self._mode or "a" in self._mode
284
285 def seekable(self):
286 if self._seekable is None:
287 try:
288 os.lseek(self._fd, 0, 1)
289 except os.error:
290 self._seekable = False
291 else:
292 self._seekable = True
293 return self._seekable
294
Guido van Rossum28524c72007-02-27 05:47:44 +0000295 def fileno(self):
296 return self._fd
297
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000298
Guido van Rossuma9e20242007-03-08 00:43:48 +0000299try:
300 import _fileio
301except ImportError:
302 # Let's use the Python version
Guido van Rossum78892e42007-04-06 17:31:18 +0000303 warnings.warn("Can't import _fileio, using slower Python lookalike",
304 RuntimeWarning)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000305 FileIO = _PyFileIO
306else:
307 # Create a trivial subclass with the proper inheritance structure
308 class FileIO(_fileio._FileIO, RawIOBase):
309 """Raw I/O implementation for OS files."""
310 # XXX More docs
311
312
Guido van Rossum28524c72007-02-27 05:47:44 +0000313class SocketIO(RawIOBase):
314
315 """Raw I/O implementation for stream sockets."""
316
Guido van Rossum17e43e52007-02-27 15:45:13 +0000317 # XXX More docs
318
Guido van Rossum28524c72007-02-27 05:47:44 +0000319 def __init__(self, sock, mode):
320 assert mode in ("r", "w", "rw")
321 self._sock = sock
322 self._mode = mode
Guido van Rossum28524c72007-02-27 05:47:44 +0000323
324 def readinto(self, b):
325 return self._sock.recv_into(b)
326
327 def write(self, b):
328 return self._sock.send(b)
329
330 def close(self):
331 self._sock.close()
332
333 def readable(self):
334 return "r" in self._mode
335
336 def writable(self):
337 return "w" in self._mode
338
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000339 def fileno(self):
340 return self._sock.fileno()
Neal Norwitz8b41c3d2007-02-27 06:26:14 +0000341
Guido van Rossum28524c72007-02-27 05:47:44 +0000342
Guido van Rossum18668592007-04-06 18:11:47 +0000343class _MemoryIOBase(RawIOBase):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000344
Guido van Rossum78892e42007-04-06 17:31:18 +0000345 # XXX docstring
Guido van Rossum28524c72007-02-27 05:47:44 +0000346
Guido van Rossum78892e42007-04-06 17:31:18 +0000347 def __init__(self, buffer):
348 self._buffer = buffer
Guido van Rossum28524c72007-02-27 05:47:44 +0000349 self._pos = 0
Guido van Rossum28524c72007-02-27 05:47:44 +0000350
351 def getvalue(self):
352 return self._buffer
353
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000354 def read(self, n=None):
355 if n is None:
356 n = len(self._buffer)
Guido van Rossum28524c72007-02-27 05:47:44 +0000357 assert n >= 0
358 newpos = min(len(self._buffer), self._pos + n)
359 b = self._buffer[self._pos : newpos]
360 self._pos = newpos
361 return b
362
363 def readinto(self, b):
Guido van Rossum00efead2007-03-07 05:23:25 +0000364 tmp = self.read(len(b))
365 n = len(tmp)
366 b[:n] = tmp
367 return n
Guido van Rossum28524c72007-02-27 05:47:44 +0000368
369 def write(self, b):
370 n = len(b)
371 newpos = self._pos + n
372 self._buffer[self._pos:newpos] = b
373 self._pos = newpos
374 return n
375
376 def seek(self, pos, whence=0):
377 if whence == 0:
378 self._pos = max(0, pos)
379 elif whence == 1:
380 self._pos = max(0, self._pos + pos)
381 elif whence == 2:
382 self._pos = max(0, len(self._buffer) + pos)
383 else:
384 raise IOError("invalid whence value")
385
386 def tell(self):
387 return self._pos
388
389 def truncate(self, pos=None):
390 if pos is None:
391 pos = self._pos
392 else:
393 self._pos = max(0, pos)
394 del self._buffer[pos:]
395
396 def readable(self):
397 return True
398
399 def writable(self):
400 return True
401
402 def seekable(self):
403 return True
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000404
405
Guido van Rossum18668592007-04-06 18:11:47 +0000406class BytesIO(_MemoryIOBase):
Guido van Rossum78892e42007-04-06 17:31:18 +0000407
408 """Buffered I/O implementation using a bytes buffer, like StringIO."""
409
410 # XXX More docs
411
412 def __init__(self, inital_bytes=None):
413 buffer = b""
414 if inital_bytes is not None:
415 buffer += inital_bytes
Guido van Rossum18668592007-04-06 18:11:47 +0000416 _MemoryIOBase.__init__(self, buffer)
Guido van Rossum78892e42007-04-06 17:31:18 +0000417
418
Guido van Rossum18668592007-04-06 18:11:47 +0000419class StringIO(_MemoryIOBase):
Guido van Rossum78892e42007-04-06 17:31:18 +0000420
421 """Buffered I/O implementation using a string buffer, like StringIO."""
422
423 # XXX More docs
424
425 # XXX Reuses the same code as BytesIO, just with a string rather
426 # that bytes as the _buffer value. That won't work in C of course.
427
428 def __init__(self, inital_string=None):
429 buffer = ""
430 if inital_string is not None:
431 buffer += inital_string
Guido van Rossum18668592007-04-06 18:11:47 +0000432 _MemoryIOBase.__init__(self, buffer)
Guido van Rossum78892e42007-04-06 17:31:18 +0000433
434
Guido van Rossum01a27522007-03-07 01:00:12 +0000435class BufferedIOBase(RawIOBase):
436
437 """Base class for buffered IO objects."""
438
439 def flush(self):
440 """Flush the buffer to the underlying raw IO object."""
441 raise IOError(".flush() unsupported")
442
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000443 def seekable(self):
444 return self.raw.seekable()
445
Guido van Rossum01a27522007-03-07 01:00:12 +0000446
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000447class BufferedReader(BufferedIOBase):
448
Guido van Rossum01a27522007-03-07 01:00:12 +0000449 """Buffer for a readable sequential RawIO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000450
Guido van Rossum18668592007-04-06 18:11:47 +0000451 Does not allow random access (seek, tell).
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000452 """
453
Guido van Rossum78892e42007-04-06 17:31:18 +0000454 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
Guido van Rossum01a27522007-03-07 01:00:12 +0000455 """Create a new buffered reader using the given readable raw IO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000456 """
457 assert raw.readable()
458 self.raw = raw
Guido van Rossum01a27522007-03-07 01:00:12 +0000459 self._read_buf = b""
Guido van Rossum78892e42007-04-06 17:31:18 +0000460 self.buffer_size = buffer_size
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000461 if hasattr(raw, 'fileno'):
462 self.fileno = raw.fileno
463
464 def read(self, n=None):
Guido van Rossum01a27522007-03-07 01:00:12 +0000465 """Read n bytes.
466
467 Returns exactly n bytes of data unless the underlying raw IO
468 stream reaches EOF of if the call would block in non-blocking
469 mode. If n is None, read until EOF or until read() would
470 block.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000471 """
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000472 # XXX n == 0 should return b""? n < 0 should be the same as n is None?
Guido van Rossum78892e42007-04-06 17:31:18 +0000473 assert n is None or n > 0, '.read(): Bad read size %r' % n
474 nodata_val = b""
475 while n is None or len(self._read_buf) < n:
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000476 to_read = max(self.buffer_size,
477 n if n is not None else 2*len(self._read_buf))
Guido van Rossum78892e42007-04-06 17:31:18 +0000478 current = self.raw.read(to_read)
479
480 if current in (b"", None):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000481 nodata_val = current
482 break
Guido van Rossum01a27522007-03-07 01:00:12 +0000483 self._read_buf += current
484 if self._read_buf:
485 if n is None:
486 n = len(self._read_buf)
487 out = self._read_buf[:n]
488 self._read_buf = self._read_buf[n:]
489 else:
490 out = nodata_val
491 return out
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000492
493 def readable(self):
494 return True
495
Guido van Rossum01a27522007-03-07 01:00:12 +0000496 def fileno(self):
497 return self.raw.fileno()
498
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000499 def flush(self):
500 # Flush is a no-op
501 pass
502
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000503 def tell(self):
504 return self.raw.tell() - len(self._read_buf)
505
506 def seek(self, pos, whence=0):
507 if whence == 1:
508 pos -= len(self._read_buf)
509 self.raw.seek(pos, whence)
510 self._read_buf = b""
511
Guido van Rossum01a27522007-03-07 01:00:12 +0000512 def close(self):
513 self.raw.close()
514
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000515
516class BufferedWriter(BufferedIOBase):
517
Guido van Rossum78892e42007-04-06 17:31:18 +0000518 # XXX docstring
519
Guido van Rossum01a27522007-03-07 01:00:12 +0000520 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
521 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
522 assert raw.writable()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000523 self.raw = raw
524 self.buffer_size = buffer_size
Guido van Rossum01a27522007-03-07 01:00:12 +0000525 self.max_buffer_size = max_buffer_size
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000526 self._write_buf = b""
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000527
528 def write(self, b):
Guido van Rossum01a27522007-03-07 01:00:12 +0000529 # XXX we can implement some more tricks to try and avoid partial writes
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000530 assert issubclass(type(b), bytes)
Guido van Rossum01a27522007-03-07 01:00:12 +0000531 if len(self._write_buf) > self.buffer_size:
532 # We're full, so let's pre-flush the buffer
533 try:
534 self.flush()
535 except BlockingIO as e:
536 # We can't accept anything else.
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000537 # XXX Why not just let the exception pass through?
Guido van Rossum01a27522007-03-07 01:00:12 +0000538 raise BlockingIO(e.errno, e.strerror, 0)
539 self._write_buf += b
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000540 if len(self._write_buf) > self.buffer_size:
Guido van Rossum01a27522007-03-07 01:00:12 +0000541 try:
542 self.flush()
543 except BlockingIO as e:
544 if (len(self._write_buf) > self.max_buffer_size):
545 # We've hit max_buffer_size. We have to accept a partial
546 # write and cut back our buffer.
547 overage = len(self._write_buf) - self.max_buffer_size
548 self._write_buf = self._write_buf[:self.max_buffer_size]
549 raise BlockingIO(e.errno, e.strerror, overage)
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000550
Guido van Rossum01a27522007-03-07 01:00:12 +0000551 def writable(self):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000552 return True
553
554 def flush(self):
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000555 written = 0
Guido van Rossum01a27522007-03-07 01:00:12 +0000556 try:
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000557 while self._write_buf:
558 n = self.raw.write(self._write_buf)
559 del self._write_buf[:n]
560 written += n
Guido van Rossum01a27522007-03-07 01:00:12 +0000561 except BlockingIO as e:
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000562 n = e.characters_written
563 del self._write_buf[:n]
564 written += n
565 raise BlockingIO(e.errno, e.strerror, written)
566
567 def tell(self):
568 return self.raw.tell() + len(self._write_buf)
569
570 def seek(self, pos, whence=0):
571 self.flush()
572 self.raw.seek(pos, whence)
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000573
Guido van Rossum01a27522007-03-07 01:00:12 +0000574 def fileno(self):
575 return self.raw.fileno()
576
577 def close(self):
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000578 self.flush()
Guido van Rossum01a27522007-03-07 01:00:12 +0000579 self.raw.close()
580
581 def __del__(self):
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000582 self.close()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000583
584
585class BufferedRWPair(BufferedReader, BufferedWriter):
586
Guido van Rossum01a27522007-03-07 01:00:12 +0000587 """A buffered reader and writer object together.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000588
589 A buffered reader object and buffered writer object put together to
590 form a sequential IO object that can read and write.
Guido van Rossum78892e42007-04-06 17:31:18 +0000591
592 This is typically used with a socket or two-way pipe.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000593 """
594
Guido van Rossum01a27522007-03-07 01:00:12 +0000595 def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE,
596 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
597 assert reader.readable()
598 assert writer.writable()
599 BufferedReader.__init__(self, reader)
600 BufferedWriter.__init__(self, writer, buffer_size, max_buffer_size)
601 self.reader = reader
602 self.writer = writer
603
604 def read(self, n=None):
605 return self.reader.read(n)
606
607 def write(self, b):
608 return self.writer.write(b)
609
610 def readable(self):
611 return self.reader.readable()
612
613 def writable(self):
614 return self.writer.writable()
615
616 def flush(self):
617 return self.writer.flush()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000618
619 def seekable(self):
620 return False
Guido van Rossum01a27522007-03-07 01:00:12 +0000621
622 def fileno(self):
623 # XXX whose fileno do we return? Reader's? Writer's? Unsupported?
624 raise IOError(".fileno() unsupported")
625
626 def close(self):
627 self.reader.close()
628 self.writer.close()
629
630
631class BufferedRandom(BufferedReader, BufferedWriter):
632
Guido van Rossum78892e42007-04-06 17:31:18 +0000633 # XXX docstring
634
Guido van Rossum01a27522007-03-07 01:00:12 +0000635 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
636 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
637 assert raw.seekable()
638 BufferedReader.__init__(self, raw)
639 BufferedWriter.__init__(self, raw, buffer_size, max_buffer_size)
640
Guido van Rossum01a27522007-03-07 01:00:12 +0000641 def readable(self):
642 return self.raw.readable()
643
644 def writable(self):
645 return self.raw.writable()
646
647 def seek(self, pos, whence=0):
648 self.flush()
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000649 # First do the raw seek, then empty the read buffer, so that
650 # if the raw seek fails, we don't lose buffered data forever.
Guido van Rossum01a27522007-03-07 01:00:12 +0000651 self.raw.seek(pos, whence)
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000652 self._read_buf = b""
Guido van Rossum01a27522007-03-07 01:00:12 +0000653 # XXX I suppose we could implement some magic here to move through the
654 # existing read buffer in the case of seek(<some small +ve number>, 1)
Guido van Rossum76c5d4d2007-04-06 19:10:29 +0000655 # XXX OTOH it might be good to *guarantee* that the buffer is
656 # empty after a seek or flush; for small relative forward
657 # seeks one might as well use small reads instead.
Guido van Rossum01a27522007-03-07 01:00:12 +0000658
659 def tell(self):
660 if (self._write_buf):
661 return self.raw.tell() + len(self._write_buf)
662 else:
663 return self.raw.tell() - len(self._read_buf)
664
665 def read(self, n=None):
666 self.flush()
667 return BufferedReader.read(self, n)
668
669 def write(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000670 if self._read_buf:
671 self.raw.seek(-len(self._read_buf), 1) # Undo readahead
672 self._read_buf = b""
Guido van Rossum01a27522007-03-07 01:00:12 +0000673 return BufferedWriter.write(self, b)
674
675 def flush(self):
676 BufferedWriter.flush(self)
677
678 def close(self):
679 self.raw.close()
Guido van Rossum78892e42007-04-06 17:31:18 +0000680
681
682class TextIOBase(BufferedIOBase):
683
684 """Base class for text I/O.
685
686 This class provides a character and line based interface to stream I/O.
687 """
688
689 def read(self, n: int = -1) -> str:
690 """read(n: int = -1) -> str. Read at most n characters from stream.
691
692 Read from underlying buffer until we have n characters or we hit EOF.
693 If n is negative or omitted, read until EOF.
694 """
695 raise IOError(".read() not supported")
696
697 def write(self, s: str):
698 """write(s: str) -> None. Write string s to stream.
699 """
700 raise IOError(".write() not supported")
701
702 def readline(self) -> str:
703 """readline() -> str. Read until newline or EOF.
704
705 Returns an empty string if EOF is hit immediately.
706 """
707 raise IOError(".readline() not supported")
708
709 def __iter__(self):
710 """__iter__() -> Iterator. Return line iterator (actually just self).
711 """
712 return self
713
714 def next(self):
715 """Same as readline() except raises StopIteration on immediate EOF.
716 """
717 line = self.readline()
718 if line == '':
719 raise StopIteration
720 return line
721
Guido van Rossum9be55972007-04-07 02:59:27 +0000722 # The following are provided for backwards compatibility
723
724 def readlines(self, hint=None):
725 if hint is None:
726 return list(self)
727 n = 0
728 lines = []
729 while not lines or n < hint:
730 line = self.readline()
731 if not line:
732 break
733 lines.append(line)
734 n += len(line)
735 return lines
736
737 def writelines(self, lines):
738 for line in lines:
739 self.write(line)
740
Guido van Rossum78892e42007-04-06 17:31:18 +0000741
742class TextIOWrapper(TextIOBase):
743
744 """Buffered text stream.
745
746 Character and line based layer over a BufferedIOBase object.
747 """
748
749 # XXX tell(), seek()
750
751 def __init__(self, buffer, encoding=None, newline=None):
752 if newline not in (None, '\n', '\r\n'):
753 raise IOError("illegal newline %s" % newline) # XXX: ValueError?
754 if encoding is None:
755 # XXX This is questionable
756 encoding = sys.getfilesystemencoding()
757 if encoding is None:
758 encoding = "latin-1" # XXX, but this is best for transparancy
759
760 self.buffer = buffer
761 self._encoding = encoding
762 self._newline = newline or os.linesep
763 self._fix_newlines = newline is None
764 self._decoder = None
765 self._pending = ''
766
Guido van Rossum9be55972007-04-07 02:59:27 +0000767 def fileno(self):
768 return self.buffer.fileno()
769
Guido van Rossum78892e42007-04-06 17:31:18 +0000770 def write(self, s: str):
771 return self.buffer.write(s.encode(self._encoding))
772
773 def _get_decoder(self):
774 make_decoder = codecs.getincrementaldecoder(self._encoding)
775 if make_decoder is None:
776 raise IOError(".readline() not supported for encoding %s" %
777 self._encoding)
778 decoder = self._decoder = make_decoder() # XXX: errors
779 if isinstance(decoder, codecs.BufferedIncrementalDecoder):
780 # XXX Hack: make the codec use bytes instead of strings
781 decoder.buffer = b""
782 return decoder
783
784 def read(self, n: int = -1):
785 decoder = self._decoder or self._get_decoder()
786 res = self._pending
787 if n < 0:
788 res += decoder.decode(self.buffer.read(), True)
789 self._pending = ''
790 return res
791 else:
792 while len(res) < n:
793 data = self.buffer.read(64)
794 res += decoder.decode(data, not data)
795 if not data:
796 break
797 self._pending = res[n:]
798 return res[:n]
799
800 def readline(self):
801 line = self._pending
802 start = 0
803 decoder = self._decoder or self._get_decoder()
804
805 while True:
806 # In C we'd look for these in parallel of course.
807 nlpos = line.find("\n", start)
808 crpos = line.find("\r", start)
809 if nlpos >= 0 and crpos >= 0:
810 endpos = min(nlpos, crpos)
811 else:
812 endpos = nlpos if nlpos >= 0 else crpos
813
814 if endpos != -1:
815 endc = line[endpos]
816 if endc == "\n":
817 ending = "\n"
818 break
819
820 # We've seen \r - is it standalone, \r\n or \r at end of line?
821 if endpos + 1 < len(line):
822 if line[endpos+1] == '\n':
823 ending = "\r\n"
824 else:
825 ending = "\r"
826 break
827 # There might be a following \n in the next block of data ...
828 start = endpos
829 else:
830 start = len(line)
831
832 # No line ending seen yet - get more data
833 while True:
834 data = self.buffer.read(64)
835 more_line = decoder.decode(data, not data)
836 if more_line != "" or not data:
837 break
838
839 if more_line == "":
840 ending = ''
841 endpos = len(line)
842 break
843
844 line += more_line
845
846 nextpos = endpos + len(ending)
847 self._pending = line[nextpos:]
848
849 # XXX Update self.newlines here if we want to support that
850
851 if self._fix_newlines and ending != "\n" and ending != '':
852 return line[:endpos] + "\n"
853 else:
854 return line[:nextpos]