blob: 23e29baafd73c4092cfe9982209bc60e87a92ec0 [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 Rossum68bbcd22007-02-27 17:19:33 +0000334class BufferedIOBase(RawIOBase):
Guido van Rossum28524c72007-02-27 05:47:44 +0000335
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000336 """XXX Docstring."""
337
338
Guido van Rossum78892e42007-04-06 17:31:18 +0000339class _MemoryBufferMixin:
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000340
Guido van Rossum78892e42007-04-06 17:31:18 +0000341 # XXX docstring
Guido van Rossum28524c72007-02-27 05:47:44 +0000342
Guido van Rossum78892e42007-04-06 17:31:18 +0000343 def __init__(self, buffer):
344 self._buffer = buffer
Guido van Rossum28524c72007-02-27 05:47:44 +0000345 self._pos = 0
Guido van Rossum28524c72007-02-27 05:47:44 +0000346
347 def getvalue(self):
348 return self._buffer
349
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000350 def read(self, n=None):
351 if n is None:
352 n = len(self._buffer)
Guido van Rossum28524c72007-02-27 05:47:44 +0000353 assert n >= 0
354 newpos = min(len(self._buffer), self._pos + n)
355 b = self._buffer[self._pos : newpos]
356 self._pos = newpos
357 return b
358
359 def readinto(self, b):
Guido van Rossum00efead2007-03-07 05:23:25 +0000360 tmp = self.read(len(b))
361 n = len(tmp)
362 b[:n] = tmp
363 return n
Guido van Rossum28524c72007-02-27 05:47:44 +0000364
365 def write(self, b):
366 n = len(b)
367 newpos = self._pos + n
368 self._buffer[self._pos:newpos] = b
369 self._pos = newpos
370 return n
371
372 def seek(self, pos, whence=0):
373 if whence == 0:
374 self._pos = max(0, pos)
375 elif whence == 1:
376 self._pos = max(0, self._pos + pos)
377 elif whence == 2:
378 self._pos = max(0, len(self._buffer) + pos)
379 else:
380 raise IOError("invalid whence value")
381
382 def tell(self):
383 return self._pos
384
385 def truncate(self, pos=None):
386 if pos is None:
387 pos = self._pos
388 else:
389 self._pos = max(0, pos)
390 del self._buffer[pos:]
391
392 def readable(self):
393 return True
394
395 def writable(self):
396 return True
397
398 def seekable(self):
399 return True
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000400
401
Guido van Rossum78892e42007-04-06 17:31:18 +0000402class BytesIO(_MemoryBufferMixin, BufferedIOBase):
403
404 """Buffered I/O implementation using a bytes buffer, like StringIO."""
405
406 # XXX More docs
407
408 def __init__(self, inital_bytes=None):
409 buffer = b""
410 if inital_bytes is not None:
411 buffer += inital_bytes
412 _MemoryBufferMixin.__init__(self, buffer)
413
414
415class StringIO(_MemoryBufferMixin, BufferedIOBase):
416
417 """Buffered I/O implementation using a string buffer, like StringIO."""
418
419 # XXX More docs
420
421 # XXX Reuses the same code as BytesIO, just with a string rather
422 # that bytes as the _buffer value. That won't work in C of course.
423
424 def __init__(self, inital_string=None):
425 buffer = ""
426 if inital_string is not None:
427 buffer += inital_string
428 _MemoryBufferMixin.__init__(self, buffer)
429
430
Guido van Rossum01a27522007-03-07 01:00:12 +0000431class BufferedIOBase(RawIOBase):
432
433 """Base class for buffered IO objects."""
434
435 def flush(self):
436 """Flush the buffer to the underlying raw IO object."""
437 raise IOError(".flush() unsupported")
438
439
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000440class BufferedReader(BufferedIOBase):
441
Guido van Rossum01a27522007-03-07 01:00:12 +0000442 """Buffer for a readable sequential RawIO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000443
Guido van Rossum78892e42007-04-06 17:31:18 +0000444 Does not allow random access (seek, tell). (Use BufferedRandom
445 for that.)
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000446 """
447
Guido van Rossum78892e42007-04-06 17:31:18 +0000448 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
Guido van Rossum01a27522007-03-07 01:00:12 +0000449 """Create a new buffered reader using the given readable raw IO object.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000450 """
451 assert raw.readable()
452 self.raw = raw
Guido van Rossum01a27522007-03-07 01:00:12 +0000453 self._read_buf = b""
Guido van Rossum78892e42007-04-06 17:31:18 +0000454 self.buffer_size = buffer_size
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000455 if hasattr(raw, 'fileno'):
456 self.fileno = raw.fileno
457
458 def read(self, n=None):
Guido van Rossum01a27522007-03-07 01:00:12 +0000459 """Read n bytes.
460
461 Returns exactly n bytes of data unless the underlying raw IO
462 stream reaches EOF of if the call would block in non-blocking
463 mode. If n is None, read until EOF or until read() would
464 block.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000465 """
Guido van Rossum78892e42007-04-06 17:31:18 +0000466 assert n is None or n > 0, '.read(): Bad read size %r' % n
467 nodata_val = b""
468 while n is None or len(self._read_buf) < n:
469 to_read = None if n is None else max(n, self.buffer_size)
470 current = self.raw.read(to_read)
471
472 if current in (b"", None):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000473 nodata_val = current
474 break
Guido van Rossum01a27522007-03-07 01:00:12 +0000475 self._read_buf += current
476 if self._read_buf:
477 if n is None:
478 n = len(self._read_buf)
479 out = self._read_buf[:n]
480 self._read_buf = self._read_buf[n:]
481 else:
482 out = nodata_val
483 return out
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000484
485 def readable(self):
486 return True
487
Guido van Rossum01a27522007-03-07 01:00:12 +0000488 def fileno(self):
489 return self.raw.fileno()
490
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000491 def flush(self):
492 # Flush is a no-op
493 pass
494
Guido van Rossum01a27522007-03-07 01:00:12 +0000495 def close(self):
496 self.raw.close()
497
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000498
499class BufferedWriter(BufferedIOBase):
500
Guido van Rossum78892e42007-04-06 17:31:18 +0000501 # XXX docstring
502
Guido van Rossum01a27522007-03-07 01:00:12 +0000503 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
504 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
505 assert raw.writable()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000506 self.raw = raw
507 self.buffer_size = buffer_size
Guido van Rossum01a27522007-03-07 01:00:12 +0000508 self.max_buffer_size = max_buffer_size
509 self._write_buf = b''
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000510
511 def write(self, b):
Guido van Rossum01a27522007-03-07 01:00:12 +0000512 # XXX we can implement some more tricks to try and avoid partial writes
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000513 assert issubclass(type(b), bytes)
Guido van Rossum01a27522007-03-07 01:00:12 +0000514 if len(self._write_buf) > self.buffer_size:
515 # We're full, so let's pre-flush the buffer
516 try:
517 self.flush()
518 except BlockingIO as e:
519 # We can't accept anything else.
520 raise BlockingIO(e.errno, e.strerror, 0)
521 self._write_buf += b
522 if (len(self._write_buf) > self.buffer_size):
523 try:
524 self.flush()
525 except BlockingIO as e:
526 if (len(self._write_buf) > self.max_buffer_size):
527 # We've hit max_buffer_size. We have to accept a partial
528 # write and cut back our buffer.
529 overage = len(self._write_buf) - self.max_buffer_size
530 self._write_buf = self._write_buf[:self.max_buffer_size]
531 raise BlockingIO(e.errno, e.strerror, overage)
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000532
Guido van Rossum01a27522007-03-07 01:00:12 +0000533 def writable(self):
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000534 return True
535
536 def flush(self):
Guido van Rossum01a27522007-03-07 01:00:12 +0000537 try:
538 while len(self._write_buf):
539 self._write_buf = self._write_buf[
540 self.raw.write(self._write_buf):]
541 except BlockingIO as e:
542 self._write_buf[e.characters_written:]
543 raise
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000544
Guido van Rossum01a27522007-03-07 01:00:12 +0000545 def fileno(self):
546 return self.raw.fileno()
547
548 def close(self):
549 self.raw.close()
550
551 def __del__(self):
552 # XXX flush buffers before dying. Is there a nicer way to do this?
553 if self._write_buf:
554 self.flush()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000555
556
557class BufferedRWPair(BufferedReader, BufferedWriter):
558
Guido van Rossum01a27522007-03-07 01:00:12 +0000559 """A buffered reader and writer object together.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000560
561 A buffered reader object and buffered writer object put together to
562 form a sequential IO object that can read and write.
Guido van Rossum78892e42007-04-06 17:31:18 +0000563
564 This is typically used with a socket or two-way pipe.
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000565 """
566
Guido van Rossum01a27522007-03-07 01:00:12 +0000567 def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE,
568 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
569 assert reader.readable()
570 assert writer.writable()
571 BufferedReader.__init__(self, reader)
572 BufferedWriter.__init__(self, writer, buffer_size, max_buffer_size)
573 self.reader = reader
574 self.writer = writer
575
576 def read(self, n=None):
577 return self.reader.read(n)
578
579 def write(self, b):
580 return self.writer.write(b)
581
582 def readable(self):
583 return self.reader.readable()
584
585 def writable(self):
586 return self.writer.writable()
587
588 def flush(self):
589 return self.writer.flush()
Guido van Rossum68bbcd22007-02-27 17:19:33 +0000590
591 def seekable(self):
592 return False
Guido van Rossum01a27522007-03-07 01:00:12 +0000593
594 def fileno(self):
595 # XXX whose fileno do we return? Reader's? Writer's? Unsupported?
596 raise IOError(".fileno() unsupported")
597
598 def close(self):
599 self.reader.close()
600 self.writer.close()
601
602
603class BufferedRandom(BufferedReader, BufferedWriter):
604
Guido van Rossum78892e42007-04-06 17:31:18 +0000605 # XXX docstring
606
Guido van Rossum01a27522007-03-07 01:00:12 +0000607 def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE,
608 max_buffer_size=DEFAULT_MAX_BUFFER_SIZE):
609 assert raw.seekable()
610 BufferedReader.__init__(self, raw)
611 BufferedWriter.__init__(self, raw, buffer_size, max_buffer_size)
612
613 def seekable(self):
614 return self.raw.seekable()
615
616 def readable(self):
617 return self.raw.readable()
618
619 def writable(self):
620 return self.raw.writable()
621
622 def seek(self, pos, whence=0):
623 self.flush()
624 self._read_buf = b""
625 self.raw.seek(pos, whence)
626 # XXX I suppose we could implement some magic here to move through the
627 # existing read buffer in the case of seek(<some small +ve number>, 1)
628
629 def tell(self):
630 if (self._write_buf):
631 return self.raw.tell() + len(self._write_buf)
632 else:
633 return self.raw.tell() - len(self._read_buf)
634
635 def read(self, n=None):
636 self.flush()
637 return BufferedReader.read(self, n)
638
639 def write(self, b):
Guido van Rossum78892e42007-04-06 17:31:18 +0000640 if self._read_buf:
641 self.raw.seek(-len(self._read_buf), 1) # Undo readahead
642 self._read_buf = b""
Guido van Rossum01a27522007-03-07 01:00:12 +0000643 return BufferedWriter.write(self, b)
644
645 def flush(self):
646 BufferedWriter.flush(self)
647
648 def close(self):
649 self.raw.close()
Guido van Rossum78892e42007-04-06 17:31:18 +0000650
651
652class TextIOBase(BufferedIOBase):
653
654 """Base class for text I/O.
655
656 This class provides a character and line based interface to stream I/O.
657 """
658
659 def read(self, n: int = -1) -> str:
660 """read(n: int = -1) -> str. Read at most n characters from stream.
661
662 Read from underlying buffer until we have n characters or we hit EOF.
663 If n is negative or omitted, read until EOF.
664 """
665 raise IOError(".read() not supported")
666
667 def write(self, s: str):
668 """write(s: str) -> None. Write string s to stream.
669 """
670 raise IOError(".write() not supported")
671
672 def readline(self) -> str:
673 """readline() -> str. Read until newline or EOF.
674
675 Returns an empty string if EOF is hit immediately.
676 """
677 raise IOError(".readline() not supported")
678
679 def __iter__(self):
680 """__iter__() -> Iterator. Return line iterator (actually just self).
681 """
682 return self
683
684 def next(self):
685 """Same as readline() except raises StopIteration on immediate EOF.
686 """
687 line = self.readline()
688 if line == '':
689 raise StopIteration
690 return line
691
692
693class TextIOWrapper(TextIOBase):
694
695 """Buffered text stream.
696
697 Character and line based layer over a BufferedIOBase object.
698 """
699
700 # XXX tell(), seek()
701
702 def __init__(self, buffer, encoding=None, newline=None):
703 if newline not in (None, '\n', '\r\n'):
704 raise IOError("illegal newline %s" % newline) # XXX: ValueError?
705 if encoding is None:
706 # XXX This is questionable
707 encoding = sys.getfilesystemencoding()
708 if encoding is None:
709 encoding = "latin-1" # XXX, but this is best for transparancy
710
711 self.buffer = buffer
712 self._encoding = encoding
713 self._newline = newline or os.linesep
714 self._fix_newlines = newline is None
715 self._decoder = None
716 self._pending = ''
717
718 def write(self, s: str):
719 return self.buffer.write(s.encode(self._encoding))
720
721 def _get_decoder(self):
722 make_decoder = codecs.getincrementaldecoder(self._encoding)
723 if make_decoder is None:
724 raise IOError(".readline() not supported for encoding %s" %
725 self._encoding)
726 decoder = self._decoder = make_decoder() # XXX: errors
727 if isinstance(decoder, codecs.BufferedIncrementalDecoder):
728 # XXX Hack: make the codec use bytes instead of strings
729 decoder.buffer = b""
730 return decoder
731
732 def read(self, n: int = -1):
733 decoder = self._decoder or self._get_decoder()
734 res = self._pending
735 if n < 0:
736 res += decoder.decode(self.buffer.read(), True)
737 self._pending = ''
738 return res
739 else:
740 while len(res) < n:
741 data = self.buffer.read(64)
742 res += decoder.decode(data, not data)
743 if not data:
744 break
745 self._pending = res[n:]
746 return res[:n]
747
748 def readline(self):
749 line = self._pending
750 start = 0
751 decoder = self._decoder or self._get_decoder()
752
753 while True:
754 # In C we'd look for these in parallel of course.
755 nlpos = line.find("\n", start)
756 crpos = line.find("\r", start)
757 if nlpos >= 0 and crpos >= 0:
758 endpos = min(nlpos, crpos)
759 else:
760 endpos = nlpos if nlpos >= 0 else crpos
761
762 if endpos != -1:
763 endc = line[endpos]
764 if endc == "\n":
765 ending = "\n"
766 break
767
768 # We've seen \r - is it standalone, \r\n or \r at end of line?
769 if endpos + 1 < len(line):
770 if line[endpos+1] == '\n':
771 ending = "\r\n"
772 else:
773 ending = "\r"
774 break
775 # There might be a following \n in the next block of data ...
776 start = endpos
777 else:
778 start = len(line)
779
780 # No line ending seen yet - get more data
781 while True:
782 data = self.buffer.read(64)
783 more_line = decoder.decode(data, not data)
784 if more_line != "" or not data:
785 break
786
787 if more_line == "":
788 ending = ''
789 endpos = len(line)
790 break
791
792 line += more_line
793
794 nextpos = endpos + len(ending)
795 self._pending = line[nextpos:]
796
797 # XXX Update self.newlines here if we want to support that
798
799 if self._fix_newlines and ending != "\n" and ending != '':
800 return line[:endpos] + "\n"
801 else:
802 return line[:nextpos]