summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2023-04-28 14:02:40 +0300
committerGitHub <noreply@github.com>2023-04-28 14:02:40 +0300
commit46055823a517d9e53918cb9b4495d05633ff6f35 (patch)
tree3df4dabdb5ab63fd42fa5d1de408c38a89dcfde3
parent6d15eddf8f7d856b9b84f800ef4858858a52498e (diff)
parent6ce690dc5584666beb13b41650110d6a601160b1 (diff)
downloadnumpy-46055823a517d9e53918cb9b4495d05633ff6f35.tar.gz
Merge pull request #23528 from seberg/allow-backcomp-builds
ENH: Allow, and default to, downstream building with old API
-rw-r--r--doc/release/upcoming_changes/23528.compatibility.rst16
-rw-r--r--doc/source/dev/depending_on_numpy.rst106
-rw-r--r--doc/source/dev/reviewer_guidelines.rst29
-rw-r--r--numpy/core/code_generators/cversions.txt4
-rw-r--r--numpy/core/code_generators/genapi.py52
-rw-r--r--numpy/core/code_generators/numpy_api.py12
-rw-r--r--numpy/core/include/numpy/arrayscalars.h4
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h33
-rw-r--r--numpy/core/include/numpy/numpyconfig.h85
-rw-r--r--numpy/core/include/numpy/ufuncobject.h6
-rw-r--r--numpy/core/meson.build3
-rw-r--r--numpy/core/setup_common.py12
-rw-r--r--numpy/core/tests/test_mem_policy.py1
13 files changed, 257 insertions, 106 deletions
diff --git a/doc/release/upcoming_changes/23528.compatibility.rst b/doc/release/upcoming_changes/23528.compatibility.rst
new file mode 100644
index 000000000..439fb6a27
--- /dev/null
+++ b/doc/release/upcoming_changes/23528.compatibility.rst
@@ -0,0 +1,16 @@
+By default, the exported NumPy C API is now compatible with NumPy 1.19
+----------------------------------------------------------------------
+Starting with NumPy 1.25 when including NumPy headers, NumPy now
+defaults to exposing a backwards compatible API.
+This means that by default binaries such as wheels build against
+NumPy 1.25 will also work with NumPy 1.16 because it has the same API version
+as NumPy 1.19 which is the oldest NumPy version compatible with Python 3.9.
+
+You can customize this behavior using::
+
+ #define NPY_TARGET_VERSION NPY_1_22_API_VERSION
+
+or the equivalent ``-D`` option to the compiler. For more details
+please see `for-downstream-package-authors`_.
+A change should only be required in rare cases when a package relies on newly
+added C-API.
diff --git a/doc/source/dev/depending_on_numpy.rst b/doc/source/dev/depending_on_numpy.rst
index 0582048cb..868b44162 100644
--- a/doc/source/dev/depending_on_numpy.rst
+++ b/doc/source/dev/depending_on_numpy.rst
@@ -48,70 +48,80 @@ job, either all warnings or otherwise at least ``DeprecationWarning`` and
adapt your code.
+.. _depending_on_numpy:
+
Adding a dependency on NumPy
----------------------------
Build-time dependency
~~~~~~~~~~~~~~~~~~~~~
+.. note::
+
+ Before NumPy 1.25, the NumPy C-API was *not* backwards compatible. This
+ means that when compiling with a NumPy version earlier than 1.25 you
+ have to compile with the oldest version you wish to support.
+ This can be done by using
+ `oldest-supported-numpy <https://github.com/scipy/oldest-supported-numpy/>`__.
+ Please see the NumPy 1.24 documentation at
+ `https://numpy.org/doc/1.24/dev/depending_on_numpy.html`__.
+
+
If a package either uses the NumPy C API directly or it uses some other tool
that depends on it like Cython or Pythran, NumPy is a *build-time* dependency
-of the package. Because the NumPy ABI is only forward compatible, you must
-build your own binaries (wheels or other package formats) against the lowest
-NumPy version that you support (or an even older version).
-
-Picking the correct NumPy version to build against for each Python version and
-platform can get complicated. There are a couple of ways to do this.
-Build-time dependencies are specified in ``pyproject.toml`` (see PEP 517),
-which is the file used to build wheels by PEP 517 compliant tools (e.g.,
-when using ``pip wheel``).
-
-You can specify everything manually in ``pyproject.toml``, or you can instead
-rely on the `oldest-supported-numpy <https://github.com/scipy/oldest-supported-numpy/>`__
-metapackage. ``oldest-supported-numpy`` will specify the correct NumPy version
-at build time for wheels, taking into account Python version, Python
-implementation (CPython or PyPy), operating system and hardware platform. It
-will specify the oldest NumPy version that supports that combination of
-characteristics. Note: for platforms for which NumPy provides wheels on PyPI,
-it will be the first version with wheels (even if some older NumPy version
-happens to build).
-
-For conda-forge it's a little less complicated: there's dedicated handling for
-NumPy in build-time and runtime dependencies, so typically this is enough
-(see `here <https://conda-forge.org/docs/maintainer/knowledge_base.html#building-against-numpy>`__ for docs)::
+of the package.
- host:
- - numpy
- run:
- - {{ pin_compatible('numpy') }}
+By default, NumPy will expose an API that is backwards compatible with the
+oldest NumPy version that supports the currently oldest compatible Python
+version. NumPy 1.25.0 supports Python 3.9 and higher and NumPy 1.19 is the
+first version to support Python 3.9. Thus, we guarantee that, when using
+defaults, NumPy 1.25 will expose a C-API compatible with NumPy 1.19.
+(the exact version is set within NumPy-internal header files).
-.. note::
+NumPy is also forward compatible for all minor releases, but a major release
+will require recompilation.
+
+The default behavior can be customized for example by adding::
- ``pip`` has ``--no-use-pep517`` and ``--no-build-isolation`` flags that may
- ignore ``pyproject.toml`` or treat it differently - if users use those
- flags, they are responsible for installing the correct build dependencies
- themselves.
+ #define NPY_TARGET_VERSION NPY_1_22_API_VERSION
- ``conda`` will always use ``-no-build-isolation``; dependencies for conda
- builds are given in the conda recipe (``meta.yaml``), the ones in
- ``pyproject.toml`` have no effect.
+before including any NumPy headers (or the equivalent ``-D`` compiler flag) in
+every extension module that requires the NumPy C-API.
+This is mainly useful if you need to use newly added API at the cost of not
+being compatible with older versions.
- Please do not use ``setup_requires`` (it is deprecated and may invoke
- ``easy_install``).
+If for some reason you wish to compile for the currently installed NumPy
+version by default you can add::
-Because for NumPy you have to care about ABI compatibility, you
-specify the version with ``==`` to the lowest supported version. For your other
-build dependencies you can probably be looser, however it's still important to
-set lower and upper bounds for each dependency. It's fine to specify either a
-range or a specific version for a dependency like ``wheel`` or ``setuptools``.
+ #ifndef NPY_TARGET_VERSION
+ #define NPY_TARGET_VERSION NPY_API_VERSION
+ #endif
-.. warning::
+Which allows a user to override the default via ``-DNPY_TARGET_VERSION``.
+This define must be consistent for each extension module (use of
+``import_array()``) and also applies to the umath module.
+
+When you compile against NumPy, you should add the proper version restrictions
+to your ``pyproject.toml`` (see PEP 517). Since your extension will not be
+compatible with a new major release of NumPy and may not be compatible with
+very old versions.
+
+For conda-forge packages, please see
+`here <https://conda-forge.org/docs/maintainer/knowledge_base.html#building-against-numpy>`__.
+
+as of now, it is usually as easy as including::
+
+ host:
+ - numpy
+ run:
+ - {{ pin_compatible('numpy') }}
+
+.. note::
- Note that ``setuptools`` does major releases often and those may contain
- changes that break ``numpy.distutils``, which will *not* be updated anymore
- for new ``setuptools`` versions. It is therefore recommended to set an
- upper version bound in your build configuration for the last known version
- of ``setuptools`` that works with your build.
+ At the time of NumPy 1.25, NumPy 2.0 is expected to be the next release
+ of NumPy. The NumPy 2.0 release is expected to require a different pin,
+ since NumPy 2+ will be needed in order to be compatible with both NumPy
+ 1.x and 2.x.
Runtime dependency & version ranges
diff --git a/doc/source/dev/reviewer_guidelines.rst b/doc/source/dev/reviewer_guidelines.rst
index f3bc1600b..0ed9bf2e5 100644
--- a/doc/source/dev/reviewer_guidelines.rst
+++ b/doc/source/dev/reviewer_guidelines.rst
@@ -101,7 +101,34 @@ For maintainers
If a PR becomes inactive, maintainers may make larger changes.
Remember, a PR is a collaboration between a contributor and a reviewer/s,
sometimes a direct push is the best way to finish it.
-
+
+API Changes
+-----------
+As mentioned most public API changes should be discussed ahead of time and
+often with a wider audience (on the mailing list, or even through a NEP).
+
+For changes in the public C-API be aware that the NumPy C-API is backwards
+compatible so that any addition must be ABI compatible with previous versions.
+When it is not the case, you must add a guard.
+
+For example ``PyUnicodeScalarObject`` struct contains the following::
+
+ #if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
+ char *buffer_fmt;
+ #endif
+
+Because the ``buffer_fmt`` field was added to its end in NumPy 1.20 (all
+previous fields remained ABI compatible).
+Similarly, any function added to the API table in
+``numpy/core/code_generators/numpy_api.py`` must use the ``MinVersion``
+annotation.
+For example::
+
+ 'PyDataMem_SetHandler': (304, MinVersion("1.22")),
+
+Header only functionality (such as a new macro) typically does not need to be
+guarded.
+
GitHub Workflow
---------------
diff --git a/numpy/core/code_generators/cversions.txt b/numpy/core/code_generators/cversions.txt
index bd4b71180..e52193d7a 100644
--- a/numpy/core/code_generators/cversions.txt
+++ b/numpy/core/code_generators/cversions.txt
@@ -67,5 +67,7 @@
# Version 16 (NumPy 1.23)
# NonNull attributes removed from numpy_api.py
# Version 16 (NumPy 1.24) No change.
-# Version 16 (NumPy 1.25) No change.
0x00000010 = 04a7bf1e65350926a0e528798da263c0
+
+# Version 17 (NumPy 1.25) No actual change.
+0x00000011 = ca1aebdad799358149567d9d93cbca09
diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py
index 655d5ed67..2cdaba52d 100644
--- a/numpy/core/code_generators/genapi.py
+++ b/numpy/core/code_generators/genapi.py
@@ -12,6 +12,7 @@ import os
import re
import sys
import importlib.util
+import textwrap
from os.path import join
@@ -98,6 +99,27 @@ def _repl(str):
return str.replace('Bool', 'npy_bool')
+class MinVersion:
+ def __init__(self, version):
+ """ Version should be the normal NumPy version, e.g. "1.25" """
+ major, minor = version.split(".")
+ self.version = f"NPY_{major}_{minor}_API_VERSION"
+
+ def __str__(self):
+ # Used by version hashing:
+ return self.version
+
+ def add_guard(self, name, normal_define):
+ """Wrap a definition behind a version guard"""
+ wrap = textwrap.dedent(f"""
+ #if NPY_FEATURE_VERSION >= {self.version}
+ {{define}}
+ #endif""")
+
+ # we only insert `define` later to avoid confusing dedent:
+ return wrap.format(define=normal_define)
+
+
class StealRef:
def __init__(self, arg):
self.arg = arg # counting from 1
@@ -391,7 +413,20 @@ class FunctionApi:
def __init__(self, name, index, annotations, return_type, args, api_name):
self.name = name
self.index = index
- self.annotations = annotations
+
+ self.min_version = None
+ self.annotations = []
+ for annotation in annotations:
+ # String checks, because manual import breaks isinstance
+ if type(annotation).__name__ == "StealRef":
+ self.annotations.append(annotation)
+ elif type(annotation).__name__ == "MinVersion":
+ if self.min_version is not None:
+ raise ValueError("Two minimum versions specified!")
+ self.min_version = annotation
+ else:
+ raise ValueError(f"unknown annotation {annotation}")
+
self.return_type = return_type
self.args = args
self.api_name = api_name
@@ -403,13 +438,14 @@ class FunctionApi:
return argstr
def define_from_array_api_string(self):
- define = """\
-#define %s \\\n (*(%s (*)(%s)) \\
- %s[%d])""" % (self.name,
- self.return_type,
- self._argtypes_string(),
- self.api_name,
- self.index)
+ arguments = self._argtypes_string()
+ define = textwrap.dedent(f"""\
+ #define {self.name} \\
+ (*({self.return_type} (*)({arguments})) \\
+ {self.api_name}[{self.index}])""")
+
+ if self.min_version is not None:
+ define = self.min_version.add_guard(self.name, define)
return define
def array_api_define(self):
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index 6b9080403..bb3b15806 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -18,17 +18,17 @@ import os
import importlib.util
-def get_StealRef():
+def get_annotations():
# Convoluted because we can't import from numpy.distutils
# (numpy is not yet built)
genapi_py = os.path.join(os.path.dirname(__file__), 'genapi.py')
spec = importlib.util.spec_from_file_location('conv_template', genapi_py)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
- return mod.StealRef
+ return mod.StealRef, mod.MinVersion
-StealRef = get_StealRef()
+StealRef, MinVersion = get_annotations()
#from code_generators.genapi import StealRef
# index, type
@@ -367,8 +367,8 @@ multiarray_funcs_api = {
'PyArray_ResolveWritebackIfCopy': (302,),
'PyArray_SetWritebackIfCopyBase': (303,),
# End 1.14 API
- 'PyDataMem_SetHandler': (304,),
- 'PyDataMem_GetHandler': (305,),
+ 'PyDataMem_SetHandler': (304, MinVersion("1.22")),
+ 'PyDataMem_GetHandler': (305, MinVersion("1.22")),
# End 1.22 API
}
@@ -422,7 +422,7 @@ ufunc_funcs_api = {
# End 1.7 API
'PyUFunc_RegisterLoopForDescr': (41,),
# End 1.8 API
- 'PyUFunc_FromFuncAndDataAndSignatureAndIdentity': (42,),
+ 'PyUFunc_FromFuncAndDataAndSignatureAndIdentity': (42, MinVersion("1.16")),
# End 1.16 API
}
diff --git a/numpy/core/include/numpy/arrayscalars.h b/numpy/core/include/numpy/arrayscalars.h
index a20a68016..258bf95b6 100644
--- a/numpy/core/include/numpy/arrayscalars.h
+++ b/numpy/core/include/numpy/arrayscalars.h
@@ -139,7 +139,9 @@ typedef struct {
/* note that the PyObject_HEAD macro lives right here */
PyUnicodeObject base;
Py_UCS4 *obval;
+ #if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
char *buffer_fmt;
+ #endif
} PyUnicodeScalarObject;
@@ -149,7 +151,9 @@ typedef struct {
PyArray_Descr *descr;
int flags;
PyObject *base;
+ #if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
void *_buffer_info; /* private buffer info, tagged to allow warning */
+ #endif
} PyVoidScalarObject;
/* Macros
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 45ecb6955..742ba5261 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -44,23 +44,6 @@
#define NPY_FAIL 0
#define NPY_SUCCEED 1
-/*
- * Binary compatibility version number. This number is increased
- * whenever the C-API is changed such that binary compatibility is
- * broken, i.e. whenever a recompile of extension modules is needed.
- */
-#define NPY_VERSION NPY_ABI_VERSION
-
-/*
- * Minor API version. This number is increased whenever a change is
- * made to the C-API -- whether it breaks binary compatibility or not.
- * Some changes, such as adding a function pointer to the end of the
- * function table, can be made without breaking binary compatibility.
- * In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION)
- * would be increased. Whenever binary compatibility is broken, both
- * NPY_VERSION and NPY_FEATURE_VERSION should be increased.
- */
-#define NPY_FEATURE_VERSION NPY_API_VERSION
enum NPY_TYPES { NPY_BOOL=0,
NPY_BYTE, NPY_UBYTE,
@@ -729,11 +712,15 @@ typedef struct tagPyArrayObject_fields {
int flags;
/* For weak references */
PyObject *weakreflist;
+#if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
void *_buffer_info; /* private buffer info, tagged to allow warning */
+#endif
/*
* For malloc/calloc/realloc/free per object
*/
+#if NPY_FEATURE_VERSION >= NPY_1_22_API_VERSION
PyObject *mem_handler;
+#endif
} PyArrayObject_fields;
/*
@@ -1671,11 +1658,13 @@ PyArray_CLEARFLAGS(PyArrayObject *arr, int flags)
((PyArrayObject_fields *)arr)->flags &= ~flags;
}
-static inline NPY_RETURNS_BORROWED_REF PyObject *
-PyArray_HANDLER(PyArrayObject *arr)
-{
- return ((PyArrayObject_fields *)arr)->mem_handler;
-}
+#if NPY_FEATURE_VERSION >= NPY_1_22_API_VERSION
+ static inline NPY_RETURNS_BORROWED_REF PyObject *
+ PyArray_HANDLER(PyArrayObject *arr)
+ {
+ return ((PyArrayObject_fields *)arr)->mem_handler;
+ }
+#endif
#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL)
diff --git a/numpy/core/include/numpy/numpyconfig.h b/numpy/core/include/numpy/numpyconfig.h
index b7d7e2ca4..1c25aa5fc 100644
--- a/numpy/core/include/numpy/numpyconfig.h
+++ b/numpy/core/include/numpy/numpyconfig.h
@@ -56,30 +56,83 @@
/**
- * To help with the NPY_NO_DEPRECATED_API macro, we include API version
- * numbers for specific versions of NumPy. To exclude all API that was
- * deprecated as of 1.7, add the following before #including any NumPy
- * headers:
+ * To help with both NPY_TARGET_VERSION and the NPY_NO_DEPRECATED_API macro,
+ * we include API version numbers for specific versions of NumPy.
+ * To exclude all API that was deprecated as of 1.7, add the following before
+ * #including any NumPy headers:
* #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+ * The same is true for NPY_TARGET_VERSION, although NumPy will default to
+ * a backwards compatible build anyway.
*/
#define NPY_1_7_API_VERSION 0x00000007
#define NPY_1_8_API_VERSION 0x00000008
-#define NPY_1_9_API_VERSION 0x00000008
-#define NPY_1_10_API_VERSION 0x00000008
-#define NPY_1_11_API_VERSION 0x00000008
-#define NPY_1_12_API_VERSION 0x00000008
-#define NPY_1_13_API_VERSION 0x00000008
-#define NPY_1_14_API_VERSION 0x00000008
-#define NPY_1_15_API_VERSION 0x00000008
-#define NPY_1_16_API_VERSION 0x00000008
-#define NPY_1_17_API_VERSION 0x00000008
-#define NPY_1_18_API_VERSION 0x00000008
-#define NPY_1_19_API_VERSION 0x00000008
+#define NPY_1_9_API_VERSION 0x00000009
+#define NPY_1_10_API_VERSION 0x0000000a
+#define NPY_1_11_API_VERSION 0x0000000a
+#define NPY_1_12_API_VERSION 0x0000000a
+#define NPY_1_13_API_VERSION 0x0000000b
+#define NPY_1_14_API_VERSION 0x0000000c
+#define NPY_1_15_API_VERSION 0x0000000c
+#define NPY_1_16_API_VERSION 0x0000000d
+#define NPY_1_17_API_VERSION 0x0000000d
+#define NPY_1_18_API_VERSION 0x0000000d
+#define NPY_1_19_API_VERSION 0x0000000d
#define NPY_1_20_API_VERSION 0x0000000e
#define NPY_1_21_API_VERSION 0x0000000e
#define NPY_1_22_API_VERSION 0x0000000f
#define NPY_1_23_API_VERSION 0x00000010
#define NPY_1_24_API_VERSION 0x00000010
-#define NPY_1_25_API_VERSION 0x00000010
+#define NPY_1_25_API_VERSION 0x00000011
+
+
+/*
+ * Binary compatibility version number. This number is increased
+ * whenever the C-API is changed such that binary compatibility is
+ * broken, i.e. whenever a recompile of extension modules is needed.
+ */
+#define NPY_VERSION NPY_ABI_VERSION
+
+/*
+ * Minor API version we are compiling to be compatible with. The version
+ * Number is always increased when the API changes via: `NPY_API_VERSION`
+ * (and should maybe just track the NumPy version).
+ *
+ * If we have an internal build, we always target the current version of
+ * course.
+ *
+ * For downstream users, we default to an older version to provide them with
+ * maximum compatibility by default. Downstream can choose to extend that
+ * default, or narrow it down if they wish to use newer API. If you adjust
+ * this, consider the Python version support (example for 1.25.x):
+ *
+ * NumPy 1.25.x supports Python: 3.9 3.10 3.11 (3.12)
+ * NumPy 1.19.x supports Python: 3.6 3.7 3.8 3.9
+ * NumPy 1.17.x supports Python: 3.5 3.6 3.7 3.8
+ * NumPy 1.15.x supports Python: ... 3.6 3.7
+ *
+ * Users of the stable ABI may wish to target the last Python that is not
+ * end of life. This would be 3.8 at NumPy 1.25 release time.
+ * 1.17 as default was the choice of oldest-support-numpy at the time and
+ * has in practice no limit (comapared to 1.19). Even earlier becomes legacy.
+ */
+#if defined(NPY_INTERNAL_BUILD) && NPY_INTERNAL_BUILD
+ /* NumPy internal build, always use current version. */
+ #define NPY_FEATURE_VERSION NPY_API_VERSION
+#elif defined(NPY_TARGET_VERSION) && NPY_TARGET_VERSION
+ /* user provided a target version, use it */
+ #define NPY_FEATURE_VERSION NPY_TARGET_VERSION
+#else
+ /* Use the default (increase when dropping Python 3.9 support) */
+ #define NPY_FEATURE_VERSION NPY_1_19_API_VERSION
+#endif
+
+/* Sanity check the (requested) feature version */
+#if NPY_FEATURE_VERSION > NPY_API_VERSION
+ #error "NPY_TARGET_VERSION higher than NumPy headers!"
+#elif NPY_FEATURE_VERSION < NPY_1_15_API_VERSION
+ /* No support for irrelevant old targets, no need for error, but warn. */
+ #warning "Requested NumPy target lower than supported NumPy 1.15."
+#endif
+
#endif /* NUMPY_CORE_INCLUDE_NUMPY_NPY_NUMPYCONFIG_H_ */
diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h
index bb0633100..9e00f2e56 100644
--- a/numpy/core/include/numpy/ufuncobject.h
+++ b/numpy/core/include/numpy/ufuncobject.h
@@ -197,7 +197,7 @@ typedef struct _tagPyUFuncObject {
npy_uint32 iter_flags;
/* New in NPY_API_VERSION 0x0000000D and above */
-
+ #if NPY_FEATURE_VERSION >= NPY_1_16_API_VERSION
/*
* for each core_num_dim_ix distinct dimension names,
* the possible "frozen" size (-1 if not frozen).
@@ -211,13 +211,15 @@ typedef struct _tagPyUFuncObject {
/* Identity for reduction, when identity == PyUFunc_IdentityValue */
PyObject *identity_value;
+ #endif /* NPY_FEATURE_VERSION >= NPY_1_16_API_VERSION */
/* New in NPY_API_VERSION 0x0000000F and above */
-
+ #if NPY_FEATURE_VERSION >= NPY_1_22_API_VERSION
/* New private fields related to dispatching */
void *_dispatch_cache;
/* A PyListObject of `(tuple of DTypes, ArrayMethod/Promoter)` */
PyObject *_loops;
+ #endif
} PyUFuncObject;
#include "arrayobject.h"
diff --git a/numpy/core/meson.build b/numpy/core/meson.build
index e51a7ba3b..f375e9647 100644
--- a/numpy/core/meson.build
+++ b/numpy/core/meson.build
@@ -44,7 +44,8 @@ C_ABI_VERSION = '0x01000009'
# 0x0000000f - 1.22.x
# 0x00000010 - 1.23.x
# 0x00000010 - 1.24.x
-C_API_VERSION = '0x00000010'
+# 0x00000011 - 1.25.x
+C_API_VERSION = '0x00000011'
# Check whether we have a mismatch between the set C API VERSION and the
# actual C API VERSION. Will raise a MismatchCAPIError if so.
diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py
index ef8d21fa7..b5bc0dec1 100644
--- a/numpy/core/setup_common.py
+++ b/numpy/core/setup_common.py
@@ -48,7 +48,13 @@ C_ABI_VERSION = 0x01000009
# 0x0000000f - 1.22.x
# 0x00000010 - 1.23.x
# 0x00000010 - 1.24.x
-C_API_VERSION = 0x00000010
+# 0x00000011 - 1.25.x
+C_API_VERSION = 0x00000011
+
+# By default, when compiling downstream libraries against NumPy,```
+# pick an older feature version. For example, for 1.25.x we default to the
+# 1.19 API and support going back all the way to 1.15.x (if so desired).
+# This is set up in `numpyconfig.h`.
class MismatchCAPIError(ValueError):
pass
@@ -91,6 +97,10 @@ def check_api_version(apiversion, codegen_dir):
f"checksum in core/codegen_dir/cversions.txt is {api_hash}. If "
"functions were added in the C API, you have to update "
f"C_API_VERSION in {__file__}."
+ "\n"
+ "Please make sure that new additions are guarded with "
+ "MinVersion() to make them unavailable when wishing support "
+ "for older NumPy versions."
)
raise MismatchCAPIError(msg)
diff --git a/numpy/core/tests/test_mem_policy.py b/numpy/core/tests/test_mem_policy.py
index d5dfbc38b..479f702ea 100644
--- a/numpy/core/tests/test_mem_policy.py
+++ b/numpy/core/tests/test_mem_policy.py
@@ -89,6 +89,7 @@ def get_module(tmp_path):
"""),
]
prologue = '''
+ #define NPY_TARGET_VERSION NPY_1_22_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/arrayobject.h>
/*