[pypy-commit] pypy default: merge
fijal
noreply at buildbot.pypy.org
Wed Jun 3 09:17:22 CEST 2015
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r77802:05a0a598cdd6
Date: 2015-06-03 09:17 +0200
http://bitbucket.org/pypy/pypy/changeset/05a0a598cdd6/
Log: merge
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
@@ -5,4 +5,5 @@
.. this is a revision shortly after release-2.6.0
.. startrev: 91904d5c5188
-
+.. branch: use_min_scalar
+Correctly resolve the output dtype of ufunc(array, scalar) calls.
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -95,6 +95,23 @@
else:
raise KeyError # don't handle this error case here
+ def _ffi_bad_type(self, input_text):
+ info = self.ctxobj.info
+ errmsg = rffi.charp2str(info.c_error_message)
+ if len(input_text) > 500:
+ raise oefmt(self.w_FFIError, "%s", errmsg)
+ printable_text = ['?'] * len(input_text)
+ for i in range(len(input_text)):
+ if ' ' <= input_text[i] < '\x7f':
+ printable_text[i] = input_text[i]
+ elif input_text[i] == '\t' or input_text[i] == '\n':
+ printable_text[i] = ' '
+ num_spaces = rffi.getintfield(info, 'c_error_location')
+ raise oefmt(self.w_FFIError, "%s\n%s\n%s^",
+ rffi.charp2str(info.c_error_message),
+ ''.join(printable_text),
+ " " * num_spaces)
+
@jit.dont_look_inside
def parse_string_to_type(self, string, consider_fn_as_fnptr):
# This cannot be made @elidable because it calls general space
@@ -108,11 +125,7 @@
info = self.ctxobj.info
index = parse_c_type.parse_c_type(info, string)
if index < 0:
- num_spaces = rffi.getintfield(info, 'c_error_location')
- raise oefmt(self.w_FFIError, "%s\n%s\n%s^",
- rffi.charp2str(info.c_error_message),
- string,
- " " * num_spaces)
+ raise self._ffi_bad_type(string)
x = realize_c_type.realize_c_type_or_func(
self, self.ctxobj.info.c_output, index)
assert x is not None
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -181,6 +181,12 @@
assert str(e.value) == ("undefined struct/union name\n"
"struct never_heard_of_s\n"
" ^")
+ e = raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0)
+ assert str(e.value) == ("identifier expected\n"
+ " ??~???\n"
+ " ^")
+ e = raises(ffi.error, ffi.cast, "X" * 600, 0)
+ assert str(e.value) == ("undefined type name")
def test_ffi_buffer(self):
import _cffi_backend as _cffi1_backend
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
@@ -1129,6 +1129,20 @@
exc = raises(ValueError, "dtype([('a', '<i8'), ('a', '<f8')])")
assert exc.value[0] == 'two fields with the same name'
+ def test_array_from_record(self):
+ import numpy as np
+ a = np.array(('???', -999, -12345678.9),
+ dtype=[('c', '|S3'), ('a', '<i8'), ('b', '<f8')])
+ # Change the order of the keys
+ b = np.array(a, dtype=[('a', '<i8'), ('b', '<f8'), ('c', '|S3')])
+ assert b.base is None
+ assert b.dtype.fields['a'][1] == 0
+ assert b['a'] == -999
+ a = np.array(('N/A', 1e+20, 1e+20, 999999),
+ dtype=[('name', '|S4'), ('x', '<f8'),
+ ('y', '<f8'), ('block', '<i8', (2, 3))])
+ assert (a['block'] == 999999).all()
+
def test_create_from_dict(self):
import numpy as np
import sys
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -656,6 +656,7 @@
self.output += 'In __array_wrap__:'
self.output += ' self is %s' % repr(self)
self.output += ' arr is %r\n' % (out_arr,)
+ self.output += ' context is %r\n' % (context,)
# then just call the parent
ret = np.ndarray.__array_wrap__(self, out_arr, context)
print 'wrap',self.output
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
@@ -1349,3 +1349,6 @@
assert np.add(np.float16(0), np.longdouble(0)).dtype == np.longdouble
assert np.add(np.float16(0), np.complex64(0)).dtype == np.complex64
assert np.add(np.float16(0), np.complex128(0)).dtype == np.complex128
+ assert np.add(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
+ assert np.subtract(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
+ assert np.divide(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
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
@@ -20,7 +20,7 @@
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 import boxes, support
from pypy.module.micronumpy.concrete import SliceArray, VoidBoxStorage, V_OBJECTSTORE
from pypy.module.micronumpy.strides import calc_strides
from . import constants as NPY
@@ -2265,10 +2265,12 @@
def _coerce(self, space, arr, ofs, dtype, w_items, shape):
# TODO: Make sure the shape and the array match
from pypy.module.micronumpy.descriptor import W_Dtype
- if w_items is not None:
+ if w_items is None:
+ items_w = [None] * shape[0]
+ elif support.issequence_w(space, w_items):
items_w = space.fixedview(w_items)
else:
- items_w = [None] * shape[0]
+ items_w = [w_items] * shape[0]
subdtype = dtype.subdtype
assert isinstance(subdtype, W_Dtype)
itemtype = subdtype.itemtype
@@ -2363,8 +2365,16 @@
def coerce(self, space, dtype, w_item):
from pypy.module.micronumpy.base import W_NDimArray
if isinstance(w_item, boxes.W_VoidBox):
- return w_item
- if w_item is not None:
+ if dtype == w_item.dtype:
+ return w_item
+ else:
+ # match up the field names
+ items_w = [None] * len(dtype.fields)
+ for i in range(len(dtype.fields)):
+ name = dtype.names[i]
+ if name in w_item.dtype.names:
+ items_w[i] = w_item.descr_getitem(space, space.wrap(name))
+ elif w_item is not None:
if space.isinstance_w(w_item, space.w_tuple):
if len(dtype.fields) != space.len_w(w_item):
raise OperationError(space.w_ValueError, space.wrap(
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
@@ -21,7 +21,8 @@
from pypy.module.micronumpy.support import (_parse_signature, product,
get_storage_as_int, is_rhs_priority_higher)
from .casting import (
- can_cast_type, can_cast_to, find_result_type, promote_types)
+ can_cast_type, can_cast_array, can_cast_to,
+ find_result_type, promote_types)
from .boxes import W_GenericBox, W_ObjectBox
def done_if_true(dtype, val):
@@ -474,7 +475,8 @@
if out is None:
if w_res.is_scalar():
return w_res.get_scalar_value()
- w_res = space.call_method(w_obj, '__array_wrap__', w_res)
+ ctxt = space.newtuple([self, space.newtuple([w_obj]), space.wrap(0)])
+ w_res = space.call_method(w_obj, '__array_wrap__', w_res, ctxt)
return w_res
def call_scalar(self, space, w_arg, in_dtype):
@@ -494,17 +496,12 @@
return dt_in, dt_out, self.func
def _calc_dtype(self, space, arg_dtype, out=None, casting='unsafe'):
- use_min_scalar = False
if arg_dtype.is_object():
return arg_dtype, arg_dtype
in_casting = safe_casting_mode(casting)
for dt_in, dt_out in self.dtypes:
- if use_min_scalar:
- if not can_cast_array(space, w_arg, dt_in, in_casting):
- continue
- else:
- if not can_cast_type(space, arg_dtype, dt_in, in_casting):
- continue
+ if not can_cast_type(space, arg_dtype, dt_in, in_casting):
+ continue
if out is not None:
res_dtype = out.get_dtype()
if not can_cast_type(space, dt_out, res_dtype, casting):
@@ -604,21 +601,18 @@
w_rdtype.get_name(), w_ldtype.get_name(),
self.name)
- if self.are_common_types(w_ldtype, w_rdtype):
- if not w_lhs.is_scalar() and w_rhs.is_scalar():
- w_rdtype = w_ldtype
- elif w_lhs.is_scalar() and not w_rhs.is_scalar():
- w_ldtype = w_rdtype
- calc_dtype, dt_out, func = self.find_specialization(space, w_ldtype, w_rdtype, out, casting)
if (isinstance(w_lhs, W_GenericBox) and
isinstance(w_rhs, W_GenericBox) and out is None):
- return self.call_scalar(space, w_lhs, w_rhs, calc_dtype)
+ return self.call_scalar(space, w_lhs, w_rhs, casting)
if isinstance(w_lhs, W_GenericBox):
w_lhs = W_NDimArray.from_scalar(space, w_lhs)
assert isinstance(w_lhs, W_NDimArray)
if isinstance(w_rhs, W_GenericBox):
w_rhs = W_NDimArray.from_scalar(space, w_rhs)
assert isinstance(w_rhs, W_NDimArray)
+ calc_dtype, dt_out, func = self.find_specialization(
+ space, w_ldtype, w_rdtype, out, casting, w_lhs, w_rhs)
+
new_shape = shape_agreement(space, w_lhs.get_shape(), w_rhs)
new_shape = shape_agreement(space, new_shape, out, broadcast_down=False)
w_highpriority, out_subtype = array_priority(space, w_lhs, w_rhs)
@@ -632,10 +626,14 @@
if out is None:
if w_res.is_scalar():
return w_res.get_scalar_value()
- w_res = space.call_method(w_highpriority, '__array_wrap__', w_res)
+ ctxt = space.newtuple([self, space.newtuple([w_lhs, w_rhs]), space.wrap(0)])
+ w_res = space.call_method(w_highpriority, '__array_wrap__', w_res, ctxt)
return w_res
- def call_scalar(self, space, w_lhs, w_rhs, in_dtype):
+ def call_scalar(self, space, w_lhs, w_rhs, casting):
+ in_dtype, out_dtype, func = self.find_specialization(
+ space, w_lhs.get_dtype(space), w_rhs.get_dtype(space),
+ out=None, casting=casting)
w_val = self.func(in_dtype,
w_lhs.convert_to(space, in_dtype),
w_rhs.convert_to(space, in_dtype))
@@ -643,7 +641,8 @@
return w_val.w_obj
return w_val
- def _find_specialization(self, space, l_dtype, r_dtype, out, casting):
+ def _find_specialization(self, space, l_dtype, r_dtype, out, casting,
+ w_arg1, w_arg2):
if (not self.allow_bool and (l_dtype.is_bool() or
r_dtype.is_bool()) or
not self.allow_complex and (l_dtype.is_complex() or
@@ -655,15 +654,23 @@
dtype = find_result_type(space, [], [l_dtype, r_dtype])
bool_dtype = get_dtype_cache(space).w_booldtype
return dtype, bool_dtype, self.func
- dt_in, dt_out = self._calc_dtype(space, l_dtype, r_dtype, out, casting)
+ dt_in, dt_out = self._calc_dtype(
+ space, l_dtype, r_dtype, out, casting, w_arg1, w_arg2)
return dt_in, dt_out, self.func
- def find_specialization(self, space, l_dtype, r_dtype, out, casting):
+ def find_specialization(self, space, l_dtype, r_dtype, out, casting,
+ w_arg1=None, w_arg2=None):
if self.simple_binary:
if out is None and not (l_dtype.is_object() or r_dtype.is_object()):
- dtype = promote_types(space, l_dtype, r_dtype)
+ if w_arg1 is not None and w_arg2 is not None:
+ w_arg1 = convert_to_array(space, w_arg1)
+ w_arg2 = convert_to_array(space, w_arg2)
+ dtype = find_result_type(space, [w_arg1, w_arg2], [])
+ else:
+ dtype = promote_types(space, l_dtype, r_dtype)
return dtype, dtype, self.func
- return self._find_specialization(space, l_dtype, r_dtype, out, casting)
+ return self._find_specialization(
+ space, l_dtype, r_dtype, out, casting, w_arg1, w_arg2)
def find_binop_type(self, space, dtype):
"""Find a valid dtype signature of the form xx->x"""
@@ -684,15 +691,21 @@
"requested type has type code '%s'" % (self.name, dtype.char))
- def _calc_dtype(self, space, l_dtype, r_dtype, out=None, casting='unsafe'):
- use_min_scalar = False
+ def _calc_dtype(self, space, l_dtype, r_dtype, out, casting,
+ w_arg1, w_arg2):
if l_dtype.is_object() or r_dtype.is_object():
dtype = get_dtype_cache(space).w_objectdtype
return dtype, dtype
+ use_min_scalar = (w_arg1 is not None and w_arg2 is not None and
+ ((w_arg1.is_scalar() and not w_arg2.is_scalar()) or
+ (not w_arg1.is_scalar() and w_arg2.is_scalar())))
in_casting = safe_casting_mode(casting)
for dt_in, dt_out in self.dtypes:
if use_min_scalar:
- if not can_cast_array(space, w_arg, dt_in, in_casting):
+ w_arg1 = convert_to_array(space, w_arg1)
+ w_arg2 = convert_to_array(space, w_arg2)
+ if not (can_cast_array(space, w_arg1, dt_in, in_casting) and
+ can_cast_array(space, w_arg2, dt_in, in_casting)):
continue
else:
if not (can_cast_type(space, l_dtype, dt_in, in_casting) and
More information about the pypy-commit
mailing list