Commit 669620f1 authored by Martin v. Löwis's avatar Martin v. Löwis

Patch 520694: arraymodule.c improvements:

- make array.array a type
- add Py_UNICODE arrays
- support +=, *=
parent 398cafcf
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
\modulesynopsis{Efficient arrays of uniformly typed numeric values.} \modulesynopsis{Efficient arrays of uniformly typed numeric values.}
This module defines a new object type which can efficiently represent This module defines an object type which can efficiently represent
an array of basic values: characters, integers, floating point an array of basic values: characters, integers, floating point
numbers. Arrays\index{arrays} are sequence types and behave very much numbers. Arrays\index{arrays} are sequence types and behave very much
like lists, except that the type of objects stored in them is like lists, except that the type of objects stored in them is
...@@ -17,6 +17,7 @@ codes are defined: ...@@ -17,6 +17,7 @@ codes are defined:
\lineiii{'c'}{character}{1} \lineiii{'c'}{character}{1}
\lineiii{'b'}{signed int}{1} \lineiii{'b'}{signed int}{1}
\lineiii{'B'}{unsigned int}{1} \lineiii{'B'}{unsigned int}{1}
\lineiii{'u'}{Unicode character}{2}
\lineiii{'h'}{signed int}{2} \lineiii{'h'}{signed int}{2}
\lineiii{'H'}{unsigned int}{2} \lineiii{'H'}{unsigned int}{2}
\lineiii{'i'}{signed int}{2} \lineiii{'i'}{signed int}{2}
...@@ -35,23 +36,25 @@ Python long integers when retrieved, because Python's plain integer ...@@ -35,23 +36,25 @@ Python long integers when retrieved, because Python's plain integer
type cannot represent the full range of C's unsigned (long) integers. type cannot represent the full range of C's unsigned (long) integers.
The module defines the following function and type object: The module defines the following type:
\begin{funcdesc}{array}{typecode\optional{, initializer}} \begin{funcdesc}{array}{typecode\optional{, initializer}}
Return a new array whose items are restricted by \var{typecode}, and Return a new array whose items are restricted by \var{typecode},
initialized from the optional \var{initializer} value, which must be a and initialized from the optional \var{initializer} value, which
list or a string. The list or string is passed to the new array's must be a list or a string. The list or string is passed to the
\method{fromlist()} or \method{fromstring()} method (see below) to add new array's \method{fromlist()}, \method{fromstring()}, or
initial items to the array. \method{fromunicode()} method (see below) to add initial items to
the array.
\end{funcdesc} \end{funcdesc}
\begin{datadesc}{ArrayType} \begin{datadesc}{ArrayType}
Type object corresponding to the objects returned by Obsolete alias for \function{array}.
\function{array()}.
\end{datadesc} \end{datadesc}
Array objects support the following data items and methods: Array objects support the ordinary sequence operations of
indexing, slicing, concatenation, and multiplication. The
following data items and methods are also supported:
\begin{memberdesc}[array]{typecode} \begin{memberdesc}[array]{typecode}
The typecode character used to create the array. The typecode character used to create the array.
...@@ -121,6 +124,13 @@ array of machine values (as if it had been read from a ...@@ -121,6 +124,13 @@ array of machine values (as if it had been read from a
file using the \method{fromfile()} method). file using the \method{fromfile()} method).
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}[array]{fromunicode}{s}
Extends this array with data from the given unicode string.
The array must be a type 'u' array; otherwise a ValueError
is raised. Use \samp{array.fromstring(ustr.decode(enc))} to
append Unicode data to an array of some other type.
\end{methoddesc}
\begin{methoddesc}[array]{index}{x} \begin{methoddesc}[array]{index}{x}
Return the smallest \var{i} such that \var{i} is the index of Return the smallest \var{i} such that \var{i} is the index of
the first occurence of \var{x} in the array. the first occurence of \var{x} in the array.
...@@ -170,6 +180,13 @@ string representation (the same sequence of bytes that would ...@@ -170,6 +180,13 @@ string representation (the same sequence of bytes that would
be written to a file by the \method{tofile()} method.) be written to a file by the \method{tofile()} method.)
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}[array]{tounicode}{}
Convert the array to a unicode string. The array must be
a type 'u' array; otherwise a ValueError is raised. Use
array.tostring().decode(enc) to obtain a unicode string
from an array of some other type.
\end{methoddesc}
\begin{methoddesc}[array]{write}{f} \begin{methoddesc}[array]{write}{f}
\deprecated {1.5.1} \deprecated {1.5.1}
{Use the \method{tofile()} method.} {Use the \method{tofile()} method.}
...@@ -188,6 +205,7 @@ imported using \code{from array import array}. Examples: ...@@ -188,6 +205,7 @@ imported using \code{from array import array}. Examples:
\begin{verbatim} \begin{verbatim}
array('l') array('l')
array('c', 'hello world') array('c', 'hello world')
array('u', u'hello \textbackslash u2641')
array('l', [1, 2, 3, 4, 5]) array('l', [1, 2, 3, 4, 5])
array('d', [1.0, 2.0, 3.14]) array('d', [1.0, 2.0, 3.14])
\end{verbatim} \end{verbatim}
......
...@@ -6,14 +6,87 @@ import array ...@@ -6,14 +6,87 @@ import array
from test_support import verbose, TESTFN, unlink, TestFailed from test_support import verbose, TESTFN, unlink, TestFailed
def main(): def main():
testtype('c', 'c') testtype('c', 'c')
testtype('u', u'\u263a')
for type in (['b', 'h', 'i', 'l', 'f', 'd']): for type in (['b', 'h', 'i', 'l', 'f', 'd']):
testtype(type, 1) testtype(type, 1)
testunicode()
testsubclassing()
unlink(TESTFN) unlink(TESTFN)
def testunicode():
try:
array.array('b', u'foo')
except TypeError:
pass
else:
raise TestFailed("creating a non-unicode array from "
"a Unicode string should fail")
x = array.array('u', u'\xa0\xc2\u1234')
x.fromunicode(u' ')
x.fromunicode(u'')
x.fromunicode(u'')
x.fromunicode(u'\x11abc\xff\u1234')
s = x.tounicode()
if s != u'\xa0\xc2\u1234 \x11abc\xff\u1234':
raise TestFailed("fromunicode()/tounicode()")
s = u'\x00="\'a\\b\x80\xff\u0000\u0001\u1234'
a = array.array('u', s)
if verbose:
print "repr of type 'u' array:", repr(a)
print " expected: array('u', %r)" % s
def testsubclassing():
class EditableString(array.array):
def __new__(cls, s, *args, **kwargs):
return array.array.__new__(cls, 'c', s)
def __init__(self, s, color='blue'):
array.array.__init__(self, 'c', s)
self.color = color
def strip(self):
self[:] = array.array('c', self.tostring().strip())
def __repr__(self):
return 'EditableString(%r)' % self.tostring()
s = EditableString("\ttest\r\n")
s.strip()
if s.tostring() != 'test':
raise TestFailed, "subclassing array.array failed somewhere"
if s.color != 'blue':
raise TestFailed, "assigning attributes to instance of array subclass"
s.color = 'red'
if s.color != 'red':
raise TestFailed, "assigning attributes to instance of array subclass"
if s.__dict__.keys() != ['color']:
raise TestFailed, "array subclass __dict__"
class ExaggeratingArray(array.array):
__slots__ = ['offset']
def __new__(cls, typecode, data, offset):
return array.array.__new__(cls, typecode, data)
def __init__(self, typecode, data, offset):
self.offset = offset
def __getitem__(self, i):
return array.array.__getitem__(self, i) + self.offset
a = ExaggeratingArray('i', [3, 6, 7, 11], 4)
if a[0] != 7:
raise TestFailed, "array subclass overriding __getitem__"
try:
a.color = 'blue'
except AttributeError:
pass
else:
raise TestFailed, "array subclass __slots__ was ignored"
def testoverflow(type, lowerLimit, upperLimit): def testoverflow(type, lowerLimit, upperLimit):
# should not overflow assigning lower limit # should not overflow assigning lower limit
...@@ -54,7 +127,6 @@ def testoverflow(type, lowerLimit, upperLimit): ...@@ -54,7 +127,6 @@ def testoverflow(type, lowerLimit, upperLimit):
def testtype(type, example): def testtype(type, example):
a = array.array(type) a = array.array(type)
a.append(example) a.append(example)
if verbose: if verbose:
...@@ -97,6 +169,33 @@ def testtype(type, example): ...@@ -97,6 +169,33 @@ def testtype(type, example):
print 'array of %s converted to a string: ' \ print 'array of %s converted to a string: ' \
% a.typecode, `a.tostring()` % a.typecode, `a.tostring()`
# Try out inplace addition and multiplication
a = array.array(type, [example])
b = a
a += array.array(type, [example]*2)
if a is not b:
raise TestFailed, "array(%s) inplace addition" % `type`
if a != array.array(type, [example] * 3):
raise TestFailed, "array(%s) inplace addition" % `type`
a *= 5
if a is not b:
raise TestFailed, "array(%s) inplace multiplication" % `type`
if a != array.array(type, [example] * 15):
raise TestFailed, "array(%s) inplace multiplication" % `type`
a *= 0
if a is not b:
raise TestFailed, "array(%s) inplace multiplication by 0" % `type`
if a != array.array(type, []):
raise TestFailed, "array(%s) inplace multiplication by 0" % `type`
a *= 1000
if a is not b:
raise TestFailed, "empty array(%s) inplace multiplication" % `type`
if a != array.array(type, []):
raise TestFailed, "empty array(%s) inplace multiplication" % `type`
if type == 'c': if type == 'c':
a = array.array(type, "abcde") a = array.array(type, "abcde")
a[:-1] = a a[:-1] = a
...@@ -135,6 +234,44 @@ def testtype(type, example): ...@@ -135,6 +234,44 @@ def testtype(type, example):
a.reverse() a.reverse()
if a != array.array(type, "dca"): if a != array.array(type, "dca"):
raise TestFailed, "array(%s) reverse-test" % `type` raise TestFailed, "array(%s) reverse-test" % `type`
elif type == 'u':
a = array.array(type, u"abcde")
a[:-1] = a
if a != array.array(type, u"abcdee"):
raise TestFailed, "array(%s) self-slice-assign (head)" % `type`
a = array.array(type, u"abcde")
a[1:] = a
if a != array.array(type, u"aabcde"):
raise TestFailed, "array(%s) self-slice-assign (tail)" % `type`
a = array.array(type, u"abcde")
a[1:-1] = a
if a != array.array(type, u"aabcdee"):
raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type`
if a.index(u"e") != 5:
raise TestFailed, "array(%s) index-test" % `type`
if a.count(u"a") != 2:
raise TestFailed, "array(%s) count-test" % `type`
a.remove(u"e")
if a != array.array(type, u"aabcde"):
raise TestFailed, "array(%s) remove-test" % `type`
if a.pop(0) != u"a":
raise TestFailed, "array(%s) pop-test" % `type`
if a.pop(1) != u"b":
raise TestFailed, "array(%s) pop-test" % `type`
a.extend(array.array(type, u"xyz"))
if a != array.array(type, u"acdexyz"):
raise TestFailed, "array(%s) extend-test" % `type`
a.pop()
a.pop()
a.pop()
x = a.pop()
if x != u'e':
raise TestFailed, "array(%s) pop-test" % `type`
if a != array.array(type, u"acd"):
raise TestFailed, "array(%s) pop-test" % `type`
a.reverse()
if a != array.array(type, u"dca"):
raise TestFailed, "array(%s) reverse-test" % `type`
else: else:
a = array.array(type, [1, 2, 3, 4, 5]) a = array.array(type, [1, 2, 3, 4, 5])
a[:-1] = a a[:-1] = a
......
...@@ -17,6 +17,11 @@ Core and builtins ...@@ -17,6 +17,11 @@ Core and builtins
Extension modules Extension modules
- array.array is now a type object. A new format character
'u' indicates Py_UNICODE arrays. For those, .tounicode and
.fromunicode methods are available. Arrays now support __iadd__
and __imul__.
- dl now builds on every system that has dlfcn.h. Failure in case - dl now builds on every system that has dlfcn.h. Failure in case
of sizeof(int)!=sizeof(long)!=sizeof(void*) is delayed until dl.open of sizeof(int)!=sizeof(long)!=sizeof(void*) is delayed until dl.open
is called. is called.
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment