python-numba/py313.patch

4128 lines
145 KiB
Diff
Raw Normal View History

From 3e89582a41fc2712a0ce86528be98cf3dd768a23 Mon Sep 17 00:00:00 2001
From: Siu Kwan Lam <1929845+sklam@users.noreply.github.com>
Date: Tue, 16 Jan 2024 14:31:01 -0600
Subject: [PATCH 01/61] Minimal changes to get compiling
Added pythoncapi_compat.h from https://github.com/python/pythoncapi-compat
---
numba/_devicearray.cpp | 2 +-
numba/_dispatcher.cpp | 8 +-
numba/_dynfunc.c | 12 +-
numba/_helperlib.c | 4 +-
numba/_pymodule.h | 4 +
numba/_typeof.cpp | 8 +
numba/core/runtime/_nrt_python.c | 2 +-
numba/experimental/jitclass/_box.c | 2 +-
numba/mviewbuf.c | 2 +-
numba/np/ufunc/_internal.c | 4 +-
numba/pythoncapi_compat.h | 1114 ++++++++++++++++++++++++++++
setup.py | 2 +-
12 files changed, 1148 insertions(+), 16 deletions(-)
create mode 100644 numba/pythoncapi_compat.h
Index: numba-0.60.0/numba/_devicearray.cpp
===================================================================
--- numba-0.60.0.orig/numba/_devicearray.cpp
+++ numba-0.60.0/numba/_devicearray.cpp
@@ -96,7 +96,7 @@ PyTypeObject DeviceArrayType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/_dispatcher.cpp
===================================================================
--- numba-0.60.0.orig/numba/_dispatcher.cpp
+++ numba-0.60.0/numba/_dispatcher.cpp
@@ -27,7 +27,7 @@
*
*/
-#if (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 12)
+#if (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 12) || (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 13)
#ifndef Py_BUILD_CORE
#define Py_BUILD_CORE 1
@@ -39,7 +39,10 @@
# undef HAVE_STD_ATOMIC
#endif
#undef _PyGC_FINALIZED
-#include "internal/pycore_atomic.h"
+
+#if (PY_MINOR_VERSION == 12)
+ #include "internal/pycore_atomic.h"
+#endif
#include "internal/pycore_interp.h"
#include "internal/pycore_pyerrors.h"
#include "internal/pycore_instruments.h"
@@ -780,7 +783,7 @@ call_cfunc(Dispatcher *self, PyObject *c
}
}
-#elif (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 12)
+#elif (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13))
// Python 3.12 has a completely new approach to tracing and profiling due to
// the new `sys.monitoring` system.
@@ -1589,7 +1592,7 @@ static PyTypeObject DispatcherType = {
0, /* tp_version_tag */
0, /* tp_finalize */
0, /* tp_vectorcall */
-#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12)
+#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12) || (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 13)
/* This was introduced first in 3.12
* https://github.com/python/cpython/issues/91051
*/
@@ -1599,7 +1602,7 @@ static PyTypeObject DispatcherType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/_dynfunc.c
===================================================================
--- numba-0.60.0.orig/numba/_dynfunc.c
+++ numba-0.60.0/numba/_dynfunc.c
@@ -7,6 +7,12 @@
#include <string.h>
+
+// if python version is 3.13
+#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 13)
+ #include "pythoncapi_compat.h"
+ #define _Py_IsFinalizing Py_IsFinalizing
+#endif
/* NOTE: EnvironmentObject and ClosureObject must be kept in sync with
* the definitions in numba/targets/base.py (EnvBody and ClosureBody).
*/
@@ -146,7 +152,7 @@ static PyTypeObject EnvironmentType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
@@ -265,7 +271,7 @@ static PyTypeObject ClosureType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
@@ -485,7 +491,7 @@ static PyTypeObject GeneratorType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/_helperlib.c
===================================================================
--- numba-0.60.0.orig/numba/_helperlib.c
+++ numba-0.60.0/numba/_helperlib.c
@@ -293,7 +293,7 @@ numba_recreate_record(void *pdata, int s
return NULL;
}
- numpy = PyImport_ImportModuleNoBlock("numpy");
+ numpy = PyImport_ImportModule("numpy");
if (!numpy) goto CLEANUP;
numpy_record = PyObject_GetAttrString(numpy, "record");
@@ -833,7 +833,7 @@ static void traceback_add(const char *fu
if (!frame)
goto error;
-#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12) /* 3.12 */
+#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12) || (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 13) /* 3.12 or 3.13 */
#elif (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 11) /* 3.11 */
/* unsafe cast to our copy of _frame to access the f_lineno field */
@@ -851,7 +851,7 @@ static void traceback_add(const char *fu
Py_DECREF(frame);
return;
-#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12) /* 3.12 */
+#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 12) || (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION == 13) /* 3.12 or 3.13 */
error:
_PyErr_ChainExceptions1(exc);
#elif (PY_MAJOR_VERSION == 3) && ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11)) /* 3.11 and below */
Index: numba-0.60.0/numba/_pymodule.h
===================================================================
--- numba-0.60.0.orig/numba/_pymodule.h
+++ numba-0.60.0/numba/_pymodule.h
@@ -29,4 +29,7 @@
PyObject_SetAttrString(m, #name, tmp); \
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))
+
#endif /* NUMBA_PY_MODULE_H_ */
Index: numba-0.60.0/numba/_typeof.cpp
===================================================================
--- numba-0.60.0.orig/numba/_typeof.cpp
+++ numba-0.60.0/numba/_typeof.cpp
@@ -16,6 +16,14 @@
#include <numpy/npy_2_compat.h>
#endif
+#if (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION == 13)
+ #ifndef Py_BUILD_CORE
+ #define Py_BUILD_CORE 1
+ #endif
+ #include "internal/pycore_setobject.h" // _PySet_NextEntry()
+#endif
+
+
/* Cached typecodes for basic scalar types */
static int tc_int8;
static int tc_int16;
Index: numba-0.60.0/numba/core/runtime/_nrt_python.c
===================================================================
--- numba-0.60.0.orig/numba/core/runtime/_nrt_python.c
+++ numba-0.60.0/numba/core/runtime/_nrt_python.c
@@ -229,7 +229,7 @@ static PyTypeObject MemInfoType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/experimental/jitclass/_box.c
===================================================================
--- numba-0.60.0.orig/numba/experimental/jitclass/_box.c
+++ numba-0.60.0/numba/experimental/jitclass/_box.c
@@ -110,7 +110,7 @@ static PyTypeObject BoxType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/mviewbuf.c
===================================================================
--- numba-0.60.0.orig/numba/mviewbuf.c
+++ numba-0.60.0/numba/mviewbuf.c
@@ -344,7 +344,7 @@ static PyTypeObject MemAllocType = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/np/ufunc/_internal.c
===================================================================
--- numba-0.60.0.orig/numba/np/ufunc/_internal.c
+++ numba-0.60.0/numba/np/ufunc/_internal.c
@@ -100,7 +100,7 @@ PyTypeObject PyUFuncCleaner_Type = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
@@ -753,7 +753,7 @@ PyTypeObject PyDUFunc_Type = {
/* WARNING: Do not remove this, only modify it! It is a version guard to
* act as a reminder to update this struct on Python version update! */
#if (PY_MAJOR_VERSION == 3)
-#if ! ((PY_MINOR_VERSION == 9) || (PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12))
+#if ! (NB_SUPPORTED_PYTHON_MINOR)
#error "Python minor version is not supported."
#endif
#else
Index: numba-0.60.0/numba/core/bytecode.py
===================================================================
--- numba-0.60.0.orig/numba/core/bytecode.py
+++ numba-0.60.0/numba/core/bytecode.py
@@ -9,7 +9,7 @@ from numba.core import errors, utils, se
from numba.core.utils import PYVERSION
-if PYVERSION in ((3, 12), ):
+if PYVERSION in ((3, 12), (3, 13)):
from opcode import _inline_cache_entries
# Instruction/opcode length in bytes
INSTR_LEN = 2
@@ -104,7 +104,12 @@ class ByteCodeInst(object):
# https://bugs.python.org/issue27129
# https://github.com/python/cpython/pull/25069
assert self.is_jump
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 13),):
+ if self.opcode in (dis.opmap[k]
+ for k in ["JUMP_BACKWARD",
+ "JUMP_BACKWARD_NO_INTERRUPT"]):
+ return self.next - (self.arg * 2)
+ elif PYVERSION in ((3, 12),):
if self.opcode in (dis.opmap[k]
for k in ["JUMP_BACKWARD"]):
return self.offset - (self.arg - 1) * 2
@@ -121,7 +126,7 @@ class ByteCodeInst(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
if self.opcode in JREL_OPS:
return self.next + self.arg * 2
else:
@@ -160,7 +165,7 @@ OPCODE_NOP = dis.opname.index('NOP')
# Adapted from Lib/dis.py
-def _unpack_opargs(code):
+def _unpack_opargs_pre_3_13(code):
"""
Returns a 4-int-tuple of
(bytecode offset, opcode, argument, offset of next bytecode).
@@ -176,7 +181,7 @@ def _unpack_opargs(code):
for j in range(ARG_LEN):
arg |= code[i + j] << (8 * j)
i += ARG_LEN
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12),):
# Python 3.12 introduced cache slots. We need to account for
# cache slots when we determine the offset of the next opcode.
# The number of cache slots is specific to each opcode and can
@@ -200,7 +205,7 @@ def _unpack_opargs(code):
else:
arg = None
i += NO_ARG_LEN
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12),):
# Python 3.12 introduced cache slots. We need to account for
# cache slots when we determine the offset of the next opcode.
# The number of cache slots is specific to each opcode and can
@@ -216,6 +221,80 @@ def _unpack_opargs(code):
offset = i # Mark inst offset at first extended
+# Adapted from Lib/dis.py
+def _unpack_opargs_pre_3_13(code):
+ """
+ Returns a 4-int-tuple of
+ (bytecode offset, opcode, argument, offset of next bytecode).
+ """
+ extended_arg = 0
+ n = len(code)
+ offset = i = 0
+ while i < n:
+ op = code[i]
+ i += CODE_LEN
+ if op >= HAVE_ARGUMENT:
+ arg = code[i] | extended_arg
+ for j in range(ARG_LEN):
+ arg |= code[i + j] << (8 * j)
+ i += ARG_LEN
+ if PYVERSION in ((3, 12),):
+ # Python 3.12 introduced cache slots. We need to account for
+ # cache slots when we determine the offset of the next opcode.
+ # The number of cache slots is specific to each opcode and can
+ # be looked up in the _inline_cache_entries dictionary.
+ i += _inline_cache_entries[op] * INSTR_LEN
+ elif PYVERSION in ((3, 10), (3, 11)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+ if op == EXTENDED_ARG:
+ # This is a deviation from what dis does...
+ # In python 3.11 it seems like EXTENDED_ARGs appear more often
+ # and are also used as jump targets. So as to not have to do
+ # "book keeping" for where EXTENDED_ARGs have been "skipped"
+ # they are replaced with NOPs so as to provide a legal jump
+ # target and also ensure that the bytecode offsets are correct.
+ yield (offset, OPCODE_NOP, arg, i)
+ extended_arg = arg << 8 * ARG_LEN
+ offset = i
+ continue
+ else:
+ arg = None
+ i += NO_ARG_LEN
+ if PYVERSION in ((3, 12),):
+ # Python 3.12 introduced cache slots. We need to account for
+ # cache slots when we determine the offset of the next opcode.
+ # The number of cache slots is specific to each opcode and can
+ # be looked up in the _inline_cache_entries dictionary.
+ i += _inline_cache_entries[op] * INSTR_LEN
+ elif PYVERSION in ((3, 10), (3, 11)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
+ extended_arg = 0
+ yield (offset, op, arg, i)
+ offset = i # Mark inst offset at first extended
+
+
+if PYVERSION in ((3, 13),):
+
+ def _unpack_opargs(code):
+ buf = []
+ for i, start_offset, op, arg in dis._unpack_opargs(code):
+ buf.append((start_offset, op, arg))
+ for i, (start_offset, op, arg) in enumerate(buf):
+ if i + 1 < len(buf):
+ next_offset = buf[i + 1][0]
+ else:
+ next_offset = len(code)
+ yield (start_offset, op, arg, next_offset)
+
+else:
+ _unpack_opargs = _unpack_opargs_pre_3_13
+
+
def _patched_opargs(bc_stream):
"""Patch the bytecode stream.
@@ -298,7 +377,7 @@ class _ByteCode(object):
# Start with first bytecode's lineno
known = code.co_firstlineno
for inst in table.values():
- if inst.lineno >= 0:
+ if inst.lineno is not None and inst.lineno >= 0:
known = inst.lineno
else:
inst.lineno = known
@@ -363,7 +442,7 @@ class _ByteCode(object):
def _fix_LOAD_GLOBAL_arg(arg):
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
return arg >> 1
elif PYVERSION in ((3, 9), (3, 10)):
return arg
@@ -452,8 +531,15 @@ class ByteCodePy312(ByteCodePy311):
entirely along with the dead exceptions that it points to.
A pair of exception that sandwiches these exception will
also be merged into a single exception.
- """
+ Update for Python 3.13, the ending of the pattern has a extra
+ POP_TOP:
+
+ ...
+ END_FOR
+ POP_TOP
+ SWAP(2)
+ """
def pop_and_merge_exceptions(entries: list,
entry_to_remove: _ExceptionTableEntry):
lower_entry_idx = entries.index(entry_to_remove) - 1
@@ -505,17 +591,34 @@ class ByteCodePy312(ByteCodePy311):
if not next_inst.opname == "FOR_ITER":
continue
- # Check end of pattern, two instructions.
- # Check for the corresponding END_FOR, exception table end is
- # non-inclusive, so subtract one.
- index = self.ordered_offsets.index(entry.end)
- curr_inst = self.table[self.ordered_offsets[index - 1]]
- if not curr_inst.opname == "END_FOR":
- continue
- # END_FOR must be followed by SWAP(2)
- next_inst = self.table[self.ordered_offsets[index]]
- if not next_inst.opname == "SWAP" and next_inst.arg == 2:
- continue
+ if PYVERSION == (3, 13):
+ # Check end of pattern, two instructions.
+ # Check for the corresponding END_FOR, exception table end
+ # is non-inclusive, so subtract one.
+ index = self.ordered_offsets.index(entry.end)
+ curr_inst = self.table[self.ordered_offsets[index - 2]]
+ if not curr_inst.opname == "END_FOR":
+ continue
+ next_inst = self.table[self.ordered_offsets[index - 1]]
+ if not next_inst.opname == "POP_TOP":
+ continue
+ # END_FOR must be followed by SWAP(2)
+ next_inst = self.table[self.ordered_offsets[index]]
+ if not next_inst.opname == "SWAP" and next_inst.arg == 2:
+ continue
+ else:
+ assert PYVERSION < (3, 13)
+ # Check end of pattern, two instructions.
+ # Check for the corresponding END_FOR, exception table end
+ # is non-inclusive, so subtract one.
+ index = self.ordered_offsets.index(entry.end)
+ curr_inst = self.table[self.ordered_offsets[index - 1]]
+ if not curr_inst.opname == "END_FOR":
+ continue
+ # END_FOR must be followed by SWAP(2)
+ next_inst = self.table[self.ordered_offsets[index]]
+ if not next_inst.opname == "SWAP" and next_inst.arg == 2:
+ continue
# If all conditions are met that means this exception entry
# is for a list/dict/set comprehension and can be removed.
# Also if there exist exception entries above and below this
@@ -528,7 +631,7 @@ class ByteCodePy312(ByteCodePy311):
if PYVERSION == (3, 11):
ByteCode = ByteCodePy311
-elif PYVERSION == (3, 12):
+elif PYVERSION in ((3, 12), (3, 13),):
ByteCode = ByteCodePy312
elif PYVERSION < (3, 11):
ByteCode = _ByteCode
Index: numba-0.60.0/numba/core/byteflow.py
===================================================================
--- numba-0.60.0.orig/numba/core/byteflow.py
+++ numba-0.60.0/numba/core/byteflow.py
@@ -10,7 +10,7 @@ from functools import total_ordering
from numba.core.utils import UniqueDict, PYVERSION, ALL_BINOPS_TO_OPERATORS
from numba.core.controlflow import NEW_BLOCKERS, CFGraph
from numba.core.ir import Loc
-from numba.core.errors import UnsupportedError
+from numba.core.errors import UnsupportedBytecodeError
_logger = logging.getLogger(__name__)
@@ -24,7 +24,7 @@ _NO_RAISE_OPS = frozenset({
'PRECALL',
})
-if PYVERSION in ((3, 12), ):
+if PYVERSION in ((3, 12), (3, 13)):
from enum import Enum
# Operands for CALL_INTRINSIC_1
@@ -149,7 +149,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def _run_handle_exception(self, runner, state):
if not state.in_with() and (
state.has_active_try() and
@@ -312,7 +312,7 @@ class Flow(object):
msg = ("The 'with (context manager) as "
"(variable):' construct is not "
"supported.")
- raise UnsupportedError(msg)
+ raise UnsupportedBytecodeError(msg)
def _is_null_temp_reg(reg):
@@ -331,7 +331,7 @@ class TraceRunner(object):
return Loc(self.debug_filename, lineno)
def dispatch(self, state):
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
if state._blockstack:
state: State
while state._blockstack:
@@ -354,7 +354,8 @@ class TraceRunner(object):
fn(state, inst)
else:
msg = "Use of unsupported opcode (%s) found" % inst.opname
- raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno))
+ raise UnsupportedBytecodeError(msg,
+ loc=self.get_debug_loc(inst.lineno))
def _adjust_except_stack(self, state):
"""
@@ -405,6 +406,15 @@ class TraceRunner(object):
state.push(state.make_temp())
state.append(inst)
+ if PYVERSION in ((3, 13),):
+ def op_FORMAT_SIMPLE(self, state, inst):
+ assert PYVERSION == (3, 13)
+ value = state.pop()
+ strvar = state.make_temp()
+ res = state.make_temp()
+ state.append(inst, value=value, res=res, strvar=strvar)
+ state.push(res)
+
def op_FORMAT_VALUE(self, state, inst):
"""
FORMAT_VALUE(flags): flags argument specifies format spec which is
@@ -415,7 +425,8 @@ class TraceRunner(object):
"""
if inst.arg != 0:
msg = "format spec in f-strings not supported yet"
- raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno))
+ raise UnsupportedBytecodeError(msg,
+ loc=self.get_debug_loc(inst.lineno))
value = state.pop()
strvar = state.make_temp()
res = state.make_temp()
@@ -442,7 +453,27 @@ class TraceRunner(object):
def op_POP_TOP(self, state, inst):
state.pop()
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 13),):
+ def op_TO_BOOL(self, state, inst):
+ res = state.make_temp()
+ tos = state.pop()
+ state.append(inst, val=tos, res=res)
+ state.push(res)
+
+ elif PYVERSION < (3, 13):
+ pass
+
+ if PYVERSION in ((3, 13),):
+ def op_LOAD_GLOBAL(self, state, inst):
+ # Ordering of the global value and NULL is swapped in Py3.13
+ res = state.make_temp()
+ idx = inst.arg >> 1
+ state.append(inst, idx=idx, res=res)
+ state.push(res)
+ # ignoring the NULL
+ if inst.arg & 1:
+ state.push(state.make_null())
+ elif PYVERSION in ((3, 11), (3, 12)):
def op_LOAD_GLOBAL(self, state, inst):
res = state.make_temp()
idx = inst.arg >> 1
@@ -471,30 +502,89 @@ class TraceRunner(object):
state.push(res)
def op_LOAD_CONST(self, state, inst):
- res = state.make_temp("const")
+ # append const index for interpreter to read the const value
+ res = state.make_temp("const") + f".{inst.arg}"
state.push(res)
state.append(inst, res=res)
def op_LOAD_ATTR(self, state, inst):
item = state.pop()
- if PYVERSION in ((3, 12), ):
+ res = state.make_temp()
+ if PYVERSION in ((3, 13),):
+ state.push(res) # the attr
+ if inst.arg & 1:
+ state.push(state.make_null())
+ elif PYVERSION in ((3, 12),):
if inst.arg & 1:
state.push(state.make_null())
+ state.push(res)
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
- pass
+ state.push(res)
else:
raise NotImplementedError(PYVERSION)
- res = state.make_temp()
state.append(inst, item=item, res=res)
- state.push(res)
def op_LOAD_FAST(self, state, inst):
- name = state.get_varname(inst)
+ assert PYVERSION <= (3, 13)
+ if PYVERSION in ((3, 13), ):
+ try:
+ name = state.get_varname(inst)
+ except IndexError: # oparg is out of range
+ # Handle this like a LOAD_DEREF
+ # Assume MAKE_CELL and COPY_FREE_VARS has correctly setup the
+ # states.
+ # According to https://github.com/python/cpython/blob/9ac606080a0074cdf7589d9b7c9413a73e0ddf37/Objects/codeobject.c#L730C9-L759 # noqa E501
+ # localsplus is locals + cells + freevars
+ bc = state._bytecode
+ num_varnames = len(bc.co_varnames)
+ num_freevars = len(bc.co_freevars)
+ num_cellvars = len(bc.co_cellvars)
+ max_fast_local = num_cellvars + num_freevars
+ assert 0 <= inst.arg - num_varnames < max_fast_local
+ res = state.make_temp()
+ state.append(inst, res=res, as_load_deref=True)
+ state.push(res)
+ return
+ else:
+ name = state.get_varname(inst)
res = state.make_temp(name)
state.append(inst, res=res)
state.push(res)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 13),):
+ def op_LOAD_FAST_LOAD_FAST(self, state, inst):
+ oparg = inst.arg
+ oparg1 = oparg >> 4
+ oparg2 = oparg & 15
+ name1 = state.get_varname_by_arg(oparg1)
+ name2 = state.get_varname_by_arg(oparg2)
+ res1 = state.make_temp(name1)
+ res2 = state.make_temp(name2)
+ state.append(inst, res1=res1, res2=res2)
+ state.push(res1)
+ state.push(res2)
+
+ def op_STORE_FAST_LOAD_FAST(self, state, inst):
+ oparg = inst.arg
+ # oparg1 = oparg >> 4 # not needed
+ oparg2 = oparg & 15
+ store_value = state.pop()
+ load_name = state.get_varname_by_arg(oparg2)
+ load_res = state.make_temp(load_name)
+ state.append(inst, store_value=store_value, load_res=load_res)
+ state.push(load_res)
+
+ def op_STORE_FAST_STORE_FAST(self, state, inst):
+ value1 = state.pop()
+ value2 = state.pop()
+ state.append(inst, value1=value1, value2=value2)
+
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
+ if PYVERSION in ((3, 12), (3, 13)):
op_LOAD_FAST_CHECK = op_LOAD_FAST
op_LOAD_FAST_AND_CLEAR = op_LOAD_FAST
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
@@ -753,7 +843,7 @@ class TraceRunner(object):
)
state.push(res)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_BINARY_SLICE(self, state, inst):
end = state.pop()
start = state.pop()
@@ -771,7 +861,7 @@ class TraceRunner(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_STORE_SLICE(self, state, inst):
end = state.pop()
start = state.pop()
@@ -804,7 +894,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), ):
+ if PYVERSION in ((3, 12), (3, 13)):
op_POP_JUMP_IF_NONE = _op_POP_JUMP_IF
op_POP_JUMP_IF_NOT_NONE = _op_POP_JUMP_IF
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
@@ -853,6 +943,8 @@ class TraceRunner(object):
state.append(inst)
state.fork(pc=inst.get_jump_target())
+ op_JUMP_BACKWARD_NO_INTERRUPT = op_JUMP_BACKWARD
+
def op_JUMP_ABSOLUTE(self, state, inst):
state.append(inst)
state.fork(pc=inst.get_jump_target())
@@ -868,7 +960,7 @@ class TraceRunner(object):
state.append(inst, retval=state.pop(), castval=state.make_temp())
state.terminate()
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_RETURN_CONST(self, state, inst):
res = state.make_temp("const")
state.append(inst, retval=res, castval=state.make_temp())
@@ -884,14 +976,14 @@ class TraceRunner(object):
state.append(inst, value=val, res=res)
state.push(res)
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_RAISE_VARARGS(self, state, inst):
if inst.arg == 0:
exc = None
# No re-raising within a try-except block.
# But we allow bare reraise.
if state.has_active_try():
- raise UnsupportedError(
+ raise UnsupportedBytecodeError(
"The re-raising of an exception is not yet supported.",
loc=self.get_debug_loc(inst.lineno),
)
@@ -915,7 +1007,7 @@ class TraceRunner(object):
if inst.arg == 0:
exc = None
if in_exc_block:
- raise UnsupportedError(
+ raise UnsupportedBytecodeError(
"The re-raising of an exception is not yet supported.",
loc=self.get_debug_loc(inst.lineno),
)
@@ -940,7 +1032,10 @@ class TraceRunner(object):
blk = state.pop_block()
state.reset_stack(blk['entry_stack'])
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 13),):
+ def op_END_FOR(self, state, inst):
+ state.pop()
+ elif PYVERSION in ((3, 12),):
def op_END_FOR(self, state, inst):
state.pop()
state.pop()
@@ -954,7 +1049,8 @@ class TraceRunner(object):
if inst.arg != 0:
msg = ('Unsupported use of a bytecode related to try..finally'
' or a with-context')
- raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno))
+ raise UnsupportedBytecodeError(msg,
+ loc=self.get_debug_loc(inst.lineno))
def op_CALL_FINALLY(self, state, inst):
pass
@@ -1068,7 +1164,7 @@ class TraceRunner(object):
'FINALLY', state, next=inst.next, end=inst.get_jump_target(),
)
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_POP_EXCEPT(self, state, inst):
state.pop()
@@ -1076,7 +1172,7 @@ class TraceRunner(object):
def op_POP_EXCEPT(self, state, inst):
blk = state.pop_block()
if blk['kind'] not in {BlockKind('EXCEPT'), BlockKind('FINALLY')}:
- raise UnsupportedError(
+ raise UnsupportedBytecodeError(
f"POP_EXCEPT got an unexpected block: {blk['kind']}",
loc=self.get_debug_loc(inst.lineno),
)
@@ -1117,16 +1213,24 @@ class TraceRunner(object):
def op_CALL(self, state, inst):
narg = inst.arg
args = list(reversed([state.pop() for _ in range(narg)]))
- callable_or_firstarg = state.pop()
- null_or_callable = state.pop()
- if _is_null_temp_reg(null_or_callable):
- callable = callable_or_firstarg
- else:
- callable = null_or_callable
- args = [callable_or_firstarg, *args]
+ if PYVERSION == (3, 13):
+ null_or_self = state.pop()
+ # position of the callable is fixed
+ callable = state.pop()
+ if not _is_null_temp_reg(null_or_self):
+ args = [null_or_self, *args]
+ kw_names = None
+ elif PYVERSION < (3, 13):
+ callable_or_firstarg = state.pop()
+ null_or_callable = state.pop()
+ if _is_null_temp_reg(null_or_callable):
+ callable = callable_or_firstarg
+ else:
+ callable = null_or_callable
+ args = [callable_or_firstarg, *args]
+ kw_names = state.pop_kw_names()
res = state.make_temp()
- kw_names = state.pop_kw_names()
state.append(inst, func=callable, args=args, kw_names=kw_names, res=res)
state.push(res)
@@ -1152,28 +1256,67 @@ class TraceRunner(object):
state.append(inst, func=func, args=args, names=names, res=res)
state.push(res)
- def op_CALL_FUNCTION_EX(self, state, inst):
- if inst.arg & 1 and PYVERSION < (3, 10):
- errmsg = "CALL_FUNCTION_EX with **kwargs not supported"
- raise UnsupportedError(errmsg)
- if inst.arg & 1:
- varkwarg = state.pop()
- else:
- varkwarg = None
- vararg = state.pop()
- func = state.pop()
+ if PYVERSION in ((3, 13),):
+ def op_CALL_KW(self, state, inst):
+ narg = inst.arg
+ kw_names = state.pop()
+ args = list(reversed([state.pop() for _ in range(narg)]))
+ null_or_firstarg = state.pop()
+ callable = state.pop()
+ if not _is_null_temp_reg(null_or_firstarg):
+ args = [null_or_firstarg, *args]
- if PYVERSION in ((3, 11), (3, 12)):
- if _is_null_temp_reg(state.peek(1)):
- state.pop() # pop NULL, it's not used
- elif PYVERSION in ((3, 9), (3, 10)):
- pass
- else:
- raise NotImplementedError(PYVERSION)
+ res = state.make_temp()
+ state.append(inst, func=callable, args=args, kw_names=kw_names,
+ res=res)
+ state.push(res)
- res = state.make_temp()
- state.append(inst, func=func, vararg=vararg, varkwarg=varkwarg, res=res)
- state.push(res)
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
+ if PYVERSION in ((3, 13),):
+ def op_CALL_FUNCTION_EX(self, state, inst):
+ # (func, unused, callargs, kwargs if (oparg & 1) -- result))
+ if inst.arg & 1:
+ varkwarg = state.pop()
+ else:
+ varkwarg = None
+
+ vararg = state.pop()
+ state.pop() # unused
+ func = state.pop()
+
+ res = state.make_temp()
+ state.append(inst, func=func, vararg=vararg, varkwarg=varkwarg,
+ res=res)
+ state.push(res)
+
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+
+ def op_CALL_FUNCTION_EX(self, state, inst):
+ if inst.arg & 1:
+ varkwarg = state.pop()
+ else:
+ varkwarg = None
+ vararg = state.pop()
+ func = state.pop()
+
+ if PYVERSION in ((3, 11), (3, 12)):
+ if _is_null_temp_reg(state.peek(1)):
+ state.pop() # pop NULL, it's not used
+ elif PYVERSION in ((3, 9), (3, 10)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
+ res = state.make_temp()
+ state.append(inst, func=func, vararg=vararg, varkwarg=varkwarg,
+ res=res)
+ state.push(res)
+ else:
+ raise NotImplementedError(PYVERSION)
def _dup_topx(self, state, inst, count):
orig = [state.pop() for _ in range(count)]
@@ -1187,7 +1330,7 @@ class TraceRunner(object):
for val in duped:
state.push(val)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
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
@@ -1404,7 +1547,7 @@ class TraceRunner(object):
pred=pred)
state.push(indval)
end = inst.get_jump_target()
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
# 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.
@@ -1490,7 +1633,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
# https://github.com/python/cpython/commit/2f180ce
# name set via co_qualname
name = None
@@ -1500,14 +1643,19 @@ class TraceRunner(object):
raise NotImplementedError(PYVERSION)
code = state.pop()
closure = annotations = kwdefaults = defaults = None
- if inst.arg & 0x8:
- closure = state.pop()
- if inst.arg & 0x4:
- annotations = state.pop()
- if inst.arg & 0x2:
- kwdefaults = state.pop()
- if inst.arg & 0x1:
- defaults = state.pop()
+ if PYVERSION in ((3, 13), ):
+ assert inst.arg is None
+ # SET_FUNCTION_ATTRIBUTE is responsible for setting
+ # closure, annotations, kwdefaults and defaults.
+ else:
+ if inst.arg & 0x8:
+ closure = state.pop()
+ if inst.arg & 0x4:
+ annotations = state.pop()
+ if inst.arg & 0x2:
+ kwdefaults = state.pop()
+ if inst.arg & 0x1:
+ defaults = state.pop()
res = state.make_temp()
state.append(
inst,
@@ -1521,6 +1669,27 @@ class TraceRunner(object):
)
state.push(res)
+ def op_SET_FUNCTION_ATTRIBUTE(self, state, inst):
+ assert PYVERSION in ((3, 13), )
+ make_func_stack = state.pop()
+ data = state.pop()
+ if inst.arg == 0x1:
+ # 0x01 a tuple of default values for positional-only and
+ # positional-or-keyword parameters in positional order
+ state.set_function_attribute(make_func_stack, defaults=data)
+ elif inst.arg & 0x2:
+ # 0x02 a tuple of strings containing parameters annotations
+ state.set_function_attribute(make_func_stack, kwdefaults=data)
+ elif inst.arg & 0x4:
+ # 0x04 a tuple of strings containing parameters annotations
+ state.set_function_attribute(make_func_stack, annotations=data)
+ elif inst.arg == 0x8:
+ # 0x08 a tuple containing cells for free variables, making a closure
+ state.set_function_attribute(make_func_stack, closure=data)
+ else:
+ raise AssertionError("unreachable")
+ state.push(make_func_stack)
+
def op_MAKE_CLOSURE(self, state, inst):
self.op_MAKE_FUNCTION(state, inst, MAKE_CLOSURE=True)
@@ -1551,7 +1720,7 @@ class TraceRunner(object):
state.fork(pc=inst.next)
state.fork(pc=inst.get_jump_target())
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_RERAISE(self, state, inst):
# This isn't handled, but the state is set up anyway
exc = state.pop()
@@ -1576,7 +1745,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), ):
+ if PYVERSION in ((3, 12), (3, 13)):
# LOAD_METHOD has become a pseudo-instruction in 3.12
pass
elif PYVERSION in ((3, 11), ):
@@ -1828,9 +1997,14 @@ class _State(object):
return self.get_top_block('TRY') is not None
def get_varname(self, inst):
+ """Get referenced variable name from the instruction's oparg
+ """
+ return self.get_varname_by_arg(inst.arg)
+
+ def get_varname_by_arg(self, oparg: int):
"""Get referenced variable name from the oparg
"""
- return self._bytecode.co_varnames[inst.arg]
+ return self._bytecode.co_varnames[oparg]
def terminate(self):
"""Mark block as terminated
@@ -1852,7 +2026,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
# pop expired block in destination pc
while blockstack:
top = blockstack[-1]
@@ -1940,7 +2114,21 @@ class StatePy311(_State):
return self.make_temp(prefix="null$")
-if PYVERSION >= (3, 11):
+class StatePy313(StatePy311):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._make_func_attrs = defaultdict(dict)
+
+ def set_function_attribute(self, make_func_res, **kwargs):
+ self._make_func_attrs[make_func_res].update(kwargs)
+
+ def get_function_attributes(self, make_func_res):
+ return self._make_func_attrs[make_func_res]
+
+
+if PYVERSION in ((3, 13), ):
+ State = StatePy313
+elif PYVERSION in ((3, 11), (3, 12)):
State = StatePy311
elif PYVERSION < (3, 11):
State = _State
@@ -1970,8 +2158,20 @@ AdaptBlockInfo = namedtuple(
def adapt_state_infos(state):
+ def process_function_attributes(inst_pair):
+ offset, data = inst_pair
+ inst = state._bytecode[offset]
+ if inst.opname == "MAKE_FUNCTION":
+ data.update(state.get_function_attributes(data['res']))
+ return offset, data
+ if PYVERSION in ((3, 13), ):
+ insts = tuple(map(process_function_attributes, state.instructions))
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ insts = tuple(state.instructions)
+ else:
+ raise NotImplementedError(PYVERSION)
return AdaptBlockInfo(
- insts=tuple(state.instructions),
+ insts=insts,
outgoing_phis=state.outgoing_phis,
blockstack=state.blockstack_initial,
active_try_block=state.find_initial_try_block(),
Index: numba-0.60.0/numba/core/controlflow.py
===================================================================
--- numba-0.60.0.orig/numba/core/controlflow.py
+++ numba-0.60.0/numba/core/controlflow.py
@@ -954,7 +954,7 @@ class ControlFlowAnalysis(object):
self._curblock.terminating = True
self._force_new_block = True
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_RETURN_CONST(self, inst):
self._curblock.terminating = True
self._force_new_block = True
Index: numba-0.60.0/numba/core/interpreter.py
===================================================================
--- numba-0.60.0.orig/numba/core/interpreter.py
+++ numba-0.60.0/numba/core/interpreter.py
@@ -6,7 +6,11 @@ import logging
import textwrap
from numba.core import errors, ir, config
-from numba.core.errors import NotDefinedError, UnsupportedError, error_extras
+from numba.core.errors import (
+ NotDefinedError,
+ UnsupportedBytecodeError,
+ error_extras,
+)
from numba.core.ir_utils import get_definition, guard
from numba.core.utils import (PYVERSION, BINOPS_TO_OPERATORS,
INPLACE_BINOPS_TO_OPERATORS,)
@@ -15,7 +19,7 @@ from numba.core.unsafe import eh
from numba.cpython.unsafe.tuple import unpack_single_tuple
-if PYVERSION in ((3, 12), ):
+if PYVERSION in ((3, 12), (3, 13)):
# Operands for CALL_INTRINSIC_1
from numba.core.byteflow import CALL_INTRINSIC_1_Operand as ci1op
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
@@ -108,7 +112,7 @@ def _remove_assignment_definition(old_bo
func_ir._definitions[lhs].remove(rhs)
already_deleted_defs[lhs].add(rhs)
elif rhs not in already_deleted_defs[lhs]:
- raise UnsupportedError(
+ raise UnsupportedBytecodeError(
"Inconsistency found in the definitions while executing"
" a peephole optimization. This suggests an internal"
" error or inconsistency elsewhere in the compiler."
@@ -211,7 +215,7 @@ def _call_function_ex_replace_kws_large(
):
# We cannot handle this format so raise the
# original error message.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
key_var_name = const_stmt.target.name
key_val = const_stmt.value.value
search_start += 1
@@ -257,7 +261,7 @@ def _call_function_ex_replace_kws_large(
):
# We cannot handle this format so raise the
# original error message.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
setitem_stmt = old_body[search_start + 1]
if not (
isinstance(setitem_stmt, ir.Assign)
@@ -277,7 +281,7 @@ def _call_function_ex_replace_kws_large(
# getattr. If for some reason this doesn't match the code
# format, we raise the original error message. This check
# is meant as a precaution.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
arg_var = setitem_stmt.value.args[1]
# Append the (key, value) pair.
kws.append((key_val, arg_var))
@@ -421,7 +425,7 @@ def _call_function_ex_replace_args_large
and concat_stmt.value.fn == operator.add
):
# We cannot handle this format.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
lhs_name = concat_stmt.value.lhs.name
rhs_name = concat_stmt.value.rhs.name
# The previous statement should be a
@@ -439,7 +443,7 @@ def _call_function_ex_replace_args_large
and len(arg_tuple_stmt.value.items) == 1
):
# We cannot handle this format.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
if arg_tuple_stmt.target.name == lhs_name:
# The tuple should always be generated on the RHS.
raise AssertionError("unreachable")
@@ -447,7 +451,7 @@ def _call_function_ex_replace_args_large
target_name = lhs_name
else:
# We cannot handle this format.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
total_args.append(
arg_tuple_stmt.value.items[0]
)
@@ -497,7 +501,7 @@ def _call_function_ex_replace_args_large
# If we reached the start we never found the build_tuple.
# We cannot handle this format so raise the
# original error message.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
# Reverse the arguments so we get the correct order.
return total_args[::-1]
@@ -586,7 +590,7 @@ def peep_hole_call_function_ex_to_call_f
# If we couldn't find where the kwargs are created
# then it should be a normal **kwargs call
# so we produce an unsupported message.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
# Determine the kws
if keyword_def.value.items:
# n_kws <= 15 case.
@@ -638,7 +642,7 @@ def peep_hole_call_function_ex_to_call_f
if args:
# If we have vararg then args is expected to
# be an empty list.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
vararg_loc = start_search
args_def = None
found = False
@@ -654,7 +658,7 @@ def peep_hole_call_function_ex_to_call_f
if not found:
# If we couldn't find where the args are created
# then we can't handle this format.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
if (
isinstance(args_def.value, ir.Expr)
and args_def.value.op == "build_tuple"
@@ -683,7 +687,7 @@ def peep_hole_call_function_ex_to_call_f
# If there is a call with vararg we need to check
# if the list -> tuple conversion failed and if so
# throw an error.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
else:
# Here the IR is an initial empty build_tuple.
# Then for each arg, a new tuple with a single
@@ -747,7 +751,7 @@ def peep_hole_call_function_ex_to_call_f
# exception.
expr = func_ir._definitions[vararg_name][0]
if isinstance(expr, ir.Expr) and expr.op == "list_to_tuple":
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
new_body.append(stmt)
# Replace the block body if we changed the IR
@@ -1197,7 +1201,7 @@ def peep_hole_fuse_dict_add_updates(func
else:
# If we cannot remove _update_from_bytecode
# Then raise an error for the user.
- raise UnsupportedError(errmsg)
+ raise UnsupportedBytecodeError(errmsg)
# Check if we need to drop any maps from being tracked.
# Skip the setitem/_update_from_bytecode getattr that
@@ -1385,7 +1389,7 @@ class Interpreter(object):
max(inst_blocks.body))
self.last_active_offset = last_active_offset
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
self.active_exception_entries = tuple(
[entry for entry in self.bytecode.exception_entries
if entry.start < self.last_active_offset])
@@ -1401,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
# Insert end of try markers
self._end_try_blocks()
elif PYVERSION in ((3, 9), (3, 10)):
@@ -1418,12 +1422,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
peepholes.append(peep_hole_split_at_pop_block)
- if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
+ if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13)):
peepholes.append(peep_hole_list_to_tuple)
peepholes.append(peep_hole_delete_with_exit)
- if PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
# 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
@@ -1456,7 +1460,7 @@ class Interpreter(object):
See also: _insert_try_block_end
"""
- assert PYVERSION in ((3, 11), (3, 12))
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13))
graph = self.cfa.graph
for offset, block in self.blocks.items():
# Get current blockstack
@@ -1507,7 +1511,7 @@ class Interpreter(object):
first = uservar[0]
loc = self.current_scope.get(first).loc
msg = "Exception object cannot be stored into variable ({})."
- raise errors.UnsupportedError(msg.format(first), loc=loc)
+ raise errors.UnsupportedBytecodeError(msg.format(first), loc=loc)
def init_first_block(self):
# Define variables receiving the function arguments
@@ -1564,7 +1568,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)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
# This is recreating pre-3.11 code structure
while self.syntax_blocks:
if offset >= self.syntax_blocks[-1].exit:
@@ -1735,7 +1739,7 @@ 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)), \
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13)), \
"unexpected missing definition"
val = ir.Const(value=None, loc=self.loc)
stmt = ir.Assign(value=val, target=target,
@@ -1795,7 +1799,7 @@ class Interpreter(object):
if self._DEBUG_PRINT:
print(inst)
assert self.current_block is not None
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
if self.syntax_blocks:
top = self.syntax_blocks[-1]
if isinstance(top, ir.With) :
@@ -1825,6 +1829,9 @@ class Interpreter(object):
if not config.FULL_TRACEBACKS:
raise err from None
else:
+ m = f"handling op: {inst} | offset: {inst.offset}"
+ err.add_context(m)
+ err.add_context(self.bytecode.dump())
raise err
# --- Scope operations ---
@@ -1921,6 +1928,10 @@ class Interpreter(object):
loc=self.loc)
self.store(expr, st)
+ def op_FORMAT_SIMPLE(self, inst, value, res, strvar):
+ # Same as FORMAT_VALUE
+ return self.op_FORMAT_VALUE(inst, value, res, strvar)
+
def op_FORMAT_VALUE(self, inst, value, res, strvar):
"""
FORMAT_VALUE(flags): flags argument specifies format spec which is not
@@ -1971,7 +1982,7 @@ class Interpreter(object):
(), loc=self.loc)
self.store(value=sliceinst, name=res)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_BINARY_SLICE(self, inst, start, end, container, res, slicevar,
temp_res):
start = self.get(start)
@@ -1990,7 +2001,7 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_STORE_SLICE(self, inst, start, end, container, value, res,
slicevar):
start = self.get(start)
@@ -2218,11 +2229,58 @@ class Interpreter(object):
stmt = ir.DelItem(base, self.get(indexvar), loc=self.loc)
self.current_block.append(stmt)
- def op_LOAD_FAST(self, inst, res):
+ def _op_LOAD_FAST(self, inst, res):
srcname = self.code_locals[inst.arg]
self.store(value=self.get(srcname), name=res)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 13), ):
+ def op_LOAD_FAST(self, inst, res, as_load_deref=False):
+ if as_load_deref:
+ self.op_LOAD_DEREF(inst, res)
+ else:
+ self._op_LOAD_FAST(inst, res)
+
+ else:
+ op_LOAD_FAST = _op_LOAD_FAST
+
+ if PYVERSION in ((3, 13),):
+ def op_LOAD_FAST_LOAD_FAST(self, inst, res1, res2):
+ oparg = inst.arg
+ oparg1 = oparg >> 4
+ oparg2 = oparg & 15
+ src1 = self.get(self.code_locals[oparg1])
+ src2 = self.get(self.code_locals[oparg2])
+ self.store(value=src1, name=res1)
+ self.store(value=src2, name=res2)
+
+ def op_STORE_FAST_LOAD_FAST(self, inst, store_value, load_res):
+ oparg = inst.arg
+ oparg1 = oparg >> 4
+ oparg2 = oparg & 15
+
+ dstname = self.code_locals[oparg1]
+ dst_value = self.get(store_value)
+ self.store(value=dst_value, name=dstname)
+
+ src_value = self.get(self.code_locals[oparg2])
+ self.store(value=src_value, name=load_res)
+
+ def op_STORE_FAST_STORE_FAST(self, inst, value1, value2):
+ oparg = inst.arg
+ oparg1 = oparg >> 4
+ oparg2 = oparg & 15
+
+ dstname = self.code_locals[oparg1]
+ self.store(value=self.get(value1), name=dstname)
+ dstname = self.code_locals[oparg2]
+ self.store(value=self.get(value2), name=dstname)
+
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
+ if PYVERSION in ((3, 12), (3, 13)):
op_LOAD_FAST_CHECK = op_LOAD_FAST
def op_LOAD_FAST_AND_CLEAR(self, inst, res):
@@ -2269,7 +2327,7 @@ class Interpreter(object):
def op_LOAD_ATTR(self, inst, item, res):
item = self.get(item)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
attr = self.code_names[inst.arg >> 1]
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
attr = self.code_names[inst.arg]
@@ -2300,7 +2358,7 @@ class Interpreter(object):
const = ir.Const(value, loc=self.loc)
self.store(const, res)
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_LOAD_GLOBAL(self, inst, idx, res):
name = self.code_names[idx]
value = self.get_global_value(name)
@@ -2318,11 +2376,15 @@ class Interpreter(object):
def op_COPY_FREE_VARS(self, inst):
pass
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_LOAD_DEREF(self, inst, res):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
if name in self.code_cellvars:
- gl = self.get(name)
+ try:
+ gl = self.get(name)
+ except NotDefinedError:
+ msg = "Unsupported use of cell variable encountered"
+ raise NotImplementedError(msg)
elif name in self.code_freevars:
idx = self.code_freevars.index(name)
value = self.get_closure_value(idx)
@@ -2343,11 +2405,11 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_MAKE_CELL(self, inst):
pass # ignored bytecode
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_STORE_DEREF(self, inst, value):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
value = self.get(value)
@@ -2387,7 +2449,7 @@ class Interpreter(object):
def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
assert self.blocks[inst.offset] is self.current_block
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
# Python 3.12 hack for handling nested with blocks
if end > self.last_active_offset:
# Use exception entries to figure out end of syntax block
@@ -2437,6 +2499,7 @@ class Interpreter(object):
func = self.get(func)
args = [self.get(x) for x in args]
if kw_names is not None:
+ assert PYVERSION < (3, 13)
names = self.code_consts[kw_names]
kwargs = list(zip(names, args[-len(names):]))
args = args[:-len(names)]
@@ -2445,6 +2508,19 @@ class Interpreter(object):
expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
self.store(expr, res)
+ if PYVERSION in ((3, 13),):
+ def op_CALL_KW(self, inst, func, args, kw_names, res):
+ func = self.get(func)
+ args = [self.get(x) for x in args]
+ consti = int(kw_names.rsplit('.', 2)[-1])
+ names = self.code_consts[consti]
+ kwargs = list(zip(names, args[-len(names):]))
+ args = args[:-len(names)]
+ expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
+ self.store(expr, res)
+ else:
+ assert PYVERSION < (3, 13)
+
def op_CALL_FUNCTION(self, inst, func, args, res):
func = self.get(func)
args = [self.get(x) for x in args]
@@ -2878,6 +2954,8 @@ class Interpreter(object):
jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
self.current_block.append(jmp)
+ op_JUMP_BACKWARD_NO_INTERRUPT = op_JUMP_BACKWARD
+
def op_POP_BLOCK(self, inst, kind=None):
if kind is None:
self.syntax_blocks.pop()
@@ -2892,7 +2970,7 @@ class Interpreter(object):
ret = ir.Return(self.get(castval), loc=self.loc)
self.current_block.append(ret)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_RETURN_CONST(self, inst, retval, castval):
value = self.code_consts[inst.arg]
const = ir.Const(value, loc=self.loc)
@@ -2905,8 +2983,20 @@ class Interpreter(object):
else:
raise NotImplementedError(PYVERSION)
+ if PYVERSION in ((3, 13),):
+ def op_TO_BOOL(self, inst, val, res):
+ self.store(self.get(val), res) # TODO: just a lazy hack
+
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ pass
+ else:
+ raise NotImplementedError(PYVERSION)
+
def op_COMPARE_OP(self, inst, lhs, rhs, res):
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 13),):
+ op = dis.cmp_op[inst.arg >> 5]
+ # TODO: fifth lowest bit now indicates a forced version to bool.
+ elif PYVERSION in ((3, 12),):
op = dis.cmp_op[inst.arg >> 4]
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
op = dis.cmp_op[inst.arg]
@@ -3024,7 +3114,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), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_POP_JUMP_IF_NONE(self, inst, pred):
self._jump_if_none(inst, pred, True)
@@ -3152,7 +3242,7 @@ class Interpreter(object):
"Probably caused by complex control-flow constructs; "
"e.g. try-except"
)
- raise errors.UnsupportedError(msg, loc=self.loc)
+ raise errors.UnsupportedBytecodeError(msg, loc=self.loc)
fcode = assume_code_const.value
if name:
name = self.get(name)
@@ -3166,14 +3256,14 @@ class Interpreter(object):
self.op_MAKE_FUNCTION(inst, name, code, closure, annotations,
kwdefaults, defaults, res)
- if PYVERSION in ((3, 11), (3, 12)):
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
def op_LOAD_CLOSURE(self, inst, res):
name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
if name in self.code_cellvars:
try:
gl = self.get(name)
except NotDefinedError:
- msg = "Unsupported use of op_LOAD_CLOSURE encountered"
+ msg = "Unsupported use of cell variable encountered"
raise NotImplementedError(msg)
elif name in self.code_freevars:
idx = self.code_freevars.index(name)
@@ -3191,7 +3281,7 @@ class Interpreter(object):
try:
gl = self.get(name)
except NotDefinedError:
- msg = "Unsupported use of op_LOAD_CLOSURE encountered"
+ msg = "Unsupported use of cell variable encountered"
raise NotImplementedError(msg)
else:
idx = inst.arg - n_cellvars
@@ -3228,7 +3318,7 @@ class Interpreter(object):
"op_LIST_EXTEND at the start of a block.\n\nThis could be "
"due to the use of a branch in a tuple unpacking statement.")
if not self.current_block.body:
- raise errors.UnsupportedError(msg)
+ raise errors.UnsupportedBytecodeError(msg)
# is last emitted statement a build_tuple?
stmt = self.current_block.body[-1]
@@ -3258,7 +3348,7 @@ class Interpreter(object):
ok = False
break
if ok and build_empty_list is None:
- raise errors.UnsupportedError(msg)
+ raise errors.UnsupportedBytecodeError(msg)
if ok:
stmts = self.current_block.body
build_tuple_asgn = self.current_block.body[-1]
@@ -3304,7 +3394,7 @@ class Interpreter(object):
def op_CALL_METHOD(self, *args, **kws):
self.op_CALL_FUNCTION(*args, **kws)
- if PYVERSION in ((3, 12), ):
+ if PYVERSION in ((3, 12), (3, 13)):
def op_CALL_INTRINSIC_1(self, inst, operand, **kwargs):
if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
stmt = ir.StaticRaise(INTRINSIC_STOPITERATION_ERROR, (),
@@ -3325,7 +3415,7 @@ class Interpreter(object):
raise NotImplementedError(PYVERSION)
-if PYVERSION in ((3, 12), ):
+if PYVERSION in ((3, 12), (3, 13)):
class INTRINSIC_STOPITERATION_ERROR(AssertionError):
pass
elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
Index: numba-0.60.0/numba/cpython/unicode.py
===================================================================
--- numba-0.60.0.orig/numba/cpython/unicode.py
+++ numba-0.60.0/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),):
+if PYVERSION in ((3, 12), (3, 13)):
@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),):
+if PYVERSION in ((3, 12), (3, 13)):
@register_jitable
def _kind_to_byte_width(kind):
if kind == PY_UNICODE_1BYTE_KIND:
@@ -2047,7 +2047,7 @@ def _is_upper(is_lower, is_upper, is_tit
def impl(a):
l = len(a)
if l == 1:
- return is_upper(_get_code_point(a, 0))
+ return is_upper(_get_code_point(a, 0)) != 0
if l == 0:
return False
cased = False
Index: numba-0.60.0/numba/experimental/jitclass/base.py
===================================================================
--- numba-0.60.0.orig/numba/experimental/jitclass/base.py
+++ numba-0.60.0/numba/experimental/jitclass/base.py
@@ -282,6 +282,9 @@ def _drop_ignored_attrs(dct):
drop = set(['__weakref__',
'__module__',
'__dict__'])
+ if utils.PYVERSION == (3, 13):
+ # new in python 3.13
+ drop |= set(['__firstlineno__', '__static_attributes__'])
if '__annotations__' in dct:
drop.add('__annotations__')
@@ -300,7 +303,7 @@ def _drop_ignored_attrs(dct):
drop.add('__hash__')
for k in drop:
- del dct[k]
+ dct.pop(k)
class ClassBuilder(object):
Index: numba-0.60.0/numba/core/compiler.py
===================================================================
--- numba-0.60.0.orig/numba/core/compiler.py
+++ numba-0.60.0/numba/core/compiler.py
@@ -476,10 +476,7 @@ class CompilerBase(object):
res = e.result
break
except Exception as e:
- if (utils.use_new_style_errors() and not
- isinstance(e, errors.NumbaError)):
- raise e
-
+ utils.handle_new_style_errors(e)
self.state.status.fail_reason = e
if is_final_pipeline:
raise e
Index: numba-0.60.0/numba/core/compiler_machinery.py
===================================================================
--- numba-0.60.0.orig/numba/core/compiler_machinery.py
+++ numba-0.60.0/numba/core/compiler_machinery.py
@@ -304,7 +304,8 @@ class PassManager(object):
args=str(internal_state.args),
return_type=str(internal_state.return_type),
)
- with ev.trigger_event("numba:run_pass", data=ev_details):
+ errctx = errors.new_error_context(f"Pass {pss.name()}")
+ with ev.trigger_event("numba:run_pass", data=ev_details), errctx:
with SimpleTimer() as init_time:
mutated |= check(pss.run_initialization, internal_state)
with SimpleTimer() as pass_time:
@@ -359,9 +360,7 @@ class PassManager(object):
except _EarlyPipelineCompletion as e:
raise e
except Exception as e:
- if (utils.use_new_style_errors() and not
- isinstance(e, errors.NumbaError)):
- raise e
+ utils.handle_new_style_errors(e)
msg = "Failed in %s mode pipeline (step: %s)" % \
(self.pipeline_name, pass_desc)
patched_exception = self._patch_error(msg, e)
Index: numba-0.60.0/numba/core/errors.py
===================================================================
--- numba-0.60.0.orig/numba/core/errors.py
+++ numba-0.60.0/numba/core/errors.py
@@ -532,7 +532,6 @@ class WarningsFixer(object):
class NumbaError(Exception):
-
def __init__(self, msg, loc=None, highlighting=True):
self.msg = msg
self.loc = loc
@@ -578,7 +577,13 @@ class UnsupportedError(NumbaError):
"""
Numba does not have an implementation for this functionality.
"""
- pass
+
+
+class UnsupportedBytecodeError(Exception):
+ """Unsupported bytecode is non-recoverable
+ """
+ def __init__(self, msg, loc=None):
+ super().__init__(f"{msg}. Raised from {loc}")
class UnsupportedRewriteError(UnsupportedError):
Index: numba-0.60.0/numba/core/types/functions.py
===================================================================
--- numba-0.60.0.orig/numba/core/types/functions.py
+++ numba-0.60.0/numba/core/types/functions.py
@@ -307,12 +307,9 @@ class BaseFunction(Callable):
for k, v in kws.items()}
sig = temp.apply(nolitargs, nolitkws)
except Exception as e:
- if (utils.use_new_style_errors() and not
- isinstance(e, errors.NumbaError)):
- raise e
- else:
- sig = None
- failures.add_error(temp, False, e, uselit)
+ utils.handle_new_style_errors(e)
+ sig = None
+ failures.add_error(temp, False, e, uselit)
else:
if sig is not None:
self._impl_keys[sig.args] = temp.get_impl_key(sig)
Index: numba-0.60.0/numba/core/utils.py
===================================================================
--- numba-0.60.0.orig/numba/core/utils.py
+++ numba-0.60.0/numba/core/utils.py
@@ -230,6 +230,17 @@ def use_old_style_errors():
return res
+def handle_new_style_errors(e):
+ """Handle new_style error by raising the exception immediately if they are
+ non-recoverable.
+ """
+ from numba.core import errors
+
+ if use_new_style_errors():
+ if not isinstance(e, errors.NumbaError):
+ raise e
+
+
class ThreadLocalStack:
"""A TLS stack container.
Index: numba-0.60.0/numba/stencils/stencil.py
===================================================================
--- numba-0.60.0.orig/numba/stencils/stencil.py
+++ numba-0.60.0/numba/stencils/stencil.py
@@ -402,8 +402,9 @@ class StencilFunc(object):
sig = signature(real_ret, *argtys_extra)
dummy_text = ("def __numba_dummy_stencil({}{}):\n pass\n".format(
",".join(self.kernel_ir.arg_names), sig_extra))
- exec(dummy_text) in globals(), locals()
- dummy_func = eval("__numba_dummy_stencil")
+ dct = {}
+ exec(dummy_text, dct)
+ dummy_func = dct["__numba_dummy_stencil"]
sig = sig.replace(pysig=utils.pysignature(dummy_func))
self._targetctx.insert_func_defn([(self._lower_me, self, argtys_extra)])
self._type_cache[argtys_extra] = (sig, result, typemap, calltypes)
@@ -659,8 +660,10 @@ class StencilFunc(object):
print(func_text)
# Force the new stencil function into existence.
- exec(func_text) in globals(), locals()
- stencil_func = eval(stencil_func_name)
+ dct = {}
+ dct.update(globals())
+ exec(func_text, dct)
+ stencil_func = dct[stencil_func_name]
if sigret is not None:
pysig = utils.pysignature(stencil_func)
sigret.pysig = pysig
Index: numba-0.60.0/numba/tests/test_debug.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_debug.py
+++ numba-0.60.0/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)):
+ if utils.PYVERSION in ((3, 11), (3, 12), (3, 13)):
self.assertIn('BINARY_OP', out)
elif utils.PYVERSION in ((3, 9), (3, 10)):
self.assertIn('BINARY_ADD', out)
Index: numba-0.60.0/numba/tests/test_ir_inlining.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_ir_inlining.py
+++ numba-0.60.0/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), ):
+ if utils.PYVERSION in ((3, 12), (3, 13)):
bc = 39
elif utils.PYVERSION in ((3, 10), (3, 11)):
bc = 35
Index: numba-0.60.0/numba/tests/test_closure.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_closure.py
+++ numba-0.60.0/numba/tests/test_closure.py
@@ -400,13 +400,13 @@ class TestInlinedClosure(TestCase):
with self.assertRaises(NotImplementedError) as raises:
cfunc = jit(nopython=True)(outer3)
cfunc(var)
- msg = "Unsupported use of op_LOAD_CLOSURE encountered"
+ msg = "Unsupported use of cell variable encountered"
self.assertIn(msg, str(raises.exception))
with self.assertRaises(NotImplementedError) as raises:
cfunc = jit(nopython=True)(outer4)
cfunc(var)
- msg = "Unsupported use of op_LOAD_CLOSURE encountered"
+ msg = "Unsupported use of cell variable encountered"
self.assertIn(msg, str(raises.exception))
with self.assertRaises(TypingError) as raises:
Index: numba-0.60.0/numba/core/inline_closurecall.py
===================================================================
--- numba-0.60.0.orig/numba/core/inline_closurecall.py
+++ numba-0.60.0/numba/core/inline_closurecall.py
@@ -95,7 +95,7 @@ class InlineClosureCallPass(object):
modified = False
work_list = list(self.func_ir.blocks.items())
debug_print = _make_debug_print("InlineClosureCallPass")
- debug_print("START")
+ debug_print(f"START {self.func_ir.func_id.func_qualname}")
while work_list:
_label, block = work_list.pop()
for i, instr in enumerate(block.body):
Index: numba-0.60.0/numba/pycc/modulemixin.c
===================================================================
--- numba-0.60.0.orig/numba/pycc/modulemixin.c
+++ numba-0.60.0/numba/pycc/modulemixin.c
@@ -23,6 +23,12 @@
#include "../core/runtime/nrt.h"
#endif
+#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 12)
+ #define Py_BUILD_CORE 1
+ #include "internal/pycore_pyhash.h"
+ #undef Py_BUILD_CORE
+#endif
+
/* Defines hashsecret variables (see issue #6386) */
int64_t _numba_hashsecret_siphash_k0;
int64_t _numba_hashsecret_siphash_k1;
Index: numba-0.60.0/numba/tests/test_operators.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_operators.py
+++ numba-0.60.0/numba/tests/test_operators.py
@@ -768,7 +768,7 @@ class TestOperators(TestCase):
# error message depends on Python version.
if utils.PYVERSION in ((3, 9),):
msg = "can't mod complex numbers"
- elif utils.PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ elif utils.PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
msg = "unsupported operand type(s) for %"
else:
raise NotImplementedError(utils.PYVERSION)
Index: numba-0.60.0/numba/tests/test_parfors.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_parfors.py
+++ numba-0.60.0/numba/tests/test_parfors.py
@@ -3550,7 +3550,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)):
+ if utils.PYVERSION in ((3, 11), (3, 12), (3, 13)):
# this is the inverse of _fix_LOAD_GLOBAL_arg
prange_idx = 1 + (prange_idx << 1)
elif utils.PYVERSION in ((3, 9), (3, 10)):
Index: numba-0.60.0/numba/tests/support.py
===================================================================
--- numba-0.60.0.orig/numba/tests/support.py
+++ numba-0.60.0/numba/tests/support.py
@@ -128,6 +128,12 @@ def expected_failure_np2(fn):
else:
return fn
+def expected_failure_py313(fn):
+ if utils.PYVERSION == (3, 13):
+ return unittest.expectedFailure(fn)
+ else:
+ return fn
+
_msg = "SciPy needed for test"
skip_unless_scipy = unittest.skipIf(scipy is None, _msg)
Index: numba-0.60.0/numba/tests/test_np_functions.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_np_functions.py
+++ numba-0.60.0/numba/tests/test_np_functions.py
@@ -6192,8 +6192,9 @@ def foo():
tystr = ty.__name__
basestr = basefunc.__name__
funcstr = self.template % (tystr, basestr)
- eval(compile(funcstr, '<string>', 'exec'))
- return locals()['foo']
+ dct = {}
+ exec(compile(funcstr, '<string>', 'exec'), globals(), dct)
+ return dct['foo']
@unittest.skipIf(numpy_version >= (1, 24), "NumPy < 1.24 required")
def test_MachAr(self):
Index: numba-0.60.0/numba/tests/test_unicode.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_unicode.py
+++ numba-0.60.0/numba/tests/test_unicode.py
@@ -6,10 +6,12 @@ from numba import njit, typeof
from numba.core import types
import unittest
from numba.tests.support import (TestCase, no_pyobj_flags, MemoryLeakMixin)
-from numba.core.errors import TypingError, UnsupportedError
+from numba.core.errors import (TypingError, UnsupportedError,
+ UnsupportedBytecodeError)
from numba.cpython.unicode import _MAX_UNICODE
from numba.core.types.functions import _header_lead
from numba.extending import overload
+from numba.core.utils import PYVERSION
def isascii(s):
@@ -2697,10 +2699,17 @@ class TestUnicodeAuxillary(BaseTest):
self.assertEqual(got, expected)
# check error when format spec provided
- with self.assertRaises(UnsupportedError) as raises:
+ unsupported_errors = (UnsupportedError, UnsupportedBytecodeError)
+ with self.assertRaises(unsupported_errors) as raises:
njit(impl4)(["A", "B"])
- msg = "format spec in f-strings not supported yet"
- self.assertIn(msg, str(raises.exception))
+ if PYVERSION in ((3, 13),):
+ msg = "Use of unsupported opcode (FORMAT_WITH_SPEC)"
+ self.assertIn(msg, str(raises.exception))
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12)):
+ msg = "format spec in f-strings not supported yet"
+ self.assertIn(msg, str(raises.exception))
+ else:
+ raise NotImplementedError(PYVERSION)
self.assertEqual(impl5(), njit(impl5)())
Index: numba-0.60.0/numba/core/ir.py
===================================================================
--- numba-0.60.0.orig/numba/core/ir.py
+++ numba-0.60.0/numba/core/ir.py
@@ -90,9 +90,12 @@ class Loc(object):
def get_lines(self):
if self.lines is None:
-
- self.lines = linecache.getlines(self._get_path())
-
+ path = self._get_path()
+ # Avoid reading from dynamic string. They are most likely
+ # overridden. Problem started with Python 3.13. "<string>" seems
+ # to be something from multiprocessing.
+ lns = [] if path == "<string>" else linecache.getlines(path)
+ self.lines = lns
return self.lines
def _get_path(self):
@@ -1496,7 +1499,7 @@ class FunctionIR(object):
self.block_entry_vars = {}
def derive(self, blocks, arg_count=None, arg_names=None,
- force_non_generator=False):
+ force_non_generator=False, loc=None):
"""
Derive a new function IR from this one, using the given blocks,
and possibly modifying the argument count and generator flag.
@@ -1507,7 +1510,7 @@ class FunctionIR(object):
new_ir = copy.copy(self)
new_ir.blocks = blocks
- new_ir.loc = firstblock.loc
+ new_ir.loc = firstblock.loc if loc is None else loc
if force_non_generator:
new_ir.is_generator = False
if arg_count is not None:
Index: numba-0.60.0/numba/core/transforms.py
===================================================================
--- numba-0.60.0.orig/numba/core/transforms.py
+++ numba-0.60.0/numba/core/transforms.py
@@ -191,12 +191,20 @@ def _loop_lift_modify_blocks(func_ir, lo
loopblocks = dict((k, blocks[k].copy()) for k in loopblockkeys)
# Modify the loop blocks
_loop_lift_prepare_loop_func(loopinfo, loopblocks)
-
+ # Since Python 3.13, [END_FOR, POP_TOP] sequence becomes the start of the
+ # block causing the block to have line number of the start of previous loop.
+ # Fix this using the loc of the first getiter.
+ getiter_exprs = []
+ for blk in loopblocks.values():
+ getiter_exprs.extend(blk.find_exprs(op="getiter"))
+ first_getiter = min(getiter_exprs, key=lambda x: x.loc.line)
+ loop_loc = first_getiter.loc
# Create a new IR for the lifted loop
lifted_ir = func_ir.derive(blocks=loopblocks,
arg_names=tuple(loopinfo.inputs),
arg_count=len(loopinfo.inputs),
- force_non_generator=True)
+ force_non_generator=True,
+ loc=loop_loc)
liftedloop = LiftedLoop(lifted_ir,
typingctx, targetctx, flags, locals)
Index: numba-0.60.0/numba/tests/test_exceptions.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_exceptions.py
+++ numba-0.60.0/numba/tests/test_exceptions.py
@@ -6,6 +6,7 @@ from numba import jit, njit
from numba.core import types, errors, utils
from numba.tests.support import (TestCase, expected_failure_py311,
expected_failure_py312,
+ expected_failure_py313,
)
import unittest
@@ -440,6 +441,7 @@ class TestRaising(TestCase):
@expected_failure_py311
@expected_failure_py312
+ @expected_failure_py313
def test_dynamic_raise(self):
@njit
Index: numba-0.60.0/numba/tests/test_try_except.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_try_except.py
+++ numba-0.60.0/numba/tests/test_try_except.py
@@ -8,12 +8,13 @@ from numba import njit, typed, objmode,
from numba.core.utils import PYVERSION
from numba.core import ir_utils, ir
from numba.core.errors import (
- UnsupportedError, CompilerError, NumbaPerformanceWarning, TypingError,
+ CompilerError, NumbaPerformanceWarning, TypingError,
+ UnsupportedBytecodeError,
)
from numba.tests.support import (
TestCase, unittest, captured_stdout, MemoryLeakMixin,
skip_parfors_unsupported, skip_unless_scipy, expected_failure_py311,
- expected_failure_py312
+ expected_failure_py312, expected_failure_py313,
)
@@ -372,7 +373,7 @@ class TestTryBareExcept(TestCase):
except: # noqa: E722
raise
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
udt()
self.assertIn(
"The re-raising of an exception is not yet supported.",
@@ -459,7 +460,7 @@ class TestTryExceptCaught(TestCase):
return r
return r
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
udt(True)
self.assertIn(
"Exception object cannot be stored into variable (e)",
@@ -474,7 +475,7 @@ class TestTryExceptCaught(TestCase):
except Exception:
raise
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
udt()
self.assertIn(
"The re-raising of an exception is not yet supported.",
@@ -492,7 +493,7 @@ class TestTryExceptCaught(TestCase):
except Exception:
raise
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
udt()
self.assertIn(
"The re-raising of an exception is not yet supported.",
@@ -692,6 +693,7 @@ class TestTryExceptOtherControlFlow(Test
@expected_failure_py311
@expected_failure_py312
+ @expected_failure_py313
def test_objmode(self):
@njit
def udt():
@@ -712,6 +714,7 @@ class TestTryExceptOtherControlFlow(Test
@expected_failure_py311
@expected_failure_py312
+ @expected_failure_py313
def test_objmode_output_type(self):
def bar(x):
return np.asarray(list(reversed(x.tolist())))
Index: numba-0.60.0/numba/tests/test_withlifting.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_withlifting.py
+++ numba-0.60.0/numba/tests/test_withlifting.py
@@ -16,7 +16,8 @@ from numba.tests.support import (MemoryL
skip_unless_scipy, linux_only,
strace_supported, strace,
expected_failure_py311,
- expected_failure_py312)
+ expected_failure_py312,
+ expected_failure_py313)
from numba.core.utils import PYVERSION
from numba.experimental import jitclass
import unittest
@@ -280,6 +281,7 @@ class TestLiftCall(BaseTestWithLifting):
@expected_failure_py311
@expected_failure_py312
+ @expected_failure_py313
def test_liftcall5(self):
self.check_extracted_with(liftcall5, expect_count=1,
expected_stdout="0\n1\n2\n3\n4\n5\nA\n")
@@ -719,6 +721,7 @@ class TestLiftObj(MemoryLeak, TestCase):
@expected_failure_py311
@expected_failure_py312
+ @expected_failure_py313
def test_case19_recursion(self):
def foo(x):
with objmode_context():
@@ -1169,7 +1172,7 @@ class TestBogusContext(BaseTestWithLifti
with open('') as f:
pass
- with self.assertRaises(errors.UnsupportedError) as raises:
+ with self.assertRaises(errors.UnsupportedBytecodeError) as raises:
foo()
excstr = str(raises.exception)
Index: numba-0.60.0/numba/tests/test_sys_monitoring.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_sys_monitoring.py
+++ numba-0.60.0/numba/tests/test_sys_monitoring.py
@@ -4,7 +4,7 @@ import sys
import threading
import unittest
from unittest.mock import Mock, call
-from numba.tests.support import TestCase, skip_unless_py312
+from numba.tests.support import TestCase
from numba import jit, objmode
from numba.core.utils import PYVERSION
from numba.core.serialize import _numba_unpickle
@@ -21,7 +21,7 @@ def generate_usecase():
return foo, call_foo
-if PYVERSION == (3, 12):
+if PYVERSION in ((3, 12), (3, 13)):
PY_START = sys.monitoring.events.PY_START
PY_RETURN = sys.monitoring.events.PY_RETURN
RAISE = sys.monitoring.events.RAISE
@@ -36,7 +36,7 @@ TOOL2MONITORTYPE = {0 : "Debugger",
5 : "Optimizer"}
-@skip_unless_py312
+@unittest.skipUnless(PYVERSION >= (3, 12), "needs Python 3.12+")
class TestMonitoring(TestCase):
# Tests the interaction of the Numba dispatcher with `sys.monitoring`.
#
@@ -724,7 +724,7 @@ class TestMonitoring(TestCase):
self.assertFalse(q2.qsize())
-@skip_unless_py312
+@unittest.skipUnless(PYVERSION >= (3, 12), "needs Python 3.12+")
class TestMonitoringSelfTest(TestCase):
def test_skipping_of_tests_if_monitoring_in_use(self):
Index: numba-0.60.0/numba/_random.c
===================================================================
--- numba-0.60.0.orig/numba/_random.c
+++ numba-0.60.0/numba/_random.c
@@ -195,7 +195,7 @@ rnd_implicit_init(rnd_state_t *state)
Py_buffer buf;
PyGILState_STATE gilstate = PyGILState_Ensure();
- module = PyImport_ImportModuleNoBlock("os");
+ module = PyImport_ImportModule("os");
if (module == NULL)
goto error;
/* Read as many bytes as necessary to get the full entropy
Index: numba-0.60.0/numba/core/pythonapi.py
===================================================================
--- numba-0.60.0.orig/numba/core/pythonapi.py
+++ numba-0.60.0/numba/core/pythonapi.py
@@ -919,9 +919,9 @@ class PythonAPI(object):
# Other APIs (organize them better!)
#
- def import_module_noblock(self, modname):
+ def import_module(self, modname):
fnty = ir.FunctionType(self.pyobj, [self.cstring])
- fn = self._get_function(fnty, name="PyImport_ImportModuleNoBlock")
+ fn = self._get_function(fnty, name="PyImport_ImportModule")
return self.builder.call(fn, [modname])
def call_function_objargs(self, callee, objargs):
Index: numba-0.60.0/numba/experimental/function_type.py
===================================================================
--- numba-0.60.0.orig/numba/experimental/function_type.py
+++ numba-0.60.0/numba/experimental/function_type.py
@@ -181,7 +181,7 @@ def lower_get_wrapper_address(context, b
# caller.
modname = context.insert_const_string(builder.module, __name__)
- numba_mod = pyapi.import_module_noblock(modname)
+ numba_mod = pyapi.import_module(modname)
numba_func = pyapi.object_getattr_string(
numba_mod, '_get_wrapper_address')
pyapi.decref(numba_mod)
@@ -263,3 +263,4 @@ def lower_cast_dispatcher_to_function_ty
llty = context.get_value_type(types.voidptr)
sfunc.pyaddr = builder.ptrtoint(val, llty)
return sfunc._getvalue()
+
Index: numba-0.60.0/numba/typed/typeddict.py
===================================================================
--- numba-0.60.0.orig/numba/typed/typeddict.py
+++ numba-0.60.0/numba/typed/typeddict.py
@@ -266,7 +266,7 @@ def box_dicttype(typ, val, c):
modname = c.context.insert_const_string(
c.builder.module, 'numba.typed.typeddict',
)
- typeddict_mod = c.pyapi.import_module_noblock(modname)
+ typeddict_mod = c.pyapi.import_module(modname)
fmp_fn = c.pyapi.object_getattr_string(typeddict_mod, '_from_meminfo_ptr')
dicttype_obj = c.pyapi.unserialize(c.pyapi.serialize_object(typ))
Index: numba-0.60.0/numba/typed/typedlist.py
===================================================================
--- numba-0.60.0.orig/numba/typed/typedlist.py
+++ numba-0.60.0/numba/typed/typedlist.py
@@ -471,7 +471,7 @@ def box_lsttype(typ, val, c):
modname = c.context.insert_const_string(
c.builder.module, 'numba.typed.typedlist',
)
- typedlist_mod = c.pyapi.import_module_noblock(modname)
+ typedlist_mod = c.pyapi.import_module(modname)
fmp_fn = c.pyapi.object_getattr_string(typedlist_mod, '_from_meminfo_ptr')
lsttype_obj = c.pyapi.unserialize(c.pyapi.serialize_object(typ))
Index: numba-0.60.0/numba/tests/test_interpreter.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_interpreter.py
+++ numba-0.60.0/numba/tests/test_interpreter.py
@@ -5,7 +5,7 @@ import unittest
from numba import jit, njit, objmode, typeof, literally
from numba.extending import overload
from numba.core import types
-from numba.core.errors import UnsupportedError
+from numba.core.errors import UnsupportedBytecodeError
from numba.tests.support import (
TestCase,
MemoryLeakMixin,
@@ -388,7 +388,7 @@ class TestCallFunctionExPeepHole(MemoryL
arg41=1,
)
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
njit()(inline_func)(False)
self.assertIn(
'You can resolve this issue by moving the control flow out',
@@ -498,7 +498,7 @@ class TestCallFunctionExPeepHole(MemoryL
1,
)
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
njit()(inline_func)(False)
self.assertIn(
'You can resolve this issue by moving the control flow out',
@@ -585,7 +585,7 @@ class TestCallFunctionExPeepHole(MemoryL
arg15=1 if flag else 2,
)
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
njit()(inline_func)(False)
self.assertIn(
'You can resolve this issue by moving the control flow out',
@@ -973,7 +973,7 @@ class TestLargeConstDict(TestCase, Memor
}
return d["S"]
- with self.assertRaises(UnsupportedError) as raises:
+ with self.assertRaises(UnsupportedBytecodeError) as raises:
njit()(inline_func)("a_string", False)
self.assertIn(
'You can resolve this issue by moving the control flow out',
Index: numba-0.60.0/numba/tests/test_tuples.py
===================================================================
--- numba-0.60.0.orig/numba/tests/test_tuples.py
+++ numba-0.60.0/numba/tests/test_tuples.py
@@ -731,7 +731,7 @@ class TestTupleBuild(TestCase):
b = (3,2, 4)
return (*(b if a[0] else (5, 6)),)
- with self.assertRaises(errors.UnsupportedError) as raises:
+ with self.assertRaises(errors.UnsupportedBytecodeError) as raises:
foo()
msg = "op_LIST_EXTEND at the start of a block"
self.assertIn(msg, str(raises.exception))
Index: numba-0.60.0/setup.py
===================================================================
--- numba-0.60.0.orig/setup.py
+++ numba-0.60.0/setup.py
@@ -20,7 +20,7 @@ except ImportError:
min_python_version = "3.9"
-max_python_version = "3.13" # exclusive
+max_python_version = "3.14" # exclusive
min_numpy_build_version = "2.0.0rc1"
min_numpy_run_version = "1.22"
max_numpy_run_version = "2.1"
Index: numba-0.60.0/numba/core/boxing.py
===================================================================
--- numba-0.60.0.orig/numba/core/boxing.py
+++ numba-0.60.0/numba/core/boxing.py
@@ -655,7 +655,7 @@ class _NumbaTypeHelper(object):
def __enter__(self):
c = self.c
numba_name = c.context.insert_const_string(c.builder.module, 'numba')
- numba_mod = c.pyapi.import_module_noblock(numba_name)
+ numba_mod = c.pyapi.import_module(numba_name)
typeof_fn = c.pyapi.object_getattr_string(numba_mod, 'typeof')
self.typeof_fn = typeof_fn
c.pyapi.decref(numba_mod)
@@ -1213,7 +1213,7 @@ def unbox_numpy_random_bitgenerator(typ,
# store the results.
# First find ctypes.cast, and ctypes.c_void_p
ctypes_name = c.context.insert_const_string(c.builder.module, 'ctypes')
- ctypes_module = c.pyapi.import_module_noblock(ctypes_name)
+ ctypes_module = c.pyapi.import_module(ctypes_name)
extra_refs.append(ctypes_module)
with cgutils.early_exit_if_null(c.builder, stack, ctypes_module):
handle_failure()
Index: numba-0.60.0/numba/pythoncapi_compat.h
===================================================================
--- /dev/null
+++ numba-0.60.0/numba/pythoncapi_compat.h
@@ -0,0 +1,1696 @@
+// Header file providing new C API functions to old Python versions.
+//
+// File distributed under the Zero Clause BSD (0BSD) license.
+// Copyright Contributors to the pythoncapi_compat project.
+//
+// Homepage:
+// https://github.com/python/pythoncapi_compat
+//
+// Latest version:
+// https://raw.githubusercontent.com/python/pythoncapi-compat/0041177c4f348c8952b4c8980b2c90856e61c7c7/pythoncapi_compat.h
+//
+// SPDX-License-Identifier: 0BSD
+
+#ifndef PYTHONCAPI_COMPAT
+#define PYTHONCAPI_COMPAT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+
+// Python 3.11.0b4 added PyFrame_Back() to Python.h
+#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
+# include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
+#endif
+
+
+#ifndef _Py_CAST
+# define _Py_CAST(type, expr) ((type)(expr))
+#endif
+
+// Static inline functions should use _Py_NULL rather than using directly NULL
+// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
+// _Py_NULL is defined as nullptr.
+#if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \
+ || (defined(__cplusplus) && __cplusplus >= 201103)
+# define _Py_NULL nullptr
+#else
+# define _Py_NULL NULL
+#endif
+
+// Cast argument to PyObject* type.
+#ifndef _PyObject_CAST
+# define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
+#endif
+
+#ifndef Py_BUILD_ASSERT
+# define Py_BUILD_ASSERT(cond) \
+ do { \
+ (void)sizeof(char [1 - 2 * !(cond)]); \
+ } while(0)
+#endif
+
+
+// bpo-42262 added Py_NewRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
+static inline PyObject* _Py_NewRef(PyObject *obj)
+{
+ Py_INCREF(obj);
+ return obj;
+}
+#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
+#endif
+
+
+// bpo-42262 added Py_XNewRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef)
+static inline PyObject* _Py_XNewRef(PyObject *obj)
+{
+ Py_XINCREF(obj);
+ return obj;
+}
+#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
+#endif
+
+
+// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
+static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
+{
+ ob->ob_refcnt = refcnt;
+}
+#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
+#endif
+
+
+// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2.
+// It is excluded from the limited C API.
+#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API)
+#define Py_SETREF(dst, src) \
+ do { \
+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
+ PyObject *_tmp_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = _PyObject_CAST(src); \
+ Py_DECREF(_tmp_dst); \
+ } while (0)
+
+#define Py_XSETREF(dst, src) \
+ do { \
+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
+ PyObject *_tmp_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = _PyObject_CAST(src); \
+ Py_XDECREF(_tmp_dst); \
+ } while (0)
+#endif
+
+
+// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse()
+// to Python 3.10.0b1.
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is)
+# define Py_Is(x, y) ((x) == (y))
+#endif
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone)
+# define Py_IsNone(x) Py_Is(x, Py_None)
+#endif
+#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsTrue)
+# define Py_IsTrue(x) Py_Is(x, Py_True)
+#endif
+#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsFalse)
+# define Py_IsFalse(x) Py_Is(x, Py_False)
+#endif
+
+
+// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
+static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
+{
+ ob->ob_type = type;
+}
+#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
+#endif
+
+
+// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
+static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
+{
+ ob->ob_size = size;
+}
+#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
+#endif
+
+
+// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION)
+static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
+{
+ assert(frame != _Py_NULL);
+ assert(frame->f_code != _Py_NULL);
+ return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
+}
+#endif
+
+static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
+{
+ PyCodeObject *code = PyFrame_GetCode(frame);
+ Py_DECREF(code);
+ return code;
+}
+
+
+// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
+static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
+{
+ assert(frame != _Py_NULL);
+ return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
+}
+#endif
+
+#if !defined(PYPY_VERSION)
+static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
+{
+ PyFrameObject *back = PyFrame_GetBack(frame);
+ Py_XDECREF(back);
+ return back;
+}
+#endif
+
+
+// bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7
+#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
+static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
+{
+#if PY_VERSION_HEX >= 0x030400B1
+ if (PyFrame_FastToLocalsWithError(frame) < 0) {
+ return NULL;
+ }
+#else
+ PyFrame_FastToLocals(frame);
+#endif
+ return Py_NewRef(frame->f_locals);
+}
+#endif
+
+
+// bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7
+#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
+static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
+{
+ return Py_NewRef(frame->f_globals);
+}
+#endif
+
+
+// bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7
+#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
+static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
+{
+ return Py_NewRef(frame->f_builtins);
+}
+#endif
+
+
+// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1
+#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
+static inline int PyFrame_GetLasti(PyFrameObject *frame)
+{
+#if PY_VERSION_HEX >= 0x030A00A7
+ // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset,
+ // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes)
+ // instructions.
+ if (frame->f_lasti < 0) {
+ return -1;
+ }
+ return frame->f_lasti * 2;
+#else
+ return frame->f_lasti;
+#endif
+}
+#endif
+
+
+// gh-91248 added PyFrame_GetVar() to Python 3.12.0a2
+#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
+static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
+{
+ PyObject *locals, *value;
+
+ locals = PyFrame_GetLocals(frame);
+ if (locals == NULL) {
+ return NULL;
+ }
+#if PY_VERSION_HEX >= 0x03000000
+ value = PyDict_GetItemWithError(locals, name);
+#else
+ value = _PyDict_GetItemWithError(locals, name);
+#endif
+ Py_DECREF(locals);
+
+ if (value == NULL) {
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+#if PY_VERSION_HEX >= 0x03000000
+ PyErr_Format(PyExc_NameError, "variable %R does not exist", name);
+#else
+ PyErr_SetString(PyExc_NameError, "variable does not exist");
+#endif
+ return NULL;
+ }
+ return Py_NewRef(value);
+}
+#endif
+
+
+// gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2
+#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
+static inline PyObject*
+PyFrame_GetVarString(PyFrameObject *frame, const char *name)
+{
+ PyObject *name_obj, *value;
+#if PY_VERSION_HEX >= 0x03000000
+ name_obj = PyUnicode_FromString(name);
+#else
+ name_obj = PyString_FromString(name);
+#endif
+ if (name_obj == NULL) {
+ return NULL;
+ }
+ value = PyFrame_GetVar(frame, name_obj);
+ Py_DECREF(name_obj);
+ return value;
+}
+#endif
+
+
+// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION)
+static inline PyInterpreterState *
+PyThreadState_GetInterpreter(PyThreadState *tstate)
+{
+ assert(tstate != _Py_NULL);
+ return tstate->interp;
+}
+#endif
+
+
+// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
+static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
+{
+ assert(tstate != _Py_NULL);
+ return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
+}
+#endif
+
+#if !defined(PYPY_VERSION)
+static inline PyFrameObject*
+_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
+{
+ PyFrameObject *frame = PyThreadState_GetFrame(tstate);
+ Py_XDECREF(frame);
+ return frame;
+}
+#endif
+
+
+// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION)
+static inline PyInterpreterState* PyInterpreterState_Get(void)
+{
+ PyThreadState *tstate;
+ PyInterpreterState *interp;
+
+ tstate = PyThreadState_GET();
+ if (tstate == _Py_NULL) {
+ Py_FatalError("GIL released (tstate is NULL)");
+ }
+ interp = tstate->interp;
+ if (interp == _Py_NULL) {
+ Py_FatalError("no current interpreter");
+ }
+ return interp;
+}
+#endif
+
+
+// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6
+#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
+static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
+{
+ assert(tstate != _Py_NULL);
+ return tstate->id;
+}
+#endif
+
+// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
+#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
+static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
+{
+ tstate->tracing++;
+#if PY_VERSION_HEX >= 0x030A00A1
+ tstate->cframe->use_tracing = 0;
+#else
+ tstate->use_tracing = 0;
+#endif
+}
+#endif
+
+// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
+#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
+static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
+{
+ int use_tracing = (tstate->c_tracefunc != _Py_NULL
+ || tstate->c_profilefunc != _Py_NULL);
+ tstate->tracing--;
+#if PY_VERSION_HEX >= 0x030A00A1
+ tstate->cframe->use_tracing = use_tracing;
+#else
+ tstate->use_tracing = use_tracing;
+#endif
+}
+#endif
+
+
+// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1
+// PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11
+#if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1
+static inline PyObject* PyObject_CallNoArgs(PyObject *func)
+{
+ return PyObject_CallFunctionObjArgs(func, NULL);
+}
+#endif
+
+
+// bpo-39245 made PyObject_CallOneArg() public (previously called
+// _PyObject_CallOneArg) in Python 3.9.0a4
+// PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11
+#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4
+static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg)
+{
+ return PyObject_CallFunctionObjArgs(func, arg, NULL);
+}
+#endif
+
+
+// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3
+static inline int
+PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value)
+{
+ int res;
+
+ if (!value && !PyErr_Occurred()) {
+ // PyModule_AddObject() raises TypeError in this case
+ PyErr_SetString(PyExc_SystemError,
+ "PyModule_AddObjectRef() must be called "
+ "with an exception raised if value is NULL");
+ return -1;
+ }
+
+ Py_XINCREF(value);
+ res = PyModule_AddObject(module, name, value);
+ if (res < 0) {
+ Py_XDECREF(value);
+ }
+ return res;
+}
+#endif
+
+
+// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5
+static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
+{
+ const char *name, *dot;
+
+ if (PyType_Ready(type) < 0) {
+ return -1;
+ }
+
+ // inline _PyType_Name()
+ name = type->tp_name;
+ assert(name != _Py_NULL);
+ dot = strrchr(name, '.');
+ if (dot != _Py_NULL) {
+ name = dot + 1;
+ }
+
+ return PyModule_AddObjectRef(module, name, _PyObject_CAST(type));
+}
+#endif
+
+
+// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6.
+// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2.
+#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
+static inline int PyObject_GC_IsTracked(PyObject* obj)
+{
+ return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj));
+}
+#endif
+
+// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6.
+// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final.
+#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION)
+static inline int PyObject_GC_IsFinalized(PyObject *obj)
+{
+ PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1;
+ return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc));
+}
+#endif
+
+
+// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
+static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
+ return Py_TYPE(ob) == type;
+}
+#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type)
+#endif
+
+
+// bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7.
+// bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1.
+// Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal
+// C API: Python 3.11a2-3.11a6 versions are not supported.
+#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
+static inline int PyFloat_Pack2(double x, char *p, int le)
+{ return _PyFloat_Pack2(x, (unsigned char*)p, le); }
+
+static inline double PyFloat_Unpack2(const char *p, int le)
+{ return _PyFloat_Unpack2((const unsigned char *)p, le); }
+#endif
+
+
+// bpo-46906 added PyFloat_Pack4(), PyFloat_Pack8(), PyFloat_Unpack4() and
+// PyFloat_Unpack8() to Python 3.11a7.
+// Python 3.11a2 moved _PyFloat_Pack4(), _PyFloat_Pack8(), _PyFloat_Unpack4()
+// and _PyFloat_Unpack8() to the internal C API: Python 3.11a2-3.11a6 versions
+// are not supported.
+#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
+static inline int PyFloat_Pack4(double x, char *p, int le)
+{ return _PyFloat_Pack4(x, (unsigned char*)p, le); }
+
+static inline int PyFloat_Pack8(double x, char *p, int le)
+{ return _PyFloat_Pack8(x, (unsigned char*)p, le); }
+
+static inline double PyFloat_Unpack4(const char *p, int le)
+{ return _PyFloat_Unpack4((const unsigned char *)p, le); }
+
+static inline double PyFloat_Unpack8(const char *p, int le)
+{ return _PyFloat_Unpack8((const unsigned char *)p, le); }
+#endif
+
+
+// gh-92154 added PyCode_GetCode() to Python 3.11.0b1
+#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
+static inline PyObject* PyCode_GetCode(PyCodeObject *code)
+{
+ return Py_NewRef(code->co_code);
+}
+#endif
+
+
+// gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1
+#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
+static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
+{
+ return Py_NewRef(code->co_varnames);
+}
+#endif
+
+// gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1
+#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
+static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
+{
+ return Py_NewRef(code->co_freevars);
+}
+#endif
+
+// gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1
+#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
+static inline PyObject* PyCode_GetCellvars(PyCodeObject *code)
+{
+ return Py_NewRef(code->co_cellvars);
+}
+#endif
+
+
+// Py_UNUSED() was added to Python 3.4.0b2.
+#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
+# if defined(__GNUC__) || defined(__clang__)
+# define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
+# else
+# define Py_UNUSED(name) _unused_ ## name
+# endif
+#endif
+
+
+// gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A0
+static inline PyObject* PyImport_AddModuleRef(const char *name)
+{
+ return Py_XNewRef(PyImport_AddModule(name));
+}
+#endif
+
+
+// gh-105927 added PyWeakref_GetRef() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D0000
+static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
+{
+ PyObject *obj;
+ if (ref != NULL && !PyWeakref_Check(ref)) {
+ *pobj = NULL;
+ PyErr_SetString(PyExc_TypeError, "expected a weakref");
+ return -1;
+ }
+ obj = PyWeakref_GetObject(ref);
+ if (obj == NULL) {
+ // SystemError if ref is NULL
+ *pobj = NULL;
+ return -1;
+ }
+ if (obj == Py_None) {
+ *pobj = NULL;
+ return 0;
+ }
+ *pobj = Py_NewRef(obj);
+ return (*pobj != NULL);
+}
+#endif
+
+
+// bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1
+#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET
+# define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1))
+#endif
+
+// bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1
+#if PY_VERSION_HEX < 0x030800B1
+static inline Py_ssize_t PyVectorcall_NARGS(size_t n)
+{
+ return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
+}
+#endif
+
+
+// gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4
+static inline PyObject*
+PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames)
+{
+#if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION)
+ // bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1
+ return _PyObject_Vectorcall(callable, args, nargsf, kwnames);
+#else
+ PyObject *posargs = NULL, *kwargs = NULL;
+ PyObject *res;
+ Py_ssize_t nposargs, nkwargs, i;
+
+ if (nargsf != 0 && args == NULL) {
+ PyErr_BadInternalCall();
+ goto error;
+ }
+ if (kwnames != NULL && !PyTuple_Check(kwnames)) {
+ PyErr_BadInternalCall();
+ goto error;
+ }
+
+ nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf);
+ if (kwnames) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ }
+ else {
+ nkwargs = 0;
+ }
+
+ posargs = PyTuple_New(nposargs);
+ if (posargs == NULL) {
+ goto error;
+ }
+ if (nposargs) {
+ for (i=0; i < nposargs; i++) {
+ PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args));
+ args++;
+ }
+ }
+
+ if (nkwargs) {
+ kwargs = PyDict_New();
+ if (kwargs == NULL) {
+ goto error;
+ }
+
+ for (i = 0; i < nkwargs; i++) {
+ PyObject *key = PyTuple_GET_ITEM(kwnames, i);
+ PyObject *value = *args;
+ args++;
+ if (PyDict_SetItem(kwargs, key, value) < 0) {
+ goto error;
+ }
+ }
+ }
+ else {
+ kwargs = NULL;
+ }
+
+ res = PyObject_Call(callable, posargs, kwargs);
+ Py_DECREF(posargs);
+ Py_XDECREF(kwargs);
+ return res;
+
+error:
+ Py_DECREF(posargs);
+ Py_XDECREF(kwargs);
+ return NULL;
+#endif
+}
+#endif
+
+
+// gh-106521 added PyObject_GetOptionalAttr() and
+// PyObject_GetOptionalAttrString() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result)
+{
+ // bpo-32571 added _PyObject_LookupAttr() to Python 3.7.0b1
+#if PY_VERSION_HEX >= 0x030700B1 && !defined(PYPY_VERSION)
+ return _PyObject_LookupAttr(obj, attr_name, result);
+#else
+ *result = PyObject_GetAttr(obj, attr_name);
+ if (*result != NULL) {
+ return 1;
+ }
+ if (!PyErr_Occurred()) {
+ return 0;
+ }
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ return 0;
+ }
+ return -1;
+#endif
+}
+
+static inline int
+PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result)
+{
+ PyObject *name_obj;
+ int rc;
+#if PY_VERSION_HEX >= 0x03000000
+ name_obj = PyUnicode_FromString(attr_name);
+#else
+ name_obj = PyString_FromString(attr_name);
+#endif
+ if (name_obj == NULL) {
+ *result = NULL;
+ return -1;
+ }
+ rc = PyObject_GetOptionalAttr(obj, name_obj, result);
+ Py_DECREF(name_obj);
+ return rc;
+}
+#endif
+
+
+// gh-106307 added PyObject_GetOptionalAttr() and
+// PyMapping_GetOptionalItemString() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result)
+{
+ *result = PyObject_GetItem(obj, key);
+ if (*result) {
+ return 1;
+ }
+ if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
+ return -1;
+ }
+ PyErr_Clear();
+ return 0;
+}
+
+static inline int
+PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result)
+{
+ PyObject *key_obj;
+ int rc;
+#if PY_VERSION_HEX >= 0x03000000
+ key_obj = PyUnicode_FromString(key);
+#else
+ key_obj = PyString_FromString(key);
+#endif
+ if (key_obj == NULL) {
+ *result = NULL;
+ return -1;
+ }
+ rc = PyMapping_GetOptionalItem(obj, key_obj, result);
+ Py_DECREF(key_obj);
+ return rc;
+}
+#endif
+
+// gh-108511 added PyMapping_HasKeyWithError() and
+// PyMapping_HasKeyStringWithError() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyMapping_HasKeyWithError(PyObject *obj, PyObject *key)
+{
+ PyObject *res;
+ int rc = PyMapping_GetOptionalItem(obj, key, &res);
+ Py_XDECREF(res);
+ return rc;
+}
+
+static inline int
+PyMapping_HasKeyStringWithError(PyObject *obj, const char *key)
+{
+ PyObject *res;
+ int rc = PyMapping_GetOptionalItemString(obj, key, &res);
+ Py_XDECREF(res);
+ return rc;
+}
+#endif
+
+
+// gh-108511 added PyObject_HasAttrWithError() and
+// PyObject_HasAttrStringWithError() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyObject_HasAttrWithError(PyObject *obj, PyObject *attr)
+{
+ PyObject *res;
+ int rc = PyObject_GetOptionalAttr(obj, attr, &res);
+ Py_XDECREF(res);
+ return rc;
+}
+
+static inline int
+PyObject_HasAttrStringWithError(PyObject *obj, const char *attr)
+{
+ PyObject *res;
+ int rc = PyObject_GetOptionalAttrString(obj, attr, &res);
+ Py_XDECREF(res);
+ return rc;
+}
+#endif
+
+
+// gh-106004 added PyDict_GetItemRef() and PyDict_GetItemStringRef()
+// to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ PyObject *item = PyDict_GetItemWithError(mp, key);
+#else
+ PyObject *item = _PyDict_GetItemWithError(mp, key);
+#endif
+ if (item != NULL) {
+ *result = Py_NewRef(item);
+ return 1; // found
+ }
+ if (!PyErr_Occurred()) {
+ *result = NULL;
+ return 0; // not found
+ }
+ *result = NULL;
+ return -1;
+}
+
+static inline int
+PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result)
+{
+ int res;
+#if PY_VERSION_HEX >= 0x03000000
+ PyObject *key_obj = PyUnicode_FromString(key);
+#else
+ PyObject *key_obj = PyString_FromString(key);
+#endif
+ if (key_obj == NULL) {
+ *result = NULL;
+ return -1;
+ }
+ res = PyDict_GetItemRef(mp, key_obj, result);
+ Py_DECREF(key_obj);
+ return res;
+}
+#endif
+
+
+// gh-106307 added PyModule_Add() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyModule_Add(PyObject *mod, const char *name, PyObject *value)
+{
+ int res = PyModule_AddObjectRef(mod, name, value);
+ Py_XDECREF(value);
+ return res;
+}
+#endif
+
+
+// gh-108014 added Py_IsFinalizing() to Python 3.13.0a1
+// bpo-1856 added _Py_Finalizing to Python 3.2.1b1.
+// _Py_IsFinalizing() was added to PyPy 7.3.0.
+#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \
+ && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000)
+static inline int Py_IsFinalizing(void)
+{
+#if PY_VERSION_HEX >= 0x030700A1
+ // _Py_IsFinalizing() was added to Python 3.7.0a1.
+ return _Py_IsFinalizing();
+#else
+ return (_Py_Finalizing != NULL);
+#endif
+}
+#endif
+
+
+// gh-108323 added PyDict_ContainsString() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int PyDict_ContainsString(PyObject *op, const char *key)
+{
+ PyObject *key_obj = PyUnicode_FromString(key);
+ if (key_obj == NULL) {
+ return -1;
+ }
+ int res = PyDict_Contains(op, key_obj);
+ Py_DECREF(key_obj);
+ return res;
+}
+#endif
+
+
+// gh-108445 added PyLong_AsInt() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int PyLong_AsInt(PyObject *obj)
+{
+#ifdef PYPY_VERSION
+ long value = PyLong_AsLong(obj);
+ if (value == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (value < (long)INT_MIN || (long)INT_MAX < value) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int");
+ return -1;
+ }
+ return (int)value;
+#else
+ return _PyLong_AsInt(obj);
+#endif
+}
+#endif
+
+
+// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
+{
+ PyObject **dict = _PyObject_GetDictPtr(obj);
+ if (*dict == NULL) {
+ return -1;
+ }
+ Py_VISIT(*dict);
+ return 0;
+}
+
+static inline void
+PyObject_ClearManagedDict(PyObject *obj)
+{
+ PyObject **dict = _PyObject_GetDictPtr(obj);
+ if (*dict == NULL) {
+ return;
+ }
+ Py_CLEAR(*dict);
+}
+#endif
+
+// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1
+// Python 3.5.2 added _PyThreadState_UncheckedGet().
+#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1
+static inline PyThreadState*
+PyThreadState_GetUnchecked(void)
+{
+ return _PyThreadState_UncheckedGet();
+}
+#endif
+
+// gh-110289 added PyUnicode_EqualToUTF8() and PyUnicode_EqualToUTF8AndSize()
+// to Python 3.13.0a1
+#if PY_VERSION_HEX < 0x030D00A1
+static inline int
+PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_len)
+{
+ Py_ssize_t len;
+ const void *utf8;
+ PyObject *exc_type, *exc_value, *exc_tb;
+ int res;
+
+ // API cannot report errors so save/restore the exception
+ PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
+
+ // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize()
+#if PY_VERSION_HEX >= 0x030300A1
+ if (PyUnicode_IS_ASCII(unicode)) {
+ utf8 = PyUnicode_DATA(unicode);
+ len = PyUnicode_GET_LENGTH(unicode);
+ }
+ else {
+ utf8 = PyUnicode_AsUTF8AndSize(unicode, &len);
+ if (utf8 == NULL) {
+ // Memory allocation failure. The API cannot report error,
+ // so ignore the exception and return 0.
+ res = 0;
+ goto done;
+ }
+ }
+
+ if (len != str_len) {
+ res = 0;
+ goto done;
+ }
+ res = (memcmp(utf8, str, (size_t)len) == 0);
+#else
+ PyObject *bytes = PyUnicode_AsUTF8String(unicode);
+ if (bytes == NULL) {
+ // Memory allocation failure. The API cannot report error,
+ // so ignore the exception and return 0.
+ res = 0;
+ goto done;
+ }
+
+#if PY_VERSION_HEX >= 0x03000000
+ len = PyBytes_GET_SIZE(bytes);
+ utf8 = PyBytes_AS_STRING(bytes);
+#else
+ len = PyString_GET_SIZE(bytes);
+ utf8 = PyString_AS_STRING(bytes);
+#endif
+ if (len != str_len) {
+ Py_DECREF(bytes);
+ res = 0;
+ goto done;
+ }
+
+ res = (memcmp(utf8, str, (size_t)len) == 0);
+ Py_DECREF(bytes);
+#endif
+
+done:
+ PyErr_Restore(exc_type, exc_value, exc_tb);
+ return res;
+}
+
+static inline int
+PyUnicode_EqualToUTF8(PyObject *unicode, const char *str)
+{
+ return PyUnicode_EqualToUTF8AndSize(unicode, str, (Py_ssize_t)strlen(str));
+}
+#endif
+
+
+// gh-111138 added PyList_Extend() and PyList_Clear() to Python 3.13.0a2
+#if PY_VERSION_HEX < 0x030D00A2
+static inline int
+PyList_Extend(PyObject *list, PyObject *iterable)
+{
+ return PyList_SetSlice(list, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable);
+}
+
+static inline int
+PyList_Clear(PyObject *list)
+{
+ return PyList_SetSlice(list, 0, PY_SSIZE_T_MAX, NULL);
+}
+#endif
+
+// gh-111262 added PyDict_Pop() and PyDict_PopString() to Python 3.13.0a2
+#if PY_VERSION_HEX < 0x030D00A2
+static inline int
+PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result)
+{
+ PyObject *value;
+
+ if (!PyDict_Check(dict)) {
+ PyErr_BadInternalCall();
+ if (result) {
+ *result = NULL;
+ }
+ return -1;
+ }
+
+ // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2.
+ // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*.
+ // Python 3.13.0a1 removed _PyDict_Pop().
+#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000
+ value = PyObject_CallMethod(dict, "pop", "O", key);
+#elif PY_VERSION_HEX < 0x030600b3
+ value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL);
+#else
+ value = _PyDict_Pop(dict, key, NULL);
+#endif
+ if (value == NULL) {
+ if (result) {
+ *result = NULL;
+ }
+ if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) {
+ return -1;
+ }
+ PyErr_Clear();
+ return 0;
+ }
+ if (result) {
+ *result = value;
+ }
+ else {
+ Py_DECREF(value);
+ }
+ return 1;
+}
+
+static inline int
+PyDict_PopString(PyObject *dict, const char *key, PyObject **result)
+{
+ PyObject *key_obj = PyUnicode_FromString(key);
+ if (key_obj == NULL) {
+ if (result != NULL) {
+ *result = NULL;
+ }
+ return -1;
+ }
+
+ int res = PyDict_Pop(dict, key_obj, result);
+ Py_DECREF(key_obj);
+ return res;
+}
+#endif
+
+
+#if PY_VERSION_HEX < 0x030200A4
+// Python 3.2.0a4 added Py_hash_t type
+typedef Py_ssize_t Py_hash_t;
+#endif
+
+
+// gh-111545 added Py_HashPointer() to Python 3.13.0a3
+#if PY_VERSION_HEX < 0x030D00A3
+static inline Py_hash_t Py_HashPointer(const void *ptr)
+{
+#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION)
+ return _Py_HashPointer(ptr);
+#else
+ return _Py_HashPointer(_Py_CAST(void*, ptr));
+#endif
+}
+#endif
+
+
+// Python 3.13a4 added a PyTime API.
+// Use the private API added to Python 3.5.
+#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000
+typedef _PyTime_t PyTime_t;
+#define PyTime_MIN _PyTime_MIN
+#define PyTime_MAX _PyTime_MAX
+
+static inline double PyTime_AsSecondsDouble(PyTime_t t)
+{ return _PyTime_AsSecondsDouble(t); }
+
+static inline int PyTime_Monotonic(PyTime_t *result)
+{ return _PyTime_GetMonotonicClockWithInfo(result, NULL); }
+
+static inline int PyTime_Time(PyTime_t *result)
+{ return _PyTime_GetSystemClockWithInfo(result, NULL); }
+
+static inline int PyTime_PerfCounter(PyTime_t *result)
+{
+#if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION)
+ return _PyTime_GetPerfCounterWithInfo(result, NULL);
+#elif PY_VERSION_HEX >= 0x03070000
+ // Call time.perf_counter_ns() and convert Python int object to PyTime_t.
+ // Cache time.perf_counter_ns() function for best performance.
+ static PyObject *func = NULL;
+ if (func == NULL) {
+ PyObject *mod = PyImport_ImportModule("time");
+ if (mod == NULL) {
+ return -1;
+ }
+
+ func = PyObject_GetAttrString(mod, "perf_counter_ns");
+ Py_DECREF(mod);
+ if (func == NULL) {
+ return -1;
+ }
+ }
+
+ PyObject *res = PyObject_CallNoArgs(func);
+ if (res == NULL) {
+ return -1;
+ }
+ long long value = PyLong_AsLongLong(res);
+ Py_DECREF(res);
+
+ if (value == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ Py_BUILD_ASSERT(sizeof(value) >= sizeof(PyTime_t));
+ *result = (PyTime_t)value;
+ return 0;
+#else
+ // Call time.perf_counter() and convert C double to PyTime_t.
+ // Cache time.perf_counter() function for best performance.
+ static PyObject *func = NULL;
+ if (func == NULL) {
+ PyObject *mod = PyImport_ImportModule("time");
+ if (mod == NULL) {
+ return -1;
+ }
+
+ func = PyObject_GetAttrString(mod, "perf_counter");
+ Py_DECREF(mod);
+ if (func == NULL) {
+ return -1;
+ }
+ }
+
+ PyObject *res = PyObject_CallNoArgs(func);
+ if (res == NULL) {
+ return -1;
+ }
+ double d = PyFloat_AsDouble(res);
+ Py_DECREF(res);
+
+ if (d == -1.0 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ // Avoid floor() to avoid having to link to libm
+ *result = (PyTime_t)(d * 1e9);
+ return 0;
+#endif
+}
+
+#endif
+
+// gh-111389 added hash constants to Python 3.13.0a5. These constants were
+// added first as private macros to Python 3.4.0b1 and PyPy 7.3.9.
+#if (!defined(PyHASH_BITS) \
+ && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \
+ || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \
+ && PYPY_VERSION_NUM >= 0x07090000)))
+# define PyHASH_BITS _PyHASH_BITS
+# define PyHASH_MODULUS _PyHASH_MODULUS
+# define PyHASH_INF _PyHASH_INF
+# define PyHASH_IMAG _PyHASH_IMAG
+#endif
+
+
+// gh-111545 added Py_GetConstant() and Py_GetConstantBorrowed()
+// to Python 3.13.0a6
+#if PY_VERSION_HEX < 0x030D00A6 && !defined(Py_CONSTANT_NONE)
+
+#define Py_CONSTANT_NONE 0
+#define Py_CONSTANT_FALSE 1
+#define Py_CONSTANT_TRUE 2
+#define Py_CONSTANT_ELLIPSIS 3
+#define Py_CONSTANT_NOT_IMPLEMENTED 4
+#define Py_CONSTANT_ZERO 5
+#define Py_CONSTANT_ONE 6
+#define Py_CONSTANT_EMPTY_STR 7
+#define Py_CONSTANT_EMPTY_BYTES 8
+#define Py_CONSTANT_EMPTY_TUPLE 9
+
+static inline PyObject* Py_GetConstant(unsigned int constant_id)
+{
+ static PyObject* constants[Py_CONSTANT_EMPTY_TUPLE + 1] = {NULL};
+
+ if (constants[Py_CONSTANT_NONE] == NULL) {
+ constants[Py_CONSTANT_NONE] = Py_None;
+ constants[Py_CONSTANT_FALSE] = Py_False;
+ constants[Py_CONSTANT_TRUE] = Py_True;
+ constants[Py_CONSTANT_ELLIPSIS] = Py_Ellipsis;
+ constants[Py_CONSTANT_NOT_IMPLEMENTED] = Py_NotImplemented;
+
+ constants[Py_CONSTANT_ZERO] = PyLong_FromLong(0);
+ if (constants[Py_CONSTANT_ZERO] == NULL) {
+ goto fatal_error;
+ }
+
+ constants[Py_CONSTANT_ONE] = PyLong_FromLong(1);
+ if (constants[Py_CONSTANT_ONE] == NULL) {
+ goto fatal_error;
+ }
+
+ constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_FromStringAndSize("", 0);
+ if (constants[Py_CONSTANT_EMPTY_STR] == NULL) {
+ goto fatal_error;
+ }
+
+ constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize("", 0);
+ if (constants[Py_CONSTANT_EMPTY_BYTES] == NULL) {
+ goto fatal_error;
+ }
+
+ constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0);
+ if (constants[Py_CONSTANT_EMPTY_TUPLE] == NULL) {
+ goto fatal_error;
+ }
+ // goto dance to avoid compiler warnings about Py_FatalError()
+ goto init_done;
+
+fatal_error:
+ // This case should never happen
+ Py_FatalError("Py_GetConstant() failed to get constants");
+ }
+
+init_done:
+ if (constant_id <= Py_CONSTANT_EMPTY_TUPLE) {
+ return Py_NewRef(constants[constant_id]);
+ }
+ else {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+}
+
+static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
+{
+ PyObject *obj = Py_GetConstant(constant_id);
+ Py_XDECREF(obj);
+ return obj;
+}
+#endif
+
+
+// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
+#if PY_VERSION_HEX < 0x030D00A4
+static inline PyObject *
+PyList_GetItemRef(PyObject *op, Py_ssize_t index)
+{
+ PyObject *item = PyList_GetItem(op, index);
+ Py_XINCREF(item);
+ return item;
+}
+#endif
+
+
+// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
+#if PY_VERSION_HEX < 0x030D00A4
+static inline int
+PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
+ PyObject **result)
+{
+ PyObject *value;
+ if (PyDict_GetItemRef(d, key, &value) < 0) {
+ // get error
+ if (result) {
+ *result = NULL;
+ }
+ return -1;
+ }
+ if (value != NULL) {
+ // present
+ if (result) {
+ *result = value;
+ }
+ else {
+ Py_DECREF(value);
+ }
+ return 1;
+ }
+
+ // missing: set the item
+ if (PyDict_SetItem(d, key, default_value) < 0) {
+ // set error
+ if (result) {
+ *result = NULL;
+ }
+ return -1;
+ }
+ if (result) {
+ *result = Py_NewRef(default_value);
+ }
+ return 0;
+}
+#endif
+
+#if PY_VERSION_HEX < 0x030D00B3
+# define Py_BEGIN_CRITICAL_SECTION(op) {
+# define Py_END_CRITICAL_SECTION() }
+# define Py_BEGIN_CRITICAL_SECTION2(a, b) {
+# define Py_END_CRITICAL_SECTION2() }
+#endif
+
+#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
+typedef struct PyUnicodeWriter PyUnicodeWriter;
+
+static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
+{
+ _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer);
+ PyMem_Free(writer);
+}
+
+static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
+{
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "length must be positive");
+ return NULL;
+ }
+
+ const size_t size = sizeof(_PyUnicodeWriter);
+ PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size);
+ if (pub_writer == _Py_NULL) {
+ PyErr_NoMemory();
+ return _Py_NULL;
+ }
+ _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer;
+
+ _PyUnicodeWriter_Init(writer);
+ if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) {
+ PyUnicodeWriter_Discard(pub_writer);
+ return NULL;
+ }
+ writer->overallocate = 1;
+ return pub_writer;
+}
+
+static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
+{
+ PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer);
+ assert(((_PyUnicodeWriter*)writer)->buffer == NULL);
+ PyMem_Free(writer);
+ return str;
+}
+
+static inline int
+PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
+{
+ if (ch > 0x10ffff) {
+ PyErr_SetString(PyExc_ValueError,
+ "character must be in range(0x110000)");
+ return -1;
+ }
+
+ return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch);
+}
+
+static inline int
+PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
+{
+ PyObject *str = PyObject_Str(obj);
+ if (str == NULL) {
+ return -1;
+ }
+
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ Py_DECREF(str);
+ return res;
+}
+
+static inline int
+PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
+{
+ PyObject *str = PyObject_Repr(obj);
+ if (str == NULL) {
+ return -1;
+ }
+
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ Py_DECREF(str);
+ return res;
+}
+
+static inline int
+PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
+ const char *str, Py_ssize_t size)
+{
+ if (size < 0) {
+ size = (Py_ssize_t)strlen(str);
+ }
+
+ PyObject *str_obj = PyUnicode_FromStringAndSize(str, size);
+ if (str_obj == _Py_NULL) {
+ return -1;
+ }
+
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
+ Py_DECREF(str_obj);
+ return res;
+}
+
+static inline int
+PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer,
+ const wchar_t *str, Py_ssize_t size)
+{
+ if (size < 0) {
+ size = (Py_ssize_t)wcslen(str);
+ }
+
+ PyObject *str_obj = PyUnicode_FromWideChar(str, size);
+ if (str_obj == _Py_NULL) {
+ return -1;
+ }
+
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
+ Py_DECREF(str_obj);
+ return res;
+}
+
+static inline int
+PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str,
+ Py_ssize_t start, Py_ssize_t end)
+{
+ if (!PyUnicode_Check(str)) {
+ PyErr_Format(PyExc_TypeError, "expect str, not %T", str);
+ return -1;
+ }
+ if (start < 0 || start > end) {
+ PyErr_Format(PyExc_ValueError, "invalid start argument");
+ return -1;
+ }
+ if (end > PyUnicode_GET_LENGTH(str)) {
+ PyErr_Format(PyExc_ValueError, "invalid end argument");
+ return -1;
+ }
+
+ return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str,
+ start, end);
+}
+
+static inline int
+PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
+{
+ va_list vargs;
+ va_start(vargs, format);
+ PyObject *str = PyUnicode_FromFormatV(format, vargs);
+ va_end(vargs);
+ if (str == _Py_NULL) {
+ return -1;
+ }
+
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ Py_DECREF(str);
+ return res;
+}
+#endif // PY_VERSION_HEX < 0x030E0000
+
+// gh-116560 added PyLong_GetSign() to Python 3.14.0a0
+#if PY_VERSION_HEX < 0x030E00A0
+static inline int PyLong_GetSign(PyObject *obj, int *sign)
+{
+ if (!PyLong_Check(obj)) {
+ PyErr_Format(PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name);
+ return -1;
+ }
+
+ *sign = _PyLong_Sign(obj);
+ return 0;
+}
+#endif
+
+
+// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
+#if PY_VERSION_HEX < 0x030E00A0
+static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
+{
+ if (!PyUnicode_Check(str1)) {
+ PyErr_Format(PyExc_TypeError, "first argument must be str, not %s",
+ Py_TYPE(str1)->tp_name);
+ return -1;
+ }
+ if (!PyUnicode_Check(str2)) {
+ PyErr_Format(PyExc_TypeError, "second argument must be str, not %s",
+ Py_TYPE(str2)->tp_name);
+ return -1;
+ }
+
+#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
+ PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
+
+ return _PyUnicode_Equal(str1, str2);
+#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
+ return _PyUnicode_EQ(str1, str2);
+#elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION)
+ return _PyUnicode_EQ(str1, str2);
+#else
+ return (PyUnicode_Compare(str1, str2) == 0);
+#endif
+}
+#endif
+
+
+// gh-121645 added PyBytes_Join() to Python 3.14.0a0
+#if PY_VERSION_HEX < 0x030E00A0
+static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
+{
+ return _PyBytes_Join(sep, iterable);
+}
+#endif
+
+
+#if PY_VERSION_HEX < 0x030E00A0
+static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
+{
+#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
+ PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);
+
+ return _Py_HashBytes(ptr, len);
+#else
+ Py_hash_t hash;
+ PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len);
+ if (bytes == NULL) {
+ return -1;
+ }
+ hash = PyObject_Hash(bytes);
+ Py_DECREF(bytes);
+ return hash;
+#endif
+}
+#endif
+
+
+#if PY_VERSION_HEX < 0x030E00A0
+static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
+{
+ iternextfunc tp_iternext;
+
+ assert(iter != NULL);
+ assert(item != NULL);
+
+ tp_iternext = Py_TYPE(iter)->tp_iternext;
+ if (tp_iternext == NULL) {
+ *item = NULL;
+ PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'",
+ Py_TYPE(iter)->tp_name);
+ return -1;
+ }
+
+ if ((*item = tp_iternext(iter))) {
+ return 1;
+ }
+ if (!PyErr_Occurred()) {
+ return 0;
+ }
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Clear();
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+
+#if PY_VERSION_HEX < 0x030E00A0
+static inline PyObject* PyLong_FromInt32(int32_t value)
+{
+ Py_BUILD_ASSERT(sizeof(long) >= 4);
+ return PyLong_FromLong(value);
+}
+
+static inline PyObject* PyLong_FromInt64(int64_t value)
+{
+ Py_BUILD_ASSERT(sizeof(long long) >= 8);
+ return PyLong_FromLongLong(value);
+}
+
+static inline PyObject* PyLong_FromUInt32(uint32_t value)
+{
+ Py_BUILD_ASSERT(sizeof(unsigned long) >= 4);
+ return PyLong_FromUnsignedLong(value);
+}
+
+static inline PyObject* PyLong_FromUInt64(uint64_t value)
+{
+ Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8);
+ return PyLong_FromUnsignedLongLong(value);
+}
+
+static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
+{
+ Py_BUILD_ASSERT(sizeof(int) == 4);
+ int value = PyLong_AsInt(obj);
+ if (value == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ *pvalue = (int32_t)value;
+ return 0;
+}
+
+static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
+{
+ Py_BUILD_ASSERT(sizeof(long long) == 8);
+ long long value = PyLong_AsLongLong(obj);
+ if (value == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ *pvalue = (int64_t)value;
+ return 0;
+}
+
+static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
+{
+ Py_BUILD_ASSERT(sizeof(long) >= 4);
+ unsigned long value = PyLong_AsUnsignedLong(obj);
+ if (value == (unsigned long)-1 && PyErr_Occurred()) {
+ return -1;
+ }
+#if SIZEOF_LONG > 4
+ if ((unsigned long)UINT32_MAX < value) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint32_t");
+ return -1;
+ }
+#endif
+ *pvalue = (uint32_t)value;
+ return 0;
+}
+
+static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
+{
+ Py_BUILD_ASSERT(sizeof(long long) == 8);
+ unsigned long long value = PyLong_AsUnsignedLongLong(obj);
+ if (value == (unsigned long long)-1 && PyErr_Occurred()) {
+ return -1;
+ }
+ *pvalue = (uint64_t)value;
+ return 0;
+}
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif // PYTHONCAPI_COMPAT