diff --git a/bottleneck/src/bottleneck.h b/bottleneck/src/bottleneck.h index 371fefe99..cab332605 100644 --- a/bottleneck/src/bottleneck.h +++ b/bottleneck/src/bottleneck.h @@ -7,6 +7,11 @@ #include #include +#ifdef Py_LIMITED_API + #define PyTuple_GET_ITEM PyTuple_GetItem + #define PyTuple_GET_SIZE PyTuple_Size +#endif + /* THREADS=1 releases the GIL but increases function call * overhead. THREADS=0 does not release the GIL but keeps * function call overhead low. Curly brackets are for C89 diff --git a/pyproject.toml b/pyproject.toml index 4578f6f33..642f911ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ skip = [ "*_i686", "cp310-win_arm64", # no numpy wheels for this target ] +environment = { "BN_LIMITED_API" = "1" } [tool.ruff] exclude = [ diff --git a/setup.py b/setup.py index fd43a3cc2..4aec65613 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ import os import shutil import sys +import sysconfig from distutils.command.config import config as _config from setuptools import Command, setup @@ -11,10 +12,22 @@ import versioneer +# restrict LIMITED_API usage: +# - require BN_LIMITED_API=1 +# - LIMITED_API is not compatible with free-threading (as of CPython 3.14) +USE_PY_LIMITED_API = os.getenv( + "BN_LIMITED_API", "0" +) == "1" and not sysconfig.get_config_var("Py_GIL_DISABLED") +ABI3_TARGET_VERSION = "".join(str(_) for _ in sys.version_info[:2]) +ABI3_TARGET_HEX = hex(sys.hexversion & 0xFFFF00F0) + + define_macros = [ # keep in sync with runtime requirements (pyproject.toml) ("NPY_NO_DEPRECATED_API", "NPY_1_21_API_VERSION"), ] +if USE_PY_LIMITED_API: + define_macros.append(("Py_LIMITED_API", ABI3_TARGET_HEX)) class config(_config): @@ -151,6 +164,11 @@ def prepare_modules(): return ext +if USE_PY_LIMITED_API: + options = {"bdist_wheel": {"py_limited_api": f"cp{ABI3_TARGET_VERSION}"}} +else: + options = {} + setup( version=versioneer.get_version(), package_data={ @@ -158,4 +176,5 @@ def prepare_modules(): }, cmdclass=cmdclass, ext_modules=prepare_modules(), + options=options, )