diff options
| author | Matti Picus <matti.picus@gmail.com> | 2023-04-28 14:02:40 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-28 14:02:40 +0300 |
| commit | 46055823a517d9e53918cb9b4495d05633ff6f35 (patch) | |
| tree | 3df4dabdb5ab63fd42fa5d1de408c38a89dcfde3 | |
| parent | 6d15eddf8f7d856b9b84f800ef4858858a52498e (diff) | |
| parent | 6ce690dc5584666beb13b41650110d6a601160b1 (diff) | |
| download | numpy-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.rst | 16 | ||||
| -rw-r--r-- | doc/source/dev/depending_on_numpy.rst | 106 | ||||
| -rw-r--r-- | doc/source/dev/reviewer_guidelines.rst | 29 | ||||
| -rw-r--r-- | numpy/core/code_generators/cversions.txt | 4 | ||||
| -rw-r--r-- | numpy/core/code_generators/genapi.py | 52 | ||||
| -rw-r--r-- | numpy/core/code_generators/numpy_api.py | 12 | ||||
| -rw-r--r-- | numpy/core/include/numpy/arrayscalars.h | 4 | ||||
| -rw-r--r-- | numpy/core/include/numpy/ndarraytypes.h | 33 | ||||
| -rw-r--r-- | numpy/core/include/numpy/numpyconfig.h | 85 | ||||
| -rw-r--r-- | numpy/core/include/numpy/ufuncobject.h | 6 | ||||
| -rw-r--r-- | numpy/core/meson.build | 3 | ||||
| -rw-r--r-- | numpy/core/setup_common.py | 12 | ||||
| -rw-r--r-- | numpy/core/tests/test_mem_policy.py | 1 |
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> /* |
