11import os
22import sys
3+ import sysconfig
34import numpy
45
56from Cython .Build import cythonize
2930CFTIME_DIR = os .path .join (SRCDIR , NAME )
3031CYTHON_FNAME = os .path .join (CFTIME_DIR , '_{}.pyx' .format (NAME ))
3132
33+ USE_PY_LIMITED_API = (
34+ # require opt-in (builds are specialized by default)
35+ os .getenv ('CFTIME_LIMITED_API' , '0' ) == '1'
36+ # Cython + numpy + limited API de facto requires Python >=3.11
37+ and sys .version_info >= (3 , 11 )
38+ # as of Python 3.14t, free-threaded builds don't support the limited API
39+ and not sysconfig .get_config_var ("Py_GIL_DISABLED" )
40+ )
41+ ABI3_TARGET_VERSION = "" .join (str (_ ) for _ in sys .version_info [:2 ])
42+ ABI3_TARGET_HEX = hex (sys .hexversion & 0xFFFF00F0 )
43+
44+ if USE_PY_LIMITED_API :
45+ SETUP_OPTIONS = {"bdist_wheel" : {"py_limited_api" : f"cp{ ABI3_TARGET_VERSION } " }}
46+ else :
47+ SETUP_OPTIONS = {}
3248
3349class CleanCython (Command ):
3450 description = 'Purge artifacts built by Cython'
@@ -60,6 +76,8 @@ def run(self):
6076 }
6177 DEFINE_MACROS += [('CYTHON_TRACE' , '1' ),
6278 ('CYTHON_TRACE_NOGIL' , '1' )]
79+ if USE_PY_LIMITED_API :
80+ DEFINE_MACROS .append (("Py_LIMITED_API" , ABI3_TARGET_HEX ))
6381 if FLAG_COVERAGE in sys .argv :
6482 sys .argv .remove (FLAG_COVERAGE )
6583 print ('enable: "linetrace" Cython compiler directive' )
@@ -71,7 +89,8 @@ def run(self):
7189 extension = Extension ('{}._{}' .format (NAME , NAME ),
7290 sources = [os .path .relpath (CYTHON_FNAME , BASEDIR )],
7391 define_macros = DEFINE_MACROS ,
74- include_dirs = [numpy .get_include (),])
92+ include_dirs = [numpy .get_include ()],
93+ py_limited_api = USE_PY_LIMITED_API )
7594
7695 ext_modules = cythonize (
7796 extension ,
@@ -82,4 +101,5 @@ def run(self):
82101setup (
83102 cmdclass = {'clean_cython' : CleanCython },
84103 ext_modules = ext_modules ,
104+ options = SETUP_OPTIONS ,
85105)
0 commit comments