Hello community!
I’m experimenting with creating my own Decimal class. Someone on the scientific Python discord recommended that I try to implement it by following the Interval Example already provided. I’ve taken a crack at implementing a basic type without any special methods for now.
However when I try to run it I get the exception:
No definition for lowering <class '__main__.Decimal'>(Literal[bool](True), Literal[str](123), Literal[str](123), Literal[int](1)) -> Decimal
But, to me at least, I feel as if I have already given it the definition. Am I missing something here?
Sorry if this seems simple, I’m very new to working with numba.
Thank you
Below is the full exception output and the code for my Decimal class
/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/utils.py:213: NumbaPendingDeprecationWarning: Code using Numba extension API maybe depending on 'old_style' error-capturing, which is deprecated and will be replaced by 'new_style' in a future release. See details at https://numba.readthedocs.io/en/latest/reference/deprecation.html#deprecation-of-old-style-numba-captured-errors
Exception origin:
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/base.py", line 558, in get_function
raise NotImplementedError("No definition for lowering %s%s" % (key, sig))
warnings.warn(msg,
Traceback (most recent call last):
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/errors.py", line 832, in new_error_context
yield
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 285, in lower_block
self.lower_inst(inst)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 463, in lower_inst
val = self.lower_assign(ty, inst)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 675, in lower_assign
return self.lower_expr(ty, value)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 1211, in lower_expr
res = self.lower_call(resty, expr)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 940, in lower_call
res = self._lower_call_normal(fnty, expr, signature)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 1174, in _lower_call_normal
impl = self.context.get_function(fnty, signature)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/base.py", line 556, in get_function
return self.get_function(fn, sig, _firstcall=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/base.py", line 558, in get_function
raise NotImplementedError("No definition for lowering %s%s" % (key, sig))
NotImplementedError: No definition for lowering <class '__main__.Decimal'>(Literal[bool](True), Literal[str](123), Literal[str](123), Literal[int](1)) -> Decimal
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/kai/Projects/nb-decimal/nb_decimal/types.py", line 196, in <module>
uses_decimal()
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 487, in _compile_for_args
raise e
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 420, in _compile_for_args
return_val = self.compile(tuple(argtypes))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 965, in compile
cres = self._compiler.compile(args, return_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 125, in compile
status, retval = self._compile_cached(args, return_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 139, in _compile_cached
retval = self._compile_core(args, return_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/dispatcher.py", line 152, in _compile_core
cres = compiler.compile_extra(self.targetdescr.typing_context,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler.py", line 770, in compile_extra
return pipeline.compile_extra(func)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler.py", line 461, in compile_extra
return self._compile_bytecode()
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler.py", line 529, in _compile_bytecode
return self._compile_core()
^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler.py", line 508, in _compile_core
raise e
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler.py", line 495, in _compile_core
pm.run(self.state)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler_machinery.py", line 368, in run
raise patched_exception
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler_machinery.py", line 356, in run
self._runPass(idx, pass_inst, state)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler_lock.py", line 35, in _acquire_compile_lock
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler_machinery.py", line 311, in _runPass
mutated |= check(pss.run_pass, internal_state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/compiler_machinery.py", line 273, in check
mangled = func(compiler_state)
^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/typed_passes.py", line 466, in run_pass
lower.lower()
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 187, in lower
self.lower_normal_function(self.fndesc)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 241, in lower_normal_function
entry_block_tail = self.lower_function_body()
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 271, in lower_function_body
self.lower_block(block)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/lowering.py", line 283, in lower_block
with new_error_context('lowering "{inst}" at {loc}', inst=inst,
File "/home/kai/.pyenv/versions/3.11.3/lib/python3.11/contextlib.py", line 155, in __exit__
self.gen.throw(typ, value, traceback)
File "/home/kai/.cache/pypoetry/virtualenvs/nb-decimal-6XUNvw28-py3.11/lib/python3.11/site-packages/numba/core/errors.py", line 846, in new_error_context
raise newerr.with_traceback(tb)
numba.core.errors.LoweringError: Failed in nopython mode pipeline (step: native lowering)
No definition for lowering <class '__main__.Decimal'>(Literal[bool](True), Literal[str](123), Literal[str](123), Literal[int](1)) -> Decimal
File "types.py", line 193:
def uses_decimal():
d = Decimal(True, "123", "123", 1)
^
During: lowering "d = call $4load_global.0($const16.2, $const18.3, $const20.4, $const22.5, func=$4load_global.0, args=[Var($const16.2, types.py:193), Var($const18.3, types.py:193), Var($const20.4, types.py:193), Var($const22.5, types.py:193)], kws=(), vararg=None, varkwarg=None, target=None)" at /home/kai/Projects/nb-decimal/nb_decimal/types.py (193)
from contextlib import ExitStack
from numba import types
from numba.core import cgutils
from numba.extending import (
models,
register_model,
typeof_impl,
as_numba_type,
type_callable,
make_attribute_wrapper,
lower_builtin,
box,
unbox,
NativeValue,
)
class Decimal:
def __init__(self, sign, base, exponent, special_code):
self.sign = sign
self.base = base
self.exponent = exponent
self.special_code = special_code
class DecimalType(types.Type):
def __init__(self):
super(DecimalType, self).__init__(name="Decimal")
decimal_type = DecimalType()
@typeof_impl.register(Decimal)
def typeof_index(val, c):
return decimal_type
as_numba_type.register(Decimal, decimal_type)
@type_callable(Decimal)
def type_decimal(context):
def typer(sign, base, exponent, special_code):
sign_is_bool = isinstance(sign, types.Boolean)
base_is_string = isinstance(base, types.StringLiteral)
exponent_is_string = isinstance(exponent, types.StringLiteral)
special_code_is_int = isinstance(special_code, types.Integer)
if sign_is_bool and base_is_string and exponent_is_string and special_code_is_int:
return decimal_type
return typer
@register_model(DecimalType)
class DecimalModel(models.StructModel):
def __init__(self, dmm, fe_type):
members = [
("sign", types.boolean),
("base", types.string),
("exponent", types.string),
("special_code", types.int64),
]
models.StructModel.__init__(self, dmm, fe_type, members)
make_attribute_wrapper(DecimalType, "sign", "sign")
make_attribute_wrapper(DecimalType, "base", "base")
make_attribute_wrapper(DecimalType, "exponent", "exponent")
make_attribute_wrapper(DecimalType, "special_code", "special_code")
@lower_builtin(Decimal, types.boolean, types.string, types.string, types.int64)
def impl_decimal(context, builder, sig, args):
typ = sig.return_type
sign, base, exponent, special_code = args
decimal = cgutils.create_struct_proxy(typ)(context, builder)
decimal.sign = sign
decimal.base = base
decimal.exponent = exponent
decimal.special_code = special_code
return decimal._getvalue()
@unbox(DecimalType)
def unbox_decimal(typ, obj, c):
is_error_ptr = cgutils.alloca_once_value(c.builder, cgutils.false_bit)
decimal = cgutils.create_struct_proxy(typ)(c.context, c.builder)
with ExitStack() as stack:
sign_obj = c.pyapi.object_getattr_string(obj, "sign")
with cgutils.early_exit_if_null(c.builder, stack, sign_obj):
c.builder.store(cgutils.true_bit, is_error_ptr)
sign_native = c.unbox(types.boolean, sign_obj)
c.pyapi.decref(sign_obj)
with cgutils.early_exit_if(c.builder, stack, sign_native.is_error):
c.builder.store(cgutils.true_bit, is_error_ptr)
base_obj = c.pyapi.object_getattr_string(obj, "base")
with cgutils.early_exit_if_null(c.builder, stack, base_obj):
c.builder.store(cgutils.true_bit, is_error_ptr)
base_native = c.unbox(types.string, base_obj)
c.pyapi.decref(base_obj)
with cgutils.early_exit_if(c.builder, stack, base_native.is_error):
c.builder.store(cgutils.true_bit, is_error_ptr)
exponent_obj = c.pyapi.object_getattr_string(obj, "exponent")
with cgutils.early_exit_if_null(c.builder, stack, exponent_obj):
c.builder.store(cgutils.true_bit, is_error_ptr)
exponent_native = c.unbox(types.string, exponent_obj)
c.pyapi.decref(exponent_obj)
with cgutils.early_exit_if(c.builder, stack, exponent_native.is_error):
c.builder.store(cgutils.true_bit, is_error_ptr)
special_code_obj = c.pyapi.object_getattr_string(obj, "special_code")
with cgutils.early_exit_if_null(c.builder, stack, special_code_obj):
c.builder.store(cgutils.true_bit, is_error_ptr)
special_code_native = c.unbox(types.int64, special_code_obj)
c.pyapi.decref(special_code_obj)
with cgutils.early_exit_if(c.builder, stack, special_code_native.is_error):
c.builder.store(cgutils.true_bit, is_error_ptr)
decimal.sign = sign_native.value
decimal.base = base_native.value
decimal.exponent = exponent_native.value
decimal.special_code = special_code_native.value
return NativeValue(decimal._getvalue(), is_error=c.builder.load(is_error_ptr))
@box(DecimalType)
def box_decimal(typ, val, c):
ret_ptr = cgutils.alloca_once(c.builder, c.pyapi.pyobj)
fail_obj = c.pyapi.get_null_object()
with ExitStack as stack:
decimal = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)
sign_obj = c.box(types.boolean, decimal.sign)
with cgutils.early_exit_if_null(c.builder, stack, sign_obj):
c.builder.store(fail_obj, ret_ptr)
base_obj = c.box(types.string, decimal.base)
with cgutils.early_exit_if_null(c.builder, stack, base_obj):
c.pyapi.decref(sign_obj)
c.builder.store(fail_obj, ret_ptr)
exponent_obj = c.box(types.string, decimal.exponent)
with cgutils.early_exit_if_null(c.builder, stack, exponent_obj):
c.pyapi.decref(sign_obj)
c.pyapi.decref(base_obj)
c.builder.store(fail_obj, ret_ptr)
special_code_obj = c.box(types.int64, decimal.special_code)
with cgutils.early_exit_if_null(c.builder, stack, special_code_obj):
c.pyapi.decref(sign_obj)
c.pyapi.decref(base_obj)
c.pyapi.decref(exponent_obj)
c.builder.store(fail_obj, ret_ptr)
class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Decimal))
with cgutils.early_exit_if_null(c.builder, stack, class_obj):
c.pyapi.decref(sign_obj)
c.pyapi.decref(base_obj)
c.pyapi.decref(exponent_obj)
c.pyapi.decref(special_code_obj)
c.builder.store(fail_obj, ret_ptr)
# NOTE: The result of this call is not checked as the cleanup
# has to occur regardless of whether it is successful. If it
# fails `res` is set to NULL and a Python exception is set.
res = c.pyapi.call_function_objargs(class_obj, (sign_obj, base_obj, exponent_obj, special_code_obj))
c.pyapi.decref(sign_obj)
c.pyapi.decref(base_obj)
c.pyapi.decref(exponent_obj)
c.pyapi.decref(special_code_obj)
c.pyapi.decref(class_obj)
c.builder.store(res, ret_ptr)
return c.builder.load(ret_ptr)
if __name__ == "__main__":
from numba import njit
@njit
def uses_decimal():
d = Decimal(True, "123", "123", 1)
print(d)
uses_decimal()