def test_sentry_safe_cast_no_warn(self): ok_cases = [] ok_cases += [ # integer cases (types.int32, types.int64), (types.uint8, types.int32), # float cases (types.float32, types.float64), # complex cases (types.complex64, types.complex128), # int to float cases (types.int32, types.float64), (types.uint8, types.float32), # float to complex cases (types.float32, types.complex128), (types.float64, types.complex128), # tuple-of-ints to tuple-of-ints, (types.Tuple([types.int32]), types.Tuple([types.int64])), ] for fromty, toty in ok_cases: with self.subTest(fromty=fromty, toty=toty): with warnings.catch_warnings(record=True) as w: _sentry_safe_cast(fromty, toty) # Expect no warnings self.assertEqual(len(w), 0)
def test_tuple(self): # UniTuple -> UniTuple aty = types.UniTuple(i32, 3) bty = types.UniTuple(i64, 3) self.assert_can_convert(aty, aty, Conversion.exact) self.assert_can_convert(aty, bty, Conversion.promote) aty = types.UniTuple(i32, 3) bty = types.UniTuple(f64, 3) self.assert_can_convert(aty, bty, Conversion.safe) # Tuple -> Tuple aty = types.Tuple((i32, i32)) bty = types.Tuple((i32, i64)) self.assert_can_convert(aty, bty, Conversion.promote) # UniTuple <-> Tuple aty = types.UniTuple(i32, 2) bty = types.Tuple((i32, i64)) self.assert_can_convert(aty, bty, Conversion.promote) self.assert_can_convert(bty, aty, Conversion.unsafe) # Empty tuples aty = types.UniTuple(i64, 0) bty = types.UniTuple(i32, 0) cty = types.Tuple(()) self.assert_can_convert(aty, bty, Conversion.safe) self.assert_can_convert(bty, aty, Conversion.safe) self.assert_can_convert(aty, cty, Conversion.safe) self.assert_can_convert(cty, aty, Conversion.safe) # Failures aty = types.UniTuple(i64, 3) bty = types.UniTuple(types.none, 3) self.assert_cannot_convert(aty, bty) aty = types.UniTuple(i64, 2) bty = types.UniTuple(i64, 3)
def _str_items_mixed_values_to_tuple(tyctx, d): keys = [x for x in d.literal_value.keys()] literal_tys = [x for x in d.literal_value.values()] def impl(cgctx, builder, sig, args): lld, = args impl = cgctx.get_function('static_getitem', types.none(d, types.literal('dummy'))) items = [] for k in range(len(keys)): item = impl( builder, (lld, k), ) casted = cgctx.cast(builder, item, literal_tys[k], d.types[k]) cgctx.nrt.incref(builder, d.types[k], item) keydata = make_string_from_constant(cgctx, builder, types.unicode_type, keys[k].literal_value) pair = cgctx.make_tuple( builder, types.Tuple([types.unicode_type, d.types[k]]), (keydata, casted)) items.append(pair) ret = cgctx.make_tuple(builder, sig.return_type, items) return ret kvs = [types.Tuple((types.unicode_type, x)) for x in d.types] sig = types.Tuple(kvs)(d) return sig, impl
def _test_compare(self, pyfunc): def eq(pyfunc, cfunc, args): self.assertIs(cfunc(*args), pyfunc(*args), "mismatch for arguments %s" % (args, )) # Same-sized tuples argtypes = [ types.Tuple((types.int64, types.float32)), types.UniTuple(types.int32, 2) ] for ta, tb in itertools.product(argtypes, argtypes): cr = compile_isolated(pyfunc, (ta, tb)) cfunc = cr.entry_point for args in [((4, 5), (4, 5)), ((4, 5), (4, 6)), ((4, 6), (4, 5)), ((4, 5), (5, 4))]: eq(pyfunc, cfunc, args) # Different-sized tuples argtypes = [ types.Tuple((types.int64, types.float32)), types.UniTuple(types.int32, 3) ] cr = compile_isolated(pyfunc, tuple(argtypes)) cfunc = cr.entry_point for args in [((4, 5), (4, 5, 6)), ((4, 5), (4, 4, 6)), ((4, 5), (4, 6, 7))]: eq(pyfunc, cfunc, args)
def test_sentry_safe_cast_warnings(self): warn_cases = [] warn_cases += [ # integer cases (types.int32, types.int16), (types.int32, types.uint32), (types.int64, types.uint32), # float cases (types.float64, types.float32), # complex cases (types.complex128, types.complex64), # int to float cases (types.int32, types.float32), (types.int64, types.float32), # tuple-of-ints to tuple-of-floats, (types.Tuple([types.int32]), types.Tuple([types.float32])), ] for fromty, toty in warn_cases: with self.subTest(fromty=fromty, toty=toty): with warnings.catch_warnings(record=True) as w: _sentry_safe_cast(fromty, toty) self.assertEqual(len(w), 1) # Make sure the warning is about unsafe cast self.assertIn( "unsafe cast from {} to {}".format(fromty, toty), str(w[0]), )
def test_tuples(self): v = (1, 2) self.assertEqual(typeof(v), types.UniTuple(types.intp, 2)) v = (1, (2.0, 3)) self.assertEqual( typeof(v), types.Tuple((types.intp, types.Tuple( (types.float64, types.intp)))))
class Cuda_shfl_sync_intrinsic(ConcreteTemplate): key = cuda.shfl_sync_intrinsic cases = [ signature(types.Tuple((types.i4, types.b1)), types.i4, types.i4, types.i4, types.i4, types.i4), signature(types.Tuple((types.i8, types.b1)), types.i4, types.i4, types.i8, types.i4, types.i4), signature(types.Tuple((types.f4, types.b1)), types.i4, types.i4, types.f4, types.i4, types.i4), signature(types.Tuple((types.f8, types.b1)), types.i4, types.i4, types.f8, types.i4, types.i4), ]
class Cuda_match_all_sync(ConcreteTemplate): key = cuda.match_all_sync cases = [ signature(types.Tuple((types.i4, types.b1)), types.i4, types.i4), signature(types.Tuple((types.i4, types.b1)), types.i4, types.i8), signature(types.Tuple((types.i4, types.b1)), types.i4, types.f4), signature(types.Tuple((types.i4, types.b1)), types.i4, types.f8), ]
def impl(typingctx, l_ty, index_ty): is_none = isinstance(l_ty.item_type, types.NoneType) if is_none: resty = types.Tuple([types.int32, l_ty.item_type]) else: resty = types.Tuple([types.int32, types.Optional(l_ty.item_type)]) sig = resty(l_ty, index_ty) def codegen(context, builder, sig, args): [tl, tindex] = sig.args [l, index] = args fnty = ir.FunctionType( ll_voidptr_type, [ll_list_type], ) fname = 'numba_list_base_ptr' fn = builder.module.get_or_insert_function(fnty, fname) fn.attributes.add('alwaysinline') fn.attributes.add('nounwind') fn.attributes.add('readonly') lp = _container_get_data(context, builder, tl, l) base_ptr = builder.call( fn, [ lp, ], ) llty = context.get_data_type(tl.item_type) casted_base_ptr = builder.bitcast(base_ptr, llty.as_pointer()) item_ptr = cgutils.gep(builder, casted_base_ptr, index) if is_none: out = builder.load(item_ptr) else: out = context.make_optional_none(builder, tl.item_type) pout = cgutils.alloca_once_value(builder, out) dm_item = context.data_model_manager[tl.item_type] item = dm_item.load_from_data_pointer(builder, item_ptr) if not borrowed: context.nrt.incref(builder, tl.item_type, item) if is_none: loaded = item else: loaded = context.make_optional_value( builder, tl.item_type, item) builder.store(loaded, pout) out = builder.load(pout) return context.make_tuple(builder, resty, [ll_status(0), out]) return sig, codegen
def test_bool(self): pyfunc = bool_usecase cr = compile_isolated(pyfunc, [types.Tuple((types.int64, types.int32))]) args = ((4, 5), ) self.assertPreciseEqual(cr.entry_point(*args), pyfunc(*args)) cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 3)]) args = ((4, 5, 6), ) self.assertPreciseEqual(cr.entry_point(*args), pyfunc(*args)) cr = compile_isolated(pyfunc, [types.Tuple(())]) self.assertPreciseEqual(cr.entry_point(()), pyfunc(()))
def test_add(self): pyfunc = add_usecase samples = [(types.Tuple(()), ()), (types.UniTuple(types.int32, 0), ()), (types.UniTuple(types.int32, 1), (42,)), (types.Tuple((types.int64, types.float32)), (3, 4.5)), ] for (ta, a), (tb, b) in itertools.product(samples, samples): cr = compile_isolated(pyfunc, (ta, tb)) expected = pyfunc(a, b) got = cr.entry_point(a, b) self.assertPreciseEqual(got, expected, msg=(ta, tb))
def test_conversions(self): check = self.check_conversion fromty = types.UniTuple(types.int32, 2) check(fromty, types.UniTuple(types.float32, 2), (4, 5)) check(fromty, types.Tuple((types.float32, types.int16)), (4, 5)) aty = types.UniTuple(types.int32, 0) bty = types.Tuple(()) check(aty, bty, ()) check(bty, aty, ()) with self.assertRaises(errors.TypingError) as raises: check(fromty, types.Tuple((types.float32, )), (4, 5)) msg = "No conversion from UniTuple(int32 x 2) to UniTuple(float32 x 1)" self.assertIn(msg, str(raises.exception))
def _dict_popitem(typingctx, d): """Wrap numba_dict_popitem """ keyvalty = types.Tuple([d.key_type, d.value_type]) resty = types.Tuple([types.int32, types.Optional(keyvalty)]) sig = resty(d) def codegen(context, builder, sig, args): fnty = ir.FunctionType( ll_status, [ll_dict_type, ll_bytes, ll_bytes], ) [d] = args [td] = sig.args fn = builder.module.get_or_insert_function(fnty, name='numba_dict_popitem') dm_key = context.data_model_manager[td.key_type] dm_val = context.data_model_manager[td.value_type] ptr_key = cgutils.alloca_once(builder, dm_key.get_data_type()) ptr_val = cgutils.alloca_once(builder, dm_val.get_data_type()) dp = _container_get_data(context, builder, td, d) status = builder.call( fn, [ dp, _as_bytes(builder, ptr_key), _as_bytes(builder, ptr_val), ], ) out = context.make_optional_none(builder, keyvalty) pout = cgutils.alloca_once_value(builder, out) cond = builder.icmp_signed('==', status, status.type(int(Status.OK))) with builder.if_then(cond): key = dm_key.load_from_data_pointer(builder, ptr_key) val = dm_val.load_from_data_pointer(builder, ptr_val) keyval = context.make_tuple(builder, keyvalty, [key, val]) optkeyval = context.make_optional_value(builder, keyvalty, keyval) builder.store(optkeyval, pout) out = builder.load(pout) return cgutils.pack_struct(builder, [status, out]) return sig, codegen
def test_empty_tuples(self): # Empty tuple fe_args = [ types.UniTuple(types.int16, 0), types.Tuple(()), types.int32 ] self._test_as_arguments(fe_args)
def __init__(self, dmm, fe_type): array_types = fe_type.arrays ndim = fe_type.ndim shape_len = ndim if fe_type.need_shaped_indexing else 1 members = [ ('exhausted', types.EphemeralPointer(types.boolean)), ('arrays', types.Tuple(array_types)), # The iterator's main shape and indices ('shape', types.UniTuple(types.intp, shape_len)), ('indices', types.EphemeralArray(types.intp, shape_len)), ] # Indexing state for the various sub-iterators # XXX use a tuple instead? for i, sub in enumerate(fe_type.indexers): kind, start_dim, end_dim, _ = sub member_name = 'index%d' % i if kind == 'flat': # A single index into the flattened array members.append( (member_name, types.EphemeralPointer(types.intp))) elif kind in ('scalar', 'indexed', '0d'): # Nothing required pass else: assert 0 # Slots holding values of the scalar args # XXX use a tuple instead? for i, ty in enumerate(fe_type.arrays): if not isinstance(ty, types.Array): member_name = 'scalar%d' % i members.append((member_name, types.EphemeralPointer(ty))) super(NdIter, self).__init__(dmm, fe_type, members)
def test_tuple_types_exception(self): with self.assertRaises(errors.TypingError) as raises: types.Tuple((types.uint32)) self.assertIn( "Argument 'types' is not iterable", str(raises.exception) )
def test_len(self): pyfunc = len_usecase cr = compile_isolated(pyfunc, [types.Tuple((types.int64, types.float32))]) self.assertPreciseEqual(cr.entry_point((4, 5)), 2) cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 3)]) self.assertPreciseEqual(cr.entry_point((4, 5, 6)), 3)
def _list_getitem_pop_helper(typingctx, l, index, op): """Wrap numba_list_getitem and numba_list_pop Returns 2-tuple of (int32, ?item_type) This is a helper that is parametrized on the type of operation, which can be either 'pop' or 'getitem'. This is because, signature wise, getitem and pop and are the same. """ assert (op in ("pop", "getitem")) IS_NOT_NONE = not isinstance(l.item_type, types.NoneType) resty = types.Tuple([ types.int32, types.Optional(l.item_type if IS_NOT_NONE else types.int64) ]) sig = resty(l, index) def codegen(context, builder, sig, args): fnty = ir.FunctionType( ll_status, [ll_list_type, ll_ssize_t, ll_bytes], ) [tl, tindex] = sig.args [l, index] = args fn = builder.module.get_or_insert_function( fnty, name='numba_list_{}'.format(op)) dm_item = context.data_model_manager[tl.item_type] ll_item = context.get_data_type(tl.item_type) ptr_item = cgutils.alloca_once(builder, ll_item) lp = _container_get_data(context, builder, tl, l) status = builder.call( fn, [ lp, index, _as_bytes(builder, ptr_item), ], ) # Load item if output is available found = builder.icmp_signed('>=', status, status.type(int(ListStatus.LIST_OK))) out = context.make_optional_none( builder, tl.item_type if IS_NOT_NONE else types.int64) pout = cgutils.alloca_once_value(builder, out) with builder.if_then(found): if IS_NOT_NONE: item = dm_item.load_from_data_pointer(builder, ptr_item) context.nrt.incref(builder, tl.item_type, item) loaded = context.make_optional_value(builder, tl.item_type, item) builder.store(loaded, pout) out = builder.load(pout) return context.make_tuple(builder, resty, [status, out]) return sig, codegen
def check_slice(self, pyfunc): tup = (4, 5, 6, 7) cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 4)]) self.assertPreciseEqual(cr.entry_point(tup), pyfunc(tup)) cr = compile_isolated(pyfunc, [ types.Tuple((types.int64, types.int32, types.int64, types.int32)) ]) self.assertPreciseEqual(cr.entry_point(tup), pyfunc(tup))
def test_type_alias(self): Pair = py_typing.Tuple[int, int] ListOfPairs = py_typing.List[Pair] pair_nb_type = types.Tuple((self.int_nb_type, self.int_nb_type)) self.assertEqual(as_numba_type(Pair), pair_nb_type) self.assertEqual(as_numba_type(ListOfPairs), types.ListType(pair_nb_type))
def impl_frexp(ty, libfunc): retty = types.Tuple((ty, types.int32)) def lower_frexp_impl(context, builder, sig, args): frexp_sig = typing.signature(retty, ty) libfunc_impl = context.get_function(libfunc, frexp_sig) return libfunc_impl(builder, args) lower(math.frexp, ty)(lower_frexp_impl)
def _list_getitem(typingctx, l, index): """Wrap numba_list_getitem Returns 2-tuple of (int32, ?item_type) """ IS_NOT_NONE = not isinstance(l.item_type, types.NoneType) resty = types.Tuple([types.int32, types.Optional(l.item_type if IS_NOT_NONE else types.int64)]) sig = resty(l, index) def codegen(context, builder, sig, args): fnty = ir.FunctionType( ll_status, [ll_list_type, ll_ssize_t, ll_bytes], ) [tl, tindex] = sig.args [l, index] = args fn = builder.module.get_or_insert_function( fnty, name='numba_list_getitem') dm_item = context.data_model_manager[tl.item_type] ll_item = context.get_data_type(tl.item_type) ptr_item = cgutils.alloca_once(builder, ll_item) lp = _container_get_data(context, builder, tl, l) status = builder.call( fn, [ lp, index, _as_bytes(builder, ptr_item), ], ) # Load item if output is available found = builder.icmp_signed('>=', status, status.type(int(ListStatus.LIST_OK))) out = context.make_optional_none(builder, tl.item_type if IS_NOT_NONE else types.int64) pout = cgutils.alloca_once_value(builder, out) with builder.if_then(found): if IS_NOT_NONE: item = dm_item.load_from_data_pointer(builder, ptr_item) context.nrt.incref(builder, tl.item_type, item) loaded = context.make_optional_value( builder, tl.item_type, item) builder.store(loaded, pout) out = builder.load(pout) return context.make_tuple(builder, resty, [status, out]) return sig, codegen
def generic(self, args, kws): assert not kws # empty tuple case if len(args) == 0: return signature(types.Tuple(())) (val, ) = args # tuple as input if isinstance(val, types.BaseTuple): return signature(val, val)
def test_index(self): pyfunc = tuple_index cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 3), types.int64]) tup = (4, 3, 6) for i in range(len(tup)): self.assertPreciseEqual(cr.entry_point(tup, i), tup[i]) # test negative indexing for i in range(len(tup) + 1): self.assertPreciseEqual(cr.entry_point(tup, -i), tup[-i]) # oob indexes, +ve then -ve with self.assertRaises(IndexError) as raises: cr.entry_point(tup, len(tup)) self.assertEqual("tuple index out of range", str(raises.exception)) with self.assertRaises(IndexError) as raises: cr.entry_point(tup, -(len(tup) + 1)) self.assertEqual("tuple index out of range", str(raises.exception)) # Test empty tuple cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 0), types.int64]) with self.assertRaises(IndexError) as raises: cr.entry_point((), 0) self.assertEqual("tuple index out of range", str(raises.exception)) # test uintp indexing (because, e.g., parfor generates unsigned prange) cr = compile_isolated(pyfunc, [types.UniTuple(types.int64, 3), types.uintp]) for i in range(len(tup)): self.assertPreciseEqual(cr.entry_point(tup, types.uintp(i)), tup[i]) # With a compile-time static index (the code generation path is different) pyfunc = tuple_index_static for typ in ( types.UniTuple(types.int64, 4), types.Tuple( (types.int64, types.int32, types.int64, types.int32)), ): cr = compile_isolated(pyfunc, (typ, )) tup = (4, 3, 42, 6) self.assertPreciseEqual(cr.entry_point(tup), pyfunc(tup)) typ = types.UniTuple(types.int64, 1) with self.assertTypingError(): cr = compile_isolated(pyfunc, (typ, )) # test unpack, staticgetitem with imprecise type (issue #3895) pyfunc = tuple_unpack_static_getitem_err with self.assertTypingError() as raises: cr = compile_isolated(pyfunc, ()) msg = ("Cannot infer the type of variable 'c', have imprecise type: " "list(undefined).") self.assertIn(msg, str(raises.exception))
def test_set(self): # Different reflections aty = types.Set(i16, reflected=True) bty = types.Set(i32) cty = types.Set(i32, reflected=True) self.assert_unify(aty, bty, cty) # Incompatible dtypes aty = types.Set(i16) bty = types.Set(types.Tuple([i16])) self.assert_unify_failure(aty, bty)
def check_minmax_3(self, pyfunc, flags): def check(argty): cr = compile_isolated(pyfunc, (argty, ), flags=flags) cfunc = cr.entry_point # Check that the algorithm matches Python's with a non-total order tup = (1.5, float('nan'), 2.5) for val in [tup, tup[::-1]]: self.assertPreciseEqual(cfunc(val), pyfunc(val)) check(types.UniTuple(types.float64, 3)) check(types.Tuple((types.float32, types.float64, types.float32)))
def test_list(self): aty = types.List(types.undefined) bty = types.List(i32) self.assert_unify(aty, bty, bty) aty = types.List(i16) bty = types.List(i32) self.assert_unify(aty, bty, bty) aty = types.List(types.Tuple([i32, i16])) bty = types.List(types.Tuple([i16, i64])) cty = types.List(types.Tuple([i32, i64])) self.assert_unify(aty, bty, cty) # Different reflections aty = types.List(i16, reflected=True) bty = types.List(i32) cty = types.List(i32, reflected=True) self.assert_unify(aty, bty, cty) # Incompatible dtypes aty = types.List(i16) bty = types.List(types.Tuple([i16])) self.assert_unify_failure(aty, bty)
def test_numba_types(self): numba_types = [ types.intp, types.boolean, types.ListType(types.float64), types.DictType(types.intp, types.Tuple([types.float32, types.float32])), ] for ty in numba_types: self.assertEqual(as_numba_type(ty), ty)
def _dict_lookup(typingctx, d, key, hashval): """Wrap numba_dict_lookup Returns 2-tuple of (intp, ?value_type) """ resty = types.Tuple([types.intp, types.Optional(d.value_type)]) sig = resty(d, key, hashval) def codegen(context, builder, sig, args): fnty = ir.FunctionType( ll_ssize_t, [ll_dict_type, ll_bytes, ll_hash, ll_bytes], ) [td, tkey, thashval] = sig.args [d, key, hashval] = args fn = cgutils.get_or_insert_function(builder.module, fnty, 'numba_dict_lookup') dm_key = context.data_model_manager[tkey] dm_val = context.data_model_manager[td.value_type] data_key = dm_key.as_data(builder, key) ptr_key = cgutils.alloca_once_value(builder, data_key) cgutils.memset_padding(builder, ptr_key) ll_val = context.get_data_type(td.value_type) ptr_val = cgutils.alloca_once(builder, ll_val) dp = _container_get_data(context, builder, td, d) ix = builder.call( fn, [ dp, _as_bytes(builder, ptr_key), hashval, _as_bytes(builder, ptr_val), ], ) # Load value if output is available found = builder.icmp_signed('>', ix, ix.type(int(DKIX.EMPTY))) out = context.make_optional_none(builder, td.value_type) pout = cgutils.alloca_once_value(builder, out) with builder.if_then(found): val = dm_val.load_from_data_pointer(builder, ptr_val) context.nrt.incref(builder, td.value_type, val) loaded = context.make_optional_value(builder, td.value_type, val) builder.store(loaded, pout) out = builder.load(pout) return context.make_tuple(builder, resty, [ix, out]) return sig, codegen
def test_in(self): pyfunc = in_usecase cr = compile_isolated( pyfunc, [types.int64, types.UniTuple(types.int64, 3)]) tup = (4, 1, 5) for i in range(5): self.assertPreciseEqual(cr.entry_point(i, tup), pyfunc(i, tup)) # Test the empty case cr = compile_isolated(pyfunc, [types.int64, types.Tuple([])]) self.assertPreciseEqual(cr.entry_point(1, ()), pyfunc(1, ()))