blob: 78877f05a8f5737e8a1de47d56f7396e50ac4309 [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 Rossum28524c72007-02-27 05:47:44 +000011"""
12
Guido van Rossum68bbcd22007-02-27 17:19:33 +000013__author__ = ("Guido van Rossum <guido@python.org>, "
Guido van Rossum78892e42007-04-06 17:31:18 +000014 "Mike Verdone <mike.verdone@gmail.com>, "
15 "Mark Russell <mark.russell@zen.co.uk>")
Guido van Rossum28524c72007-02-27 05:47:44 +000016
Guido van Rossum68bbcd22007-02-27 17:19:33 +000017__all__ = ["open", "RawIOBase", "FileIO", "SocketIO", "BytesIO",
Guido van Rossum01a27522007-03-07 01:00:12 +000018 "BufferedReader", "BufferedWriter", "BufferedRWPair",
Guido van Rossum78892e42007-04-06 17:31:18 +000019 "BufferedRandom"]
Guido van Rossum28524c72007-02-27 05:47:44 +000020
21import os
Guido van Rossum78892e42007-04-06 17:31:18 +000022import sys
23import codecs
24import warnings
Guido van Rossum28524c72007-02-27 05:47:44 +000025
Guido van Rossum68bbcd22007-02-27 17:19:33 +000026DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes
Guido van Rossum01a27522007-03-07 01:00:12 +000027DEFAULT_MAX_BUFFER_SIZE = 16 * 1024 # bytes
Guido van Rossum01a27522007-03-07 01:00:12 +000028
29
30class BlockingIO(IOError):
Guido van Rossum78892e42007-04-06 17:31:18 +000031
Guido van Rossum01a27522007-03-07 01:00:12 +000032 def __init__(self, errno, strerror, characters_written):
33 IOError.__init__(self, errno, strerror)
34 self.characters_written = characters_written
35
Guido van Rossum68bbcd22007-02-27 17:19:33 +000036
Guido van Rossum28524c72007-02-27 05:47:44 +000037def open(filename, mode="r", buffering=None, *, encoding=None):
Guido van Rossum17e43e52007-02-27 15:45:13 +000038 """Replacement for the built-in open function.
39
40 Args:
41 filename: string giving the name of the file to be opened
42 mode: optional mode string; see below
43 buffering: optional int >= 0 giving the buffer size; values
44 can be: 0 = unbuffered, 1 = line buffered,
45 larger = fully buffered
46 encoding: optional string giving the text encoding (*must* be given
47 as a keyword argument)
48
49 Mode strings characters:
50 'r': open for reading (default)
51 'w': open for writing, truncating the file first
52 'a': open for writing, appending to the end if the file exists
53 'b': binary mode
54 't': text mode (default)
55 '+': open a disk file for updating (implies reading and writing)
56
57 Constraints:
58 - encoding must not be given when a binary mode is given
59 - buffering must not be zero when a text mode is given
60
61 Returns:
62 Depending on the mode and buffering arguments, either a raw
63 binary stream, a buffered binary stream, or a buffered text
64 stream, open for reading and/or writing.
65 """
Guido van Rossum28524c72007-02-27 05:47:44 +000066 assert isinstance(filename, str)
67 assert isinstance(mode, str)
68 assert buffering is None or isinstance(buffering, int)
69 assert encoding is None or isinstance(encoding, str)
70 modes = set(mode)
71 if modes - set("arwb+t") or len(mode) > len(modes):
72 raise ValueError("invalid mode: %r" % mode)
73 reading = "r" in modes
Guido van Rossum17e43e52007-02-27 15:45:13 +000074 writing = "w" in modes
Guido van Rossum28524c72007-02-27 05:47:44 +000075 appending = "a" in modes
76 updating = "+" in modes
Guido van Rossum17e43e52007-02-27 15:45:13 +000077 text = "t" in modes
78 binary = "b" in modes
Guido van Rossum28524c72007-02-27 05:47:44 +000079 if text and binary:
80 raise ValueError("can't have text and binary mode at once")
81 if reading + writing + appending > 1:
82 raise ValueError("can't have read/write/append mode at once")
83 if not (reading or writing or appending):
84 raise ValueError("must have exactly one of read/write/append mode")
85 if binary and encoding is not None:
86 raise ValueError("binary mode doesn't take an encoding")
87 raw = FileIO(filename,
88 (reading and "r" or "") +
89 (writing and "w" or "") +
90 (appending and "a" or "") +
91 (updating and "+" or ""))
92 if buffering is None:
Guido van Rossum68bbcd22007-02-27 17:19:33 +000093 buffering = DEFAULT_BUFFER_SIZE
94 # XXX Should default to line buffering if os.isatty(raw.fileno())
Guido van Rossum17e43e52007-02-27 15:45:13 +000095 try:
96 bs = os.fstat(raw.fileno()).st_blksize
97 except (os.error, AttributeError):
Guido van Rossumbb09b212007-03-18 03:36:28 +000098 pass
99 else:
Guido van Rossum17e43e52007-02-27 15:45:13 +0000100 if bs > 1:
101 buffering = bs
Guido van Rossum28524c72007-02-27 05:47:44 +0000102 if buffering < 0:
103 raise ValueError("invalid buffering size")
104 if buffering == 0:
105 if binary:
106 return raw
107 raise ValueError("can't have unbuffered text I/O")
108 if updating:
109 buffer = BufferedRandom(raw, buffering)
Guido van Rossum17e43e52007-02-27 15:45:13 +0000110 elif writing or appending:
Guido van Rossum28524c72007-02-27 05:47:44 +0000111 buffer = BufferedWriter(raw, buffering)
112 else:
113 assert reading
114 buffer = BufferedReader(raw, buffering)
115 if binary:
116 return buffer
Guido van Rossum17e43e52007-02-27 15:45:13 +0000117 # XXX What about newline conventions?
118 textio = TextIOWrapper(buffer, encoding)
Guido van Rossum28524c72007-02-27 05:47:44 +0000119 return textio
120
121
122class RawIOBase:
123
Guido van Rossum17e43e52007-02-27 15:45:13 +0000124 """Base class for raw binary I/O.
125
126 This class provides dummy implementations for all methods that
127 derived classes can override selectively; the default
128 implementations represent a file that cannot be read, written or
129 seeked.
130
131 The read() method is implemented by calling readinto(); derived
Guido van Rossum78892e42007-04-06 17:31:18 +0000132 classes that want to support read() only need to implement
Guido van Rossum17e43e52007-02-27 15:45:13 +0000133 readinto() as a primitive operation.
134 """
135
Guido van Rossum28524c72007-02-27 05:47:44 +0000136 def read(self, n):
Guido van Rossum78892e42007-04-06 17:31:18 +0000137 """read(n: int) -> bytes. Read and return up to n bytes.
Guido van Rossum01a27522007-03-07 01:00:12 +0000138
139 Returns an empty bytes array on EOF, or None if the object is
140 set not to block and has no data to read.
141 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000142 b = bytes(n.__index__())
Guido van Rossum00efead2007-03-07 05:23:25 +0000143 n = self.readinto(b)
144 del b[n:]
Guido van Rossum28524c72007-02-27 05:47:44 +0000145 return b
146
147 def readinto(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000148 """readinto(b: bytes) -> None. Read up to len(b) bytes into b.
149
150 Returns number of bytes read (0 for EOF), or None if the object
151 is set not to block as has no data to read.
152 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000153 raise IOError(".readinto() not supported")
154
155 def write(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000156 """write(b: bytes) -> int. Write the given buffer to the IO stream.
Guido van Rossum01a27522007-03-07 01:00:12 +0000157
Guido van Rossum78892e42007-04-06 17:31:18 +0000158 Returns the number of bytes written, which may be less than len(b).
Guido van Rossum01a27522007-03-07 01:00:12 +0000159 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000160 raise IOError(".write() not supported")
161
162 def seek(self, pos, whence=0):
Guido van Rossum78892e42007-04-06 17:31:18 +0000163 """seek(pos: int, whence: int = 0) -> None. Change stream position.
164
165 Seek to byte offset pos relative to position indicated by whence:
166 0 Start of stream (the default). pos should be >= 0;
167 1 Current position - whence may be negative;
168 2 End of stream - whence usually negative.
169 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000170 raise IOError(".seek() not supported")
171
172 def tell(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000173 """tell() -> int. Return current stream position."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000174 raise IOError(".tell() not supported")
175
176 def truncate(self, pos=None):
Guido van Rossum78892e42007-04-06 17:31:18 +0000177 """truncate(size: int = None) -> None. Truncate file to size bytes.
178
179 Size defaults to the current IO position as reported by tell().
180 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000181 raise IOError(".truncate() not supported")
182
183 def close(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000184 """close() -> None. Close IO object."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000185 pass
186
187 def seekable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000188 """seekable() -> bool. Return whether object supports random access.
189
190 If False, seek(), tell() and truncate() will raise IOError.
191 This method may need to do a test seek().
192 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000193 return False
194
195 def readable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000196 """readable() -> bool. Return whether object was opened for reading.
197
198 If False, read() will raise IOError.
199 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000200 return False
201
202 def writable(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000203 """writable() -> bool. Return whether object was opened for writing.
204
205 If False, write() and truncate() will raise IOError.
206 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000207 return False
208
209 def __enter__(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000210 """Context management protocol. Returns self."""
Guido van Rossum28524c72007-02-27 05:47:44 +0000211 return self
212
213 def __exit__(self, *args):
Guido van Rossum78892e42007-04-06 17:31:18 +0000214 """Context management protocol. Same as close()"""
Guido van Rossum28524c72007-02-27 05:47:44 +0000215 self.close()
216
217 def fileno(self):
Guido van Rossum78892e42007-04-06 17:31:18 +0000218 """fileno() -> int. Return underlying file descriptor if there is one.
219
220 Raises IOError if the IO object does not use a file descriptor.
221 """
Guido van Rossum28524c72007-02-27 05:47:44 +0000222 raise IOError(".fileno() not supported")
223
224
Guido van Rossuma9e20242007-03-08 00:43:48 +0000225class _PyFileIO(RawIOBase):
Guido van Rossum28524c72007-02-27 05:47:44 +0000226
227 """Raw I/O implementation for OS files."""
228
Guido van Rossum17e43e52007-02-27 15:45:13 +0000229 # XXX More docs
230
Guido van Rossum28524c72007-02-27 05:47:44 +0000231 def __init__(self, filename, mode):
232 self._seekable = None
233 self._mode = mode
234 if mode == "r":
235 flags = os.O_RDONLY
236 elif mode == "w":
237 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
Guido van Rossum28524c72007-02-27 05:47:44 +0000238 elif mode == "r+":
239 flags = os.O_RDWR
240 else:
241 assert 0, "unsupported mode %r (for now)" % mode
242 if hasattr(os, "O_BINARY"):
243 flags |= os.O_BINARY
244 self._fd = os.open(filename, flags)
245
246 def readinto(self, b):
247 # XXX We really should have os.readinto()
Guido van Rossum00efead2007-03-07 05:23:25 +0000248 tmp = os.read(self._fd, len(b))
249 n = len(tmp)
250 b[:n] = tmp
251 return n
Guido van Rossum28524c72007-02-27 05:47:44 +0000252
253 def write(self, b):
254 return os.write(self._fd, b)
255
256 def seek(self, pos, whence=0):
257 os.lseek(self._fd, pos, whence)
258
259 def tell(self):
260 return os.lseek(self._fd, 0, 1)
261
262 def truncate(self, pos=None):
263 if pos is None:
264 pos = self.tell()
265 os.ftruncate(self._fd, pos)
266
267 def close(self):
268 os.close(self._fd)
269
270 def readable(self):
271 return "r" in self._mode or "+" in self._mode
272
273 def writable(self):
274 return "w" in self._mode or "+" in self._mode or "a" in self._mode
275
276 def seekable(self):
277 if self._seekable is None:
278 try:
279 os.lseek(self._fd, 0, 1)
280 except os.error:
281 self._seekable = False
282 else:
283 self._seekable = True
284 return self._seekable
285
Guido van Rossum28524c72007-02-27 05:47:44 +0000286 def fileno(self):
287 return self._fd
288
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000289
Guido van Rossuma9e20242007-03-08 00:43:48 +0000290try:
291 import _fileio
292except ImportError:
293 # Let's use the Python version
Guido van Rossum78892e42007-04-06 17:31:18 +0000294 warnings.warn("Can't import _fileio, using slower Python lookalike",
295 RuntimeWarning)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000296 FileIO = _PyFileIO
297else:
298 # Create a trivial subclass with the proper inheritance structure
299 class FileIO(_fileio._FileIO, RawIOBase):
300 """Raw I/O implementation for OS files."""
301 # XXX More docs
302
303
Guido van Rossum28524c72007-02-27 05:47:44 +0000304class SocketIO(RawIOBase):
305
306 """Raw I/O implementation for stream sockets."""
307
Guido van Rossum17e43e52007-02-27 15:45:13 +0000308 # XXX More docs
309
Guido van Rossum28524c72007-02-27 05:47:44 +0000310 def __init__(self, sock, mode):
311 assert mode in ("r", "w", "rw")
312 self._sock = sock
313 self._mode = mode
Guido van Rossum28524c72007-02-27 05:47:44 +0000314
315 def readinto(self, b):
316 return self._sock.recv_into(b)
317
318 def write(self, b):
319 return self._sock.send(b)
320
321 def close(self):
322 self._sock.close()
323
324 def readable(self):
325 return "r" in self._mode
326
327 def writable(self):
328 return "w" in self._mode
329
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000330 def fileno(self):
331 return self._sock.fileno()
Neal Norwitz8b41c3d2007-02-27 06:26:14 +0000332
Guido van Rossum28524c72007-02-27 05:47:44 +0000333
Guido van Rossum18668592007-04-06 18:11:47 +0000334class _MemoryIOBase(RawIOBase):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000335
Guido van Rossum78892e42007-04-06 17:31:18 +0000336 # XXX docstring
Guido van Rossum28524c72007-02-27 05:47:44 +0000337
Guido van Rossum78892e42007-04-06 17:31:18 +0000338 def __init__(self, buffer):
339 self._buffer = buffer
Guido van Rossum28524c72007-02-27 05:47:44 +0000340 self._pos = 0
Guido van Rossum28524c72007-02-27 05:47:44 +0000341
342 def getvalue(self):
343 return self._buffer
344
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000345 def read(self, n=None):
346 if n is None:
347 n = len(self._buffer)
Guido van Rossum28524c72007-02-27 05:47:44 +0000348 assert n >= 0
349 newpos = min(len(self._buffer), self._pos + n)
350 b = self._buffer[self._pos : newpos]
351 self._pos = newpos
352 return b
353
354 def readinto(self, b):
Guido van Rossum00efead2007-03-07 05:23:25 +0000355 tmp = self.read(len(b))
356 n = len(tmp)
357 b[:n] = tmp
358 return n
Guido van Rossum28524c72007-02-27 05:47:44 +0000359
360 def write(self, b):
361 n = len(b)
362 newpos = self._pos + n
363 self._buffer[self._pos:newpos] = b
364 self._pos = newpos
365 return n
366
367 def seek(self, pos, whence=0):
368 if whence == 0:
369 self._pos = max(0, pos)
370 elif whence == 1:
371 self._pos = max(0, self._pos + pos)
372 elif whence == 2:
373 self._pos = max(0, len(self._buffer) + pos)
374 else:
375 raise IOError("invalid whence value")
376
377 def tell(self):
378 return self._pos
379
380 def truncate(self, pos=None):
381 if pos is None:
382 pos = self._pos
383 else:
384 self._pos = max(0, pos)
385 del self._buffer[pos:]
386
387 def readable(self):
388 return True
389
390 def writable(self):
391 return True
392
393 def seekable(self):
394 return True
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000395
396
Guido van Rossum18668592007-04-06 18:11:47 +0000397class BytesIO(_MemoryIOBase):
Guido van Rossum78892e42007-04-06 17:31:18 +0000398
399 """Buffered I/O implementation using a bytes buffer, like StringIO."""
400
401 # XXX More docs
402
403 def __init__(self, inital_bytes=None):
404 buffer = b""
405 if inital_bytes is not None:
406 buffer += inital_bytes
Guido van Rossum18668592007-04-06 18:11:47 +0000407 _MemoryIOBase.__init__(self, buffer)
Guido van Rossum78892e42007-04-06 17:31:18 +0000408
409
Guido van Rossum18668592007-04-06 18:11:47 +0000410class StringIO(_MemoryIOBase):
Guido van Rossum78892e42007-04-06 17:31:18 +0000411
412 """Buffered I/O implementation using a string buffer, like StringIO."""
413
414 # XXX More docs
415
416 # XXX Reuses the same code as BytesIO, just with a string rather
417 # that bytes as the _buffer value. That won't work in C of course.
418
419 def __init__(self, inital_string=None):
420 buffer = ""
421 if inital_string is not None:
422 buffer += inital_string
Guido van Rossum18668592007-04-06 18:11:47 +0000423 _MemoryIOBase.__init__(self, buffer)
Guido van Rossum78892e42007-04-06 17:31:18 +0000424
425
Guido van Rossum01a27522007-03-07 01:00:12 +0000426class BufferedIOBase(RawIOBase):
427
428 """Base class for buffered IO objects."""
429
430 def flush(self):
431 """Flush the buffer to the underlying raw IO object."""
432 raise IOError(".flush() unsupported")
433
434
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000435class BufferedReader(BufferedIOBase):
436
Guido van Rossum01a27522007-03-07 01:00:12 +0000437 """Buffer for a readable sequential RawIO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000438
Guido van Rossum18668592007-04-06 18:11:47 +0000439 Does not allow random access (seek, tell).
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000440 """
441
Guido van Rossum78892e42007-04-06 17:31:18 +0000442 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
Guido van Rossum01a27522007-03-07 01:00:12 +0000443 """Create a new buffered reader using the given readable raw IO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000444 """
445 assert raw.readable()
446 self.raw = raw
Guido van Rossum01a27522007-03-07 01:00:12 +0000447 self._read_buf = b""
Guido van Rossum78892e42007-04-06 17:31:18 +0000448 self.buffer_size = buffer_size
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000449 if hasattr(raw, 'fileno'):
450 self.fileno = raw.fileno
451
452 def read(self, n=None):
Guido van Rossum01a27522007-03-07 01:00:12 +0000453 """Read n bytes.
454
455 Returns exactly n bytes of data unless the underlying raw IO
456 stream reaches EOF of if the call would block in non-blocking
457 mode. If n is None, read until EOF or until read() would
458 block.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000459 """
Guido van Rossum78892e42007-04-06 17:31:18 +0000460 assert n is None or n > 0, '.read(): Bad read size %r' % n
461 nodata_val = b""
462 while n is None or len(self._read_buf) < n:
463 to_read = None if n is None else max(n, self.buffer_size)
464 current = self.raw.read(to_read)
465
466 if current in (b"", None):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000467 nodata_val = current
468 break
Guido van Rossum01a27522007-03-07 01:00:12 +0000469 self._read_buf += current
470 if self._read_buf:
471 if n is None:
472 n = len(self._read_buf)
473 out = self._read_buf[:n]
474 self._read_buf = self._read_buf[n:]
475 else:
476 out = nodata_val
477 return out
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000478
479 def readable(self):
480 return True
481
Guido van Rossum01a27522007-03-07 01:00:12 +0000482 def fileno(self):
483 return self.raw.fileno()
484
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000485 def flush(self):
486 # Flush is a no-op
487 pass
488
Guido van Rossum01a27522007-03-07 01:00:12 +0000489 def close(self):
490 self.raw.close()
491
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000492
493class BufferedWriter(BufferedIOBase):
494
Guido van Rossum78892e42007-04-06 17:31:18 +0000495 # XXX docstring
496
Guido van Rossum01a27522007-03-07 01:00:12 +0000497 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
498 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
499 assert raw.writable()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000500 self.raw = raw
501 self.buffer_size = buffer_size
Guido van Rossum01a27522007-03-07 01:00:12 +0000502 self.max_buffer_size = max_buffer_size
503 self._write_buf = b''
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000504
505 def write(self, b):
Guido van Rossum01a27522007-03-07 01:00:12 +0000506 # XXX we can implement some more tricks to try and avoid partial writes
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000507 assert issubclass(type(b), bytes)
Guido van Rossum01a27522007-03-07 01:00:12 +0000508 if len(self._write_buf) > self.buffer_size:
509 # We're full, so let's pre-flush the buffer
510 try:
511 self.flush()
512 except BlockingIO as e:
513 # We can't accept anything else.
514 raise BlockingIO(e.errno, e.strerror, 0)
515 self._write_buf += b
516 if (len(self._write_buf) > self.buffer_size):
517 try:
518 self.flush()
519 except BlockingIO as e:
520 if (len(self._write_buf) > self.max_buffer_size):
521 # We've hit max_buffer_size. We have to accept a partial
522 # write and cut back our buffer.
523 overage = len(self._write_buf) - self.max_buffer_size
524 self._write_buf = self._write_buf[:self.max_buffer_size]
525 raise BlockingIO(e.errno, e.strerror, overage)
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000526
Guido van Rossum01a27522007-03-07 01:00:12 +0000527 def writable(self):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000528 return True
529
530 def flush(self):
Guido van Rossum01a27522007-03-07 01:00:12 +0000531 try:
532 while len(self._write_buf):
533 self._write_buf = self._write_buf[
534 self.raw.write(self._write_buf):]
535 except BlockingIO as e:
536 self._write_buf[e.characters_written:]
537 raise
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000538
Guido van Rossum01a27522007-03-07 01:00:12 +0000539 def fileno(self):
540 return self.raw.fileno()
541
542 def close(self):
543 self.raw.close()
544
545 def __del__(self):
546 # XXX flush buffers before dying. Is there a nicer way to do this?
547 if self._write_buf:
548 self.flush()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000549
550
551class BufferedRWPair(BufferedReader, BufferedWriter):
552
Guido van Rossum01a27522007-03-07 01:00:12 +0000553 """A buffered reader and writer object together.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000554
555 A buffered reader object and buffered writer object put together to
556 form a sequential IO object that can read and write.
Guido van Rossum78892e42007-04-06 17:31:18 +0000557
558 This is typically used with a socket or two-way pipe.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000559 """
560
Guido van Rossum01a27522007-03-07 01:00:12 +0000561 def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE,
562 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
563 assert reader.readable()
564 assert writer.writable()
565 BufferedReader.__init__(self, reader)
566 BufferedWriter.__init__(self, writer, buffer_size, max_buffer_size)
567 self.reader = reader
568 self.writer = writer
569
570 def read(self, n=None):
571 return self.reader.read(n)
572
573 def write(self, b):
574 return self.writer.write(b)
575
576 def readable(self):
577 return self.reader.readable()
578
579 def writable(self):
580 return self.writer.writable()
581
582 def flush(self):
583 return self.writer.flush()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000584
585 def seekable(self):
586 return False
Guido van Rossum01a27522007-03-07 01:00:12 +0000587
588 def fileno(self):
589 # XXX whose fileno do we return? Reader's? Writer's? Unsupported?
590 raise IOError(".fileno() unsupported")
591
592 def close(self):
593 self.reader.close()
594 self.writer.close()
595
596
597class BufferedRandom(BufferedReader, BufferedWriter):
598
Guido van Rossum78892e42007-04-06 17:31:18 +0000599 # XXX docstring
600
Guido van Rossum01a27522007-03-07 01:00:12 +0000601 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
602 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
603 assert raw.seekable()
604 BufferedReader.__init__(self, raw)
605 BufferedWriter.__init__(self, raw, buffer_size, max_buffer_size)
606
607 def seekable(self):
608 return self.raw.seekable()
609
610 def readable(self):
611 return self.raw.readable()
612
613 def writable(self):
614 return self.raw.writable()
615
616 def seek(self, pos, whence=0):
617 self.flush()
618 self._read_buf = b""
619 self.raw.seek(pos, whence)
620 # XXX I suppose we could implement some magic here to move through the
621 # existing read buffer in the case of seek(<some small +ve number>, 1)
622
623 def tell(self):
624 if (self._write_buf):
625 return self.raw.tell() + len(self._write_buf)
626 else:
627 return self.raw.tell() - len(self._read_buf)
628
629 def read(self, n=None):
630 self.flush()
631 return BufferedReader.read(self, n)
632
633 def write(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000634 if self._read_buf:
635 self.raw.seek(-len(self._read_buf), 1) # Undo readahead
636 self._read_buf = b""
Guido van Rossum01a27522007-03-07 01:00:12 +0000637 return BufferedWriter.write(self, b)
638
639 def flush(self):
640 BufferedWriter.flush(self)
641
642 def close(self):
643 self.raw.close()
Guido van Rossum78892e42007-04-06 17:31:18 +0000644
645
646class TextIOBase(BufferedIOBase):
647
648 """Base class for text I/O.
649
650 This class provides a character and line based interface to stream I/O.
651 """
652
653 def read(self, n: int = -1) -> str:
654 """read(n: int = -1) -> str. Read at most n characters from stream.
655
656 Read from underlying buffer until we have n characters or we hit EOF.
657 If n is negative or omitted, read until EOF.
658 """
659 raise IOError(".read() not supported")
660
661 def write(self, s: str):
662 """write(s: str) -> None. Write string s to stream.
663 """
664 raise IOError(".write() not supported")
665
666 def readline(self) -> str:
667 """readline() -> str. Read until newline or EOF.
668
669 Returns an empty string if EOF is hit immediately.
670 """
671 raise IOError(".readline() not supported")
672
673 def __iter__(self):
674 """__iter__() -> Iterator. Return line iterator (actually just self).
675 """
676 return self
677
678 def next(self):
679 """Same as readline() except raises StopIteration on immediate EOF.
680 """
681 line = self.readline()
682 if line == '':
683 raise StopIteration
684 return line
685
686
687class TextIOWrapper(TextIOBase):
688
689 """Buffered text stream.
690
691 Character and line based layer over a BufferedIOBase object.
692 """
693
694 # XXX tell(), seek()
695
696 def __init__(self, buffer, encoding=None, newline=None):
697 if newline not in (None, '\n', '\r\n'):
698 raise IOError("illegal newline %s" % newline) # XXX: ValueError?
699 if encoding is None:
700 # XXX This is questionable
701 encoding = sys.getfilesystemencoding()
702 if encoding is None:
703 encoding = "latin-1" # XXX, but this is best for transparancy
704
705 self.buffer = buffer
706 self._encoding = encoding
707 self._newline = newline or os.linesep
708 self._fix_newlines = newline is None
709 self._decoder = None
710 self._pending = ''
711
712 def write(self, s: str):
713 return self.buffer.write(s.encode(self._encoding))
714
715 def _get_decoder(self):
716 make_decoder = codecs.getincrementaldecoder(self._encoding)
717 if make_decoder is None:
718 raise IOError(".readline() not supported for encoding %s" %
719 self._encoding)
720 decoder = self._decoder = make_decoder() # XXX: errors
721 if isinstance(decoder, codecs.BufferedIncrementalDecoder):
722 # XXX Hack: make the codec use bytes instead of strings
723 decoder.buffer = b""
724 return decoder
725
726 def read(self, n: int = -1):
727 decoder = self._decoder or self._get_decoder()
728 res = self._pending
729 if n < 0:
730 res += decoder.decode(self.buffer.read(), True)
731 self._pending = ''
732 return res
733 else:
734 while len(res) < n:
735 data = self.buffer.read(64)
736 res += decoder.decode(data, not data)
737 if not data:
738 break
739 self._pending = res[n:]
740 return res[:n]
741
742 def readline(self):
743 line = self._pending
744 start = 0
745 decoder = self._decoder or self._get_decoder()
746
747 while True:
748 # In C we'd look for these in parallel of course.
749 nlpos = line.find("\n", start)
750 crpos = line.find("\r", start)
751 if nlpos >= 0 and crpos >= 0:
752 endpos = min(nlpos, crpos)
753 else:
754 endpos = nlpos if nlpos >= 0 else crpos
755
756 if endpos != -1:
757 endc = line[endpos]
758 if endc == "\n":
759 ending = "\n"
760 break
761
762 # We've seen \r - is it standalone, \r\n or \r at end of line?
763 if endpos + 1 < len(line):
764 if line[endpos+1] == '\n':
765 ending = "\r\n"
766 else:
767 ending = "\r"
768 break
769 # There might be a following \n in the next block of data ...
770 start = endpos
771 else:
772 start = len(line)
773
774 # No line ending seen yet - get more data
775 while True:
776 data = self.buffer.read(64)
777 more_line = decoder.decode(data, not data)
778 if more_line != "" or not data:
779 break
780
781 if more_line == "":
782 ending = ''
783 endpos = len(line)
784 break
785
786 line += more_line
787
788 nextpos = endpos + len(ending)
789 self._pending = line[nextpos:]
790
791 # XXX Update self.newlines here if we want to support that
792
793 if self._fix_newlines and ending != "\n" and ending != '':
794 return line[:endpos] + "\n"
795 else:
796 return line[:nextpos]