summaryrefslogtreecommitdiff
path: root/Lib/_pyio.py
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2015-02-19 17:58:19 -0500
committerBenjamin Peterson <benjamin@python.org>2015-02-19 17:58:19 -0500
commit21db0b50addd267c7f0627c3d53b01bbba3eb2a6 (patch)
tree946b263c5d294fb9868cad2340cd58f57760d0e4 /Lib/_pyio.py
parentfa0d2fdb9dcbe2353af87e445313cdcebc898a67 (diff)
parent25d7d132b630f88298ffe921a9479f66db2f8bde (diff)
downloadcpython-21db0b50addd267c7f0627c3d53b01bbba3eb2a6.tar.gz
merge 3.4 (#23481)
Diffstat (limited to 'Lib/_pyio.py')
-rw-r--r--Lib/_pyio.py126
1 files changed, 96 insertions, 30 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index 577b6003b5..b0f0114999 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -6,6 +6,7 @@ import os
import abc
import codecs
import errno
+import array
# Import _thread instead of threading to reduce startup cost
try:
from _thread import allocate_lock as Lock
@@ -256,7 +257,7 @@ class OpenWrapper:
Trick so that open won't become a bound method when stored
as a class variable (as dbm.dumb does).
- See initstdio() in Python/pythonrun.c.
+ See initstdio() in Python/pylifecycle.c.
"""
__doc__ = DocDescriptor()
@@ -662,16 +663,33 @@ class BufferedIOBase(IOBase):
Raises BlockingIOError if the underlying raw stream has no
data at the moment.
"""
- # XXX This ought to work with anything that supports the buffer API
- data = self.read(len(b))
+
+ return self._readinto(b, read1=False)
+
+ def readinto1(self, b):
+ """Read up to len(b) bytes into *b*, using at most one system call
+
+ Returns an int representing the number of bytes read (0 for EOF).
+
+ Raises BlockingIOError if the underlying raw stream has no
+ data at the moment.
+ """
+
+ return self._readinto(b, read1=True)
+
+ def _readinto(self, b, read1):
+ if not isinstance(b, memoryview):
+ b = memoryview(b)
+ b = b.cast('B')
+
+ if read1:
+ data = self.read1(len(b))
+ else:
+ data = self.read(len(b))
n = len(data)
- try:
- b[:n] = data
- except TypeError as err:
- import array
- if not isinstance(b, array.array):
- raise err
- b[:n] = array.array('b', data)
+
+ b[:n] = data
+
return n
def write(self, b):
@@ -790,13 +808,14 @@ class _BufferedIOMixin(BufferedIOBase):
.format(self.__class__.__name__))
def __repr__(self):
- clsname = self.__class__.__name__
+ modname = self.__class__.__module__
+ clsname = self.__class__.__qualname__
try:
name = self.name
except Exception:
- return "<_pyio.{0}>".format(clsname)
+ return "<{}.{}>".format(modname, clsname)
else:
- return "<_pyio.{0} name={1!r}>".format(clsname, name)
+ return "<{}.{} name={!r}>".format(modname, clsname, name)
### Lower-level APIs ###
@@ -993,10 +1012,7 @@ class BufferedReader(_BufferedIOMixin):
current_size = 0
while True:
# Read until EOF or until read() would block.
- try:
- chunk = self.raw.read()
- except InterruptedError:
- continue
+ chunk = self.raw.read()
if chunk in empty_values:
nodata_val = chunk
break
@@ -1015,10 +1031,7 @@ class BufferedReader(_BufferedIOMixin):
chunks = [buf[pos:]]
wanted = max(self.buffer_size, n)
while avail < n:
- try:
- chunk = self.raw.read(wanted)
- except InterruptedError:
- continue
+ chunk = self.raw.read(wanted)
if chunk in empty_values:
nodata_val = chunk
break
@@ -1047,12 +1060,7 @@ class BufferedReader(_BufferedIOMixin):
have = len(self._read_buf) - self._read_pos
if have < want or have <= 0:
to_read = self.buffer_size - have
- while True:
- try:
- current = self.raw.read(to_read)
- except InterruptedError:
- continue
- break
+ current = self.raw.read(to_read)
if current:
self._read_buf = self._read_buf[self._read_pos:] + current
self._read_pos = 0
@@ -1071,6 +1079,58 @@ class BufferedReader(_BufferedIOMixin):
return self._read_unlocked(
min(size, len(self._read_buf) - self._read_pos))
+ # Implementing readinto() and readinto1() is not strictly necessary (we
+ # could rely on the base class that provides an implementation in terms of
+ # read() and read1()). We do it anyway to keep the _pyio implementation
+ # similar to the io implementation (which implements the methods for
+ # performance reasons).
+ def _readinto(self, buf, read1):
+ """Read data into *buf* with at most one system call."""
+
+ if len(buf) == 0:
+ return 0
+
+ # Need to create a memoryview object of type 'b', otherwise
+ # we may not be able to assign bytes to it, and slicing it
+ # would create a new object.
+ if not isinstance(buf, memoryview):
+ buf = memoryview(buf)
+ buf = buf.cast('B')
+
+ written = 0
+ with self._read_lock:
+ while written < len(buf):
+
+ # First try to read from internal buffer
+ avail = min(len(self._read_buf) - self._read_pos, len(buf))
+ if avail:
+ buf[written:written+avail] = \
+ self._read_buf[self._read_pos:self._read_pos+avail]
+ self._read_pos += avail
+ written += avail
+ if written == len(buf):
+ break
+
+ # If remaining space in callers buffer is larger than
+ # internal buffer, read directly into callers buffer
+ if len(buf) - written > self.buffer_size:
+ n = self.raw.readinto(buf[written:])
+ if not n:
+ break # eof
+ written += n
+
+ # Otherwise refill internal buffer - unless we're
+ # in read1 mode and already got some data
+ elif not (read1 and written):
+ if not self._peek_unlocked(1):
+ break # eof
+
+ # In readinto1 mode, return as soon as we have some data
+ if read1 and written:
+ break
+
+ return written
+
def tell(self):
return _BufferedIOMixin.tell(self) - len(self._read_buf) + self._read_pos
@@ -1149,8 +1209,6 @@ class BufferedWriter(_BufferedIOMixin):
while self._write_buf:
try:
n = self.raw.write(self._write_buf)
- except InterruptedError:
- continue
except BlockingIOError:
raise RuntimeError("self.raw should implement RawIOBase: it "
"should not raise BlockingIOError")
@@ -1220,6 +1278,9 @@ class BufferedRWPair(BufferedIOBase):
def read1(self, size):
return self.reader.read1(size)
+ def readinto1(self, b):
+ return self.reader.readinto1(b)
+
def readable(self):
return self.reader.readable()
@@ -1302,6 +1363,10 @@ class BufferedRandom(BufferedWriter, BufferedReader):
self.flush()
return BufferedReader.read1(self, size)
+ def readinto1(self, b):
+ self.flush()
+ return BufferedReader.readinto1(self, b)
+
def write(self, b):
if self._read_buf:
# Undo readahead
@@ -1564,7 +1629,8 @@ class TextIOWrapper(TextIOBase):
# - "chars_..." for integer variables that count decoded characters
def __repr__(self):
- result = "<_pyio.TextIOWrapper"
+ result = "<{}.{}".format(self.__class__.__module__,
+ self.__class__.__qualname__)
try:
name = self.name
except Exception: