Skip to content

Commit 024da5c

Browse files
committed
Make all the multibyte codec tests pass.
Changes to io.py, necessary to make this work: - Redid io.StringIO as a TextIOWrapper on top of a BytesIO instance. - Got rid of _MemoryIOMixin, folding it into BytesIO instead. - The read() functions that take -1 to mean "eveything" now also take None. - Added readline() support to BufferedIOBase. :-(
1 parent f4cfc8f commit 024da5c

10 files changed

Lines changed: 1225 additions & 1227 deletions

Lib/io.py

Lines changed: 57 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ class BufferedIOBase(IOBase):
415415
def read(self, n: int = -1) -> bytes:
416416
"""read(n: int = -1) -> bytes. Read and return up to n bytes.
417417
418-
If the argument is omitted, or negative, reads and returns all
419-
data until EOF.
418+
If the argument is omitted, None, or negative, reads and
419+
returns all data until EOF.
420420
421421
If the argument is positive, and the underlying raw stream is
422422
not 'interactive', multiple raw reads may be issued to satisfy
@@ -450,6 +450,20 @@ def readinto(self, b: bytes) -> int:
450450
b[:n] = data
451451
return n
452452

453+
def readline(self, sizehint: int = -1) -> bytes:
454+
"""For backwards compatibility, a (slow) readline()."""
455+
if sizehint is None:
456+
sizehint = -1
457+
res = b""
458+
while sizehint < 0 or len(res) < sizehint:
459+
b = self.read(1)
460+
if not b:
461+
break
462+
res += b
463+
if b == b"\n":
464+
break
465+
return res
466+
453467
def write(self, b: bytes) -> int:
454468
"""write(b: bytes) -> int. Write the given buffer to the IO stream.
455469
@@ -518,26 +532,35 @@ def isatty(self):
518532
return self.raw.isatty()
519533

520534

521-
class _MemoryIOMixin(BufferedIOBase):
535+
class BytesIO(BufferedIOBase):
522536

523-
# XXX docstring
537+
"""Buffered I/O implementation using an in-memory bytes buffer."""
524538

525-
def __init__(self, buffer):
539+
# XXX More docs
540+
541+
def __init__(self, initial_bytes=None):
542+
buffer = b""
543+
if initial_bytes is not None:
544+
buffer += initial_bytes
526545
self._buffer = buffer
527546
self._pos = 0
528547

529548
def getvalue(self):
530549
return self._buffer
531550

532-
def read(self, n=-1):
533-
assert n is not None
551+
def read(self, n=None):
552+
if n is None:
553+
n = -1
534554
if n < 0:
535555
n = len(self._buffer)
536556
newpos = min(len(self._buffer), self._pos + n)
537557
b = self._buffer[self._pos : newpos]
538558
self._pos = newpos
539559
return b
540560

561+
def read1(self, n):
562+
return self.read(n)
563+
541564
def write(self, b):
542565
n = len(b)
543566
newpos = self._pos + n
@@ -575,65 +598,6 @@ def seekable(self):
575598
return True
576599

577600

578-
class BytesIO(_MemoryIOMixin):
579-
580-
"""Buffered I/O implementation using a bytes buffer, like StringIO."""
581-
582-
# XXX More docs
583-
584-
def __init__(self, initial_bytes=None):
585-
buffer = b""
586-
if initial_bytes is not None:
587-
buffer += initial_bytes
588-
_MemoryIOMixin.__init__(self, buffer)
589-
590-
591-
# XXX This should inherit from TextIOBase
592-
class StringIO(_MemoryIOMixin):
593-
594-
"""Buffered I/O implementation using a string buffer, like StringIO."""
595-
596-
# XXX More docs
597-
598-
# Reuses the same code as BytesIO, but encode strings on the way in
599-
# and decode them on the way out.
600-
601-
charsize = len("!".encode("unicode-internal"))
602-
603-
def __init__(self, initial_string=None):
604-
if initial_string is not None:
605-
buffer = initial_string.encode("unicode-internal")
606-
else:
607-
buffer = b""
608-
_MemoryIOMixin.__init__(self, buffer)
609-
610-
def getvalue(self):
611-
return self._buffer.encode("unicode-internal")
612-
613-
def read(self, n=-1):
614-
return super(StringIO, self).read(n*self.charsize) \
615-
.decode("unicode-internal")
616-
617-
def write(self, s):
618-
return super(StringIO, self).write(s.encode("unicode-internal")) \
619-
//self.charsize
620-
621-
def seek(self, pos, whence=0):
622-
return super(StringIO, self).seek(self.charsize*pos, whence) \
623-
//self.charsize
624-
625-
def tell(self):
626-
return super(StringIO, self).tell()//self.charsize
627-
628-
def truncate(self, pos=None):
629-
if pos is not None:
630-
pos *= self.charsize
631-
return super(StringIO, self).truncate(pos)//self.charsize
632-
633-
def readinto(self, b: bytes) -> int:
634-
self._unsupported("readinto")
635-
636-
637601
class BufferedReader(_BufferedIOMixin):
638602

639603
"""Buffer for a readable sequential RawIO object."""
@@ -646,15 +610,16 @@ def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
646610
self._read_buf = b""
647611
self.buffer_size = buffer_size
648612

649-
def read(self, n=-1):
613+
def read(self, n=None):
650614
"""Read n bytes.
651615
652616
Returns exactly n bytes of data unless the underlying raw IO
653617
stream reaches EOF of if the call would block in non-blocking
654618
mode. If n is negative, read until EOF or until read() would
655619
block.
656620
"""
657-
assert n is not None
621+
if n is None:
622+
n = -1
658623
nodata_val = b""
659624
while n < 0 or len(self._read_buf) < n:
660625
to_read = max(self.buffer_size,
@@ -801,7 +766,9 @@ def __init__(self, reader, writer,
801766
self.reader = BufferedReader(reader, buffer_size)
802767
self.writer = BufferedWriter(writer, buffer_size, max_buffer_size)
803768

804-
def read(self, n=-1):
769+
def read(self, n=None):
770+
if n is None:
771+
n = -1
805772
return self.reader.read(n)
806773

807774
def readinto(self, b):
@@ -861,7 +828,9 @@ def tell(self):
861828
else:
862829
return self.raw.tell() - len(self._read_buf)
863830

864-
def read(self, n=-1):
831+
def read(self, n=None):
832+
if n is None:
833+
n = -1
865834
self.flush()
866835
return BufferedReader.read(self, n)
867836

@@ -1129,7 +1098,9 @@ def _simplify(self, u):
11291098
except UnicodeEncodeError:
11301099
return u
11311100

1132-
def read(self, n: int = -1):
1101+
def read(self, n=None):
1102+
if n is None:
1103+
n = -1
11331104
decoder = self._decoder or self._get_decoder()
11341105
res = self._pending
11351106
if n < 0:
@@ -1146,7 +1117,7 @@ def read(self, n: int = -1):
11461117
self._pending = res[n:]
11471118
return self._simplify(res[:n])
11481119

1149-
def __next__(self) -> str:
1120+
def __next__(self):
11501121
self._telling = False
11511122
line = self.readline()
11521123
if not line:
@@ -1218,3 +1189,17 @@ def readline(self, limit=None):
12181189
return self._simplify(line[:endpos] + "\n")
12191190
else:
12201191
return self._simplify(line[:nextpos])
1192+
1193+
1194+
class StringIO(TextIOWrapper):
1195+
1196+
# XXX This is really slow, but fully functional
1197+
1198+
def __init__(self, initial_value=""):
1199+
super(StringIO, self).__init__(BytesIO(), "utf-8")
1200+
if initial_value:
1201+
self.write(initial_value)
1202+
self.seek(0)
1203+
1204+
def getvalue(self):
1205+
return self.buffer.getvalue().decode("utf-8")

0 commit comments

Comments
 (0)