Index: Python/getargs.c =================================================================== --- Python/getargs.c (revision 58201) +++ Python/getargs.c (working copy) @@ -1253,7 +1253,7 @@ "string or read-only character buffer", arg, msgbuf, bufsize); - if ((*pb->bf_getbuffer)(arg, &view, PyBUF_CHARACTER) != 0) + if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0) return converterr("string or single-segment read-only buffer", arg, msgbuf, bufsize); Index: Include/bytesobject.h =================================================================== --- Include/bytesobject.h (revision 58201) +++ Include/bytesobject.h (working copy) @@ -8,7 +8,7 @@ #include -/* Type PyBytesObject represents a mutable array of bytes. +/* Type PyBytesObject represents an immutable array of bytes. * The Python API is that of a sequence; * the bytes are mapped to ints in [0, 256). * Bytes are not characters; they may be used to encode characters. Index: Objects/bytesobject.c =================================================================== --- Objects/bytesobject.c (revision 58201) +++ Objects/bytesobject.c (working copy) @@ -32,24 +32,7 @@ /* end nullbytes support */ -/* Helpers */ - static int -_getbytevalue(PyObject* arg, int *value) -{ - PyObject *intarg = PyNumber_Int(arg); - if (! intarg) - return 0; - *value = PyInt_AsLong(intarg); - Py_DECREF(intarg); - if (*value < 0 || *value >= 256) { - PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); - return 0; - } - return 1; -} - -static int bytes_getbuffer(PyBytesObject *obj, PyBuffer *view, int flags) { int ret; @@ -62,7 +45,8 @@ ptr = ""; else ptr = obj->ob_bytes; - ret = PyBuffer_FillInfo(view, ptr, Py_Size(obj), 0, flags); + ret = PyBuffer_FillInfo(view, ptr, Py_Size(obj), + 1 /* readonly */, flags); if (ret >= 0) { obj->ob_exports++; } @@ -262,7 +246,7 @@ } static PyObject * -bytes_iconcat(PyBytesObject *self, PyObject *other) +_bytes_iconcat(PyBytesObject *self, PyObject *other) { Py_ssize_t mysize; Py_ssize_t size; @@ -320,37 +304,6 @@ return (PyObject *)result; } -static PyObject * -bytes_irepeat(PyBytesObject *self, Py_ssize_t count) -{ - Py_ssize_t mysize; - Py_ssize_t size; - - if (count < 0) - count = 0; - mysize = Py_Size(self); - size = mysize * count; - if (count != 0 && size / count != mysize) - return PyErr_NoMemory(); - if (size < self->ob_alloc) { - Py_Size(self) = size; - self->ob_bytes[Py_Size(self)] = '\0'; /* Trailing null byte */ - } - else if (PyBytes_Resize((PyObject *)self, size) < 0) - return NULL; - - if (mysize == 1) - memset(self->ob_bytes, self->ob_bytes[0], size); - else { - Py_ssize_t i; - for (i = 1; i < count; i++) - memcpy(self->ob_bytes + i*mysize, self->ob_bytes, mysize); - } - - Py_INCREF(self); - return (PyObject *)self; -} - static int bytes_substring(PyBytesObject *self, PyBytesObject *other) { @@ -457,279 +410,6 @@ } static int -bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi, - PyObject *values) -{ - Py_ssize_t avail, needed; - void *bytes; - PyBuffer vbytes; - int res = 0; - - vbytes.len = -1; - if (values == (PyObject *)self) { - /* Make a copy and call this function recursively */ - int err; - values = PyBytes_FromObject(values); - if (values == NULL) - return -1; - err = bytes_setslice(self, lo, hi, values); - Py_DECREF(values); - return err; - } - if (values == NULL) { - /* del b[lo:hi] */ - bytes = NULL; - needed = 0; - } - else { - if (_getbuffer(values, &vbytes) < 0) { - PyErr_Format(PyExc_TypeError, - "can't set bytes slice from %.100s", - Py_Type(values)->tp_name); - return -1; - } - needed = vbytes.len; - bytes = vbytes.buf; - } - - if (lo < 0) - lo = 0; - if (hi < lo) - hi = lo; - if (hi > Py_Size(self)) - hi = Py_Size(self); - - avail = hi - lo; - if (avail < 0) - lo = hi = avail = 0; - - if (avail != needed) { - if (avail > needed) { - /* - 0 lo hi old_size - | |<----avail----->|<-----tomove------>| - | |<-needed->|<-----tomove------>| - 0 lo new_hi new_size - */ - memmove(self->ob_bytes + lo + needed, self->ob_bytes + hi, - Py_Size(self) - hi); - } - /* XXX(nnorwitz): need to verify this can't overflow! */ - if (PyBytes_Resize((PyObject *)self, - Py_Size(self) + needed - avail) < 0) { - res = -1; - goto finish; - } - if (avail < needed) { - /* - 0 lo hi old_size - | |<-avail->|<-----tomove------>| - | |<----needed---->|<-----tomove------>| - 0 lo new_hi new_size - */ - memmove(self->ob_bytes + lo + needed, self->ob_bytes + hi, - Py_Size(self) - lo - needed); - } - } - - if (needed > 0) - memcpy(self->ob_bytes + lo, bytes, needed); - - - finish: - if (vbytes.len != -1) - PyObject_ReleaseBuffer(values, &vbytes); - return res; -} - -static int -bytes_setitem(PyBytesObject *self, Py_ssize_t i, PyObject *value) -{ - Py_ssize_t ival; - - if (i < 0) - i += Py_Size(self); - - if (i < 0 || i >= Py_Size(self)) { - PyErr_SetString(PyExc_IndexError, "bytes index out of range"); - return -1; - } - - if (value == NULL) - return bytes_setslice(self, i, i+1, NULL); - - ival = PyNumber_AsSsize_t(value, PyExc_ValueError); - if (ival == -1 && PyErr_Occurred()) - return -1; - - if (ival < 0 || ival >= 256) { - PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); - return -1; - } - - self->ob_bytes[i] = ival; - return 0; -} - -static int -bytes_ass_subscript(PyBytesObject *self, PyObject *item, PyObject *values) -{ - Py_ssize_t start, stop, step, slicelen, needed; - char *bytes; - - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - - if (i == -1 && PyErr_Occurred()) - return -1; - - if (i < 0) - i += PyBytes_GET_SIZE(self); - - if (i < 0 || i >= Py_Size(self)) { - PyErr_SetString(PyExc_IndexError, "bytes index out of range"); - return -1; - } - - if (values == NULL) { - /* Fall through to slice assignment */ - start = i; - stop = i + 1; - step = 1; - slicelen = 1; - } - else { - Py_ssize_t ival = PyNumber_AsSsize_t(values, PyExc_ValueError); - if (ival == -1 && PyErr_Occurred()) - return -1; - if (ival < 0 || ival >= 256) { - PyErr_SetString(PyExc_ValueError, - "byte must be in range(0, 256)"); - return -1; - } - self->ob_bytes[i] = (char)ival; - return 0; - } - } - else if (PySlice_Check(item)) { - if (PySlice_GetIndicesEx((PySliceObject *)item, - PyBytes_GET_SIZE(self), - &start, &stop, &step, &slicelen) < 0) { - return -1; - } - } - else { - PyErr_SetString(PyExc_TypeError, "bytes indices must be integer"); - return -1; - } - - if (values == NULL) { - bytes = NULL; - needed = 0; - } - else if (values == (PyObject *)self || !PyBytes_Check(values)) { - /* Make a copy an call this function recursively */ - int err; - values = PyBytes_FromObject(values); - if (values == NULL) - return -1; - err = bytes_ass_subscript(self, item, values); - Py_DECREF(values); - return err; - } - else { - assert(PyBytes_Check(values)); - bytes = ((PyBytesObject *)values)->ob_bytes; - needed = Py_Size(values); - } - /* Make sure b[5:2] = ... inserts before 5, not before 2. */ - if ((step < 0 && start < stop) || - (step > 0 && start > stop)) - stop = start; - if (step == 1) { - if (slicelen != needed) { - if (slicelen > needed) { - /* - 0 start stop old_size - | |<---slicelen--->|<-----tomove------>| - | |<-needed->|<-----tomove------>| - 0 lo new_hi new_size - */ - memmove(self->ob_bytes + start + needed, self->ob_bytes + stop, - Py_Size(self) - stop); - } - if (PyBytes_Resize((PyObject *)self, - Py_Size(self) + needed - slicelen) < 0) - return -1; - if (slicelen < needed) { - /* - 0 lo hi old_size - | |<-avail->|<-----tomove------>| - | |<----needed---->|<-----tomove------>| - 0 lo new_hi new_size - */ - memmove(self->ob_bytes + start + needed, self->ob_bytes + stop, - Py_Size(self) - start - needed); - } - } - - if (needed > 0) - memcpy(self->ob_bytes + start, bytes, needed); - - return 0; - } - else { - if (needed == 0) { - /* Delete slice */ - Py_ssize_t cur, i; - - if (step < 0) { - stop = start + 1; - start = stop + step * (slicelen - 1) - 1; - step = -step; - } - for (cur = start, i = 0; - i < slicelen; cur += step, i++) { - Py_ssize_t lim = step - 1; - - if (cur + step >= PyBytes_GET_SIZE(self)) - lim = PyBytes_GET_SIZE(self) - cur - 1; - - memmove(self->ob_bytes + cur - i, - self->ob_bytes + cur + 1, lim); - } - /* Move the tail of the bytes, in one chunk */ - cur = start + slicelen*step; - if (cur < PyBytes_GET_SIZE(self)) { - memmove(self->ob_bytes + cur - slicelen, - self->ob_bytes + cur, - PyBytes_GET_SIZE(self) - cur); - } - if (PyBytes_Resize((PyObject *)self, - PyBytes_GET_SIZE(self) - slicelen) < 0) - return -1; - - return 0; - } - else { - /* Assign slice */ - Py_ssize_t cur, i; - - if (needed != slicelen) { - PyErr_Format(PyExc_ValueError, - "attempt to assign bytes of size %zd " - "to extended slice of size %zd", - needed, slicelen); - return -1; - } - for (cur = start, i = 0; i < slicelen; cur += step, i++) - self->ob_bytes[cur] = bytes[i]; - return 0; - } - } -} - -static int bytes_init(PyBytesObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"source", "encoding", "errors", 0}; @@ -779,7 +459,7 @@ Py_DECREF(encoded); return -1; } - new = bytes_iconcat(self, encoded); + new = _bytes_iconcat(self, encoded); Py_DECREF(encoded); if (new == NULL) return -1; @@ -1354,9 +1034,10 @@ table1 = PyBytes_AS_STRING(tableobj); tablen = PyBytes_GET_SIZE(tableobj); } - /* XXX -> Use the modern buffer interface */ - else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen)) + /* XXX -> use the modern buffer interface */ + else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen)) { return NULL; + } if (tablen != 256) { PyErr_SetString(PyExc_ValueError, @@ -1370,8 +1051,9 @@ dellen = PyBytes_GET_SIZE(delobj); } /* XXX -> use the modern buffer interface */ - else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) + else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) { return NULL; + } } else { del_table = NULL; @@ -2451,169 +2133,6 @@ return NULL; } -PyDoc_STRVAR(extend__doc__, -"B.extend(iterable int) -> None\n\ -\n\ -Append all the elements from the iterator or sequence to the\n\ -end of the bytes."); -static PyObject * -bytes_extend(PyBytesObject *self, PyObject *arg) -{ - if (bytes_setslice(self, Py_Size(self), Py_Size(self), arg) == -1) - return NULL; - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(reverse__doc__, -"B.reverse() -> None\n\ -\n\ -Reverse the order of the values in bytes in place."); -static PyObject * -bytes_reverse(PyBytesObject *self, PyObject *unused) -{ - char swap, *head, *tail; - Py_ssize_t i, j, n = Py_Size(self); - - j = n / 2; - head = self->ob_bytes; - tail = head + n - 1; - for (i = 0; i < j; i++) { - swap = *head; - *head++ = *tail; - *tail-- = swap; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(insert__doc__, -"B.insert(index, int) -> None\n\ -\n\ -Insert a single item into the bytes before the given index."); -static PyObject * -bytes_insert(PyBytesObject *self, PyObject *args) -{ - int value; - Py_ssize_t where, n = Py_Size(self); - - if (!PyArg_ParseTuple(args, "ni:insert", &where, &value)) - return NULL; - - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to bytes"); - return NULL; - } - if (value < 0 || value >= 256) { - PyErr_SetString(PyExc_ValueError, - "byte must be in range(0, 256)"); - return NULL; - } - if (PyBytes_Resize((PyObject *)self, n + 1) < 0) - return NULL; - - if (where < 0) { - where += n; - if (where < 0) - where = 0; - } - if (where > n) - where = n; - memmove(self->ob_bytes + where + 1, self->ob_bytes + where, n - where); - self->ob_bytes[where] = value; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(append__doc__, -"B.append(int) -> None\n\ -\n\ -Append a single item to the end of the bytes."); -static PyObject * -bytes_append(PyBytesObject *self, PyObject *arg) -{ - int value; - Py_ssize_t n = Py_Size(self); - - if (! _getbytevalue(arg, &value)) - return NULL; - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to bytes"); - return NULL; - } - if (PyBytes_Resize((PyObject *)self, n + 1) < 0) - return NULL; - - self->ob_bytes[n] = value; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pop__doc__, -"B.pop([index]) -> int\n\ -\n\ -Remove and return a single item from the bytes. If no index\n\ -argument is give, will pop the last value."); -static PyObject * -bytes_pop(PyBytesObject *self, PyObject *args) -{ - int value; - Py_ssize_t where = -1, n = Py_Size(self); - - if (!PyArg_ParseTuple(args, "|n:pop", &where)) - return NULL; - - if (n == 0) { - PyErr_SetString(PyExc_OverflowError, - "cannot pop an empty bytes"); - return NULL; - } - if (where < 0) - where += Py_Size(self); - if (where < 0 || where >= Py_Size(self)) { - PyErr_SetString(PyExc_IndexError, "pop index out of range"); - return NULL; - } - - value = self->ob_bytes[where]; - memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); - if (PyBytes_Resize((PyObject *)self, n - 1) < 0) - return NULL; - - return PyInt_FromLong(value); -} - -PyDoc_STRVAR(remove__doc__, -"B.remove(int) -> None\n\ -\n\ -Remove the first occurance of a value in bytes"); -static PyObject * -bytes_remove(PyBytesObject *self, PyObject *arg) -{ - int value; - Py_ssize_t where, n = Py_Size(self); - - if (! _getbytevalue(arg, &value)) - return NULL; - - for (where = 0; where < n; where++) { - if (self->ob_bytes[where] == value) - break; - } - if (where == n) { - PyErr_SetString(PyExc_ValueError, "value not found in bytes"); - return NULL; - } - - memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); - if (PyBytes_Resize((PyObject *)self, n - 1) < 0) - return NULL; - - Py_RETURN_NONE; -} - /* XXX These two helpers could be optimized if argsize == 1 */ static Py_ssize_t @@ -2927,17 +2446,17 @@ (ssizeargfunc)bytes_repeat, /* sq_repeat */ (ssizeargfunc)bytes_getitem, /* sq_item */ 0, /* sq_slice */ - (ssizeobjargproc)bytes_setitem, /* sq_ass_item */ + 0, /* sq_ass_item */ 0, /* sq_ass_slice */ (objobjproc)bytes_contains, /* sq_contains */ - (binaryfunc)bytes_iconcat, /* sq_inplace_concat */ - (ssizeargfunc)bytes_irepeat, /* sq_inplace_repeat */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ }; static PyMappingMethods bytes_as_mapping = { (lenfunc)bytes_length, (binaryfunc)bytes_subscript, - (objobjargproc)bytes_ass_subscript, + 0, }; static PyBufferProcs bytes_as_buffer = { @@ -2961,12 +2480,6 @@ {"rpartition", (PyCFunction)bytes_rpartition, METH_O, rpartition__doc__}, {"split", (PyCFunction)bytes_split, METH_VARARGS, split__doc__}, {"rsplit", (PyCFunction)bytes_rsplit, METH_VARARGS, rsplit__doc__}, - {"extend", (PyCFunction)bytes_extend, METH_O, extend__doc__}, - {"insert", (PyCFunction)bytes_insert, METH_VARARGS, insert__doc__}, - {"append", (PyCFunction)bytes_append, METH_O, append__doc__}, - {"reverse", (PyCFunction)bytes_reverse, METH_NOARGS, reverse__doc__}, - {"pop", (PyCFunction)bytes_pop, METH_VARARGS, pop__doc__}, - {"remove", (PyCFunction)bytes_remove, METH_O, remove__doc__}, {"strip", (PyCFunction)bytes_strip, METH_VARARGS, strip__doc__}, {"lstrip", (PyCFunction)bytes_lstrip, METH_VARARGS, lstrip__doc__}, {"rstrip", (PyCFunction)bytes_rstrip, METH_VARARGS, rstrip__doc__}, @@ -2998,7 +2511,7 @@ 0, /* tp_as_number */ &bytes_as_sequence, /* tp_as_sequence */ &bytes_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + 0, /* tp_hash TODO(jyasskin): define this.*/ 0, /* tp_call */ (reprfunc)bytes_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ Index: Lib/uuid.py =================================================================== --- Lib/uuid.py (revision 58201) +++ Lib/uuid.py (working copy) @@ -234,10 +234,9 @@ @property def bytes(self): - bytes = b'' - for shift in range(0, 128, 8): - bytes.insert(0, (self.int >> shift) & 0xff) - return bytes + b = bytes((self.int >> shift) & 0xff + for shift in range(0, 128, 8)) + return bytes(reversed(b)) @property def bytes_le(self): Index: Lib/encodings/mac_roman.py =================================================================== --- Lib/encodings/mac_roman.py (revision 58201) +++ Lib/encodings/mac_roman.py (working copy) @@ -20,6 +20,7 @@ class IncrementalDecoder(codecs.IncrementalDecoder): def decode(self, input, final=False): + import array return codecs.charmap_decode(input,self.errors,decoding_table)[0] class StreamWriter(Codec,codecs.StreamWriter): Index: Lib/encodings/idna.py =================================================================== --- Lib/encodings/idna.py (revision 58201) +++ Lib/encodings/idna.py (working copy) @@ -1,5 +1,6 @@ # This module implements the RFCs 3490 (IDNA) and 3491 (Nameprep) +import array import stringprep, re, codecs from unicodedata import ucd_3_2_0 as unicodedata @@ -153,7 +154,7 @@ if not input: return b"", 0 - result = b"" + result = array.array('B') labels = dots.split(input) if labels and not labels[-1]: trailing_dot = b'.' @@ -165,7 +166,8 @@ # Join with U+002E result.extend(b'.') result.extend(ToASCII(label)) - return result+trailing_dot, len(input) + result.extend(trailing_dot) + return bytes(result), len(input) def decode(self, input, errors='strict'): @@ -216,7 +218,7 @@ if labels: trailing_dot = b'.' - result = b"" + result = array.array('B') size = 0 for label in labels: if size: @@ -226,9 +228,9 @@ result.extend(ToASCII(label)) size += len(label) - result += trailing_dot + result.extend(trailing_dot) size += len(trailing_dot) - return (result, size) + return (bytes(result), size) class IncrementalDecoder(codecs.BufferedIncrementalDecoder): def _buffer_decode(self, input, errors, final): Index: Lib/encodings/punycode.py =================================================================== --- Lib/encodings/punycode.py (revision 58201) +++ Lib/encodings/punycode.py (working copy) @@ -5,12 +5,13 @@ """ import codecs +import array ##################### Encoding ##################################### def segregate(str): """3.1 Basic code point segregation""" - base = b"" + base = array.array('B') extended = set() for c in str: if ord(c) < 128: @@ -18,7 +19,7 @@ else: extended.add(c) extended = sorted(extended) - return (base, extended) + return (bytes(base), extended) def selective_len(str, max): """Return the length of str, considering only characters below max.""" @@ -78,13 +79,13 @@ digits = b"abcdefghijklmnopqrstuvwxyz0123456789" def generate_generalized_integer(N, bias): """3.3 Generalized variable-length integers""" - result = b"" + result = array.array('B') j = 0 while 1: t = T(j, bias) if N < t: result.append(digits[N]) - return result + return bytes(result) result.append(digits[t + ((N - t) % (36 - t))]) N = (N - t) // (36 - t) j += 1 @@ -107,13 +108,13 @@ def generate_integers(baselen, deltas): """3.4 Bias adaptation""" # Punycode parameters: initial bias = 72, damp = 700, skew = 38 - result = b"" + result = array.array('B') bias = 72 for points, delta in enumerate(deltas): s = generate_generalized_integer(delta, bias) result.extend(s) bias = adapt(delta, points==0, baselen+points+1) - return result + return bytes(result) def punycode_encode(text): base, extended = segregate(text) Index: Lib/base64.py =================================================================== --- Lib/base64.py (revision 58201) +++ Lib/base64.py (working copy) @@ -9,8 +9,8 @@ import re import struct import binascii +import array - __all__ = [ # Legacy interface exports traditional RFC 1521 Base64 encodings 'encode', 'decode', 'encodestring', 'decodestring', @@ -30,10 +30,11 @@ def _translate(s, altchars): if not isinstance(s, bytes): raise TypeError("expected bytes, not %s" % s.__class__.__name__) - translation = bytes(range(256)) + + translation = array.array('B', range(256)) for k, v in altchars.items(): translation[ord(k)] = v[0] - return s.translate(translation) + return s.translate(bytes(translation)) Index: Lib/string.py =================================================================== --- Lib/string.py (revision 58201) +++ Lib/string.py (working copy) @@ -14,6 +14,8 @@ """ +import array + # Some strings for ctype-style character classification whitespace = ' \t\n\r\v\f' ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz' @@ -53,7 +55,7 @@ raise ValueError("maketrans arguments must have same length") if not (isinstance(frm, bytes) and isinstance(to, bytes)): raise TypeError("maketrans arguments must be bytes objects") - L = bytes(range(256)) + L = array.array('B', range(256)) for i, c in enumerate(frm): L[c] = to[i] return L Index: Lib/io.py =================================================================== --- Lib/io.py (revision 58201) +++ Lib/io.py (working copy) @@ -29,13 +29,15 @@ "BufferedReader", "BufferedWriter", "BufferedRWPair", "BufferedRandom", "TextIOBase", "TextIOWrapper"] -import os +import _fileio import abc -import sys +import array import codecs -import _fileio import io +import os +import sys import warnings +import array # open() uses st_blksize whenever we can DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes @@ -438,10 +440,10 @@ n = -1 if n < 0: return self.readall() - b = bytes(n.__index__()) - n = self.readinto(b) - del b[n:] - return b + buf = array.array('B', bytes(n.__index__())) + n = self.readinto(buf) + del buf[n:] + return bytes(buf) def readall(self): """readall() -> bytes. Read until EOF, using multiple read() call.""" @@ -550,7 +552,7 @@ import array if not isinstance(b, array.array): raise err - b[:n] = array.array('b', data) + b[:n] = array.array('B', data) return n def write(self, b: bytes) -> int: @@ -634,14 +636,14 @@ # XXX More docs def __init__(self, initial_bytes=None): - buffer = b"" + buffer = array.array('B') if initial_bytes is not None: - buffer += initial_bytes + buffer += array.array('B', initial_bytes) self._buffer = buffer self._pos = 0 def getvalue(self): - return self._buffer + return bytes(self._buffer) def read(self, n=None): if n is None: @@ -651,7 +653,7 @@ newpos = min(len(self._buffer), self._pos + n) b = self._buffer[self._pos : newpos] self._pos = newpos - return b + return bytes(b) def read1(self, n): return self.read(n) @@ -666,9 +668,10 @@ if newpos > len(self._buffer): # Inserts null bytes between the current end of the file # and the new write position. - padding = b'\x00' * (newpos - len(self._buffer) - n) + padding = (array.array('B', b'\x00') * + (newpos - len(self._buffer) - n)) self._buffer[self._pos:newpos - n] = padding - self._buffer[self._pos:newpos] = b + self._buffer[self._pos:newpos] = array.array('B', bytes(b)) self._pos = newpos return n @@ -815,7 +818,7 @@ # XXX Why not just let the exception pass through? raise BlockingIOError(e.errno, e.strerror, 0) before = len(self._write_buf) - self._write_buf.extend(b) + self._write_buf += b written = len(self._write_buf) - before if len(self._write_buf) > self.buffer_size: try: @@ -836,11 +839,11 @@ try: while self._write_buf: n = self.raw.write(self._write_buf) - del self._write_buf[:n] + self._write_buf = self._write_buf[n:] written += n except BlockingIOError as e: n = e.characters_written - del self._write_buf[:n] + self._write_buf = self._write_buf[n:] written += n raise BlockingIOError(e.errno, e.strerror, written) @@ -1138,11 +1141,11 @@ x, pos = divmod(pos, 1<<64) if not x: return None, pos - b = b"" - while x: - b.append(x&0xff) - x >>= 8 - return str(b[::-1]), pos + def reversed_bytes_in_x(): + while x: + yield x&0xff + x >>= 8 + return str(reversed(reversed_bytes_in_x())), pos def tell(self): if not self._seekable: @@ -1165,7 +1168,7 @@ try: decoder.setstate((b"", decoder_state)) n = 0 - bb = bytes(1) + bb = array.array('B', b'\0') for i, bb[0] in enumerate(readahead): n += len(decoder.decode(bb)) if n >= needed: Index: Lib/tarfile.py =================================================================== --- Lib/tarfile.py (revision 58201) +++ Lib/tarfile.py (working copy) @@ -51,6 +51,7 @@ import struct import copy import re +import array if sys.platform == 'mac': # This module needs work for MacOS9, especially in the area of pathname @@ -224,11 +225,12 @@ # this could raise OverflowError. n = struct.unpack("L", struct.pack("l", n))[0] - s = b"" + s = array.array('B') for i in range(digits - 1): s.insert(0, n & 0o377) n >>= 8 s.insert(0, 0o200) + s = bytes(s) return s def calc_chksums(buf): Index: Lib/test/test_io.py =================================================================== --- Lib/test/test_io.py (revision 58201) +++ Lib/test/test_io.py (working copy) @@ -98,20 +98,19 @@ def read_ops(self, f, buffered=False): data = f.read(5) + buf = array.array('B', data) self.assertEqual(data, b"hello") - self.assertEqual(f.readinto(data), 5) - self.assertEqual(data, b" worl") - self.assertEqual(f.readinto(data), 2) - self.assertEqual(len(data), 5) - self.assertEqual(data[:2], b"d\n") + self.assertEqual(f.readinto(buf), 5) + self.assertEqual(buf, b" worl") + self.assertEqual(f.readinto(buf), 2) + self.assertEqual(len(buf), 5) + self.assertEqual(buf[:2], b"d\n") self.assertEqual(f.seek(0), 0) self.assertEqual(f.read(20), b"hello world\n") self.assertEqual(f.read(1), b"") - self.assertEqual(f.readinto(b"x"), 0) self.assertEqual(f.seek(-6, 2), 6) self.assertEqual(f.read(5), b"world") self.assertEqual(f.read(0), b"") - self.assertEqual(f.readinto(b""), 0) self.assertEqual(f.seek(-6, 1), 5) self.assertEqual(f.read(5), b" worl") self.assertEqual(f.tell(), 10) Index: Lib/test/test_socket.py =================================================================== --- Lib/test/test_socket.py (revision 58201) +++ Lib/test/test_socket.py (working copy) @@ -3,6 +3,7 @@ import unittest from test import test_support +import array import socket import select import time @@ -1073,7 +1074,7 @@ SocketConnectedTest.__init__(self, methodName=methodName) def testRecvInto(self): - buf = b" "*1024 + buf = array.array('B', b" "*1024) nbytes = self.cli_conn.recv_into(buf) self.assertEqual(nbytes, len(MSG)) msg = buf[:len(MSG)] @@ -1084,7 +1085,7 @@ self.serv_conn.send(buf) def testRecvFromInto(self): - buf = b" "*1024 + buf = array.array('B', b" "*1024) nbytes, addr = self.cli_conn.recvfrom_into(buf) self.assertEqual(nbytes, len(MSG)) msg = buf[:len(MSG)] Index: Lib/test/test_file.py =================================================================== --- Lib/test/test_file.py (revision 58201) +++ Lib/test/test_file.py (working copy) @@ -38,14 +38,14 @@ # verify readinto self.f.write(b'12') self.f.close() - a = array('b', b'x'*10) + a = array('B', b'x'*10) self.f = open(TESTFN, 'rb') n = self.f.readinto(a) self.assertEquals(b'12', a.tostring()[:n]) def testReadinto_text(self): # verify readinto refuses text files - a = array('b', b'x'*10) + a = array('B', b'x'*10) self.f.close() self.f = open(TESTFN, 'r') if hasattr(self.f, "readinto"): @@ -228,7 +228,7 @@ b"wonderful spaaaaaam.\n" ] methods = [("readline", ()), ("read", ()), ("readlines", ()), - ("readinto", (array("b", b" "*100),))] + ("readinto", (array("B", b" "*100),))] try: # Prepare the testfile @@ -265,7 +265,7 @@ self.fail("readline() after next() with empty buffer " "failed. Got %r, expected %r" % (line, testline)) testline = testlines.pop(0) - buf = array("b", b"\x00" * len(testline)) + buf = array("B", b"\x00" * len(testline)) try: f.readinto(buf) except ValueError: Index: Lib/test/test_audioop.py =================================================================== --- Lib/test/test_audioop.py (revision 58201) +++ Lib/test/test_audioop.py (working copy) @@ -1,5 +1,6 @@ # Test audioop. import audioop +import array from test.test_support import verbose def gendata1(): @@ -87,9 +88,7 @@ print('add') data2 = [] for d in data: - str = bytes(len(d)) - for i,b in enumerate(d): - str[i] = 2*b + str = bytes(2*b for b in d) data2.append(str) if audioop.add(data[0], data[0], 1) != data2[0] or \ audioop.add(data[1], data[1], 2) != data2[1] or \ @@ -177,9 +176,7 @@ print('mul') data2 = [] for d in data: - str = bytes(len(d)) - for i,b in enumerate(d): - str[i] = 2*b + str = bytes(2*b for b in d) data2.append(str) if audioop.mul(data[0], 1, 2) != data2[0] or \ audioop.mul(data[1],2, 2) != data2[1] or \ @@ -207,7 +204,7 @@ def testtomono(data): if verbose: print('tomono') - data2 = b'' + data2 = array.array('B') for d in data[0]: data2.append(d) data2.append(d) @@ -218,7 +215,7 @@ def testtostereo(data): if verbose: print('tostereo') - data2 = b'' + data2 = array.array('B') for d in data[0]: data2.append(d) data2.append(d) Index: Lib/test/test_mmap.py =================================================================== --- Lib/test/test_mmap.py (revision 58201) +++ Lib/test/test_mmap.py (working copy) @@ -299,9 +299,8 @@ for x in range(PAGESIZE): self.assertEqual(m[x], b'\0', "anonymously mmap'ed contents should be zero") - b = bytes(1) for x in range(PAGESIZE): - b[0] = x & 255 + b = bytes([x & 255]) m[x] = b self.assertEqual(m[x], b) Index: Lib/test/test_marshal.py =================================================================== --- Lib/test/test_marshal.py (revision 58201) +++ Lib/test/test_marshal.py (working copy) @@ -1,6 +1,7 @@ #!/usr/bin/env python from test import test_support +import array import marshal import sys import unittest @@ -39,7 +40,7 @@ # we're running the test on a 32-bit box, of course. def to_little_endian_string(value, nbytes): - b = bytes() + b = array.array('B') for i in range(nbytes): b.append(value & 0xff) value >>= 8 Index: Lib/test/test_binascii.py =================================================================== --- Lib/test/test_binascii.py (revision 58201) +++ Lib/test/test_binascii.py (working copy) @@ -1,6 +1,7 @@ """Test the binascii C module.""" from test import test_support +import array import unittest import binascii @@ -56,22 +57,20 @@ a = binascii.b2a_base64(b) lines.append(a) - fillers = bytes() valid = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" - for i in range(256): - if i not in valid: - fillers.append(i) + fillers = bytes(i for i in range(256) + if i not in valid) def addnoise(line): noise = fillers ratio = len(line) // len(noise) - res = bytes() + res = array.array('B') while line and noise: if len(line) // len(noise) > ratio: c, line = line[0], line[1:] else: c, noise = noise[0], noise[1:] res.append(c) - return res + noise + line + return bytes(res) + noise + line res = bytes() for line in map(addnoise, lines): b = binascii.a2b_base64(line) Index: Lib/test/test_zipimport.py =================================================================== --- Lib/test/test_zipimport.py (revision 58201) +++ Lib/test/test_zipimport.py (working copy) @@ -5,6 +5,7 @@ import struct import time import unittest +import array import zlib # implied prerequisite from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED @@ -153,7 +154,7 @@ def testBadMagic(self): # make pyc magic word invalid, forcing loading from .py - badmagic_pyc = bytes(test_pyc) + badmagic_pyc = array.array('B', test_pyc) badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit files = {TESTMOD + ".py": (NOW, test_src), TESTMOD + pyc_ext: (NOW, badmagic_pyc)} @@ -161,7 +162,7 @@ def testBadMagic2(self): # make pyc magic word invalid, causing an ImportError - badmagic_pyc = bytes(test_pyc) + badmagic_pyc = array.array('B', test_pyc) badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)} try: @@ -172,7 +173,7 @@ self.fail("expected ImportError; import from bad pyc") def testBadMTime(self): - badtime_pyc = bytes(test_pyc) + badtime_pyc = array.array('B', test_pyc) badtime_pyc[7] ^= 0x02 # flip the second bit -- not the first as that one # isn't stored in the .py's mtime in the zip archive. files = {TESTMOD + ".py": (NOW, test_src), Index: Lib/test/test_bytes.py =================================================================== --- Lib/test/test_bytes.py (revision 58201) +++ Lib/test/test_bytes.py (working copy) @@ -144,49 +144,12 @@ self.failUnless(bytes.__doc__ != None) self.failUnless(bytes.__doc__.startswith("bytes(")) - def test_buffer_api(self): - short_sample = b"Hello world\n" - sample = short_sample + b"x"*(20 - len(short_sample)) - tfn = tempfile.mktemp() - try: - # Prepare - with open(tfn, "wb") as f: - f.write(short_sample) - # Test readinto - with open(tfn, "rb") as f: - b = b"x"*20 - n = f.readinto(b) - self.assertEqual(n, len(short_sample)) - self.assertEqual(list(b), list(sample)) - # Test writing in binary mode - with open(tfn, "wb") as f: - f.write(b) - with open(tfn, "rb") as f: - self.assertEqual(f.read(), sample) - # Text mode is ambiguous; don't test - finally: - try: - os.remove(tfn) - except os.error: - pass def test_reversed(self): - input = list(map(ord, "Hello")) - b = bytes(input) + b = bytes(b"Hello") output = list(reversed(b)) - input.reverse() - self.assertEqual(output, input) + self.assertEqual(output, list(b"olleH")) - def test_reverse(self): - b = b'hello' - self.assertEqual(b.reverse(), None) - self.assertEqual(b, b'olleh') - b = b'hello1' # test even number of items - b.reverse() - self.assertEqual(b, b'1olleh') - b = bytes() - b.reverse() - self.assertFalse(b) def test_getslice(self): def by(s): @@ -225,103 +188,8 @@ b = by("Hello, world") self.assertEqual(re.findall(r"\w+", b), [by("Hello"), by("world")]) - def test_setitem(self): - b = bytes([1, 2, 3]) - b[1] = 100 - self.assertEqual(b, bytes([1, 100, 3])) - b[-1] = 200 - self.assertEqual(b, bytes([1, 100, 200])) - class C: - def __init__(self, i=0): - self.i = i - def __index__(self): - return self.i - b[0] = C(10) - self.assertEqual(b, bytes([10, 100, 200])) - try: - b[3] = 0 - self.fail("Didn't raise IndexError") - except IndexError: - pass - try: - b[-10] = 0 - self.fail("Didn't raise IndexError") - except IndexError: - pass - try: - b[0] = 256 - self.fail("Didn't raise ValueError") - except ValueError: - pass - try: - b[0] = C(-1) - self.fail("Didn't raise ValueError") - except ValueError: - pass - try: - b[0] = None - self.fail("Didn't raise TypeError") - except TypeError: - pass - def test_delitem(self): - b = bytes(range(10)) - del b[0] - self.assertEqual(b, bytes(range(1, 10))) - del b[-1] - self.assertEqual(b, bytes(range(1, 9))) - del b[4] - self.assertEqual(b, bytes([1, 2, 3, 4, 6, 7, 8])) - def test_setslice(self): - b = bytes(range(10)) - self.assertEqual(list(b), list(range(10))) - - b[0:5] = bytes([1, 1, 1, 1, 1]) - self.assertEqual(b, bytes([1, 1, 1, 1, 1, 5, 6, 7, 8, 9])) - - del b[0:-5] - self.assertEqual(b, bytes([5, 6, 7, 8, 9])) - - b[0:0] = bytes([0, 1, 2, 3, 4]) - self.assertEqual(b, bytes(range(10))) - - b[-7:-3] = bytes([100, 101]) - self.assertEqual(b, bytes([0, 1, 2, 100, 101, 7, 8, 9])) - - b[3:5] = [3, 4, 5, 6] - self.assertEqual(b, bytes(range(10))) - - b[3:0] = [42, 42, 42] - self.assertEqual(b, bytes([0, 1, 2, 42, 42, 42, 3, 4, 5, 6, 7, 8, 9])) - - def test_extended_set_del_slice(self): - indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) - for start in indices: - for stop in indices: - # Skip invalid step 0 - for step in indices[1:]: - L = list(range(255)) - b = bytes(L) - # Make sure we have a slice of exactly the right length, - # but with different data. - data = L[start:stop:step] - data.reverse() - L[start:stop:step] = data - b[start:stop:step] = data - self.assertEquals(b, bytes(L)) - - del L[start:stop:step] - del b[start:stop:step] - self.assertEquals(b, bytes(L)) - - def test_setslice_trap(self): - # This test verifies that we correctly handle assigning self - # to a slice of self (the old Lambert Meertens trap). - b = bytes(range(256)) - b[8:] = b - self.assertEqual(b, bytes(list(range(8)) + list(range(256)))) - def test_encoding(self): sample = "Hello world\n\u1234\u5678\u9abc\udef0" for enc in ("utf8", "utf16"): @@ -386,8 +254,6 @@ b1 = b b += b"def" self.assertEqual(b, b"abcdef") - self.assertEqual(b, b1) - self.failUnless(b is b1) b += str8("xyz") self.assertEqual(b, b"abcdefxyz") try: @@ -399,19 +265,13 @@ def test_irepeat(self): b = b"abc" - b1 = b b *= 3 self.assertEqual(b, b"abcabcabc") - self.assertEqual(b, b1) - self.failUnless(b is b1) def test_irepeat_1char(self): b = b"x" - b1 = b b *= 100 self.assertEqual(b, bytes([ord("x")]*100)) - self.assertEqual(b, b1) - self.failUnless(b is b1) def test_contains(self): b = b"abc" @@ -487,34 +347,8 @@ self.assertRaises(SyntaxError, eval, 'b"%s"' % chr(c)) - def test_extend(self): - orig = b'hello' - a = bytes(orig) - a.extend(a) - self.assertEqual(a, orig + orig) - self.assertEqual(a[5:], orig) - def test_remove(self): - b = b'hello' - b.remove(ord('l')) - self.assertEqual(b, b'helo') - b.remove(ord('l')) - self.assertEqual(b, b'heo') - self.assertRaises(ValueError, lambda: b.remove(ord('l'))) - self.assertRaises(ValueError, lambda: b.remove(400)) - self.assertRaises(ValueError, lambda: b.remove('e')) - # remove first and last - b.remove(ord('o')) - b.remove(ord('h')) - self.assertEqual(b, b'e') - def test_pop(self): - b = b'world' - self.assertEqual(b.pop(), ord('d')) - self.assertEqual(b.pop(0), ord('w')) - self.assertEqual(b.pop(-2), ord('r')) - self.assertRaises(IndexError, lambda: b.pop(10)) - self.assertRaises(OverflowError, lambda: bytes().pop()) def test_nosort(self): self.assertRaises(AttributeError, lambda: bytes().sort()) @@ -532,23 +366,7 @@ self.assertEqual(b.count(b'ss'), 2) self.assertEqual(b.count(b'w'), 0) - def test_append(self): - b = b'hell' - b.append(ord('o')) - self.assertEqual(b, b'hello') - self.assertEqual(b.append(100), None) - b = bytes() - b.append(ord('A')) - self.assertEqual(len(b), 1) - def test_insert(self): - b = b'msssspp' - b.insert(1, ord('i')) - b.insert(4, ord('i')) - b.insert(-2, ord('i')) - b.insert(1000, ord('i')) - self.assertEqual(b, b'mississippi') - def test_startswith(self): b = b'hello' self.assertFalse(bytes().startswith(b"anything")) @@ -606,8 +424,9 @@ def test_translate(self): b = b'hello' - rosetta = bytes(range(0, 256)) - rosetta[ord('o')] = ord('e') + r = list(range(0, 256)) + r[ord('o')] = ord('e') + rosetta = bytes(r) c = b.translate(rosetta, b'l') self.assertEqual(b, b'hello') self.assertEqual(c, b'hee') Index: Modules/Setup.dist =================================================================== --- Modules/Setup.dist (revision 58201) +++ Modules/Setup.dist (working copy) @@ -153,7 +153,7 @@ # Modules that should always be present (non UNIX dependent): -#array arraymodule.c # array objects +array arraymodule.c # array objects #cmath cmathmodule.c # -lm # complex math library functions #math mathmodule.c # -lm # math library functions, e.g. sin() #_struct _struct.c # binary structure packing/unpacking