Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bottleneck/src/bottleneck.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
#include <numpy/arrayobject.h>
#include <bn_config.h>

#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
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ skip = [
"*_i686",
"cp310-win_arm64", # no numpy wheels for this target
]
environment = { "BN_LIMITED_API" = "1" }

[tool.ruff]
exclude = [
Expand Down
19 changes: 19 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look quite right, I think we should always target the lowest-supported Python version, rather than the version that's running the build. Or do you plan to enforce (via code comment?) to handle this in the CI workflow file?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that when targeting a version that's older than the running interpreter, there are no guarantees that the resulting binaries will actually be backward compatible. Luckily, because cibuildwheel already runs targets in increasing Python version order, this approach works perfectly: the first (oldest) Python builds a wheel and runs tests, then all the other skip the build step and only check for forward compat by running tests.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rgommers, any follow up on this ?

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"),
Comment thread
neutrinoceros marked this conversation as resolved.
]
if USE_PY_LIMITED_API:
define_macros.append(("Py_LIMITED_API", ABI3_TARGET_HEX))


class config(_config):
Expand Down Expand Up @@ -151,11 +164,17 @@ 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={
"bottleneck.tests": ["data/*/*"],
},
cmdclass=cmdclass,
ext_modules=prepare_modules(),
options=options,
)
Loading