From 53ef6ebe43595a1d80517c3873e96b46c2096c04 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Thu, 22 May 2025 13:51:10 -0600 Subject: [PATCH 1/5] MAINT: Baseline setup for free-threading --- .github/workflows/tests.yml | 2 +- README.md | 6 ++++++ pyproject.toml | 4 ++-- setup.py | 14 +++++++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b73968c..dab68d1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python_version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.13t"] exclude: # The 3.9/3.10 arm64 Python binaries that `setup-python` tries to use # don't work on macOS 15 anymore, so skip those. diff --git a/README.md b/README.md index 9e21837..3e2fd89 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ pip install -U pip setuptools wheel pip install cymem ``` +### Free threading + +`cymem` has support for being built and run under free-threaded CPython. +Currently `Pool` is not thread safe when used from multiple threads at once; +**please avoid sharing a single** `Pool` instance between threads. + ## Example Use Case: An array of structs Let's say we want a sequence of sparse matrices. We need fast access, and a diff --git a/pyproject.toml b/pyproject.toml index ab36d78..f4f0898 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,9 +7,9 @@ build-backend = "setuptools.build_meta" [tool.cibuildwheel] build = "*" -skip = "pp* cp36* cp37* cp38*" +skip = "pp* cp36* cp37* cp38* *t*_i686" test-skip = "" -free-threaded-support = false +enable = ["cpython-freethreading"] archs = ["native"] diff --git a/setup.py b/setup.py index df40294..6fc2dd5 100755 --- a/setup.py +++ b/setup.py @@ -8,11 +8,21 @@ from setuptools.command.build_ext import build_ext from sysconfig import get_path from Cython.Build import cythonize +from Cython.Compiler.Version import version as cython_version +from packaging.version import Version PACKAGES = find_packages() MOD_NAMES = ["cymem.cymem"] +compiler_directives = dict() +compiler_tenv = dict() + +if Version(cython_version) >= Version("3.1.0"): + compiler_directives["freethreading_compatible"] = True + compiler_tenv["CYTHON_FREE_THREADING"] = True +else: + compiler_tenv["CYTHON_FREE_THREADING"] = False # By subclassing build_extensions we have the actual compiler that will be used which is really known only after finalize_options # http://stackoverflow.com/questions/724664/python-distutils-how-to-get-a-compiler-that-is-going-to-be-used @@ -100,7 +110,9 @@ def setup_package(): version=about["__version__"], url=about["__uri__"], license=about["__license__"], - ext_modules=cythonize(ext_modules, language_level=2), + ext_modules=cythonize(ext_modules, language_level=3, + compiler_directives=compiler_directives, + compile_time_env=compiler_tenv), setup_requires=["cython>=0.25"], classifiers=[ "Environment :: Console", From 3b40605ff20b5d456303fa0caef51332f5cd7ac4 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Thu, 22 May 2025 14:09:14 -0600 Subject: [PATCH 2/5] DOC: Add details for building the readme example --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 3e2fd89..d08e7b5 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,32 @@ pip install cymem Currently `Pool` is not thread safe when used from multiple threads at once; **please avoid sharing a single** `Pool` instance between threads. +Also remember to declare `freethreading_compatible` for the example case below: + +``` python +from setuptools import setup +from Cython.Build import cythonize + +from Cython.Compiler.Version import version as cython_version +from packaging.version import Version + + +compiler_directives = dict() +compiler_tenv = dict() + +if Version(cython_version) >= Version("3.1.0"): + compiler_directives["freethreading_compatible"] = True + compiler_tenv["CYTHON_FREE_THREADING"] = True +else: + compiler_tenv["CYTHON_FREE_THREADING"] = False + +setup( + ext_modules = cythonize("*.pyx", language_level=3, + compiler_directives=compiler_directives, + compile_time_env=compiler_tenv) +) +``` + ## Example Use Case: An array of structs Let's say we want a sequence of sparse matrices. We need fast access, and a From 885cf9afe72a92b2fd4ff364286d49508e58e76d Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Fri, 16 May 2025 19:48:55 +0200 Subject: [PATCH 3/5] DOC: Update to fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d08e7b5..1f8ff9f 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ cdef class MatrixArray: self.length = len(py_matrices) self.matrices = self.mem.alloc(self.length, sizeof(SparseMatrix*)) for i, py_matrix in enumerate(py_matrices): - self.matrices[i] = sparse_matrix_init(self.mem, py_matrix) + self.matrices[i] = sparse_matrix_init_cymem(self.mem, py_matrix) cdef SparseMatrix* sparse_matrix_init_cymem(Pool mem, list py_matrix) except NULL: sm = mem.alloc(1, sizeof(SparseMatrix)) From 8006d57fb29c9ed2f51e1b414652c5f9c86f3ad0 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Thu, 22 May 2025 14:19:00 -0600 Subject: [PATCH 4/5] MAINT: Cleanup unused Part of the next PR... --- README.md | 7 +------ setup.py | 9 ++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1f8ff9f..d2864b7 100644 --- a/README.md +++ b/README.md @@ -59,18 +59,13 @@ from packaging.version import Version compiler_directives = dict() -compiler_tenv = dict() if Version(cython_version) >= Version("3.1.0"): compiler_directives["freethreading_compatible"] = True - compiler_tenv["CYTHON_FREE_THREADING"] = True -else: - compiler_tenv["CYTHON_FREE_THREADING"] = False setup( ext_modules = cythonize("*.pyx", language_level=3, - compiler_directives=compiler_directives, - compile_time_env=compiler_tenv) + compiler_directives=compiler_directives) ) ``` diff --git a/setup.py b/setup.py index 6fc2dd5..7599d25 100755 --- a/setup.py +++ b/setup.py @@ -16,13 +16,9 @@ MOD_NAMES = ["cymem.cymem"] compiler_directives = dict() -compiler_tenv = dict() if Version(cython_version) >= Version("3.1.0"): - compiler_directives["freethreading_compatible"] = True - compiler_tenv["CYTHON_FREE_THREADING"] = True -else: - compiler_tenv["CYTHON_FREE_THREADING"] = False + compiler_directives["freethreading_compatible"] = rue # By subclassing build_extensions we have the actual compiler that will be used which is really known only after finalize_options # http://stackoverflow.com/questions/724664/python-distutils-how-to-get-a-compiler-that-is-going-to-be-used @@ -111,8 +107,7 @@ def setup_package(): url=about["__uri__"], license=about["__license__"], ext_modules=cythonize(ext_modules, language_level=3, - compiler_directives=compiler_directives, - compile_time_env=compiler_tenv), + compiler_directives=compiler_directives), setup_requires=["cython>=0.25"], classifiers=[ "Environment :: Console", From 1f5b6a37f8dfebada3b0b686c98f9e5a8e74a0ce Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 25 May 2025 09:51:07 -0700 Subject: [PATCH 5/5] MAINT: Cleanup with reviewer comments Co-authored-by: rgommers --- .github/workflows/cibuildwheel.yml | 2 +- README.md | 21 --------------------- setup.py | 2 +- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index a8419b9..66051f9 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v2.23.3 env: CIBW_SOME_OPTION: value with: diff --git a/README.md b/README.md index d2864b7..13cdd09 100644 --- a/README.md +++ b/README.md @@ -48,27 +48,6 @@ pip install cymem Currently `Pool` is not thread safe when used from multiple threads at once; **please avoid sharing a single** `Pool` instance between threads. -Also remember to declare `freethreading_compatible` for the example case below: - -``` python -from setuptools import setup -from Cython.Build import cythonize - -from Cython.Compiler.Version import version as cython_version -from packaging.version import Version - - -compiler_directives = dict() - -if Version(cython_version) >= Version("3.1.0"): - compiler_directives["freethreading_compatible"] = True - -setup( - ext_modules = cythonize("*.pyx", language_level=3, - compiler_directives=compiler_directives) -) -``` - ## Example Use Case: An array of structs Let's say we want a sequence of sparse matrices. We need fast access, and a diff --git a/setup.py b/setup.py index 7599d25..8a7b87e 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ compiler_directives = dict() if Version(cython_version) >= Version("3.1.0"): - compiler_directives["freethreading_compatible"] = rue + compiler_directives["freethreading_compatible"] = True # By subclassing build_extensions we have the actual compiler that will be used which is really known only after finalize_options # http://stackoverflow.com/questions/724664/python-distutils-how-to-get-a-compiler-that-is-going-to-be-used