python-numba/py313.patch

4128 lines
145 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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