[pypy-commit] pypy numpy-full-fromstring: Adds full fromstring support with lots of tests
jterrace
noreply at buildbot.pypy.org
Tue Dec 13 04:11:04 CET 2011
Author: Jeff Terrace <jterrace at gmail.com>
Branch: numpy-full-fromstring
Changeset: r50453:8e0167fbb05a
Date: 2011-12-12 17:53 -0500
http://bitbucket.org/pypy/pypy/changeset/8e0167fbb05a/
Log: Adds full fromstring support with lots of tests
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -1,34 +1,49 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
from pypy.module.micronumpy.interp_dtype import get_dtype_cache
-from pypy.rlib.rstruct.runpack import runpack
+from pypy.module.micronumpy import interp_dtype
from pypy.rpython.lltypesystem import lltype, rffi
FLOAT_SIZE = rffi.sizeof(lltype.Float)
- at unwrap_spec(s=str)
-def fromstring(space, s):
+ at unwrap_spec(s=str, count=int, sep=str)
+def fromstring(space, s, w_dtype=None, count=-1, sep=''):
from pypy.module.micronumpy.interp_numarray import W_NDimArray
+
+ dtype = space.interp_w(interp_dtype.W_Dtype,
+ space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
+ )
+ itemsize = abs(space.int_w(dtype.descr_get_itemsize(space)))
length = len(s)
- if length % FLOAT_SIZE == 0:
- number = length/FLOAT_SIZE
- else:
+ A = []
+ num = 0
+ ptr = 0
+
+ while (num < count or count == -1) and ptr < len(s):
+ if sep == '':
+ if length - ptr < itemsize:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "string length %d not divisable by item size %d" % (length, itemsize)))
+ val = dtype.itemtype.runpack_str(s[ptr:ptr+itemsize])
+ ptr += itemsize
+ else:
+ nextptr = s.find(sep, ptr)
+ if nextptr < 0:
+ nextptr = length
+ val = dtype.coerce(space, space.wrap(s[ptr:nextptr]))
+ ptr = nextptr + 1
+
+ num += 1
+ A.append(val)
+
+ if count > num:
raise OperationError(space.w_ValueError, space.wrap(
- "string length %d not divisable by %d" % (length, FLOAT_SIZE)))
-
- dtype = get_dtype_cache(space).w_float64dtype
- a = W_NDimArray(number, [number], dtype=dtype)
-
- start = 0
- end = FLOAT_SIZE
- i = 0
- while i < number:
- part = s[start:end]
- a.dtype.setitem(a.storage, i, dtype.box(runpack('d', part)))
- i += 1
- start += FLOAT_SIZE
- end += FLOAT_SIZE
-
+ "string is smaller than requested size"))
+
+ a = W_NDimArray(num, [num], dtype=dtype)
+ for i, val in enumerate(A):
+ a.dtype.setitem(a.storage, i, val)
+
return space.wrap(a)
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1168,13 +1168,69 @@
import struct
BaseNumpyAppTest.setup_class.im_func(cls)
cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4))
+ cls.w_fdata = cls.space.wrap(struct.pack('f', 2.3))
+ cls.w_float32val = cls.space.wrap(struct.pack('f', 5.2))
+ cls.w_float64val = cls.space.wrap(struct.pack('d', 300.4))
def test_fromstring(self):
- from numpypy import fromstring
+ from numpypy import fromstring, uint8, float32, int32
a = fromstring(self.data)
for i in range(4):
assert a[i] == i + 1
- raises(ValueError, fromstring, "abc")
+ b = fromstring('\x01\x02', dtype=uint8)
+ assert a[0] == 1
+ assert a[1] == 2
+ c = fromstring(self.fdata, dtype=float32)
+ assert c[0] == float32(2.3)
+ d = fromstring("1 2", sep=' ', count=2, dtype=uint8)
+ assert len(d) == 2
+ assert d[0] == 1
+ assert d[1] == 2
+ e = fromstring('3, 4,5', dtype=uint8, sep=',')
+ assert len(e) == 3
+ assert e[0] == 3
+ assert e[1] == 4
+ assert e[2] == 5
+ f = fromstring('\x01\x02\x03\x04\x05', dtype=uint8, count=3)
+ assert len(f) == 3
+ assert f[0] == 1
+ assert f[1] == 2
+ assert f[2] == 3
+ raises(ValueError, fromstring, "3.4 2.0 3.8 2.2", dtype=int32, sep=" ")
+
+ def test_fromstring_types(self):
+ from numpypy import fromstring
+ from numpypy import int8, int16, int32, int64
+ from numpypy import uint8, uint16, uint32
+ from numpypy import float32, float64
+ a = fromstring('\xFF', dtype=int8)
+ assert a[0] == -1
+ b = fromstring('\xFF', dtype=uint8)
+ assert b[0] == 255
+ c = fromstring('\xFF\xFF', dtype=int16)
+ assert c[0] == -1
+ d = fromstring('\xFF\xFF', dtype=uint16)
+ assert d[0] == 65535
+ e = fromstring('\xFF\xFF\xFF\xFF', dtype=int32)
+ assert e[0] == -1
+ f = fromstring('\xFF\xFF\xFF\xFF', dtype=uint32)
+ assert f[0] == 4294967295
+ g = fromstring('\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF', dtype=int64)
+ assert g[0] == -1
+ h = fromstring(self.float32val, dtype=float32)
+ assert h[0] == float32(5.2)
+ i = fromstring(self.float64val, dtype=float64)
+ assert i[0] == float64(300.4)
+
+
+ def test_fromstring_invalid(self):
+ from numpypy import fromstring, uint16, uint8
+ #default dtype is 64-bit float, so 3 bytes should fail
+ raises(ValueError, fromstring, "\x01\x02\x03")
+ #3 bytes is not modulo 2 bytes (int16)
+ raises(ValueError, fromstring, "\x01\x03\x03", dtype=uint16)
+ #5 bytes is larger than 3 bytes
+ raises(ValueError, fromstring, "\x01\x02\x03", count=5, dtype=uint8)
class AppTestRepr(BaseNumpyAppTest):
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -8,6 +8,7 @@
from pypy.rlib.objectmodel import specialize
from pypy.rlib.rarithmetic import LONG_BIT, widen
from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rstruct.runpack import runpack
def simple_unary_op(func):
@@ -55,6 +56,8 @@
class Primitive(object):
_mixin_ = True
+ char = "?"
+
def get_element_size(self):
return rffi.sizeof(self.T)
@@ -102,6 +105,11 @@
width, storage, i, offset, value
)
+ def runpack_str(self, s):
+ if self.char == "?":
+ raise NotImplementedError
+ return self.box(runpack(self.char, s))
+
@simple_binary_op
def add(self, v1, v2):
return v1 + v2
@@ -241,26 +249,32 @@
class Int8(BaseType, Integer):
T = rffi.SIGNEDCHAR
BoxType = interp_boxes.W_Int8Box
+ char = "b"
class UInt8(BaseType, Integer):
T = rffi.UCHAR
BoxType = interp_boxes.W_UInt8Box
+ char = "B"
class Int16(BaseType, Integer):
T = rffi.SHORT
BoxType = interp_boxes.W_Int16Box
+ char = "h"
class UInt16(BaseType, Integer):
T = rffi.USHORT
BoxType = interp_boxes.W_UInt16Box
+ char = "H"
class Int32(BaseType, Integer):
T = rffi.INT
BoxType = interp_boxes.W_Int32Box
+ char = "i"
class UInt32(BaseType, Integer):
T = rffi.UINT
BoxType = interp_boxes.W_UInt32Box
+ char = "I"
class Long(BaseType, Integer):
T = rffi.LONG
@@ -273,10 +287,12 @@
class Int64(BaseType, Integer):
T = rffi.LONGLONG
BoxType = interp_boxes.W_Int64Box
+ char = "q"
class UInt64(BaseType, Integer):
T = rffi.ULONGLONG
BoxType = interp_boxes.W_UInt64Box
+ char = "Q"
def _coerce(self, space, w_item):
try:
@@ -403,7 +419,9 @@
class Float32(BaseType, Float):
T = rffi.FLOAT
BoxType = interp_boxes.W_Float32Box
+ char = "f"
class Float64(BaseType, Float):
T = rffi.DOUBLE
- BoxType = interp_boxes.W_Float64Box
\ No newline at end of file
+ BoxType = interp_boxes.W_Float64Box
+ char = "d"
\ No newline at end of file
More information about the pypy-commit
mailing list