[pypy-commit] pypy default: merge in object-dtype2, which provides an object dtype for numpy
mattip
noreply at buildbot.pypy.org
Thu Apr 23 19:03:15 CEST 2015
Author: mattip <matti.picus at gmail.com>
Branch:
Changeset: r76905:bc2c76a447dc
Date: 2015-04-23 20:01 +0300
http://bitbucket.org/pypy/pypy/changeset/bc2c76a447dc/
Log: merge in object-dtype2, which provides an object dtype for numpy
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -64,3 +64,6 @@
.. branch: vmprof
.. Merged but then backed out, hopefully it will return as vmprof2
+
+.. branch: object-dtype2
+Extend numpy dtypes to allow using objects with associated garbage collection hook
diff --git a/pypy/goal/targetnumpystandalone.py b/pypy/goal/targetnumpystandalone.py
deleted file mode 100644
--- a/pypy/goal/targetnumpystandalone.py
+++ /dev/null
@@ -1,43 +0,0 @@
-
-""" Usage:
-
-./targetnumpystandalone-c <bytecode> array_size
-
-Will execute a give numpy bytecode. Arrays will be ranges (in float) modulo 10,
-constants would be consecutive starting from one.
-
-Bytecode should contain letters 'a' 'l' and 'f' so far and be correct
-"""
-
-import time
-from pypy.module.micronumpy.compile import numpy_compile
-from rpython.jit.codewriter.policy import JitPolicy
-from rpython.rtyper.annlowlevel import hlstr
-
-def entry_point(argv):
- if len(argv) != 3:
- print __doc__
- return 1
- try:
- size = int(argv[2])
- except ValueError:
- print "INVALID LITERAL FOR INT:", argv[2]
- print __doc__
- return 3
- t0 = time.time()
- main(argv[0], size)
- print "bytecode:", argv[0], "size:", size
- print "took:", time.time() - t0
- return 0
-
-def main(bc, size):
- if not isinstance(bc, str):
- bc = hlstr(bc) # for tests
- a = numpy_compile(bc, size)
- a = a.compute()
-
-def target(*args):
- return entry_point, None
-
-def jitpolicy(driver):
- return JitPolicy()
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -30,6 +30,9 @@
for c in ['MAXDIMS', 'CLIP', 'WRAP', 'RAISE']:
interpleveldefs[c] = 'space.wrap(constants.%s)' % c
+ def startup(self, space):
+ from pypy.module.micronumpy.concrete import _setup
+ _setup()
class UMathModule(MixedModule):
appleveldefs = {}
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -34,11 +34,13 @@
@staticmethod
def from_shape(space, shape, dtype, order='C', w_instance=None, zero=True):
- from pypy.module.micronumpy import concrete
+ from pypy.module.micronumpy import concrete, descriptor, boxes
from pypy.module.micronumpy.strides import calc_strides
strides, backstrides = calc_strides(shape, dtype.base, order)
impl = concrete.ConcreteArray(shape, dtype.base, order, strides,
backstrides, zero=zero)
+ if dtype == descriptor.get_dtype_cache(space).w_objectdtype:
+ impl.fill(space, boxes.W_ObjectBox(space.w_None))
if w_instance:
return wrap_impl(space, space.type(w_instance), w_instance, impl)
return W_NDimArray(impl)
@@ -123,7 +125,7 @@
def get_shape(self):
return self.implementation.get_shape()
- def get_dtype(self):
+ def get_dtype(self, space=None):
return self.implementation.dtype
def get_order(self):
diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py
--- a/pypy/module/micronumpy/boxes.py
+++ b/pypy/module/micronumpy/boxes.py
@@ -607,6 +607,19 @@
# arr.storage[i] = arg[i]
return W_UnicodeBox(arr, 0, arr.dtype)
+class W_ObjectBox(W_GenericBox):
+ descr__new__, _get_dtype, descr_reduce = new_dtype_getter(NPY.OBJECT)
+
+ def __init__(self, w_obj):
+ self.w_obj = w_obj
+
+ def convert_to(self, space, dtype):
+ if dtype.is_bool():
+ return W_BoolBox(space.bool_w(self.w_obj))
+ return self # XXX
+
+ def descr__getattr__(self, space, w_key):
+ return space.getattr(self.w_obj, w_key)
W_GenericBox.typedef = TypeDef("numpy.generic",
__new__ = interp2app(W_GenericBox.descr__new__.im_func),
@@ -856,3 +869,9 @@
__new__ = interp2app(W_UnicodeBox.descr__new__unicode_box.im_func),
__len__ = interp2app(W_UnicodeBox.descr_len),
)
+
+W_ObjectBox.typedef = TypeDef("numpy.object_", W_ObjectBox.typedef,
+ __new__ = interp2app(W_ObjectBox.descr__new__.im_func),
+ __getattr__ = interp2app(W_ObjectBox.descr__getattr__),
+)
+
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -3,7 +3,7 @@
"""
import re
from pypy.interpreter import special
-from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
+from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root, ObjSpace
from pypy.interpreter.error import OperationError
from rpython.rlib.objectmodel import specialize, instantiate
from rpython.rlib.nonconst import NonConstant
@@ -47,7 +47,7 @@
def lookup(self, name):
return self.getdictvalue(self, name)
-class FakeSpace(object):
+class FakeSpace(ObjSpace):
w_ValueError = W_TypeObject("ValueError")
w_TypeError = W_TypeObject("TypeError")
w_IndexError = W_TypeObject("IndexError")
@@ -67,6 +67,7 @@
w_unicode = W_TypeObject("unicode")
w_complex = W_TypeObject("complex")
w_dict = W_TypeObject("dict")
+ w_object = W_TypeObject("object")
def __init__(self):
"""NOT_RPYTHON"""
@@ -88,7 +89,8 @@
return self.wrap(len(w_obj.items))
def getattr(self, w_obj, w_attr):
- return StringObject(NonConstant('foo'))
+ assert isinstance(w_attr, StringObject)
+ return w_obj.getdictvalue(self, w_attr.v)
def isinstance_w(self, w_obj, w_tp):
try:
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -1,11 +1,11 @@
from pypy.interpreter.error import OperationError, oefmt
-from rpython.rlib import jit
+from rpython.rlib import jit, rgc
from rpython.rlib.buffer import Buffer
-from rpython.rlib.debug import make_sure_not_resized
+from rpython.rlib.debug import make_sure_not_resized, debug_print
from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \
raw_storage_getitem, raw_storage_setitem, RAW_STORAGE
-from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.module.micronumpy import support, loop
+from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
+from pypy.module.micronumpy import support, loop, constants as NPY
from pypy.module.micronumpy.base import convert_to_array, W_NDimArray, \
ArrayArgumentException
from pypy.module.micronumpy.iterators import ArrayIter
@@ -13,11 +13,13 @@
RecordChunk, calc_strides, calc_new_strides, shape_agreement,
calculate_broadcast_strides, calc_backstrides)
from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.rtyper.annlowlevel import cast_gcref_to_instance
+from pypy.interpreter.baseobjspace import W_Root
class BaseConcreteArray(object):
_immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]',
- 'strides[*]', 'backstrides[*]', 'order']
+ 'strides[*]', 'backstrides[*]', 'order', 'gcstruct']
start = 0
parent = None
flags = 0
@@ -333,6 +335,44 @@
loop.setslice(space, impl.get_shape(), impl, self)
return impl
+OBJECTSTORE = lltype.GcStruct('ObjectStore',
+ ('length', lltype.Signed),
+ ('step', lltype.Signed),
+ ('storage', llmemory.Address),
+ rtti=True)
+offset_of_storage = llmemory.offsetof(OBJECTSTORE, 'storage')
+offset_of_length = llmemory.offsetof(OBJECTSTORE, 'length')
+offset_of_step = llmemory.offsetof(OBJECTSTORE, 'step')
+
+V_OBJECTSTORE = lltype.nullptr(OBJECTSTORE)
+
+def customtrace(gc, obj, callback, arg):
+ #debug_print('in customtrace w/obj', obj)
+ length = (obj + offset_of_length).signed[0]
+ step = (obj + offset_of_step).signed[0]
+ storage = (obj + offset_of_storage).address[0]
+ #debug_print('tracing', length, 'objects in ndarray.storage')
+ i = 0
+ while i < length:
+ gc._trace_callback(callback, arg, storage)
+ storage += step
+ i += 1
+
+lambda_customtrace = lambda: customtrace
+
+def _setup():
+ rgc.register_custom_trace_hook(OBJECTSTORE, lambda_customtrace)
+
+ at jit.dont_look_inside
+def _create_objectstore(storage, length, elsize):
+ gcstruct = lltype.malloc(OBJECTSTORE)
+ # JIT does not support cast_ptr_to_adr
+ gcstruct.storage = llmemory.cast_ptr_to_adr(storage)
+ #print 'create gcstruct',gcstruct,'with storage',storage,'as',gcstruct.storage
+ gcstruct.length = length
+ gcstruct.step = elsize
+ return gcstruct
+
class ConcreteArrayNotOwning(BaseConcreteArray):
def __init__(self, shape, dtype, order, strides, backstrides, storage, start=0):
@@ -347,10 +387,11 @@
self.backstrides = backstrides
self.storage = storage
self.start = start
+ self.gcstruct = V_OBJECTSTORE
def fill(self, space, box):
self.dtype.itemtype.fill(self.storage, self.dtype.elsize,
- box, 0, self.size, 0)
+ box, 0, self.size, 0, self.gcstruct)
def set_shape(self, space, orig_array, new_shape):
strides, backstrides = calc_strides(new_shape, self.dtype,
@@ -374,17 +415,24 @@
def base(self):
return None
-
class ConcreteArray(ConcreteArrayNotOwning):
def __init__(self, shape, dtype, order, strides, backstrides,
storage=lltype.nullptr(RAW_STORAGE), zero=True):
+ gcstruct = V_OBJECTSTORE
if storage == lltype.nullptr(RAW_STORAGE):
- storage = dtype.itemtype.malloc(support.product(shape) *
- dtype.elsize, zero=zero)
+ length = support.product(shape)
+ if dtype.num == NPY.OBJECT:
+ storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True)
+ gcstruct = _create_objectstore(storage, length, dtype.elsize)
+ else:
+ storage = dtype.itemtype.malloc(length * dtype.elsize, zero=zero)
ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
storage)
+ self.gcstruct = gcstruct
def __del__(self):
+ if self.gcstruct:
+ self.gcstruct.length = 0
free_raw_storage(self.storage, track_allocation=False)
@@ -423,6 +471,7 @@
parent = parent.parent # one level only
self.parent = parent
self.storage = parent.storage
+ self.gcstruct = parent.gcstruct
self.order = parent.order
self.dtype = dtype
self.size = support.product(shape) * self.dtype.elsize
@@ -480,6 +529,7 @@
class VoidBoxStorage(BaseConcreteArray):
def __init__(self, size, dtype):
self.storage = alloc_raw_storage(size)
+ self.gcstruct = V_OBJECTSTORE
self.dtype = dtype
self.size = size
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -38,6 +38,34 @@
raise oefmt(space.w_ValueError,
"object __array__ method not producing an array")
+def try_interface_method(space, w_object):
+ try:
+ w_interface = space.getattr(w_object, space.wrap("__array_interface__"))
+ except OperationError, e:
+ if e.match(space, space.w_AttributeError):
+ return None
+ raise
+ if w_interface is None:
+ # happens from compile.py
+ return None
+ version = space.int_w(space.finditem(w_interface, space.wrap("version")))
+ if version < 3:
+ raise oefmt(space.w_NotImplementedError,
+ "__array_interface__ version %d not supported", version)
+ # make a view into the data
+ w_shape = space.finditem(w_interface, space.wrap('shape'))
+ w_dtype = space.finditem(w_interface, space.wrap('typestr'))
+ w_descr = space.finditem(w_interface, space.wrap('descr'))
+ data_w = space.listview(space.finditem(w_interface, space.wrap('data')))
+ w_strides = space.finditem(w_interface, space.wrap('strides'))
+ shape = [space.int_w(i) for i in space.listview(w_shape)]
+ dtype = descriptor.decode_w_dtype(space, w_dtype)
+ rw = space.is_true(data_w[1])
+ #print 'create view from shape',shape,'dtype',dtype,'descr',w_descr,'data',data_w[0],'rw',rw
+ raise oefmt(space.w_NotImplementedError,
+ "creating array from __array_interface__ not supported yet")
+ return
+
@unwrap_spec(ndmin=int, copy=bool, subok=bool)
def array(space, w_object, w_dtype=None, copy=True, w_order=None, subok=False,
@@ -63,7 +91,11 @@
# continue with w_array, but do further operations in place
w_object = w_array
copy = False
-
+ if not isinstance(w_object, W_NDimArray):
+ w_array = try_interface_method(space, w_object)
+ if w_array is not None:
+ w_object = w_array
+ copy = False
dtype = descriptor.decode_w_dtype(space, w_dtype)
if space.is_none(w_order):
diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py
--- a/pypy/module/micronumpy/descriptor.py
+++ b/pypy/module/micronumpy/descriptor.py
@@ -6,7 +6,7 @@
from pypy.interpreter.typedef import (TypeDef, GetSetProperty,
interp_attrproperty, interp_attrproperty_w)
from rpython.rlib import jit
-from rpython.rlib.objectmodel import specialize, compute_hash
+from rpython.rlib.objectmodel import specialize, compute_hash, we_are_translated
from rpython.rlib.rarithmetic import r_longlong, r_ulonglong
from pypy.module.micronumpy import types, boxes, base, support, constants as NPY
from pypy.module.micronumpy.appbridge import get_appbridge_cache
@@ -56,7 +56,7 @@
self.char = char
self.w_box_type = w_box_type
if byteorder is None:
- if itemtype.get_element_size() == 1:
+ if itemtype.get_element_size() == 1 or isinstance(itemtype, types.ObjectType):
byteorder = NPY.IGNORE
else:
byteorder = NPY.NATIVE
@@ -112,6 +112,9 @@
def is_str(self):
return self.num == NPY.STRING
+ def is_object(self):
+ return self.num == NPY.OBJECT
+
def is_str_or_unicode(self):
return self.num == NPY.STRING or self.num == NPY.UNICODE
@@ -428,7 +431,7 @@
self.names.append(name)
self.fields[name] = offset, dtype
- self.itemtype = types.RecordType()
+ self.itemtype = types.RecordType(space)
if self.is_flexible():
self.elsize = size
@@ -443,7 +446,7 @@
endian = NPY.OPPBYTE if self.is_native() else NPY.NATBYTE
elif newendian != NPY.IGNORE:
endian = newendian
- itemtype = self.itemtype.__class__(endian in (NPY.NATIVE, NPY.NATBYTE))
+ itemtype = self.itemtype.__class__(space, endian in (NPY.NATIVE, NPY.NATBYTE))
fields = self.fields
if fields is None:
fields = {}
@@ -482,7 +485,7 @@
fields[fldname] = (offset, subdtype)
offset += subdtype.elsize
names.append(fldname)
- return W_Dtype(types.RecordType(), NPY.VOID, NPY.VOIDLTR, NPY.VOIDLTR,
+ return W_Dtype(types.RecordType(space), NPY.VOID, NPY.VOIDLTR, NPY.VOIDLTR,
space.gettypefor(boxes.W_VoidBox),
names=names, fields=fields, elsize=offset)
@@ -493,8 +496,17 @@
def dtype_from_spec(space, w_spec):
- w_lst = get_appbridge_cache(space).call_method(space,
- 'numpy.core._internal', '_commastring', Arguments(space, [w_spec]))
+
+ if we_are_translated():
+ w_lst = get_appbridge_cache(space).call_method(space,
+ 'numpy.core._internal', '_commastring', Arguments(space, [w_spec]))
+ else:
+ # testing, handle manually
+ if space.eq_w(w_spec, space.wrap('u4,u4,u4')):
+ w_lst = space.newlist([space.wrap('u4')]*3)
+ else:
+ raise oefmt(space.w_RuntimeError,
+ "cannot parse w_spec")
if not space.isinstance_w(w_lst, space.w_list) or space.len_w(w_lst) < 1:
raise oefmt(space.w_RuntimeError,
"_commastring is not returning a list with len >= 1")
@@ -541,7 +553,7 @@
if size == 1:
return subdtype
size *= subdtype.elsize
- return W_Dtype(types.VoidType(), NPY.VOID, NPY.VOIDLTR, NPY.VOIDLTR,
+ return W_Dtype(types.VoidType(space), NPY.VOID, NPY.VOIDLTR, NPY.VOIDLTR,
space.gettypefor(boxes.W_VoidBox),
shape=shape, subdtype=subdtype, elsize=size)
@@ -587,8 +599,7 @@
if w_dtype is dtype.w_box_type:
return dtype
if space.isinstance_w(w_dtype, space.w_type):
- raise oefmt(space.w_NotImplementedError,
- "cannot create dtype with type '%N'", w_dtype)
+ return cache.w_objectdtype
raise oefmt(space.w_TypeError, "data type not understood")
@@ -655,7 +666,7 @@
def new_string_dtype(space, size, char=NPY.STRINGLTR):
return W_Dtype(
- types.StringType(),
+ types.StringType(space),
elsize=size,
num=NPY.STRING,
kind=NPY.STRINGLTR,
@@ -665,7 +676,7 @@
def new_unicode_dtype(space, size):
- itemtype = types.UnicodeType()
+ itemtype = types.UnicodeType(space)
return W_Dtype(
itemtype,
elsize=size * itemtype.get_element_size(),
@@ -678,7 +689,7 @@
def new_void_dtype(space, size):
return W_Dtype(
- types.VoidType(),
+ types.VoidType(space),
elsize=size,
num=NPY.VOID,
kind=NPY.VOIDLTR,
@@ -690,126 +701,126 @@
class DtypeCache(object):
def __init__(self, space):
self.w_booldtype = W_Dtype(
- types.Bool(),
+ types.Bool(space),
num=NPY.BOOL,
kind=NPY.GENBOOLLTR,
char=NPY.BOOLLTR,
w_box_type=space.gettypefor(boxes.W_BoolBox),
)
self.w_int8dtype = W_Dtype(
- types.Int8(),
+ types.Int8(space),
num=NPY.BYTE,
kind=NPY.SIGNEDLTR,
char=NPY.BYTELTR,
w_box_type=space.gettypefor(boxes.W_Int8Box),
)
self.w_uint8dtype = W_Dtype(
- types.UInt8(),
+ types.UInt8(space),
num=NPY.UBYTE,
kind=NPY.UNSIGNEDLTR,
char=NPY.UBYTELTR,
w_box_type=space.gettypefor(boxes.W_UInt8Box),
)
self.w_int16dtype = W_Dtype(
- types.Int16(),
+ types.Int16(space),
num=NPY.SHORT,
kind=NPY.SIGNEDLTR,
char=NPY.SHORTLTR,
w_box_type=space.gettypefor(boxes.W_Int16Box),
)
self.w_uint16dtype = W_Dtype(
- types.UInt16(),
+ types.UInt16(space),
num=NPY.USHORT,
kind=NPY.UNSIGNEDLTR,
char=NPY.USHORTLTR,
w_box_type=space.gettypefor(boxes.W_UInt16Box),
)
self.w_int32dtype = W_Dtype(
- types.Int32(),
+ types.Int32(space),
num=NPY.INT,
kind=NPY.SIGNEDLTR,
char=NPY.INTLTR,
w_box_type=space.gettypefor(boxes.W_Int32Box),
)
self.w_uint32dtype = W_Dtype(
- types.UInt32(),
+ types.UInt32(space),
num=NPY.UINT,
kind=NPY.UNSIGNEDLTR,
char=NPY.UINTLTR,
w_box_type=space.gettypefor(boxes.W_UInt32Box),
)
self.w_longdtype = W_Dtype(
- types.Long(),
+ types.Long(space),
num=NPY.LONG,
kind=NPY.SIGNEDLTR,
char=NPY.LONGLTR,
w_box_type=space.gettypefor(boxes.W_LongBox),
)
self.w_ulongdtype = W_Dtype(
- types.ULong(),
+ types.ULong(space),
num=NPY.ULONG,
kind=NPY.UNSIGNEDLTR,
char=NPY.ULONGLTR,
w_box_type=space.gettypefor(boxes.W_ULongBox),
)
self.w_int64dtype = W_Dtype(
- types.Int64(),
+ types.Int64(space),
num=NPY.LONGLONG,
kind=NPY.SIGNEDLTR,
char=NPY.LONGLONGLTR,
w_box_type=space.gettypefor(boxes.W_Int64Box),
)
self.w_uint64dtype = W_Dtype(
- types.UInt64(),
+ types.UInt64(space),
num=NPY.ULONGLONG,
kind=NPY.UNSIGNEDLTR,
char=NPY.ULONGLONGLTR,
w_box_type=space.gettypefor(boxes.W_UInt64Box),
)
self.w_float32dtype = W_Dtype(
- types.Float32(),
+ types.Float32(space),
num=NPY.FLOAT,
kind=NPY.FLOATINGLTR,
char=NPY.FLOATLTR,
w_box_type=space.gettypefor(boxes.W_Float32Box),
)
self.w_float64dtype = W_Dtype(
- types.Float64(),
+ types.Float64(space),
num=NPY.DOUBLE,
kind=NPY.FLOATINGLTR,
char=NPY.DOUBLELTR,
w_box_type=space.gettypefor(boxes.W_Float64Box),
)
self.w_floatlongdtype = W_Dtype(
- types.FloatLong(),
+ types.FloatLong(space),
num=NPY.LONGDOUBLE,
kind=NPY.FLOATINGLTR,
char=NPY.LONGDOUBLELTR,
w_box_type=space.gettypefor(boxes.W_FloatLongBox),
)
self.w_complex64dtype = W_Dtype(
- types.Complex64(),
+ types.Complex64(space),
num=NPY.CFLOAT,
kind=NPY.COMPLEXLTR,
char=NPY.CFLOATLTR,
w_box_type=space.gettypefor(boxes.W_Complex64Box),
)
self.w_complex128dtype = W_Dtype(
- types.Complex128(),
+ types.Complex128(space),
num=NPY.CDOUBLE,
kind=NPY.COMPLEXLTR,
char=NPY.CDOUBLELTR,
w_box_type=space.gettypefor(boxes.W_Complex128Box),
)
self.w_complexlongdtype = W_Dtype(
- types.ComplexLong(),
+ types.ComplexLong(space),
num=NPY.CLONGDOUBLE,
kind=NPY.COMPLEXLTR,
char=NPY.CLONGDOUBLELTR,
w_box_type=space.gettypefor(boxes.W_ComplexLongBox),
)
self.w_stringdtype = W_Dtype(
- types.StringType(),
+ types.StringType(space),
elsize=0,
num=NPY.STRING,
kind=NPY.STRINGLTR,
@@ -817,7 +828,7 @@
w_box_type=space.gettypefor(boxes.W_StringBox),
)
self.w_unicodedtype = W_Dtype(
- types.UnicodeType(),
+ types.UnicodeType(space),
elsize=0,
num=NPY.UNICODE,
kind=NPY.UNICODELTR,
@@ -825,7 +836,7 @@
w_box_type=space.gettypefor(boxes.W_UnicodeBox),
)
self.w_voiddtype = W_Dtype(
- types.VoidType(),
+ types.VoidType(space),
elsize=0,
num=NPY.VOID,
kind=NPY.VOIDLTR,
@@ -833,26 +844,33 @@
w_box_type=space.gettypefor(boxes.W_VoidBox),
)
self.w_float16dtype = W_Dtype(
- types.Float16(),
+ types.Float16(space),
num=NPY.HALF,
kind=NPY.FLOATINGLTR,
char=NPY.HALFLTR,
w_box_type=space.gettypefor(boxes.W_Float16Box),
)
self.w_intpdtype = W_Dtype(
- types.Long(),
+ types.Long(space),
num=NPY.LONG,
kind=NPY.SIGNEDLTR,
char=NPY.INTPLTR,
w_box_type=space.gettypefor(boxes.W_LongBox),
)
self.w_uintpdtype = W_Dtype(
- types.ULong(),
+ types.ULong(space),
num=NPY.ULONG,
kind=NPY.UNSIGNEDLTR,
char=NPY.UINTPLTR,
w_box_type=space.gettypefor(boxes.W_ULongBox),
)
+ self.w_objectdtype = W_Dtype(
+ types.ObjectType(space),
+ num=NPY.OBJECT,
+ kind=NPY.OBJECTLTR,
+ char=NPY.OBJECTLTR,
+ w_box_type=space.gettypefor(boxes.W_ObjectBox),
+ )
aliases = {
NPY.BOOL: ['bool_', 'bool8'],
NPY.BYTE: ['byte'],
@@ -871,6 +889,7 @@
NPY.CLONGDOUBLE: ['clongdouble', 'clongfloat'],
NPY.STRING: ['string_', 'str'],
NPY.UNICODE: ['unicode_'],
+ NPY.OBJECT: ['object_'],
}
self.alternate_constructors = {
NPY.BOOL: [space.w_bool],
@@ -889,6 +908,8 @@
NPY.UNICODE: [space.w_unicode],
NPY.VOID: [space.gettypefor(boxes.W_GenericBox)],
#space.w_buffer, # XXX no buffer in space
+ NPY.OBJECT: [space.gettypefor(boxes.W_ObjectBox),
+ space.w_object],
}
float_dtypes = [self.w_float16dtype, self.w_float32dtype,
self.w_float64dtype, self.w_floatlongdtype]
@@ -908,7 +929,7 @@
self.w_int64dtype, self.w_uint64dtype,
] + float_dtypes + complex_dtypes + [
self.w_stringdtype, self.w_unicodedtype, self.w_voiddtype,
- self.w_intpdtype, self.w_uintpdtype,
+ self.w_intpdtype, self.w_uintpdtype, self.w_objectdtype,
]
self.float_dtypes_by_num_bytes = sorted(
(dtype.elsize, dtype)
@@ -960,6 +981,7 @@
'USHORT': self.w_uint16dtype,
'FLOAT': self.w_float32dtype,
'BOOL': self.w_booldtype,
+ 'OBJECT': self.w_objectdtype,
}
typeinfo_partial = {
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -202,11 +202,16 @@
return self
elif isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool() \
and w_idx.ndims() > 0:
- return self.getitem_filter(space, w_idx)
- try:
- return self.implementation.descr_getitem(space, self, w_idx)
- except ArrayArgumentException:
- return self.getitem_array_int(space, w_idx)
+ w_ret = self.getitem_filter(space, w_idx)
+ else:
+ try:
+ w_ret = self.implementation.descr_getitem(space, self, w_idx)
+ except ArrayArgumentException:
+ w_ret = self.getitem_array_int(space, w_idx)
+ if isinstance(w_ret, boxes.W_ObjectBox):
+ #return the W_Root object, not a scalar
+ w_ret = w_ret.w_obj
+ return w_ret
def getitem(self, space, index_list):
return self.implementation.getitem_index(space, index_list)
@@ -550,6 +555,7 @@
else:
strides = self.descr_get_strides(space)
space.setitem_str(w_d, 'strides', strides)
+ space.setitem_str(w_d, 'version', space.wrap(3))
return w_d
w_pypy_data = None
@@ -845,7 +851,7 @@
"new type not compatible with array."))
# Strides, shape does not change
v = impl.astype(space, dtype)
- return wrap_impl(space, w_type, self, v)
+ return wrap_impl(space, w_type, self, v)
strides = impl.get_strides()
if dims == 1 or strides[0] <strides[-1]:
# Column-major, resize first dimension
@@ -1205,7 +1211,7 @@
"improper dtype '%R'", dtype)
self.implementation = W_NDimArray.from_shape_and_storage(
space, [space.int_w(i) for i in space.listview(shape)],
- rffi.str2charp(space.str_w(storage), track_allocation=False),
+ rffi.str2charp(space.str_w(storage), track_allocation=False),
dtype, storage_bytes=space.len_w(storage), owning=True).implementation
def descr___array_finalize__(self, space, w_obj):
diff --git a/pypy/module/micronumpy/test/dummy_module.py b/pypy/module/micronumpy/test/dummy_module.py
--- a/pypy/module/micronumpy/test/dummy_module.py
+++ b/pypy/module/micronumpy/test/dummy_module.py
@@ -20,7 +20,7 @@
for t in types:
globals()[t] = dtype(t).type
-types = ['bool', 'int', 'float', 'complex', 'str', 'string', 'unicode']
+types = ['bool', 'int', 'float', 'complex', 'str', 'string', 'unicode', 'object']
for t in types:
globals()[t + '_'] = dtype(t).type
del types
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -473,11 +473,13 @@
class O(object):
pass
for o in [object, O]:
- if '__pypy__' not in sys.builtin_module_names:
+ print np.dtype(o).byteorder
+ if self.ptr_size == 4:
+ assert np.dtype(o).str == '|O4'
+ elif self.ptr_size == 8:
assert np.dtype(o).str == '|O8'
else:
- exc = raises(NotImplementedError, "np.dtype(o)")
- assert exc.value[0] == "cannot create dtype with type '%s'" % o.__name__
+ assert False,'self._ptr_size unknown'
class AppTestTypes(BaseAppTestDtypes):
def test_abstract_types(self):
@@ -1349,15 +1351,4 @@
assert a[0] == 1
assert (a + a)[1] == 4
-class AppTestObjectDtypes(BaseNumpyAppTest):
- def test_scalar_from_object(self):
- from numpy import array
- import sys
- class Polynomial(object):
- pass
- if '__pypy__' in sys.builtin_module_names:
- exc = raises(NotImplementedError, array, Polynomial())
- assert exc.value.message.find('unable to create dtype from objects') >= 0
- else:
- a = array(Polynomial())
- assert a.shape == ()
+
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -17,6 +17,7 @@
def __init__(self):
self.base = self
self.elsize = 1
+ self.num = 0
def create_slice(space, a, chunks):
@@ -3150,11 +3151,7 @@
assert b[35] == 200
b[[slice(25, 30)]] = range(5)
assert all(a[:5] == range(5))
- import sys
- if '__pypy__' not in sys.builtin_module_names:
- raises(TypeError, 'b[[[slice(25, 125)]]]')
- else:
- raises(NotImplementedError, 'b[[[slice(25, 125)]]]')
+ raises(IndexError, 'b[[[slice(25, 125)]]]')
def test_cumsum(self):
from numpy import arange
diff --git a/pypy/module/micronumpy/test/test_object_arrays.py b/pypy/module/micronumpy/test/test_object_arrays.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_object_arrays.py
@@ -0,0 +1,162 @@
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestObjectDtypes(BaseNumpyAppTest):
+ def test_scalar_from_object(self):
+ from numpy import array
+ import sys
+ class Polynomial(object):
+ def whatami(self):
+ return 'an object'
+ a = array(Polynomial())
+ assert a.shape == ()
+ assert a.sum().whatami() == 'an object'
+
+ def test_uninitialized_object_array_is_filled_by_None(self):
+ import numpy as np
+
+ a = np.ndarray([5], dtype="O")
+
+ assert a[0] == None
+
+ def test_object_arrays_add(self):
+ import numpy as np
+
+ a = np.array(["foo"], dtype=object)
+ b = np.array(["bar"], dtype=object)
+ raises(TypeError, np.add, a, 1)
+ res = a + b
+ assert res[0] == "foobar"
+
+ def test_bool_func(self):
+ import numpy as np
+ a = np.array(["foo"], dtype=object)
+ b = a and complex(1, -1)
+ assert b == complex(1, -1)
+ b = np.array(complex(1, -1)) and a
+ assert (b == a).all()
+ c = np.array([1, 2, 3])
+ assert (a[0] != c[0])
+ assert (c[0] != a[0])
+ assert (a[0] > c[0])
+ assert (not a[0] < c[0])
+ assert (c[0] < a[0])
+ assert (not c[0] > a[0])
+
+ def test_logical_ufunc(self):
+ import numpy as np
+ import sys
+
+ if '__pypy__' in sys.builtin_module_names:
+ skip('need to refactor use of raw_xxx_op in types to make this work')
+ a = np.array(["foo"], dtype=object)
+ b = np.array([1], dtype=object)
+ d = np.array([complex(1, 10)], dtype=object)
+ c = np.logical_and(a, 1)
+ assert c.dtype == np.dtype('object')
+ assert c == 1
+ c = np.logical_and(b, complex(1, -1))
+ assert c.dtype == np.dtype('object')
+ assert c == complex(1, -1)
+ c = np.logical_and(d, b)
+ assert c == 1
+ c = b & 1
+ assert c.dtype == np.dtype('object')
+ assert (c == 1).all()
+ c = np.array(1) & b
+ assert (c == b).all()
+
+ def test_reduce(self):
+ import numpy as np
+ class O(object):
+ def whatami(self):
+ return 'an object'
+ fiveOs = [O()] * 5
+ a = np.array(fiveOs, dtype=object)
+ print np.maximum
+ b = np.maximum.reduce(a)
+ assert b is not None
+
+ def test_complex_op(self):
+ import numpy as np
+ import sys
+ a = np.array(['abc', 'def'], dtype=object)
+ b = np.array([1, 2, 3], dtype=object)
+ c = np.array([complex(1, 1), complex(1, -1)], dtype=object)
+ for arg in (a,b,c):
+ assert (arg == np.real(arg)).all()
+ assert (0 == np.imag(arg)).all()
+ if '__pypy__' in sys.builtin_module_names:
+ skip('not implemented yet')
+ raises(AttributeError, np.conj, a)
+ res = np.conj(b)
+ assert (res == b).all()
+ res = np.conj(c)
+ assert res[0] == c[1] and res[1] == c[0]
+
+ def test_keep_object_alive(self):
+ # only translated does it really test the gc
+ import numpy as np
+ import gc
+ class O(object):
+ def whatami(self):
+ return 'an object'
+ fiveOs = [O()] * 5
+ a = np.array(fiveOs, dtype=object)
+ del fiveOs
+ gc.collect()
+ assert a[2].whatami() == 'an object'
+
+ def test_array_interface(self):
+ import numpy as np
+ import sys
+ class DummyArray(object):
+ def __init__(self, interface, base=None):
+ self.__array_interface__ = interface
+ self.base = base
+ a = np.array([(1, 2, 3)], dtype='u4,u4,u4')
+ b = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4')
+ interface = dict(a.__array_interface__)
+ interface['shape'] = tuple([3])
+ interface['strides'] = tuple([0])
+ if '__pypy__' in sys.builtin_module_names:
+ skip('not implemented yet')
+ c = np.array(DummyArray(interface, base=a))
+ c.dtype = a.dtype
+ #print c
+ assert (c == np.array([(1, 2, 3), (1, 2, 3), (1, 2, 3)], dtype='u4,u4,u4') ).all()
+
+ def test_for_object_scalar_creation(self):
+ import numpy as np
+ import sys
+ a = np.object_()
+ b = np.object_(3)
+ b2 = np.object_(3.0)
+ c = np.object_([4, 5])
+ d = np.array([None])[0]
+ assert a is None
+ assert type(b) is int
+ assert type(b2) is float
+ assert type(c) is np.ndarray
+ assert c.dtype == object
+ assert type(d) is type(None)
+ if '__pypy__' in sys.builtin_module_names:
+ skip('not implemented yet')
+ e = np.object_([None, {}, []])
+ assert e.dtype == object
+
+ def test_mem_array_creation_invalid_specification(self):
+ # while not specifically testing object dtype, this
+ # test segfaulted during ObjectType.store due to
+ # missing gc hooks
+ import numpy as np
+ import sys
+ ytype = np.object_
+ if '__pypy__' in sys.builtin_module_names:
+ ytype = str
+ dt = np.dtype([('x', int), ('y', ytype)])
+ # Correct way
+ a = np.array([(1, 'object')], dt)
+ # Wrong way - should complain about writing buffer to object dtype
+ raises(ValueError, np.array, [1, 'object'], dt)
+
diff --git a/pypy/module/micronumpy/test/test_selection.py b/pypy/module/micronumpy/test/test_selection.py
--- a/pypy/module/micronumpy/test/test_selection.py
+++ b/pypy/module/micronumpy/test/test_selection.py
@@ -12,14 +12,11 @@
exp = sorted(range(len(exp)), key=exp.__getitem__)
c = a.copy()
res = a.argsort()
- assert (res == exp).all(), '%r\n%r\n%r' % (a,res,exp)
+ assert (res == exp).all(), 'Failed sortng %r\na=%r\nres=%r\nexp=%r' % (dtype,a,res,exp)
assert (a == c).all() # not modified
a = arange(100, dtype=dtype)
assert (a.argsort() == a).all()
- import sys
- if '__pypy__' in sys.builtin_module_names:
- raises(NotImplementedError, 'arange(10,dtype="float16").argsort()')
def test_argsort_ndim(self):
from numpy import array
@@ -63,14 +60,13 @@
'i2', complex]:
a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
exp = sorted(list(a))
- res = a.copy()
- res.sort()
- assert (res == exp).all(), '%r\n%r\n%r' % (a,res,exp)
+ a.sort()
+ assert (a == exp).all(), 'Failed sorting %r\n%r\n%r' % (dtype, a, exp)
a = arange(100, dtype=dtype)
c = a.copy()
a.sort()
- assert (a == c).all()
+ assert (a == c).all(), 'Failed sortng %r\na=%r\nc=%r' % (dtype,a,c)
def test_sort_nonnative(self):
from numpy import array
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -397,11 +397,11 @@
for i in range(3):
assert min_c_b[i] == min(b[i], c)
- def test_scalar(self):
+ def test_all_available(self):
# tests that by calling all available ufuncs on scalars, none will
# raise uncaught interp-level exceptions, (and crash the test)
# and those that are uncallable can be accounted for.
- # test on the four base-class dtypes: int, bool, float, complex
+ # test on the base-class dtypes: int, bool, float, complex, object
# We need this test since they have no common base class.
import numpy as np
def find_uncallable_ufuncs(dtype):
@@ -412,6 +412,11 @@
if isinstance(u, np.ufunc):
try:
u(* [array] * u.nin)
+ except AttributeError:
+ pass
+ except NotImplementedError:
+ print s
+ uncallable.add(s)
except TypeError:
assert s not in uncallable
uncallable.add(s)
@@ -427,6 +432,9 @@
'fabs', 'fmod', 'invert', 'mod',
'logaddexp', 'logaddexp2', 'left_shift', 'right_shift',
'copysign', 'signbit', 'ceil', 'floor', 'trunc'])
+ assert find_uncallable_ufuncs('object') == set(
+ ['isnan', 'logaddexp2', 'copysign', 'isfinite', 'signbit',
+ 'isinf', 'logaddexp'])
def test_int_only(self):
from numpy import bitwise_and, array
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -9,6 +9,7 @@
from pypy.module.micronumpy.compile import FakeSpace, Parser, InterpreterState
from pypy.module.micronumpy.base import W_NDimArray
+py.test.skip('move these to pypyjit/test_pypy_c/test_micronumpy')
class TestNumpyJit(LLJitMixin):
graph = None
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
@@ -3,8 +3,9 @@
from pypy.interpreter.error import OperationError, oefmt
from pypy.objspace.std.floatobject import float2string
from pypy.objspace.std.complexobject import str_format
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace
from rpython.rlib import clibffi, jit, rfloat, rcomplex
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, we_are_translated
from rpython.rlib.rarithmetic import widen, byteswap, r_ulonglong, \
most_neg_value_of, LONG_BIT
from rpython.rlib.rawstorage import (alloc_raw_storage,
@@ -14,10 +15,12 @@
pack_float80, unpack_float80)
from rpython.rlib.rstruct.nativefmttable import native_is_bigendian
from rpython.rlib.rstruct.runpack import runpack
-from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.annlowlevel import cast_instance_to_gcref,\
+ cast_gcref_to_instance
+from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.tool.sourcetools import func_with_new_name
from pypy.module.micronumpy import boxes
-from pypy.module.micronumpy.concrete import SliceArray, VoidBoxStorage
+from pypy.module.micronumpy.concrete import SliceArray, VoidBoxStorage, V_OBJECTSTORE
from pypy.module.micronumpy.strides import calc_strides
degToRad = math.pi / 180.0
@@ -109,10 +112,12 @@
return dispatcher
class BaseType(object):
- _immutable_fields_ = ['native']
+ _immutable_fields_ = ['native', 'space']
- def __init__(self, native=True):
+ def __init__(self, space, native=True):
+ assert isinstance(space, ObjSpace)
self.native = native
+ self.space = space
def __repr__(self):
return self.__class__.__name__
@@ -191,7 +196,7 @@
with arr as storage:
self._write(storage, i, offset, self.unbox(box))
- def fill(self, storage, width, box, start, stop, offset):
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
value = self.unbox(box)
for i in xrange(start, stop, width):
self._write(storage, i, offset, value)
@@ -306,7 +311,7 @@
@raw_unary_op
def rint(self, v):
- float64 = Float64()
+ float64 = Float64(self.space)
return float64.rint(float64.box(v))
class Bool(BaseType, Primitive):
@@ -399,7 +404,7 @@
def round(self, v, decimals=0):
if decimals != 0:
return v
- return Float64().box(self.unbox(v))
+ return Float64(self.space).box(self.unbox(v))
class Integer(Primitive):
_mixin_ = True
@@ -444,7 +449,7 @@
self.T is rffi.LONG or self.T is rffi.LONGLONG):
if v2 == -1 and v1 == self.for_computation(most_neg_value_of(self.T)):
return self.box(0)
- return self.box(v1 // v2)
+ return self.box(v1 / v2)
@simple_binary_op
def mod(self, v1, v2):
@@ -1152,7 +1157,7 @@
with arr as storage:
self._write(storage, i, offset, self.unbox(box))
- def fill(self, storage, width, box, start, stop, offset):
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
value = self.unbox(box)
for i in xrange(start, stop, width):
self._write(storage, i, offset, value)
@@ -1253,25 +1258,25 @@
def ge(self, v1, v2):
return self._lt(v2, v1) or self._eq(v2, v1)
- def _bool(self, v):
+ def _cbool(self, v):
return bool(v[0]) or bool(v[1])
@raw_binary_op
def logical_and(self, v1, v2):
- return self._bool(v1) and self._bool(v2)
+ return self._cbool(v1) and self._cbool(v2)
@raw_binary_op
def logical_or(self, v1, v2):
- return self._bool(v1) or self._bool(v2)
+ return self._cbool(v1) or self._cbool(v2)
@raw_unary_op
def logical_not(self, v):
- return not self._bool(v)
+ return not self._cbool(v)
@raw_binary_op
def logical_xor(self, v1, v2):
- a = self._bool(v1)
- b = self._bool(v2)
+ a = self._cbool(v1)
+ b = self._cbool(v2)
return (not b and a) or (not a and b)
def min(self, v1, v2):
@@ -1629,6 +1634,283 @@
BoxType = boxes.W_ComplexLongBox
ComponentBoxType = boxes.W_FloatLongBox
+_all_objs_for_tests = [] # for tests
+
+class ObjectType(Primitive, BaseType):
+ T = lltype.Signed
+ BoxType = boxes.W_ObjectBox
+
+ def get_element_size(self):
+ return rffi.sizeof(lltype.Signed)
+
+ def coerce(self, space, dtype, w_item):
+ if isinstance(w_item, boxes.W_ObjectBox):
+ return w_item
+ return boxes.W_ObjectBox(w_item)
+
+ def coerce_subtype(self, space, w_subtype, w_item):
+ # return the item itself
+ return self.unbox(self.box(w_item))
+
+ def store(self, arr, i, offset, box):
+ if arr.gcstruct is V_OBJECTSTORE:
+ raise oefmt(self.space.w_NotImplementedError,
+ "cannot store object in array with no gc hook")
+ self._write(arr.storage, i, offset, self.unbox(box),
+ arr.gcstruct)
+
+ def read(self, arr, i, offset, dtype=None):
+ return self.box(self._read(arr.storage, i, offset))
+
+ def byteswap(self, w_v):
+ return w_v
+
+ @jit.dont_look_inside
+ def _write(self, storage, i, offset, w_obj, gcstruct):
+ # no GC anywhere in this function!
+ if we_are_translated():
+ from rpython.rlib import rgc
+ rgc.ll_writebarrier(gcstruct)
+ value = rffi.cast(lltype.Signed, cast_instance_to_gcref(w_obj))
+ else:
+ value = len(_all_objs_for_tests)
+ _all_objs_for_tests.append(w_obj)
+ raw_storage_setitem_unaligned(storage, i + offset, value)
+
+ @jit.dont_look_inside
+ def _read(self, storage, i, offset):
+ res = raw_storage_getitem_unaligned(self.T, storage, i + offset)
+ if we_are_translated():
+ gcref = rffi.cast(llmemory.GCREF, res)
+ w_obj = cast_gcref_to_instance(W_Root, gcref)
+ else:
+ w_obj = _all_objs_for_tests[res]
+ return w_obj
+
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
+ value = self.unbox(box)
+ for i in xrange(start, stop, width):
+ self._write(storage, i, offset, value, gcstruct)
+
+ def unbox(self, box):
+ if isinstance(box, self.BoxType):
+ return box.w_obj
+ else:
+ raise oefmt(self.space.w_NotImplementedError,
+ "object dtype cannot unbox %s", str(box))
+
+ @specialize.argtype(1)
+ def box(self, w_obj):
+ if isinstance(w_obj, W_Root):
+ pass
+ elif isinstance(w_obj, bool):
+ w_obj = self.space.newbool(w_obj)
+ elif isinstance(w_obj, int):
+ w_obj = self.space.newint(w_obj)
+ elif isinstance(w_obj, lltype.Number):
+ w_obj = self.space.newint(w_obj)
+ elif isinstance(w_obj, float):
+ w_obj = self.space.newfloat(w_obj)
+ elif w_obj is None:
+ w_obj = self.space.w_None
+ else:
+ raise oefmt(self.space.w_NotImplementedError,
+ "cannot create object array/scalar from lltype")
+ return self.BoxType(w_obj)
+
+ @specialize.argtype(1, 2)
+ def box_complex(self, real, imag):
+ if isinstance(real, rffi.r_singlefloat):
+ real = rffi.cast(rffi.DOUBLE, real)
+ if isinstance(imag, rffi.r_singlefloat):
+ imag = rffi.cast(rffi.DOUBLE, imag)
+ w_obj = self.space.newcomplex(real, imag)
+ return self.BoxType(w_obj)
+
+ def str_format(self, box):
+ return self.space.str_w(self.space.repr(self.unbox(box)))
+
+ def runpack_str(self, space, s):
+ raise oefmt(space.w_NotImplementedError,
+ "fromstring not implemented for object type")
+
+ def to_builtin_type(self, space, box):
+ assert isinstance(box, self.BoxType)
+ return box.w_obj
+
+ @staticmethod
+ def for_computation(v):
+ return v
+
+ @raw_binary_op
+ def eq(self, v1, v2):
+ return self.space.eq_w(v1, v2)
+
+ @simple_binary_op
+ def max(self, v1, v2):
+ if self.space.is_true(self.space.ge(v1, v2)):
+ return v1
+ return v2
+
+ @simple_binary_op
+ def min(self, v1, v2):
+ if self.space.is_true(self.space.le(v1, v2)):
+ return v1
+ return v2
+
+ @raw_unary_op
+ def bool(self,v):
+ return self._obool(v)
+
+ def _obool(self, v):
+ if self.space.is_true(v):
+ return True
+ return False
+
+ @raw_binary_op
+ def logical_and(self, v1, v2):
+ if self._obool(v1):
+ return self.space.bool_w(v2)
+ return self.space.bool_w(v1)
+
+ @raw_binary_op
+ def logical_or(self, v1, v2):
+ if self._obool(v1):
+ return self.space.bool_w(v1)
+ return self.space.bool_w(v2)
+
+ @raw_unary_op
+ def logical_not(self, v):
+ return not self._obool(v)
+
+ @raw_binary_op
+ def logical_xor(self, v1, v2):
+ a = self._obool(v1)
+ b = self._obool(v2)
+ return (not b and a) or (not a and b)
+
+ @simple_binary_op
+ def bitwise_and(self, v1, v2):
+ return self.space.and_(v1, v2)
+
+ @simple_binary_op
+ def bitwise_or(self, v1, v2):
+ return self.space.or_(v1, v2)
+
+ @simple_binary_op
+ def bitwise_xor(self, v1, v2):
+ return self.space.xor(v1, v2)
+
+ @simple_binary_op
+ def pow(self, v1, v2):
+ return self.space.pow(v1, v2, self.space.wrap(1))
+
+ @simple_unary_op
+ def reciprocal(self, v1):
+ return self.space.div(self.space.wrap(1.0), v1)
+
+ @simple_unary_op
+ def sign(self, v):
+ zero = self.space.wrap(0)
+ one = self.space.wrap(1)
+ m_one = self.space.wrap(-1)
+ if self.space.is_true(self.space.gt(v, zero)):
+ return one
+ elif self.space.is_true(self.space.lt(v, zero)):
+ return m_one
+ else:
+ return zero
+
+ @simple_unary_op
+ def real(self, v):
+ return v
+
+ @simple_unary_op
+ def imag(self, v):
+ return 0
+
+ @simple_unary_op
+ def square(self, v):
+ return self.space.mul(v, v)
+
+ @raw_binary_op
+ def le(self, v1, v2):
+ return self.space.bool_w(self.space.le(v1, v2))
+
+ @raw_binary_op
+ def ge(self, v1, v2):
+ return self.space.bool_w(self.space.ge(v1, v2))
+
+ @raw_binary_op
+ def lt(self, v1, v2):
+ return self.space.bool_w(self.space.lt(v1, v2))
+
+ @raw_binary_op
+ def gt(self, v1, v2):
+ return self.space.bool_w(self.space.gt(v1, v2))
+
+ @raw_binary_op
+ def ne(self, v1, v2):
+ return self.space.bool_w(self.space.ne(v1, v2))
+
+def add_attributeerr_op(cls, op):
+ def func(self, *args):
+ raise oefmt(self.space.w_AttributeError,
+ "%s", op)
+ func.__name__ = 'object_' + op
+ setattr(cls, op, func)
+
+def add_unsupported_op(cls, op):
+ def func(self, *args):
+ raise oefmt(self.space.w_TypeError,
+ "ufunc '%s' not supported for input types", op)
+ func.__name__ = 'object_' + op
+ setattr(cls, op, func)
+
+def add_unary_op(cls, op, method):
+ @simple_unary_op
+ def func(self, w_v):
+ space = self.space
+ w_impl = space.lookup(w_v, method)
+ if w_impl is None:
+ raise oefmt(space.w_AttributeError, 'unknown op "%s" on object' % op)
+ return space.get_and_call_function(w_impl, w_v)
+ func.__name__ = 'object_' + op
+ setattr(cls, op, func)
+
+def add_space_unary_op(cls, op):
+ @simple_unary_op
+ def func(self, v):
+ return getattr(self.space, op)(v)
+ func.__name__ = 'object_' + op
+ setattr(cls, op, func)
+
+def add_space_binary_op(cls, op):
+ @simple_binary_op
+ def func(self, v1, v2):
+ return getattr(self.space, op)(v1, v2)
+ func.__name__ = 'object_' + op
+ setattr(cls, op, func)
+
+for op in ('copysign', 'isfinite', 'isinf', 'isnan', 'logaddexp', 'logaddexp2',
+ 'signbit'):
+ add_unsupported_op(ObjectType, op)
+for op in ('arctan2', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan',
+ 'arctanh', 'ceil', 'floor', 'cos', 'sin', 'tan', 'cosh', 'sinh',
+ 'tanh', 'radians', 'degrees', 'exp','exp2', 'expm1', 'fabs',
+ 'log', 'log10', 'log1p', 'log2', 'sqrt', 'trunc'):
+ add_attributeerr_op(ObjectType, op)
+for op in ('abs', 'neg', 'pos', 'invert'):
+ add_space_unary_op(ObjectType, op)
+for op, method in (('conj', 'descr_conjugate'), ('rint', 'descr_rint')):
+ add_unary_op(ObjectType, op, method)
+for op in ('add', 'floordiv', 'div', 'mod', 'mul', 'sub', 'lshift', 'rshift'):
+ add_space_binary_op(ObjectType, op)
+
+ObjectType.fmax = ObjectType.max
+ObjectType.fmin = ObjectType.min
+ObjectType.fmod = ObjectType.mod
+
class FlexibleType(BaseType):
def get_element_size(self):
return rffi.sizeof(self.T)
@@ -1758,7 +2040,7 @@
def bool(self, v):
return bool(self.to_str(v))
- def fill(self, storage, width, box, start, stop, offset):
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
for i in xrange(start, stop, width):
self._store(storage, i, offset, box, width)
@@ -1775,6 +2057,57 @@
raise OperationError(space.w_NotImplementedError, space.wrap(
"coerce (probably from set_item) not implemented for unicode type"))
+ def store(self, arr, i, offset, box):
+ assert isinstance(box, boxes.W_UnicodeBox)
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def read(self, arr, i, offset, dtype=None):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def str_format(self, item):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def to_builtin_type(self, space, box):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def eq(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def ne(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def lt(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def le(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def gt(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def ge(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def logical_and(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def logical_or(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def logical_not(self, v):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ @str_binary_op
+ def logical_xor(self, v1, v2):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def bool(self, v):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
+ raise oefmt(self.space.w_NotImplementedError, "unicode type not completed")
+
+
class VoidType(FlexibleType):
T = lltype.Char
@@ -1882,6 +2215,9 @@
items_w = space.fixedview(w_item)
elif isinstance(w_item, W_NDimArray) and w_item.is_scalar():
items_w = space.fixedview(w_item.get_scalar_value())
+ elif space.isinstance_w(w_item, space.w_list):
+ raise oefmt(space.w_TypeError,
+ "expected a readable buffer object")
else:
# XXX support initializing from readable buffers
items_w = [w_item] * len(dtype.fields)
@@ -1913,7 +2249,7 @@
for k in range(size):
storage[k + i + ofs] = box_storage[k + box.ofs]
- def fill(self, storage, width, box, start, stop, offset):
+ def fill(self, storage, width, box, start, stop, offset, gcstruct):
assert isinstance(box, boxes.W_VoidBox)
assert width == box.dtype.elsize
for i in xrange(start, stop, width):
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -349,7 +349,7 @@
if dtype.is_flexible():
raise OperationError(space.w_TypeError,
space.wrap('Not implemented for this type'))
- if (self.int_only and not dtype.is_int() or
+ if (self.int_only and not (dtype.is_int() or dtype.is_object()) or
not self.allow_bool and dtype.is_bool() or
not self.allow_complex and dtype.is_complex()):
raise oefmt(space.w_TypeError,
@@ -378,6 +378,8 @@
w_val = self.func(calc_dtype,
w_obj.get_scalar_value().convert_to(space, calc_dtype))
if out is None:
+ if res_dtype.is_object():
+ w_val = w_obj.get_scalar_value()
return w_val
w_val = res_dtype.coerce(space, w_val)
if out.is_scalar():
@@ -434,11 +436,20 @@
w_rhs = numpify(space, w_rhs)
w_ldtype = _get_dtype(space, w_lhs)
w_rdtype = _get_dtype(space, w_rhs)
- if w_ldtype.is_str() and w_rdtype.is_str() and \
+ if w_ldtype.is_object() or w_rdtype.is_object():
+ pass
+ elif w_ldtype.is_str() and w_rdtype.is_str() and \
self.comparison_func:
pass
- elif (w_ldtype.is_str() or w_rdtype.is_str()) and \
+ elif (w_ldtype.is_str()) and \
self.comparison_func and w_out is None:
+ if self.name in ('equal', 'less_equal', 'less'):
+ return space.wrap(False)
+ return space.wrap(True)
+ elif (w_rdtype.is_str()) and \
+ self.comparison_func and w_out is None:
+ if self.name in ('not_equal','less', 'less_equal'):
+ return space.wrap(True)
return space.wrap(False)
elif w_ldtype.is_flexible() or w_rdtype.is_flexible():
if self.comparison_func:
@@ -463,9 +474,9 @@
w_ldtype, w_rdtype,
promote_to_float=self.promote_to_float,
promote_bools=self.promote_bools)
- if (self.int_only and (not w_ldtype.is_int() or
- not w_rdtype.is_int() or
- not calc_dtype.is_int()) or
+ if (self.int_only and (not (w_ldtype.is_int() or w_ldtype.is_object()) or
+ not (w_rdtype.is_int() or w_rdtype.is_object()) or
+ not (calc_dtype.is_int() or calc_dtype.is_object())) or
not self.allow_bool and (w_ldtype.is_bool() or
w_rdtype.is_bool()) or
not self.allow_complex and (w_ldtype.is_complex() or
@@ -643,7 +654,7 @@
# from frompyfunc
pass
# mimic NpyIter_AdvancedNew with a nditer
- w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
+ w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
w_op_flags, w_op_dtypes, w_casting, w_op_axes,
w_itershape)
@@ -749,7 +760,7 @@
else:
raise oefmt(space.w_TypeError, "a type-string for %s " \
"requires 1 typecode or %d typecode(s) before and %d" \
- " after the -> sign, not '%s'", self.name, self.nin,
+ " after the -> sign, not '%s'", self.name, self.nin,
self.nout, type_tup)
except KeyError:
raise oefmt(space.w_ValueError, "unknown typecode in" \
@@ -773,11 +784,11 @@
for j in range(self.nargs):
if dtypes[j] is not None and dtypes[j] != _dtypes[i+j]:
allok = False
- if allok:
+ if allok:
break
else:
if len(self.funcs) > 1:
-
+
dtypesstr = ''
for d in dtypes:
if d is None:
@@ -787,7 +798,7 @@
_dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
for d in _dtypes])
raise oefmt(space.w_TypeError,
- "input dtype [%s] did not match any known dtypes [%s] ",
+ "input dtype [%s] did not match any known dtypes [%s] ",
dtypesstr,_dtypesstr)
i = 0
# Fill in empty dtypes
@@ -807,7 +818,7 @@
assert isinstance(curarg, W_NDimArray)
if len(arg_shapes[i]) != curarg.ndims():
# reshape
-
+
sz = product(curarg.get_shape()) * curarg.get_dtype().elsize
with curarg.implementation as storage:
inargs[i] = W_NDimArray.from_shape_and_storage(
@@ -865,7 +876,7 @@
"%s of gufunc was not specified",
self.name, name, _i, core_dim_index, self.signature)
target_dims.append(v)
- arg_shapes.append(iter_shape + target_dims)
+ arg_shapes.append(iter_shape + target_dims)
continue
n = len(curarg.get_shape()) - num_dims
if n < 0:
@@ -907,7 +918,7 @@
raise oefmt(space.w_ValueError, "%s: %s operand %d has a "
"mismatch in its core dimension %d, with gufunc "
"signature %s (expected %d, got %d)",
- self.name, name, _i, j,
+ self.name, name, _i, j,
self.signature, matched_dims[core_dim_index],
dims_to_match[core_dim_index])
#print 'adding',iter_shape,'+',dims_to_match,'to arg_shapes'
@@ -950,6 +961,10 @@
return dt1
if dt1 is None:
return dt2
+
+ if dt1.num == NPY.OBJECT or dt2.num == NPY.OBJECT:
+ return get_dtype_cache(space).w_objectdtype
+
# dt1.num should be <= dt2.num
if dt1.num > dt2.num:
dt1, dt2 = dt2, dt1
@@ -1032,6 +1047,8 @@
@jit.unroll_safe
def find_unaryop_result_dtype(space, dt, promote_to_float=False,
promote_bools=False, promote_to_largest=False):
+ if dt.is_object():
+ return dt
if promote_to_largest:
if dt.kind == NPY.GENBOOLLTR or dt.kind == NPY.SIGNEDLTR:
if dt.elsize * 8 < LONG_BIT:
@@ -1064,6 +1081,7 @@
uint64_dtype = get_dtype_cache(space).w_uint64dtype
complex_dtype = get_dtype_cache(space).w_complex128dtype
float_dtype = get_dtype_cache(space).w_float64dtype
+ object_dtype = get_dtype_cache(space).w_objectdtype
if isinstance(w_obj, boxes.W_GenericBox):
dtype = w_obj.get_dtype(space)
return find_binop_result_dtype(space, dtype, current_guess)
@@ -1097,9 +1115,10 @@
return variable_dtype(space,
'S%d' % space.len_w(w_obj))
return current_guess
- raise oefmt(space.w_NotImplementedError,
- 'unable to create dtype from objects, "%T" instance not '
- 'supported', w_obj)
+ return object_dtype
+ #raise oefmt(space.w_NotImplementedError,
+ # 'unable to create dtype from objects, "%T" instance not '
+ # 'supported', w_obj)
def ufunc_dtype_caller(space, ufunc_name, op_name, nin, comparison_func,
@@ -1263,7 +1282,7 @@
w_identity=None, name='', doc='', stack_inputs=False):
''' frompyfunc(func, nin, nout) #cpython numpy compatible
frompyfunc(func, nin, nout, dtypes=None, signature='',
- identity=None, name='', doc='',
+ identity=None, name='', doc='',
stack_inputs=False)
Takes an arbitrary Python function and returns a ufunc.
@@ -1282,7 +1301,7 @@
dtypes: None or [dtype, ...] of the input, output args for each function,
or 'match' to force output to exactly match input dtype
Note that 'match' is a pypy-only extension to allow non-object
- return dtypes
+ return dtypes
signature*: str, default=''
The mapping of input args to output args, defining the
inner-loop indexing. If it is empty, the func operates on scalars
@@ -1293,7 +1312,7 @@
stack_inputs*: boolean, whether the function is of the form
out = func(*in) False
or
- func(*[in + out]) True
+ func(*[in + out]) True
only one of out_dtype or signature may be specified
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -686,6 +686,15 @@
lambda_customtrace = lambda: customtrace
"""
+ at specialize.ll()
+def ll_writebarrier(gc_obj):
+ """Use together with custom tracers. When you update some object pointer
+ stored in raw memory, you must call this function on 'gc_obj', which must
+ be the object of type TP with the custom tracer (*not* the value stored!).
+ This makes sure that the custom hook will be called again."""
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ llop.gc_writebarrier(lltype.Void, gc_obj)
+
class RegisterGcTraceEntry(ExtRegistryEntry):
_about_ = register_custom_trace_hook
More information about the pypy-commit
mailing list