numba: FTBFS building against python 3.15
Maximiliano Curia <[email protected]>
| Newsgroups | gmane.linux.debian.devel.python |
|---|---|
| Message-ID | <[email protected]> |
Package: src:numba Version: 0.65.1+dfsg-3 User: [email protected] Usertags: python3.15 Tags: patch Hi! While rebuilding the python related packages against the python version 3.15rc1 we found that python-gevent fails to build from source [1]. Upstream is currently working on adding the support, and the open pr can be seen in https://github.com/numba/numba/pull/10732. But as numba was a blocker to build other packages I used a backport of the changes in that pr to keep building the packages that depend on numba. I'm attaching the backported and squashed upstream patch. Happy hacking, [1]: https://debusine.debian.net/debian/r-python-python3.15/work-request/1014450/ -- "Can you imagine what I would do if I could do all I can?" -- Sun Tzu Saludos /\/\ /\ >< `/
0013-Python-3.15-support.patch
(text/x-diff, 59.7 KB)
Description: Support Python 3.15
Backport fixes from upstream PR #10732 to support Python 3.15.
Includes updates to setup.py, C/C++ extension modules, bytecode analysis,
byteflow, interpreter, and test suite.
Origin: backport, https://github.com/numba/numba/pull/10732
Forwarded: not-needed
Index: numba/numba/_dispatcher.cpp
===================================================================
--- numba.orig/numba/_dispatcher.cpp
+++ numba/numba/_dispatcher.cpp
@@ -27,7 +27,7 @@
*
*/
-#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
#ifndef Py_BUILD_CORE
#define Py_BUILD_CORE 1
@@ -791,7 +791,7 @@ call_cfunc(Dispatcher *self, PyObject *c
}
}
-#elif (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#elif (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
// Python 3.12 has a completely new approach to tracing and profiling due to
// the new `sys.monitoring` system.
@@ -1672,7 +1672,7 @@ static PyTypeObject DispatcherType = {
};
-#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
static
bool is_sysmon_enabled(Dispatcher * self) {
return self->enable_sysmon;
Index: numba/numba/_dynfunc.c
===================================================================
--- numba.orig/numba/_dynfunc.c
+++ numba/numba/_dynfunc.c
@@ -8,8 +8,8 @@
#include <string.h>
-// if python version is 3.13
-#if ((PY_MAJOR_VERSION == 3) && ((PY_MINOR_VERSION == 13) || PY_MINOR_VERSION == 14))
+// if python version is 3.13+
+#if ((PY_MAJOR_VERSION == 3) && ((PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15)))
#include "pythoncapi_compat.h"
#define _Py_IsFinalizing Py_IsFinalizing
#endif
Index: numba/numba/_helperlib.c
===================================================================
--- numba.orig/numba/_helperlib.c
+++ numba/numba/_helperlib.c
@@ -839,7 +839,7 @@ static void traceback_add(const char *fu
if (!frame)
goto error;
-#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
#elif (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 11) /* 3.11 */
/* unsafe cast to our copy of _frame to access the f_lineno field */
@@ -857,7 +857,7 @@ static void traceback_add(const char *fu
Py_DECREF(frame);
return;
-#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
error:
_PyErr_ChainExceptions1(exc);
#elif (PY_MAJOR_VERSION == 3) && ((PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11)) /* 3.11 and below */
Index: numba/numba/_pymodule.h
===================================================================
--- numba.orig/numba/_pymodule.h
+++ numba/numba/_pymodule.h
@@ -46,6 +46,6 @@
Py_DECREF(tmp); } while (0)
-#define NB_SUPPORTED_PYTHON_MINOR ((PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#define NB_SUPPORTED_PYTHON_MINOR ((PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
#endif /* NUMBA_PY_MODULE_H_ */
Index: numba/numba/_typeof.cpp
===================================================================
--- numba.orig/numba/_typeof.cpp
+++ numba/numba/_typeof.cpp
@@ -16,7 +16,7 @@
#include <numpy/npy_2_compat.h>
#endif
-#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14) || (PY_MINOR_VERSION == 15))
#ifndef Py_BUILD_CORE
#define Py_BUILD_CORE 1
#endif
Index: numba/numba/core/bytecode.py
===================================================================
--- numba.orig/numba/core/bytecode.py
+++ numba/numba/core/bytecode.py
@@ -10,7 +10,7 @@ from numba.core import errors, utils, se
from numba.core.utils import PYVERSION
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
from opcode import _inline_cache_entries
# Instruction/opcode length in bytes
INSTR_LEN = 2
@@ -105,7 +105,7 @@ class ByteCodeInst(object):
# https://bugs.python.org/issue27129
# https://github.com/python/cpython/pull/25069
assert self.is_jump
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
if self.opcode in (dis.opmap[k]
for k in ["JUMP_BACKWARD",
"JUMP_BACKWARD_NO_INTERRUPT"]):
@@ -127,7 +127,7 @@ class ByteCodeInst(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
if self.opcode in JREL_OPS:
return self.next + self.arg * 2
else:
@@ -159,7 +159,7 @@ NO_ARG_LEN = 1
OPCODE_NOP = dis.opname.index('NOP')
-if PYVERSION in ((3, 13), (3, 14)):
+if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def _unpack_opargs(code):
buf = []
@@ -383,7 +383,7 @@ class _ByteCode(object):
def _fix_LOAD_GLOBAL_arg(arg):
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
return arg >> 1
elif PYVERSION in ((3, 10),):
return arg
@@ -484,6 +484,17 @@ class ByteCodePy312(ByteCodePy311):
Update for Python 3.13.1, there's now a GET_ITER before FOR_ITER.
This patch the GET_ITER to NOP to minimize changes downstream
(e.g. array-comprehension).
+
+ Update for Python 3.15, a ternary ``x if c else y`` in a
+ comprehension inserts NOT_TAKEN and splits the exception
+ table into two same-target entries:
+
+ ExceptionTable:
+ L1 to L3 -> L9 # ends at NOT_TAKEN
+ L4 to L8 -> L9 # resumes after NOT_TAKEN
+
+ Merge those halves so the pattern below still matches
+ (e.g. array-comprehension).
"""
def pop_and_merge_exceptions(entries: list,
entry_to_remove: _ExceptionTableEntry):
@@ -542,16 +553,41 @@ class ByteCodePy312(ByteCodePy311):
# In Python 3.13.4, this becomes the only GET_ITER,
# so don't turn it into a NOP.
# Python 3.13.5 reverted the change.
- if sys.version_info[:3] != (3, 13, 4):
- # Add the inst to potentially be replaced to NOP.
- current_nop_fixes.add(next_inst)
+ # Python 3.15 likewise keeps the GET_ITER.
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if sys.version_info[:3] != (3, 13, 4):
+ # Add the inst to potentially be replaced to NOP.
+ current_nop_fixes.add(next_inst)
+ elif PYVERSION in ((3, 15),):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
# Loop up next instruction.
next_inst = self.table[self.ordered_offsets[index + 3]]
if not next_inst.opname == "FOR_ITER":
continue
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 15),):
+ # NOT_TAKEN may split one region into two same-target
+ # entries. Merge them and retry.
+ end_inst = self.table.get(entry.end)
+ if (entry in entries
+ and end_inst is not None
+ and end_inst.opname == "NOT_TAKEN"):
+ i = entries.index(entry)
+ if (i + 1 < len(entries)
+ and entries[i + 1].target == entry.target
+ and entries[i + 1].start == end_inst.next):
+ nxt = entries[i + 1]
+ entries[i] = _ExceptionTableEntry(
+ entry.start, nxt.end, entry.target,
+ entry.depth, nxt.lasti)
+ entries.pop(i + 1)
+ work_remaining = True
+ continue
+
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
# Check end of pattern, two instructions.
# Check for the corresponding END_FOR, exception table end
# is non-inclusive, so subtract one.
@@ -563,7 +599,7 @@ class ByteCodePy312(ByteCodePy311):
if PYVERSION in ((3, 13), ):
if not next_inst.opname == "POP_TOP":
continue
- elif PYVERSION in ((3, 14), ):
+ elif PYVERSION in ((3, 14), (3, 15)):
if not next_inst.opname == "POP_ITER":
continue
else:
@@ -609,7 +645,7 @@ class ByteCodePy312(ByteCodePy311):
if PYVERSION == (3, 11):
ByteCode = ByteCodePy311
-elif PYVERSION in ((3, 12), (3, 13), (3, 14)):
+elif PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
ByteCode = ByteCodePy312
elif PYVERSION < (3, 11):
ByteCode = _ByteCode
Index: numba/numba/core/byteflow.py
===================================================================
--- numba.orig/numba/core/byteflow.py
+++ numba/numba/core/byteflow.py
@@ -24,7 +24,7 @@ _NO_RAISE_OPS = frozenset({
'PRECALL',
})
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
from enum import Enum
# Operands for CALL_INTRINSIC_1
@@ -141,7 +141,7 @@ class Flow(object):
self.block_infos[state.pc_initial] = si = adapt_state_infos(state)
_logger.debug("block_infos %s:\n%s", state, si)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def _run_handle_exception(self, runner, state):
if not state.in_with() and (
state.has_active_try() and
@@ -293,7 +293,7 @@ class Flow(object):
else:
return False
- if PYVERSION in ((3, 14),):
+ if PYVERSION in ((3, 14), (3, 15)):
def _guard_with_as(self, state):
# Handled as part of `LOAD_SPECIAL` as of 3.14.
pass
@@ -330,7 +330,7 @@ class TraceRunner(object):
return Loc(self.debug_filename, lineno)
def dispatch(self, state):
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
if state._blockstack:
state: State
while state._blockstack:
@@ -379,7 +379,7 @@ class TraceRunner(object):
def op_NOP(self, state, inst):
state.append(inst)
- if PYVERSION in ((3,14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14
op_NOT_TAKEN = op_NOP
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -413,7 +413,7 @@ class TraceRunner(object):
state.push(state.make_temp())
state.append(inst)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_FORMAT_SIMPLE(self, state, inst):
value = state.pop()
strvar = state.make_temp()
@@ -463,7 +463,12 @@ class TraceRunner(object):
def op_POP_TOP(self, state, inst):
state.pop()
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 15), ):
+ # 3.15: POP_ITER pops both iterator and iterable (stack effect -2)
+ def op_POP_ITER(self, state, inst):
+ state.pop()
+ state.pop()
+ elif PYVERSION in ((3, 14), ):
# New in 3.14
op_POP_ITER = op_POP_TOP
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -471,7 +476,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 13), (3,14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_TO_BOOL(self, state, inst):
res = state.make_temp()
tos = state.pop()
@@ -482,7 +487,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_LOAD_GLOBAL(self, state, inst):
# Ordering of the global value and NULL is swapped in Py3.13
res = state.make_temp()
@@ -526,7 +531,7 @@ class TraceRunner(object):
state.push(res)
state.append(inst, res=res)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14
def op_LOAD_SMALL_INT(self, state, inst):
assert 0 <= inst.arg < 256
@@ -541,7 +546,7 @@ class TraceRunner(object):
def op_LOAD_ATTR(self, state, inst):
item = state.pop()
res = state.make_temp()
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
state.push(res) # the attr
if inst.arg & 1:
state.push(state.make_null())
@@ -556,7 +561,7 @@ class TraceRunner(object):
state.append(inst, item=item, res=res)
def op_LOAD_FAST(self, state, inst):
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
try:
name = state.get_varname(inst)
except IndexError: # oparg is out of range
@@ -583,7 +588,7 @@ class TraceRunner(object):
state.append(inst, res=res)
state.push(res)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_LOAD_FAST_LOAD_FAST(self, state, inst):
oparg = inst.arg
oparg1 = oparg >> 4
@@ -616,7 +621,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
op_LOAD_FAST_CHECK = op_LOAD_FAST
op_LOAD_FAST_AND_CLEAR = op_LOAD_FAST
elif PYVERSION in ((3, 10), (3, 11)):
@@ -624,7 +629,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14),):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14.
op_LOAD_FAST_BORROW = op_LOAD_FAST
op_LOAD_FAST_BORROW_LOAD_FAST_BORROW = op_LOAD_FAST_LOAD_FAST
@@ -884,7 +889,7 @@ class TraceRunner(object):
)
state.push(res)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_BINARY_SLICE(self, state, inst):
end = state.pop()
start = state.pop()
@@ -902,7 +907,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_STORE_SLICE(self, state, inst):
end = state.pop()
start = state.pop()
@@ -935,7 +940,7 @@ class TraceRunner(object):
op_POP_JUMP_IF_TRUE = _op_POP_JUMP_IF
op_POP_JUMP_IF_FALSE = _op_POP_JUMP_IF
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
op_POP_JUMP_IF_NONE = _op_POP_JUMP_IF
op_POP_JUMP_IF_NOT_NONE = _op_POP_JUMP_IF
elif PYVERSION in ((3, 10), (3, 11)):
@@ -1001,7 +1006,7 @@ class TraceRunner(object):
state.append(inst, retval=state.pop(), castval=state.make_temp())
state.terminate()
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_RETURN_CONST(self, state, inst):
res = state.make_temp("const")
state.append(inst, retval=res, castval=state.make_temp())
@@ -1017,7 +1022,7 @@ class TraceRunner(object):
state.append(inst, value=val, res=res)
state.push(res)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_RAISE_VARARGS(self, state, inst):
if inst.arg == 0:
exc = None
@@ -1073,7 +1078,7 @@ class TraceRunner(object):
blk = state.pop_block()
state.reset_stack(blk['entry_stack'])
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_END_FOR(self, state, inst):
state.pop()
elif PYVERSION in ((3, 12),):
@@ -1115,7 +1120,7 @@ class TraceRunner(object):
end=inst.get_jump_target(),
)
)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# Replaced by LOAD_SPECIAL in 3.14.
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -1202,7 +1207,7 @@ class TraceRunner(object):
'FINALLY', state, next=inst.next, end=inst.get_jump_target(),
)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_POP_EXCEPT(self, state, inst):
state.pop()
@@ -1230,7 +1235,7 @@ class TraceRunner(object):
state.append(inst, kind='with')
state.fork(pc=inst.next)
- if PYVERSION in ((3, 14),):
+ if PYVERSION in ((3, 14), (3, 15)):
# Removed in 3.14 -- replaced with BINARY_OP and []
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -1257,7 +1262,7 @@ class TraceRunner(object):
def op_CALL(self, state, inst):
narg = inst.arg
args = list(reversed([state.pop() for _ in range(narg)]))
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
null_or_self = state.pop()
# position of the callable is fixed
callable = state.pop()
@@ -1300,7 +1305,7 @@ class TraceRunner(object):
state.append(inst, func=func, args=args, names=names, res=res)
state.push(res)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_CALL_KW(self, state, inst):
narg = inst.arg
kw_names = state.pop()
@@ -1320,7 +1325,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
def op_CALL_FUNCTION_EX(self, state, inst):
# (func, unused, callargs, kwargs -- result))
# In 3.14 CALL_FUNCTION_EX always take a kwargs argument
@@ -1388,7 +1393,7 @@ class TraceRunner(object):
for val in duped:
state.push(val)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_CALL_INTRINSIC_1(self, state, inst):
# See https://github.com/python/cpython/blob/v3.12.0rc2/Include/
# internal/pycore_intrinsics.h#L3-L17C36
@@ -1600,7 +1605,14 @@ class TraceRunner(object):
res=res)
def op_GET_ITER(self, state, inst):
- value = state.pop()
+ if PYVERSION in ((3, 15), ):
+ # 3.15: GET_ITER keeps iterable on stack and pushes iterator
+ # on top. POP_ITER later cleans up both.
+ value = state.get_tos()
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
+ value = state.pop()
+ else:
+ raise NotImplementedError(PYVERSION)
res = state.make_temp()
state.append(inst, value=value, res=res)
state.push(res)
@@ -1614,7 +1626,7 @@ class TraceRunner(object):
pred=pred)
state.push(indval)
end = inst.get_jump_target()
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
# Changed in version 3.12: Up until 3.11 the iterator was
# popped when it was exhausted. Now this is handled using END_FOR
# op code.
@@ -1641,8 +1653,8 @@ class TraceRunner(object):
rhs = state.pop()
lhs = state.pop()
if op == '[]':
- # Special case 3.14 -- body of BINARY_SUBSCR now here
- assert PYVERSION == (3, 14)
+ # Special case 3.14+ -- body of BINARY_SUBSCR now here
+ assert PYVERSION in ((3, 14), (3, 15))
res = state.make_temp()
state.append(inst, op=op, lhs=lhs, rhs=rhs, res=res)
state.push(res)
@@ -1707,7 +1719,7 @@ class TraceRunner(object):
op_BINARY_XOR = _binaryop
def op_MAKE_FUNCTION(self, state, inst, MAKE_CLOSURE=False):
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# https://github.com/python/cpython/commit/2f180ce
# name set via co_qualname
name = None
@@ -1717,7 +1729,7 @@ class TraceRunner(object):
raise NotImplementedError(PYVERSION)
code = state.pop()
closure = annotations = annotate = kwdefaults = defaults = None
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
assert inst.arg is None
# SET_FUNCTION_ATTRIBUTE is responsible for setting
# closure, annotations, annotate, kwdefaults and defaults.
@@ -1745,7 +1757,7 @@ class TraceRunner(object):
state.push(res)
def op_SET_FUNCTION_ATTRIBUTE(self, state, inst):
- assert PYVERSION in ((3, 13), (3, 14))
+ assert PYVERSION in ((3, 13), (3, 14), (3, 15))
make_func_stack = state.pop()
data = state.pop()
if inst.arg & 0x01:
@@ -1777,7 +1789,7 @@ class TraceRunner(object):
state.append(inst, res=res)
state.push(res)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# Removed in 3.14
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -1805,7 +1817,7 @@ class TraceRunner(object):
state.fork(pc=inst.next)
state.fork(pc=inst.get_jump_target())
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3,14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_RERAISE(self, state, inst):
# This isn't handled, but the state is set up anyway
exc = state.pop()
@@ -1830,7 +1842,7 @@ class TraceRunner(object):
# NOTE: Please see notes in `interpreter.py` surrounding the implementation
# of LOAD_METHOD and CALL_METHOD.
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
# LOAD_METHOD has become a pseudo-instruction in 3.12
pass
elif PYVERSION in ((3, 11), ):
@@ -1850,7 +1862,7 @@ class TraceRunner(object):
def op_CALL_METHOD(self, state, inst):
self.op_CALL_FUNCTION(state, inst)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14, replaces BEFORE_WITH.
def op_LOAD_SPECIAL(self, state, inst):
@@ -1970,14 +1982,17 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
def op_LOAD_COMMON_CONSTANT(self, state, inst):
+ # Keep in sync with dis._common_constants and
+ # interpreter.op_LOAD_COMMON_CONSTANT.
oparg = inst.arg
- if dis._common_constants[oparg] == AssertionError:
- name = 'assertion_error'
- else:
- raise NotImplementedError
- res = state.make_temp(name)
+ const = dis._common_constants[oparg]
+ if const not in (AssertionError, NotImplementedError,
+ tuple, all, any, list, set,
+ None, '', True, False, -1):
+ raise NotImplementedError(const)
+ res = state.make_temp('common_constant')
state.append(inst, res=res, idx=oparg)
state.push(res)
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -2246,7 +2261,7 @@ class _State(object):
stack.append(self.make_temp())
# Handle changes on the blockstack
blockstack = list(self._blockstack)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# pop expired block in destination pc
while blockstack:
top = blockstack[-1]
@@ -2346,7 +2361,7 @@ class StatePy313(StatePy311):
return self._make_func_attrs[make_func_res]
-if PYVERSION in ((3, 13), (3, 14)):
+if PYVERSION in ((3, 13), (3, 14), (3, 15)):
State = StatePy313
elif PYVERSION in ((3, 11), (3, 12)):
State = StatePy311
@@ -2384,7 +2399,7 @@ def adapt_state_infos(state):
if inst.opname == "MAKE_FUNCTION":
data.update(state.get_function_attributes(data['res']))
return offset, data
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
insts = tuple(map(process_function_attributes, state.instructions))
elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
insts = tuple(state.instructions)
Index: numba/numba/core/controlflow.py
===================================================================
--- numba.orig/numba/core/controlflow.py
+++ numba/numba/core/controlflow.py
@@ -8,7 +8,7 @@ from numba.core.utils import PYVERSION
# List of bytecodes creating a new block in the control flow graph
# (in addition to explicit jump labels).
-if PYVERSION in ((3, 14),):
+if PYVERSION in ((3, 14), (3, 15)):
NEW_BLOCKERS = frozenset([
'SETUP_LOOP', 'FOR_ITER', 'SETUP_WITH', 'BEFORE_WITH', 'LOAD_SPECIAL'
])
@@ -961,7 +961,7 @@ class ControlFlowAnalysis(object):
self._curblock.terminating = True
self._force_new_block = True
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_RETURN_CONST(self, inst):
self._curblock.terminating = True
self._force_new_block = True
Index: numba/numba/core/interpreter.py
===================================================================
--- numba.orig/numba/core/interpreter.py
+++ numba/numba/core/interpreter.py
@@ -19,7 +19,7 @@ from numba.core.unsafe import eh
from numba.cpython.unsafe.tuple import unpack_single_tuple
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
# Operands for CALL_INTRINSIC_1
from numba.core.byteflow import CALL_INTRINSIC_1_Operand as ci1op
elif PYVERSION in ((3, 10), (3, 11)):
@@ -1389,7 +1389,7 @@ class Interpreter(object):
max(inst_blocks.body))
self.last_active_offset = last_active_offset
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
self.active_exception_entries = tuple(
[entry for entry in self.bytecode.exception_entries
if entry.start < self.last_active_offset])
@@ -1405,7 +1405,7 @@ class Interpreter(object):
# Interpret loop
for inst, kws in self._iter_inst():
self._dispatch(inst, kws)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# Insert end of try markers
self._end_try_blocks()
elif PYVERSION in ((3, 10),):
@@ -1423,12 +1423,12 @@ class Interpreter(object):
# post process the IR to rewrite opcodes/byte sequences that are too
# involved to risk handling as part of direct interpretation
peepholes = []
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
peepholes.append(peep_hole_split_at_pop_block)
- if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
peepholes.append(peep_hole_list_to_tuple)
peepholes.append(peep_hole_delete_with_exit)
- if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# peep_hole_call_function_ex_to_call_function_kw
# depends on peep_hole_list_to_tuple converting
# any large number of arguments from a list to a
@@ -1461,7 +1461,7 @@ class Interpreter(object):
See also: _insert_try_block_end
"""
- assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14))
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15))
graph = self.cfa.graph
for offset, block in self.blocks.items():
# Get current blockstack
@@ -1569,7 +1569,7 @@ class Interpreter(object):
self.dfainfo = self.dfa.infos[self.current_block_offset]
self.assigner = Assigner()
# Check out-of-scope syntactic-block
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# This is recreating pre-3.11 code structure
while self.syntax_blocks:
if offset >= self.syntax_blocks[-1].exit:
@@ -1740,7 +1740,8 @@ class Interpreter(object):
val = self.get(varname)
except ir.NotDefinedError:
# Hack to make sure exception variables are defined
- assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)), \
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13),
+ (3, 14), (3, 15)), \
"unexpected missing definition"
val = ir.Const(value=None, loc=self.loc)
stmt = ir.Assign(value=val, target=target,
@@ -1800,7 +1801,7 @@ class Interpreter(object):
if self._DEBUG_PRINT:
print(inst)
assert self.current_block is not None
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
if self.syntax_blocks:
top = self.syntax_blocks[-1]
if isinstance(top, ir.With) :
@@ -1887,7 +1888,7 @@ class Interpreter(object):
def op_NOP(self, inst):
pass
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14
op_NOT_TAKEN = op_NOP
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -1991,7 +1992,7 @@ class Interpreter(object):
(), loc=self.loc)
self.store(value=sliceinst, name=res)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_BINARY_SLICE(self, inst, start, end, container, res, slicevar,
temp_res):
start = self.get(start)
@@ -2010,7 +2011,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_STORE_SLICE(self, inst, start, end, container, value, res,
slicevar):
start = self.get(start)
@@ -2242,7 +2243,7 @@ class Interpreter(object):
srcname = self.code_locals[inst.arg]
self.store(value=self.get(srcname), name=res)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_LOAD_FAST(self, inst, res, as_load_deref=False):
if as_load_deref:
self.op_LOAD_DEREF(inst, res)
@@ -2252,7 +2253,7 @@ class Interpreter(object):
else:
op_LOAD_FAST = _op_LOAD_FAST
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_LOAD_FAST_LOAD_FAST(self, inst, res1, res2):
oparg = inst.arg
oparg1 = oparg >> 4
@@ -2289,7 +2290,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
op_LOAD_FAST_CHECK = op_LOAD_FAST
def op_LOAD_FAST_AND_CLEAR(self, inst, res):
@@ -2307,7 +2308,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14),):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14.
op_LOAD_FAST_BORROW = op_LOAD_FAST
op_LOAD_FAST_BORROW_LOAD_FAST_BORROW = op_LOAD_FAST_LOAD_FAST
@@ -2346,7 +2347,7 @@ class Interpreter(object):
def op_LOAD_ATTR(self, inst, item, res):
item = self.get(item)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
attr = self.code_names[inst.arg >> 1]
elif PYVERSION in ((3, 10), (3, 11)):
attr = self.code_names[inst.arg]
@@ -2404,7 +2405,7 @@ class Interpreter(object):
const = ir.Const(value, loc=self.loc)
self.store(const, res)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14
def op_LOAD_SMALL_INT(self, inst, res):
value = inst.arg
@@ -2415,7 +2416,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_LOAD_GLOBAL(self, inst, idx, res):
name = self.code_names[idx]
value = self.get_global_value(name)
@@ -2433,7 +2434,7 @@ class Interpreter(object):
def op_COPY_FREE_VARS(self, inst):
pass
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_LOAD_DEREF(self, inst, res):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
if name in self.code_cellvars:
@@ -2462,11 +2463,11 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_MAKE_CELL(self, inst):
pass # ignored bytecode
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_STORE_DEREF(self, inst, value):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
value = self.get(value)
@@ -2504,7 +2505,7 @@ class Interpreter(object):
exit_fn_obj = ir.Const(None, loc=self.loc)
self.store(value=exit_fn_obj, name=exitfn)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# Replaced by LOAD_SPECIAL in 3.14.
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -2571,7 +2572,7 @@ class Interpreter(object):
expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
self.store(expr, res)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_CALL_KW(self, inst, func, args, kw_names, res):
func = self.get(func)
args = [self.get(x) for x in args]
@@ -2770,7 +2771,7 @@ class Interpreter(object):
loc=self.loc)
self.current_block.append(br)
- if PYVERSION in ((3, 14),):
+ if PYVERSION in ((3, 14), (3, 15)):
# Removed in 3.14 -- replaced with BINARY_OP and []
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -2931,7 +2932,7 @@ class Interpreter(object):
def op_BINARY_OP(self, inst, op, lhs, rhs, res):
if op == "[]":
- # Special case 3.14 -- body of BINARY_SUBSCR now here
+ # Special case 3.14+: body of BINARY_SUBSCR now here
lhs = self.get(lhs)
rhs = self.get(rhs)
expr = ir.Expr.getitem(lhs, index=rhs, loc=self.loc)
@@ -3053,7 +3054,7 @@ class Interpreter(object):
ret = ir.Return(self.get(castval), loc=self.loc)
self.current_block.append(ret)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_RETURN_CONST(self, inst, retval, castval):
value = self.code_consts[inst.arg]
const = ir.Const(value, loc=self.loc)
@@ -3066,7 +3067,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
def op_TO_BOOL(self, inst, val, res):
self.store(self.get(val), res) # TODO: just a lazy hack
@@ -3076,7 +3077,7 @@ class Interpreter(object):
raise NotImplementedError(PYVERSION)
def op_COMPARE_OP(self, inst, lhs, rhs, res):
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
op = dis.cmp_op[inst.arg >> 5]
# TODO: fifth lowest bit now indicates a forced version to bool.
elif PYVERSION in ((3, 12),):
@@ -3197,7 +3198,7 @@ class Interpreter(object):
def op_POP_JUMP_FORWARD_IF_NOT_NONE(self, inst, pred):
self._jump_if_none(inst, pred, False)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_POP_JUMP_IF_NONE(self, inst, pred):
self._jump_if_none(inst, pred, True)
@@ -3341,7 +3342,7 @@ class Interpreter(object):
self.op_MAKE_FUNCTION(inst, name, code, closure, annotations,
kwdefaults, defaults, res)
- if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
def op_LOAD_CLOSURE(self, inst, res):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
if name in self.code_cellvars:
@@ -3461,7 +3462,7 @@ class Interpreter(object):
loc=self.loc)
self.store(value=appendinst, name=res)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# Removed in 3.14
pass
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -3485,7 +3486,7 @@ class Interpreter(object):
def op_CALL_METHOD(self, *args, **kws):
self.op_CALL_FUNCTION(*args, **kws)
- if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
def op_CALL_INTRINSIC_1(self, inst, operand, **kwargs):
if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
stmt = ir.StaticRaise(INTRINSIC_STOPITERATION_ERROR, (),
@@ -3505,7 +3506,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# New in 3.14, replaces BEFORE_WITH.
def op_LOAD_SPECIAL(self, inst, contextmanager, exit_method, block_end):
assert self.blocks[inst.offset] is self.current_block
@@ -3534,22 +3535,28 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
def op_LOAD_COMMON_CONSTANT(self, inst, res, idx):
- if dis._common_constants[idx] == AssertionError:
- gv_fn = ir.Global("AssertionError",
- AssertionError,
- loc=self.loc)
- self.store(value=gv_fn, name=res)
+ # Keep in sync with dis._common_constants and
+ # byteflow.op_LOAD_COMMON_CONSTANT.
+ # Types/callables become ir.Global (like LOAD_GLOBAL);
+ # literals become ir.Const (like LOAD_CONST).
+ const = dis._common_constants[idx]
+ if const in (AssertionError, NotImplementedError,
+ tuple, all, any, list, set):
+ value = ir.Global(const.__name__, const, loc=self.loc)
+ elif const in (None, '', True, False, -1):
+ value = ir.Const(const, loc=self.loc)
else:
- raise NotImplementedError
+ raise NotImplementedError(const)
+ self.store(value=value, name=res)
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
pass
else:
raise NotImplementedError(PYVERSION)
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
class INTRINSIC_STOPITERATION_ERROR(AssertionError):
pass
elif PYVERSION in ((3, 10), (3, 11)):
Index: numba/numba/core/typing/asnumbatype.py
===================================================================
--- numba.orig/numba/core/typing/asnumbatype.py
+++ numba/numba/core/typing/asnumbatype.py
@@ -41,7 +41,7 @@ class AsNumbaTypeRegistry:
return py_type
def _builtin_infer(self, py_type):
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# As of 3.14 the typing module has been updated to return a
# different type when calling: `typing.Optional[X]`.
#
Index: numba/numba/cpython/unicode.py
===================================================================
--- numba.orig/numba/cpython/unicode.py
+++ numba/numba/cpython/unicode.py
@@ -349,7 +349,7 @@ def _set_code_point(a, i, ch):
"Unexpected unicode representation in _set_code_point")
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
@register_jitable
def _pick_kind(kind1, kind2):
if kind1 == PY_UNICODE_1BYTE_KIND:
@@ -393,7 +393,7 @@ def _pick_ascii(is_ascii1, is_ascii2):
return types.uint32(0)
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
@register_jitable
def _kind_to_byte_width(kind):
if kind == PY_UNICODE_1BYTE_KIND:
Index: numba/numba/experimental/jitclass/base.py
===================================================================
--- numba.orig/numba/experimental/jitclass/base.py
+++ numba/numba/experimental/jitclass/base.py
@@ -282,7 +282,7 @@ def _drop_ignored_attrs(dct):
drop = set(['__weakref__',
'__module__',
'__dict__'])
- if utils.PYVERSION in ((3, 13), (3, 14)):
+ if utils.PYVERSION in ((3, 13), (3, 14), (3, 15)):
# new in python 3.13
drop |= set(['__firstlineno__', '__static_attributes__'])
Index: numba/numba/tests/support.py
===================================================================
--- numba.orig/numba/tests/support.py
+++ numba/numba/tests/support.py
@@ -113,6 +113,10 @@ skip_if_py314= unittest.skipIf(
utils.PYVERSION == (3, 14), "Test unstable on 3.14"
)
+skip_if_py315= unittest.skipIf(
+ utils.PYVERSION == (3, 15), "Test unstable on 3.15"
+ )
+
skip_if_linux_aarch64 = unittest.skipIf(
sys.platform.startswith('linux') and platform.machine() == 'aarch64',
"Not supported on Linux aarch64"
@@ -173,6 +177,13 @@ def expected_failure_py314(fn):
return unittest.expectedFailure(fn)
else:
return fn
+
+
+def expected_failure_py315(fn):
+ if utils.PYVERSION == (3, 15):
+ return unittest.expectedFailure(fn)
+ else:
+ return fn
def expected_failure_np2(fn):
Index: numba/numba/tests/test_analysis.py
===================================================================
--- numba.orig/numba/tests/test_analysis.py
+++ numba/numba/tests/test_analysis.py
@@ -654,7 +654,7 @@ class TestBranchPrunePredicates(TestBran
_CONST2 = "PLACEHOLDER2"
return _CONST2 + 4
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# The order of the __code__.co_consts changes with 3.14
new = self._literal_const_sample_generator(impl, {0:0, 2:20})
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
@@ -665,7 +665,7 @@ class TestBranchPrunePredicates(TestBran
iconst = impl.__code__.co_consts
nconst = new.__code__.co_consts
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
self.assertEqual(iconst, ("PLACEHOLDER1", 3.14159,
"PLACEHOLDER2"))
self.assertEqual(nconst, (0, 3.14159, 20))
@@ -689,7 +689,7 @@ class TestBranchPrunePredicates(TestBran
for c_inp, prune in (self._TRUTHY, False), (self._FALSEY, True):
for const in c_inp:
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# The order of the __code__.co_consts changes with 3.14
func = self._literal_const_sample_generator(impl,
{0: const})
@@ -712,7 +712,7 @@ class TestBranchPrunePredicates(TestBran
for c_inp, prune in (self._TRUTHY, False), (self._FALSEY, True):
for const in c_inp:
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# The order of the __code__.co_consts changes with 3.14
func = self._literal_const_sample_generator(impl,
{0: const})
@@ -737,7 +737,7 @@ class TestBranchPrunePredicates(TestBran
for c_inp, prune in (self._TRUTHY, False), (self._FALSEY, True):
for const in c_inp:
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# The order of the __code__.co_consts changes with 3.14
func = self._literal_const_sample_generator(impl,
{0: const})
@@ -762,7 +762,7 @@ class TestBranchPrunePredicates(TestBran
for c_inp, prune in (self._TRUTHY, False), (self._FALSEY, True):
for const in c_inp:
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
# The order of the __code__.co_consts changes with 3.14
func = self._literal_const_sample_generator(impl,
{0: const})
Index: numba/numba/tests/test_caching.py
===================================================================
--- numba.orig/numba/tests/test_caching.py
+++ numba/numba/tests/test_caching.py
@@ -232,6 +232,19 @@ class BaseCacheTest(TestCase):
sys.modules.pop(self.modname, None)
sys.path.remove(self.tempdir)
+ @staticmethod
+ def _module_cached_path(module):
+ # Python 3.15 no longer sets module.__cached__, use
+ # __spec__.cached instead. See:
+ # https://docs.python.org/3/deprecations/pending-removal-in-3.15.html
+ cached = getattr(module, '__cached__', None)
+ if cached is not None:
+ return cached
+ spec = getattr(module, '__spec__', None)
+ if spec is not None:
+ return spec.cached
+ return None
+
def import_module(self):
# Import a fresh version of the test module. All jitted functions
# in the test module will start anew and load overloads from
@@ -239,10 +252,10 @@ class BaseCacheTest(TestCase):
old = sys.modules.pop(self.modname, None)
if old is not None:
# Make sure cached bytecode is removed
- cached = [old.__cached__]
- for fn in cached:
+ cached_path = self._module_cached_path(old)
+ if cached_path:
try:
- os.unlink(fn)
+ os.unlink(cached_path)
except FileNotFoundError:
pass
mod = import_dynamic(self.modname)
Index: numba/numba/tests/test_complex.py
===================================================================
--- numba.orig/numba/tests/test_complex.py
+++ numba/numba/tests/test_complex.py
@@ -3,7 +3,7 @@ import math
import sys
from numba import jit, types
-from numba.tests.support import TestCase, skip_if_py314
+from numba.tests.support import TestCase, skip_if_py314, skip_if_py315
from .complex_usecases import *
import unittest
@@ -115,6 +115,7 @@ class TestComplex(BaseComplexTest, TestC
self.run_binary(div_usecase, value_types, values, flags=flags)
@skip_if_py314
+ @skip_if_py315
def test_div_npm(self):
self.test_div(flags=no_pyobj_flags)
@@ -209,6 +210,7 @@ class TestCMath(BaseComplexTest, TestCas
ulps=3)
@skip_if_py314
+ @skip_if_py315
def test_log_base_npm(self):
self.test_log_base(flags=no_pyobj_flags)
Index: numba/numba/tests/test_debug.py
===================================================================
--- numba.orig/numba/tests/test_debug.py
+++ numba/numba/tests/test_debug.py
@@ -73,7 +73,7 @@ class DebugTestBase(TestCase):
self.assert_fails(check_meth, out)
def _check_dump_bytecode(self, out):
- if utils.PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if utils.PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
self.assertIn('BINARY_OP', out)
elif utils.PYVERSION in ((3, 10),):
self.assertIn('BINARY_ADD', out)
Index: numba/numba/tests/test_dyn_array.py
===================================================================
--- numba.orig/numba/tests/test_dyn_array.py
+++ numba/numba/tests/test_dyn_array.py
@@ -501,7 +501,7 @@ class TestDynArray(NrtRefCtTest, TestCas
np.testing.assert_equal(expected_x, got_x)
np.testing.assert_equal(expected_y, got_y)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
expected_refcount = 1
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
expected_refcount = 2
@@ -528,7 +528,7 @@ class TestDynArray(NrtRefCtTest, TestCas
arr = np.arange(10)
old_refct = sys.getrefcount(arr)
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
self.assertEqual(2, sys.getrefcount(pyfunc(arr)))
self.assertEqual(2, sys.getrefcount(cfunc(arr)))
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
Index: numba/numba/tests/test_exceptions.py
===================================================================
--- numba.orig/numba/tests/test_exceptions.py
+++ numba/numba/tests/test_exceptions.py
@@ -8,6 +8,7 @@ from numba.tests.support import (TestCas
expected_failure_py312,
expected_failure_py313,
expected_failure_py314,
+ expected_failure_py315,
)
import unittest
@@ -444,6 +445,7 @@ class TestRaising(TestCase):
@expected_failure_py312
@expected_failure_py313
@expected_failure_py314
+ @expected_failure_py315
def test_dynamic_raise(self):
@njit
Index: numba/numba/tests/test_extended_arg.py
===================================================================
--- numba.orig/numba/tests/test_extended_arg.py
+++ numba/numba/tests/test_extended_arg.py
@@ -4,7 +4,6 @@ import dis
import struct
from numba import jit
-from numba.core import utils
from numba.tests.support import TestCase
@@ -26,12 +25,10 @@ class TestExtendedArg(TestCase):
consts = f.__code__.co_consts
bytecode_format = "<BB"
consts = consts + (None,) * self.bytecode_len + (42,)
- if utils.PYVERSION >= (3, 11):
- # Python 3.11 has a RESUME op code at the start of a function, need
- # to inject the EXTENDED_ARG after this to influence the LOAD_CONST
- offset = 2 # 2 byte op code
- else:
- offset = 0
+ offset = next(
+ i for i in range(0, len(b), 2)
+ if b[i] == dis.opmap['LOAD_CONST']
+ )
packed_extend_arg = struct.pack(bytecode_format, dis.EXTENDED_ARG, 1)
b[:] = b[:offset] + packed_extend_arg + b[offset:]
Index: numba/numba/tests/test_ir_inlining.py
===================================================================
--- numba.orig/numba/tests/test_ir_inlining.py
+++ numba/numba/tests/test_ir_inlining.py
@@ -444,7 +444,7 @@ class TestFunctionInlining(MemoryLeakMix
return bar(z + 2)
# block count changes with Python version due to bytecode differences.
- if utils.PYVERSION in ((3, 12), (3, 13), (3, 14)):
+ if utils.PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
bc = 39
elif utils.PYVERSION in ((3, 10), (3, 11)):
bc = 35
Index: numba/numba/tests/test_object_mode.py
===================================================================
--- numba.orig/numba/tests/test_object_mode.py
+++ numba/numba/tests/test_object_mode.py
@@ -91,7 +91,7 @@ class TestObjectMode(TestCase):
# This tests 'None in None' with the python interpreter. The error
# message has changed in 3.14.
- if PYVERSION in ((3, 14), ):
+ if PYVERSION in ((3, 14), (3, 15)):
expected_snippet = "is not a container or iterable"
elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
expected_snippet = "is not iterable"
Index: numba/numba/tests/test_operators.py
===================================================================
--- numba.orig/numba/tests/test_operators.py
+++ numba/numba/tests/test_operators.py
@@ -766,7 +766,7 @@ class TestOperators(TestCase):
cres(4j, 2j)
# error message depends on Python version.
- if utils.PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
+ if utils.PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
msg = "unsupported operand type(s) for %"
else:
raise NotImplementedError(utils.PYVERSION)
Index: numba/numba/tests/test_parfors.py
===================================================================
--- numba.orig/numba/tests/test_parfors.py
+++ numba/numba/tests/test_parfors.py
@@ -3567,7 +3567,7 @@ class TestPrangeBase(TestParforsBase):
prange_names.append('prange')
prange_names = tuple(prange_names)
prange_idx = len(prange_names) - 1
- if utils.PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
+ if utils.PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14), (3, 15)):
# this is the inverse of _fix_LOAD_GLOBAL_arg
prange_idx = 1 + (prange_idx << 1)
elif utils.PYVERSION in ((3, 10),):
Index: numba/numba/tests/test_sys_monitoring.py
===================================================================
--- numba.orig/numba/tests/test_sys_monitoring.py
+++ numba/numba/tests/test_sys_monitoring.py
@@ -31,7 +31,7 @@ def generate_usecase():
return foo, call_foo
-if PYVERSION in ((3, 12), (3, 13), (3, 14)):
+if PYVERSION in ((3, 12), (3, 13), (3, 14), (3, 15)):
PY_START = sys.monitoring.events.PY_START
PY_RETURN = sys.monitoring.events.PY_RETURN
RAISE = sys.monitoring.events.RAISE
Index: numba/numba/tests/test_try_except.py
===================================================================
--- numba.orig/numba/tests/test_try_except.py
+++ numba/numba/tests/test_try_except.py
@@ -15,6 +15,7 @@ from numba.tests.support import (
TestCase, unittest, captured_stdout, MemoryLeakMixin,
skip_parfors_unsupported, skip_unless_scipy, expected_failure_py311,
expected_failure_py312, expected_failure_py313, expected_failure_py314,
+ expected_failure_py315,
)
@@ -695,6 +696,7 @@ class TestTryExceptOtherControlFlow(Test
@expected_failure_py312
@expected_failure_py313
@expected_failure_py314
+ @expected_failure_py315
def test_objmode(self):
@njit
def udt():
@@ -717,6 +719,7 @@ class TestTryExceptOtherControlFlow(Test
@expected_failure_py312
@expected_failure_py313
@expected_failure_py314
+ @expected_failure_py315
def test_objmode_output_type(self):
def bar(x):
return np.asarray(list(reversed(x.tolist())))
Index: numba/numba/tests/test_unicode.py
===================================================================
--- numba.orig/numba/tests/test_unicode.py
+++ numba/numba/tests/test_unicode.py
@@ -2702,7 +2702,7 @@ class TestUnicodeAuxillary(BaseTest):
unsupported_errors = (UnsupportedError, UnsupportedBytecodeError)
with self.assertRaises(unsupported_errors) as raises:
njit(impl4)(["A", "B"])
- if PYVERSION in ((3, 13), (3, 14)):
+ if PYVERSION in ((3, 13), (3, 14), (3, 15)):
msg = "Use of unsupported opcode (FORMAT_WITH_SPEC)"
self.assertIn(msg, str(raises.exception))
elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
Index: numba/numba/tests/test_withlifting.py
===================================================================
--- numba.orig/numba/tests/test_withlifting.py
+++ numba/numba/tests/test_withlifting.py
@@ -19,6 +19,7 @@ from numba.tests.support import (MemoryL
expected_failure_py312,
expected_failure_py313,
expected_failure_py314,
+ expected_failure_py315,
)
from numba.core.utils import PYVERSION
from numba.experimental import jitclass
@@ -285,6 +286,7 @@ class TestLiftCall(BaseTestWithLifting):
@expected_failure_py312
@expected_failure_py313
@expected_failure_py314
+ @expected_failure_py315
def test_liftcall5(self):
self.check_extracted_with(liftcall5, expect_count=1,
expected_stdout="0\n1\n2\n3\n4\n5\nA\n")
@@ -726,6 +728,7 @@ class TestLiftObj(MemoryLeak, TestCase):
@expected_failure_py312
@expected_failure_py313
@expected_failure_py314
+ @expected_failure_py315
def test_case19_recursion(self):
def foo(x):
with objmode_context():
Index: numba/setup.py
===================================================================
--- numba.orig/setup.py
+++ numba/setup.py
@@ -20,7 +20,7 @@ except ImportError:
min_python_version = "3.10"
-max_python_version = "3.15" # exclusive
+max_python_version = "3.16" # exclusive
min_numpy_build_version = "2.0.0rc1"
min_numpy_run_version = "1.22"
max_numpy_run_version = "2.5"
@@ -403,6 +403,7 @@ metadata = dict(
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Topic :: Software Development :: Compilers",
],
package_data={