Skip to content

Conversation

@sackio
Copy link

@sackio sackio commented Dec 10, 2025

Summary

This PR fixes multiple compatibility issues preventing zigzag from building on Python 3.12 with NumPy 2.x and Cython 3.x. These changes enable zigzag to work with modern Python environments.

Problem

The current version fails to install on Python 3.12+ with errors:

  1. Invalid pyproject.toml: error: invalid-pyproject-build-system-requires - invalid requirement: 'Cython>=^0.29'
  2. Missing distutils: ModuleNotFoundError: No module named 'distutils' (removed in Python 3.12)
  3. NumPy 2.x types: Invalid type errors with np.int_ (removed in NumPy 2.x)
  4. Cython 3.x types: Invalid type errors with int_t (deprecated in Cython 3.x)
  5. Build script errors: get_outputs() fails without build_py command

Changes

1. Fix pyproject.toml (commit e0c62a0)

File: pyproject.toml

Before:

requires = ["Cython>=^0.29", "setuptools", "wheel"]

After:

requires = ["Cython>=0.29", "setuptools", "wheel"]

Reason: The ^ operator is Poetry-specific syntax and not valid in PEP 508/PEP 440 dependency specifications used by build-system.requires.

2. Replace distutils with setuptools (commit 013d2cc)

File: build.py

Changes:

  • from distutils.command.build_ext import build_extfrom setuptools.command.build_ext import build_ext
  • from distutils.core import Distribution, Extensionfrom setuptools.dist import Distribution + from setuptools import Extension

Reason: Python 3.12 removed the distutils module. Use setuptools as the modern replacement.

3. Add setuptools to build requirements (commit 922933f)

File: pyproject.toml

Before:

requires = [
    "poetry-core>=1.0.0",
    "Cython>=0.29",
    "numpy >=1.21.1",
]

After:

requires = [
    "poetry-core>=1.0.0",
    "setuptools",
    "Cython>=0.29",
    "numpy >=1.21.1",
]

Reason: Since build.py now imports from setuptools, it must be in build-system.requires.

4. Fix NumPy 2.x type compatibility (commit 98167d0)

File: zigzag/core.pyx

Changes:

  • Line 107: dtype=np.int_dtype=np.intp
  • Line 213: dtype=np.int_dtype=np.intp

Reason: NumPy 2.0 removed np.int_ type alias. Use np.intp (platform-specific signed integer type used for indexing).

5. Fix Cython 3.x type compatibility (commit 7a2df2e)

File: zigzag/core.pyx

Changes:

  • Added: cimport numpy as cnp
  • Replaced all 12 occurrences of int_t with cnp.intp_t

Reason: The int_t type is deprecated in modern Cython with NumPy 2.x. Use cnp.intp_t for platform-specific integer types.

6. Add error handling to build script (commit 1b7bcf3)

File: build.py

Changes: Added try/except block with glob fallback for cmd.get_outputs():

try:
    outputs = cmd.get_outputs()
except (AttributeError, KeyError):
    # Fallback: manually find built extension files
    import glob
    outputs = glob.glob(os.path.join(cmd.build_lib, 'zigzag', '*.so'))
    outputs.extend(glob.glob(os.path.join(cmd.build_lib, 'zigzag', '*.pyd')))

Reason: get_outputs() can fail when build_py command doesn't exist in the minimal Distribution setup. Fallback uses glob to find built .so/.pyd files.

Testing

Tested successfully on:

  • Python: 3.12
  • NumPy: 2.2.6
  • Cython: 0.29.37
  • Platform: Linux x86_64 (Docker)

Build output:

Building wheel for zigzag (pyproject.toml): finished with status 'done'
Created wheel for zigzag: filename=zigzag-0.3.2-cp312-cp312-manylinux_2_41_x86_64.whl
Successfully installed zigzag-0.3.2

Import test:

import zigzag
print(zigzag.peak_valley_pivots([1, 2, 3, 2, 1], 0.1, -0.1))  # Works!

Impact

This fixes installation for:

  • Dependent packages like smartmoneyconcepts that require zigzag
  • Modern Python 3.12+ environments
  • Projects using NumPy 2.x
  • Docker containers with recent Python versions

Backward Compatibility

All changes maintain backward compatibility:

  • Cython>=0.29 still accepts older versions
  • setuptools is widely available
  • np.intp works on all NumPy versions
  • cnp.intp_t is the recommended modern Cython type

References

The ^ operator is Poetry-specific syntax and not valid in PEP 508
build requirements. This was causing pip install failures with:
"invalid-pyproject-build-system-requires"

Changed from: Cython>=^0.29
Changed to: Cython>=0.29

Fixes compatibility with modern pip versions that strictly validate
pyproject.toml build-system.requires per PEP 518.
Python 3.12 removed the distutils module. This update replaces
distutils imports with their setuptools equivalents:
- distutils.command.build_ext -> setuptools.command.build_ext
- distutils.core.Distribution -> setuptools.dist.Distribution
- distutils.core.Extension -> setuptools.Extension

This maintains the same functionality while being compatible with
Python 3.12+.
build.py imports from setuptools (build_ext, Distribution, Extension)
but setuptools was not declared in build-system.requires, causing:
ModuleNotFoundError: No module named 'setuptools'

This is required for the build.py script to execute successfully
during the wheel build process.
np.int_ was removed in NumPy 2.0. The correct replacement is np.intp
which represents a platform-specific integer pointer type (equivalent
to the old np.int_ behavior).

Changed in zigzag/core.pyx:
- Line 107: np.zeros(t_n, dtype=np.int_) -> np.intp
- Line 213: np.zeros(len(pivots), dtype=np.int_) -> np.intp

This fixes the Cython compilation error:
"zigzag/core.pyx:107:16: Invalid type."
Replaced deprecated int_t with cnp.intp_t throughout core.pyx.
The int_t type is no longer available in modern Cython with NumPy 2.x.

Changes:
- Added 'cimport numpy as cnp' to imports
- Removed 'int_t' from imports
- Replaced all 12 occurrences of 'int_t' with 'cnp.intp_t'

This resolves the Cython compilation error:
"zigzag/core.pyx:107:16: Invalid type."
The get_outputs() method can fail when build_py command doesn't exist
in the minimal Distribution setup. Added try/except fallback that uses
glob to manually find built extension files (.so/.pyd) in build_lib.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant