[pypy-commit] pypy can_cast: Create pypy.module.micronumpy.casting
rlamy
noreply at buildbot.pypy.org
Fri May 1 20:05:19 CEST 2015
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: can_cast
Changeset: r76971:c9fbdb4fd4eb
Date: 2015-05-01 19:05 +0100
http://bitbucket.org/pypy/pypy/changeset/c9fbdb4fd4eb/
Log: Create pypy.module.micronumpy.casting
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
@@ -20,9 +20,9 @@
'concatenate': 'arrayops.concatenate',
'count_nonzero': 'arrayops.count_nonzero',
'dot': 'arrayops.dot',
- 'result_type': 'arrayops.result_type',
- 'can_cast': 'arrayops.can_cast',
'where': 'arrayops.where',
+ 'result_type': 'casting.result_type',
+ 'can_cast': 'casting.can_cast',
'set_string_function': 'appbridge.set_string_function',
'typeinfo': 'descriptor.get_dtype_cache(space).w_typeinfo',
diff --git a/pypy/module/micronumpy/arrayops.py b/pypy/module/micronumpy/arrayops.py
--- a/pypy/module/micronumpy/arrayops.py
+++ b/pypy/module/micronumpy/arrayops.py
@@ -1,4 +1,3 @@
-from rpython.rlib import jit
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import unwrap_spec
from pypy.module.micronumpy import loop, descriptor, ufuncs, support, \
@@ -7,10 +6,6 @@
from pypy.module.micronumpy.converters import clipmode_converter
from pypy.module.micronumpy.strides import (
Chunk, Chunks, shape_agreement, shape_agreement_multiple)
-from .boxes import W_GenericBox
-from .types import (
- Bool, ULong, Long, Float64, Complex64, UnicodeType, VoidType, ObjectType)
-from .descriptor import get_dtype_cache
def where(space, w_arr, w_x=None, w_y=None):
@@ -288,105 +283,3 @@
else:
loop.diagonal_array(space, arr, out, offset, axis1, axis2, shape)
return out
-
-
- at jit.unroll_safe
-def result_type(space, __args__):
- args_w, kw_w = __args__.unpack()
- if kw_w:
- raise oefmt(space.w_TypeError, "result_type() takes no keyword arguments")
- if not args_w:
- raise oefmt(space.w_ValueError, "at least one array or dtype is required")
- result = None
- for w_arg in args_w:
- dtype = as_dtype(space, w_arg)
- result = ufuncs.find_binop_result_dtype(space, result, dtype)
- return result
-
- at unwrap_spec(casting=str)
-def can_cast(space, w_from, w_totype, casting='safe'):
- try:
- target = as_dtype(space, w_totype, allow_None=False)
- except TypeError:
- raise oefmt(space.w_TypeError,
- "did not understand one of the types; 'None' not accepted")
- if isinstance(w_from, W_NDimArray):
- return space.wrap(can_cast_array(space, w_from, target, casting))
- elif is_scalar_w(space, w_from):
- w_scalar = as_scalar(space, w_from)
- w_arr = W_NDimArray.from_scalar(space, w_scalar)
- return space.wrap(can_cast_array(space, w_arr, target, casting))
-
- try:
- origin = as_dtype(space, w_from, allow_None=False)
- except TypeError:
- raise oefmt(space.w_TypeError,
- "did not understand one of the types; 'None' not accepted")
- return space.wrap(can_cast_type(space, origin, target, casting))
-
-kind_ordering = {
- Bool.kind: 0, ULong.kind: 1, Long.kind: 2,
- Float64.kind: 4, Complex64.kind: 5,
- NPY.STRINGLTR: 6, NPY.STRINGLTR2: 6,
- UnicodeType.kind: 7, VoidType.kind: 8, ObjectType.kind: 9}
-
-def can_cast_type(space, origin, target, casting):
- if casting == 'no':
- return origin.eq(space, target)
- elif casting == 'equiv':
- return origin.num == target.num and origin.elsize == target.elsize
- elif casting == 'unsafe':
- return True
- elif casting == 'same_kind':
- if origin.can_cast_to(target):
- return True
- if origin.kind in kind_ordering and target.kind in kind_ordering:
- return kind_ordering[origin.kind] <= kind_ordering[target.kind]
- return False
- else:
- return origin.can_cast_to(target)
-
-def can_cast_array(space, w_from, target, casting):
- origin = w_from.get_dtype()
- if w_from.is_scalar():
- return can_cast_scalar(
- space, origin, w_from.get_scalar_value(), target, casting)
- else:
- return can_cast_type(space, origin, target, casting)
-
-def can_cast_scalar(space, from_type, value, target, casting):
- if from_type == target or casting == 'unsafe':
- return True
- if not from_type.is_number() or casting in ('no', 'equiv'):
- return can_cast_type(space, from_type, target, casting)
- if not from_type.is_native():
- value = value.descr_byteswap(space)
- dtypenum, altnum = value.min_dtype()
- if target.is_unsigned():
- dtypenum = altnum
- dtype = get_dtype_cache(space).dtypes_by_num[dtypenum]
- return can_cast_type(space, dtype, target, casting) # XXX: stub impl
-
-def is_scalar_w(space, w_arg):
- return (isinstance(w_arg, W_GenericBox) or
- space.isinstance_w(w_arg, space.w_int) or
- space.isinstance_w(w_arg, space.w_float) or
- space.isinstance_w(w_arg, space.w_complex) or
- space.isinstance_w(w_arg, space.w_long) or
- space.isinstance_w(w_arg, space.w_bool))
-
-def as_dtype(space, w_arg, allow_None=True):
- # roughly equivalent to CNumPy's PyArray_DescrConverter2
- if not allow_None and space.is_none(w_arg):
- raise TypeError("Cannot create dtype from None here")
- if isinstance(w_arg, W_NDimArray):
- return w_arg.get_dtype()
- elif is_scalar_w(space, w_arg):
- return ufuncs.find_dtype_for_scalar(space, w_arg)
- else:
- return space.interp_w(descriptor.W_Dtype,
- space.call_function(space.gettypefor(descriptor.W_Dtype), w_arg))
-
-def as_scalar(space, w_obj):
- dtype = ufuncs.find_dtype_for_scalar(space, w_obj)
- return dtype.coerce(space, w_obj)
diff --git a/pypy/module/micronumpy/casting.py b/pypy/module/micronumpy/casting.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/casting.py
@@ -0,0 +1,117 @@
+"""Functions and helpers for converting between dtypes"""
+
+from rpython.rlib import jit
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.error import oefmt
+
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy import constants as NPY
+from pypy.module.micronumpy.ufuncs import (
+ find_binop_result_dtype, find_dtype_for_scalar)
+from .boxes import W_GenericBox
+from .types import (
+ Bool, ULong, Long, Float64, Complex64, UnicodeType, VoidType, ObjectType)
+from .descriptor import get_dtype_cache, W_Dtype
+
+ at jit.unroll_safe
+def result_type(space, __args__):
+ args_w, kw_w = __args__.unpack()
+ if kw_w:
+ raise oefmt(space.w_TypeError,
+ "result_type() takes no keyword arguments")
+ if not args_w:
+ raise oefmt(space.w_ValueError,
+ "at least one array or dtype is required")
+ result = None
+ for w_arg in args_w:
+ dtype = as_dtype(space, w_arg)
+ result = find_binop_result_dtype(space, result, dtype)
+ return result
+
+ at unwrap_spec(casting=str)
+def can_cast(space, w_from, w_totype, casting='safe'):
+ try:
+ target = as_dtype(space, w_totype, allow_None=False)
+ except TypeError:
+ raise oefmt(space.w_TypeError,
+ "did not understand one of the types; 'None' not accepted")
+ if isinstance(w_from, W_NDimArray):
+ return space.wrap(can_cast_array(space, w_from, target, casting))
+ elif is_scalar_w(space, w_from):
+ w_scalar = as_scalar(space, w_from)
+ w_arr = W_NDimArray.from_scalar(space, w_scalar)
+ return space.wrap(can_cast_array(space, w_arr, target, casting))
+
+ try:
+ origin = as_dtype(space, w_from, allow_None=False)
+ except TypeError:
+ raise oefmt(space.w_TypeError,
+ "did not understand one of the types; 'None' not accepted")
+ return space.wrap(can_cast_type(space, origin, target, casting))
+
+kind_ordering = {
+ Bool.kind: 0, ULong.kind: 1, Long.kind: 2,
+ Float64.kind: 4, Complex64.kind: 5,
+ NPY.STRINGLTR: 6, NPY.STRINGLTR2: 6,
+ UnicodeType.kind: 7, VoidType.kind: 8, ObjectType.kind: 9}
+
+def can_cast_type(space, origin, target, casting):
+ if casting == 'no':
+ return origin.eq(space, target)
+ elif casting == 'equiv':
+ return origin.num == target.num and origin.elsize == target.elsize
+ elif casting == 'unsafe':
+ return True
+ elif casting == 'same_kind':
+ if origin.can_cast_to(target):
+ return True
+ if origin.kind in kind_ordering and target.kind in kind_ordering:
+ return kind_ordering[origin.kind] <= kind_ordering[target.kind]
+ return False
+ else:
+ return origin.can_cast_to(target)
+
+def can_cast_array(space, w_from, target, casting):
+ origin = w_from.get_dtype()
+ if w_from.is_scalar():
+ return can_cast_scalar(
+ space, origin, w_from.get_scalar_value(), target, casting)
+ else:
+ return can_cast_type(space, origin, target, casting)
+
+def can_cast_scalar(space, from_type, value, target, casting):
+ if from_type == target or casting == 'unsafe':
+ return True
+ if not from_type.is_number() or casting in ('no', 'equiv'):
+ return can_cast_type(space, from_type, target, casting)
+ if not from_type.is_native():
+ value = value.descr_byteswap(space)
+ dtypenum, altnum = value.min_dtype()
+ if target.is_unsigned():
+ dtypenum = altnum
+ dtype = get_dtype_cache(space).dtypes_by_num[dtypenum]
+ return can_cast_type(space, dtype, target, casting) # XXX: stub impl
+
+def is_scalar_w(space, w_arg):
+ return (isinstance(w_arg, W_GenericBox) or
+ space.isinstance_w(w_arg, space.w_int) or
+ space.isinstance_w(w_arg, space.w_float) or
+ space.isinstance_w(w_arg, space.w_complex) or
+ space.isinstance_w(w_arg, space.w_long) or
+ space.isinstance_w(w_arg, space.w_bool))
+
+def as_dtype(space, w_arg, allow_None=True):
+ # roughly equivalent to CNumPy's PyArray_DescrConverter2
+ if not allow_None and space.is_none(w_arg):
+ raise TypeError("Cannot create dtype from None here")
+ if isinstance(w_arg, W_NDimArray):
+ return w_arg.get_dtype()
+ elif is_scalar_w(space, w_arg):
+ return find_dtype_for_scalar(space, w_arg)
+ else:
+ return space.interp_w(W_Dtype,
+ space.call_function(space.gettypefor(W_Dtype), w_arg))
+
+def as_scalar(space, w_obj):
+ dtype = find_dtype_for_scalar(space, w_obj)
+ return dtype.coerce(space, w_obj)
diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py
--- a/pypy/module/micronumpy/test/test_arrayops.py
+++ b/pypy/module/micronumpy/test/test_arrayops.py
@@ -199,19 +199,3 @@
a.put(23, -1, mode=1) # wrap
assert (a == array([0, 1, -10, -1, -15])).all()
raises(TypeError, "arange(5).put(22, -5, mode='zzzz')") # unrecognized mode
-
- def test_result_type(self):
- import numpy as np
- exc = raises(ValueError, np.result_type)
- assert str(exc.value) == "at least one array or dtype is required"
- exc = raises(TypeError, np.result_type, a=2)
- assert str(exc.value) == "result_type() takes no keyword arguments"
- assert np.result_type(True) is np.dtype('bool')
- assert np.result_type(1) is np.dtype('int')
- assert np.result_type(1.) is np.dtype('float64')
- assert np.result_type(1+2j) is np.dtype('complex128')
- assert np.result_type(1, 1.) is np.dtype('float64')
- assert np.result_type(np.array([1, 2])) is np.dtype('int')
- assert np.result_type(np.array([1, 2]), 1, 1+2j) is np.dtype('complex128')
- assert np.result_type(np.array([1, 2]), 1, 'float64') is np.dtype('float64')
- assert np.result_type(np.array([1, 2]), 1, None) is np.dtype('float64')
diff --git a/pypy/module/micronumpy/test/test_casting.py b/pypy/module/micronumpy/test/test_casting.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_casting.py
@@ -0,0 +1,114 @@
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestNumSupport(BaseNumpyAppTest):
+ def test_result_type(self):
+ import numpy as np
+ exc = raises(ValueError, np.result_type)
+ assert str(exc.value) == "at least one array or dtype is required"
+ exc = raises(TypeError, np.result_type, a=2)
+ assert str(exc.value) == "result_type() takes no keyword arguments"
+ assert np.result_type(True) is np.dtype('bool')
+ assert np.result_type(1) is np.dtype('int')
+ assert np.result_type(1.) is np.dtype('float64')
+ assert np.result_type(1+2j) is np.dtype('complex128')
+ assert np.result_type(1, 1.) is np.dtype('float64')
+ assert np.result_type(np.array([1, 2])) is np.dtype('int')
+ assert np.result_type(np.array([1, 2]), 1, 1+2j) is np.dtype('complex128')
+ assert np.result_type(np.array([1, 2]), 1, 'float64') is np.dtype('float64')
+ assert np.result_type(np.array([1, 2]), 1, None) is np.dtype('float64')
+
+ def test_can_cast(self):
+ import numpy as np
+
+ assert np.can_cast(np.int32, np.int64)
+ assert np.can_cast(np.float64, complex)
+ assert not np.can_cast(np.complex64, float)
+
+ assert np.can_cast('i8', 'f8')
+ assert not np.can_cast('i8', 'f4')
+ assert np.can_cast('i4', 'S11')
+
+ assert np.can_cast('i8', 'i8', 'no')
+ assert not np.can_cast('<i8', '>i8', 'no')
+
+ assert np.can_cast('<i8', '>i8', 'equiv')
+ assert not np.can_cast('<i4', '>i8', 'equiv')
+
+ assert np.can_cast('<i4', '>i8', 'safe')
+ assert not np.can_cast('<i8', '>i4', 'safe')
+
+ assert np.can_cast('<i8', '>i4', 'same_kind')
+ assert not np.can_cast('<i8', '>u4', 'same_kind')
+
+ assert np.can_cast('<i8', '>u4', 'unsafe')
+
+ assert np.can_cast('bool', 'S5')
+ assert not np.can_cast('bool', 'S4')
+
+ assert np.can_cast('b', 'S4')
+ assert not np.can_cast('b', 'S3')
+
+ assert np.can_cast('u1', 'S3')
+ assert not np.can_cast('u1', 'S2')
+ assert np.can_cast('u2', 'S5')
+ assert not np.can_cast('u2', 'S4')
+ assert np.can_cast('u4', 'S10')
+ assert not np.can_cast('u4', 'S9')
+ assert np.can_cast('u8', 'S20')
+ assert not np.can_cast('u8', 'S19')
+
+ assert np.can_cast('i1', 'S4')
+ assert not np.can_cast('i1', 'S3')
+ assert np.can_cast('i2', 'S6')
+ assert not np.can_cast('i2', 'S5')
+ assert np.can_cast('i4', 'S11')
+ assert not np.can_cast('i4', 'S10')
+ assert np.can_cast('i8', 'S21')
+ assert not np.can_cast('i8', 'S20')
+
+ assert np.can_cast('bool', 'S5')
+ assert not np.can_cast('bool', 'S4')
+
+ assert np.can_cast('b', 'U4')
+ assert not np.can_cast('b', 'U3')
+
+ assert np.can_cast('u1', 'U3')
+ assert not np.can_cast('u1', 'U2')
+ assert np.can_cast('u2', 'U5')
+ assert not np.can_cast('u2', 'U4')
+ assert np.can_cast('u4', 'U10')
+ assert not np.can_cast('u4', 'U9')
+ assert np.can_cast('u8', 'U20')
+ assert not np.can_cast('u8', 'U19')
+
+ assert np.can_cast('i1', 'U4')
+ assert not np.can_cast('i1', 'U3')
+ assert np.can_cast('i2', 'U6')
+ assert not np.can_cast('i2', 'U5')
+ assert np.can_cast('i4', 'U11')
+ assert not np.can_cast('i4', 'U10')
+ assert np.can_cast('i8', 'U21')
+ assert not np.can_cast('i8', 'U20')
+
+ raises(TypeError, np.can_cast, 'i4', None)
+ raises(TypeError, np.can_cast, None, 'i4')
+
+ def test_can_cast_scalar(self):
+ import numpy as np
+ assert np.can_cast(True, np.bool_)
+ assert np.can_cast(True, np.int8)
+ assert not np.can_cast(0, np.bool_)
+ assert np.can_cast(127, np.int8)
+ assert not np.can_cast(128, np.int8)
+ assert np.can_cast(128, np.int16)
+
+ assert np.can_cast(np.float32('inf'), np.float32)
+ assert np.can_cast(float('inf'), np.float32) # XXX: False in CNumPy?!
+ assert np.can_cast(3.3e38, np.float32)
+ assert not np.can_cast(3.4e38, np.float32)
+
+ assert np.can_cast(1 + 2j, np.complex64)
+ assert not np.can_cast(1 + 1e50j, np.complex64)
+ assert np.can_cast(1., np.complex64)
+ assert not np.can_cast(1e50, np.complex64)
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
@@ -3971,98 +3971,3 @@
a = ndarray._from_shape_and_storage((2,), addr, int, sz,
strides=[2 * base.strides[0]])
assert a[1] == 3
-
- def test_can_cast(self):
- import numpy as np
-
- assert np.can_cast(np.int32, np.int64)
- assert np.can_cast(np.float64, complex)
- assert not np.can_cast(np.complex64, float)
-
- assert np.can_cast('i8', 'f8')
- assert not np.can_cast('i8', 'f4')
- assert np.can_cast('i4', 'S11')
-
- assert np.can_cast('i8', 'i8', 'no')
- assert not np.can_cast('<i8', '>i8', 'no')
-
- assert np.can_cast('<i8', '>i8', 'equiv')
- assert not np.can_cast('<i4', '>i8', 'equiv')
-
- assert np.can_cast('<i4', '>i8', 'safe')
- assert not np.can_cast('<i8', '>i4', 'safe')
-
- assert np.can_cast('<i8', '>i4', 'same_kind')
- assert not np.can_cast('<i8', '>u4', 'same_kind')
-
- assert np.can_cast('<i8', '>u4', 'unsafe')
-
- assert np.can_cast('bool', 'S5')
- assert not np.can_cast('bool', 'S4')
-
- assert np.can_cast('b', 'S4')
- assert not np.can_cast('b', 'S3')
-
- assert np.can_cast('u1', 'S3')
- assert not np.can_cast('u1', 'S2')
- assert np.can_cast('u2', 'S5')
- assert not np.can_cast('u2', 'S4')
- assert np.can_cast('u4', 'S10')
- assert not np.can_cast('u4', 'S9')
- assert np.can_cast('u8', 'S20')
- assert not np.can_cast('u8', 'S19')
-
- assert np.can_cast('i1', 'S4')
- assert not np.can_cast('i1', 'S3')
- assert np.can_cast('i2', 'S6')
- assert not np.can_cast('i2', 'S5')
- assert np.can_cast('i4', 'S11')
- assert not np.can_cast('i4', 'S10')
- assert np.can_cast('i8', 'S21')
- assert not np.can_cast('i8', 'S20')
-
- assert np.can_cast('bool', 'S5')
- assert not np.can_cast('bool', 'S4')
-
- assert np.can_cast('b', 'U4')
- assert not np.can_cast('b', 'U3')
-
- assert np.can_cast('u1', 'U3')
- assert not np.can_cast('u1', 'U2')
- assert np.can_cast('u2', 'U5')
- assert not np.can_cast('u2', 'U4')
- assert np.can_cast('u4', 'U10')
- assert not np.can_cast('u4', 'U9')
- assert np.can_cast('u8', 'U20')
- assert not np.can_cast('u8', 'U19')
-
- assert np.can_cast('i1', 'U4')
- assert not np.can_cast('i1', 'U3')
- assert np.can_cast('i2', 'U6')
- assert not np.can_cast('i2', 'U5')
- assert np.can_cast('i4', 'U11')
- assert not np.can_cast('i4', 'U10')
- assert np.can_cast('i8', 'U21')
- assert not np.can_cast('i8', 'U20')
-
- raises(TypeError, np.can_cast, 'i4', None)
- raises(TypeError, np.can_cast, None, 'i4')
-
- def test_can_cast_scalar(self):
- import numpy as np
- assert np.can_cast(True, np.bool_)
- assert np.can_cast(True, np.int8)
- assert not np.can_cast(0, np.bool_)
- assert np.can_cast(127, np.int8)
- assert not np.can_cast(128, np.int8)
- assert np.can_cast(128, np.int16)
-
- assert np.can_cast(np.float32('inf'), np.float32)
- assert np.can_cast(float('inf'), np.float32) # XXX: False in CNumPy?!
- assert np.can_cast(3.3e38, np.float32)
- assert not np.can_cast(3.4e38, np.float32)
-
- assert np.can_cast(1 + 2j, np.complex64)
- assert not np.can_cast(1 + 1e50j, np.complex64)
- assert np.can_cast(1., np.complex64)
- assert not np.can_cast(1e50, np.complex64)
More information about the pypy-commit
mailing list