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 test_bad_union_throws(self): bad_unions = [ py_typing.Union[str, int], py_typing.Union[int, type(None), py_typing.Tuple[bool, bool]], ] for bad_py_type in bad_unions: with self.assertRaises(TypingError) as raises: as_numba_type(bad_py_type) self.assertIn("Cannot type Union", str(raises.exception))
def test_jitclass_registers(self): @jitclass class MyInt: x: int def __init__(self, value): self.x = value self.assertEqual(as_numba_type(MyInt), MyInt.class_type.instance_type)
def test_nested_containers(self): IntList = py_typing.List[int] self.assertEqual( as_numba_type(py_typing.List[IntList]), types.ListType(types.ListType(self.int_nb_type)), ) self.assertEqual( as_numba_type(py_typing.List[py_typing.Dict[float, bool]]), types.ListType( types.DictType(self.float_nb_type, self.bool_nb_type)), ) self.assertEqual( as_numba_type( py_typing.Set[py_typing.Tuple[py_typing.Optional[int], float]]), types.Set( types.Tuple( [types.Optional(self.int_nb_type), self.float_nb_type])), )
def test_any_throws(self): Any = py_typing.Any any_types = [ py_typing.Optional[Any], py_typing.List[Any], py_typing.Set[Any], py_typing.Dict[float, Any], py_typing.Dict[Any, float], py_typing.Tuple[int, Any], ] for bad_py_type in any_types: with self.assertRaises(TypingError) as raises: as_numba_type(bad_py_type) self.assertIn( "Cannot infer numba type of python type", str(raises.exception), )
def test_optional(self): self.assertEqual( as_numba_type(py_typing.Optional[float]), types.Optional(self.float_nb_type), ) self.assertEqual( as_numba_type(py_typing.Union[str, None]), types.Optional(self.str_nb_type), ) self.assertEqual( as_numba_type(py_typing.Union[None, bool]), types.Optional(self.bool_nb_type), ) # Optional[x] is a special case of Union[x, None]. We raise a # TypingError if the right type is not NoneType. with self.assertRaises(TypingError) as raises: as_numba_type(py_typing.Union[int, float]) self.assertIn("Cannot type Union that is not an Optional", str(raises.exception))
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 test_single_containers(self): self.assertEqual( as_numba_type(py_typing.List[float]), types.ListType(self.float_nb_type), ) self.assertEqual( as_numba_type(py_typing.Dict[float, str]), types.DictType(self.float_nb_type, self.str_nb_type), ) self.assertEqual( as_numba_type(py_typing.Set[complex]), types.Set(self.complex_nb_type), ) self.assertEqual( as_numba_type(py_typing.Tuple[float, float]), types.Tuple([self.float_nb_type, self.float_nb_type]), ) self.assertEqual( as_numba_type(py_typing.Tuple[float, complex]), types.Tuple([self.float_nb_type, self.complex_nb_type]), )
def test_simple_types(self): self.assertEqual(as_numba_type(int), self.int_nb_type) self.assertEqual(as_numba_type(float), self.float_nb_type) self.assertEqual(as_numba_type(complex), self.complex_nb_type) self.assertEqual(as_numba_type(str), self.str_nb_type) self.assertEqual(as_numba_type(bool), self.bool_nb_type) self.assertEqual(as_numba_type(type(None)), self.none_nb_type)
def ol_isinstance(var, typs): def true_impl(var, typs): return True def false_impl(var, typs): return False var_ty = as_numba_type(var) if isinstance(var_ty, types.Optional): msg = f'isinstance cannot handle optional types. Found: "{var_ty}"' raise NumbaTypeError(msg) # NOTE: The current implementation of `isinstance` restricts the type of the # instance variable to types that are well known and in common use. The # danger of unrestricted tyoe comparison is that a "default" of `False` is # required and this means that if there is a bug in the logic of the # comparison tree `isinstance` returns False! It's therefore safer to just # reject the compilation as untypable! supported_var_ty = (types.Number, types.Bytes, types.RangeType, types.DictType, types.LiteralStrKeyDict, types.List, types.ListType, types.Tuple, types.UniTuple, types.Set, types.Function, types.ClassType, types.UnicodeType, types.ClassInstanceType, types.NoneType, types.Array) if not isinstance(var_ty, supported_var_ty): msg = f'isinstance() does not support variables of type "{var_ty}".' raise NumbaTypeError(msg) # Warn about the experimental nature of this feature. msg = "Use of isinstance() detected. This is an experimental feature." warnings.warn(msg, category=NumbaExperimentalFeatureWarning) t_typs = typs # Check the types that the var can be an instance of, it'll be a scalar, # a unituple or a tuple. if isinstance(t_typs, types.UniTuple): # corner case - all types in isinstance are the same t_typs = (t_typs.key[0]) if not isinstance(t_typs, types.Tuple): t_typs = (t_typs, ) for typ in t_typs: if isinstance(typ, types.Function): key = typ.key[0] # functions like int(..), float(..), str(..) elif isinstance(typ, types.ClassType): key = typ # jitclasses else: key = typ.key # corner cases for bytes, range, ... # avoid registering those types on `as_numba_type` types_not_registered = { bytes: types.Bytes, range: types.RangeType, dict: (types.DictType, types.LiteralStrKeyDict), list: types.List, tuple: types.BaseTuple, set: types.Set, } if key in types_not_registered: if isinstance(var_ty, types_not_registered[key]): return true_impl continue if isinstance(typ, types.TypeRef): # Use of Numba type classes is in general not supported as they do # not work when the jit is disabled. if key not in (types.ListType, types.DictType): msg = ("Numba type classes (except numba.typed.* container " "types) are not supported.") raise NumbaTypeError(msg) # Case for TypeRef (i.e. isinstance(var, typed.List)) # var_ty == ListType[int64] (instance) # typ == types.ListType (class) return true_impl if type(var_ty) is key else false_impl else: numba_typ = as_numba_type(key) if var_ty == numba_typ: return true_impl elif isinstance(numba_typ, types.ClassType) and \ isinstance(var_ty, types.ClassInstanceType) and \ var_ty.key == numba_typ.instance_type.key: # check for jitclasses return true_impl elif isinstance(numba_typ, types.Container) and \ numba_typ.key[0] == types.undefined: # check for containers (list, tuple, set, ...) if isinstance(var_ty, numba_typ.__class__) or \ (isinstance(var_ty, types.BaseTuple) and \ isinstance(numba_typ, types.BaseTuple)): return true_impl return false_impl
def register_class_type(cls, spec, class_ctor, builder): """ Internal function to create a jitclass. Args ---- cls: the original class object (used as the prototype) spec: the structural specification contains the field types. class_ctor: the numba type to represent the jitclass builder: the internal jitclass builder """ # Normalize spec if spec is None: spec = OrderedDict() elif isinstance(spec, Sequence): spec = OrderedDict(spec) # Extend spec with class annotations. for attr, py_type in pt.get_type_hints(cls).items(): if attr not in spec: spec[attr] = as_numba_type(py_type) _validate_spec(spec) # Fix up private attribute names spec = _fix_up_private_attr(cls.__name__, spec) # Copy methods from base classes clsdct = {} for basecls in reversed(inspect.getmro(cls)): clsdct.update(basecls.__dict__) methods, props, static_methods, others = {}, {}, {}, {} for k, v in clsdct.items(): if isinstance(v, pytypes.FunctionType): methods[k] = v elif isinstance(v, property): props[k] = v elif isinstance(v, staticmethod): static_methods[k] = v else: others[k] = v # Check for name shadowing shadowed = (set(methods) | set(props) | set(static_methods)) & set(spec) if shadowed: raise NameError("name shadowing: {0}".format(', '.join(shadowed))) docstring = others.pop('__doc__', "") _drop_ignored_attrs(others) if others: msg = "class members are not yet supported: {0}" members = ', '.join(others.keys()) raise TypeError(msg.format(members)) for k, v in props.items(): if v.fdel is not None: raise TypeError("deleter is not supported: {0}".format(k)) jit_methods = {k: njit(v) for k, v in methods.items()} jit_props = {} for k, v in props.items(): dct = {} if v.fget: dct['get'] = njit(v.fget) if v.fset: dct['set'] = njit(v.fset) jit_props[k] = dct jit_static_methods = { k: njit(v.__func__) for k, v in static_methods.items() } # Instantiate class type class_type = class_ctor(cls, ConstructorTemplate, spec, jit_methods, jit_props, jit_static_methods) jit_class_dct = dict(class_type=class_type, __doc__=docstring) jit_class_dct.update(jit_static_methods) cls = JitClassType(cls.__name__, (cls, ), jit_class_dct) # Register resolution of the class object typingctx = cpu_target.typing_context typingctx.insert_global(cls, class_type) # Register class targetctx = cpu_target.target_context builder(class_type, typingctx, targetctx).register() as_numba_type.register(cls, class_type.instance_type) return cls
def test_overwrite_type(self): as_numba_type = AsNumbaTypeRegistry() self.assertEqual(as_numba_type(float), self.float_nb_type) as_numba_type.register(float, types.float32) self.assertEqual(as_numba_type(float), types.float32) self.assertNotEqual(as_numba_type(float), self.float_nb_type)