Metadata-Version: 2.4
Name: hwh-backend
Version: 1.0.0
Summary: Setuptools based backend supporting Cython 3+ extensions
Author-email: Mathias von Essen <3090690+mkgessen@users.noreply.github.com>
License-Expression: MIT
Project-URL: Repository, https://github.com/mkgessen/hwh-backend.git
Keywords: cython,build,backend,pep517
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Cython
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Operating System :: POSIX :: Linux
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: setuptools>=69.0
Requires-Dist: wheel>=0.40.0
Requires-Dist: Cython>=3.1.0
Requires-Dist: numpy>=2.0.0
Requires-Dist: pyproject-metadata>=0.8.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Requires-Dist: pytest-cov>=4.0; extra == "test"
Requires-Dist: coverage>=7.0; extra == "test"
Requires-Dist: build>=1.0.0; extra == "test"
Requires-Dist: tomli-w; extra == "test"
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: isort>=5.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: hwh-backend[test]; extra == "dev"
Dynamic: license-file

# Halfway House backend

[![Tests Passing](https://github.com/mkgessen/hwh-backend/actions/workflows/test-only.yml/badge.svg)](https://github.com/mkgessen/hwh-backend/actions/workflows/test-only.yml)

Provides [PEP-517](https://peps.python.org/pep-0517/) build hooks for building
Cython extensions with setuptools. Supports Cython 0.29 and 3.1+.

:warning: `pip intall hwh-backend` will support different Cython versions depending on 
the Python version you're running:

- Cython>=3.1 is supported for Python 3.12/3.13
- Cython==0.29 is supported for Python 3.11 (see branch [cython-0.29](https://github.com/mkgessen/hwh-backend/tree/cython-0.29))


## Requirements

- Python 3.11 - 3.13
- Cython 0.29 or 3.1+
- NumPy <2 with Cython 0.29 and 2.0+ for Cython 3 (optional, for numpy integration)
- Linux

## Features

- PEP-517 compliant build backend for Cython extensions
- Supports both regular and editable installs
- Configurable through pyproject.toml
- Support for flat and src layouts
- Package discovery using setuptools.find_packages
- Integration with numpy headers (optional)
- Cython compiler directive configuration
- Multi-threading support (complicated way of saying the `nthreads` is
  supported)
- Site-packages configuration options

## Intended use

HWH is intended to be bolt on replacement for projects that build Cython
extensions with setuptools. You should be able to get rid of your `setup.py` and
you don't need to call `python -m setup.py` to build extensions.

HWH backend is mainly configured through optional [[tool.hwh]] section of
`pyproject.toml`.

In addition to [[tool.hwh]] section, HWH emulates
`tool.setuptools.package.find`, so to support src layout and cases where package
directory name != project name in case of flat layout.

This feature is likely to be changed to [[tool.hwh.setuptools.]] in the near
future, but this is the starting point.

### Scenarios that HWH tries to solve

1. Project that has `.pyx` files, but doesn't is not designed to be used by
   other projects. Doesn't contain `.pxd` files
2. Project that has `.pyx` and `.pxd` files and plain `.py` files
3. Project that has .`pyx` and `.pxd` files and depends on another project that
   looks like #2
   - dependency used in both Cython and Python

### `[tool.hwh.cython]`

Core Cython build configuration:

- `language`: Extension language ("c" or "c++"). Defaults to "c"
- `annotate`: Generate Cython annotation HTML files (default: false)
- `nthreads`: Number of parallel compilation threads (default: CPU count)
- `force`: Force rebuild of extensions (default: false)
- `use_numpy_include`: Include numpy headers in compilation (default: false)
- `numpy_api_version`: Define NPY_NO_DEPRECATED_API macro to suppress NumPy deprecation warnings (default: none). Set to "NPY_1_7_API_VERSION" to eliminate warnings
- `legacy_implicit_noexcept`: Controls exception handling for `cdef` functions without an explicit exception spec (default: false)
  - `false`: Cython 3 default — functions check for exceptions after every call
  - `true`: Cython 0.29 behavior — functions are implicitly `noexcept`, no exception checking.

### `[tool.hwh.cython.modules]`

Extension module configuration:

- `sources`: List of .pyx files to compile (default: auto-discover)
- `exclude_dirs`: Directories to exclude from auto-discovery
- `include_dirs`: Header search paths
- `library_dirs`: Library search paths
- `libraries`: Libraries to link against
- `extra_compile_args`: Additional compilation arguments
- `extra_link_args`: Additional linker arguments
- `runtime_library_dirs`: Runtime library search paths

### `[tool.hwh.cython]` — site-packages

- `site_packages`: Controls which site-packages paths are added to include/library dirs:
  - `"purelib"`: Use sysconfig.get_path("purelib") (default)
  - `"user"`: Use site.getusersitepackages()
  - `"site"`: Use site.getsitepackages()
  - `"none"`: No automatic site-packages paths

### `[tool.hwh.cython.compiler_directives]`

Cython compiler directives configuration:

```toml
[tool.hwh.cython.compiler_directives]
binding = false            # Generate Python wrapper functions
boundscheck = false        # Array bounds checking
wraparound = false        # Negative indexing
initializedcheck = false  # Check if extension types are initialized
nonecheck = false         # Check for null Python references
overflowcheck = false     # Check for C integer overflows
embedsignature = false    # Include docstrings in the C code
cdivision = false        # Division by zero checking
cdivision_warnings = false # Division by zero warning
profile = false          # Enable profiling
linetrace = false        # Enable line tracing
infer_types = null       # Type inference
type_version_tag = true  # Enable CPython's type attribute cache
```

For more information, see
[Cython docs](https://cython.readthedocs.io/en/latest/src/userguide/source_files_and_compilation.html)
and
[Setup tools extension docs](https://setuptools.pypa.io/en/latest/userguide/ext_modules.html)

## Usage

**Build Configuration**

Build settings can be controlled via command line. Note the different syntax
between `python -m build` (plural --config-settings) and `pip` (singular
--config-setting). Consistency here is great :heart:

The following options are supported:

```shell
# Using python -m build
python -m build --wheel --no-isolation \
    --config-settings annotate=true \
    --config-settings nthreads=4 \
    --config-settings force=true \
    --config-settings linetrace=true \
    --config-settings legacy_implicit_noexcept=true

# Using pip
pip install -e . \
    --config-setting annotate=true \
    --config-setting nthreads=4 \
    --config-setting force=true \
    --config-setting linetrace=true \
    --config-setting legacy_implicit_noexcept=true
```

## Logging

```shell
pip install --config-setting verbose=debug  # Options: debub, info, warning
```

### `[tool.hwh.cython.compiler_directives]`

HWH exposes the most of Cython's compiler directives. See
[compiler directives](https://cython.readthedocs.io/en/latest/src/userguide/source_files_and_compilation.html#compiler-directives)

### Example `pyproject.toml`

```toml pyproject.toml
[build-system]
requires = ["hwh-backend", "Cython>=3.1.0"]
build-backend = "hwh_backend.build"

[project]
name = "mylib"
version = "1.0.0"

[tool.hwh.cython]
language = "c++"
annotate = true
nthreads = 4
force = false
use_numpy_include = true
numpy_api_version = "NPY_1_7_API_VERSION"
legacy_implicit_noexcept = false
site_packages = "purelib"

[tool.hwh.cython.modules]
sources = ["src/mylib/*.pyx"]
exclude_dirs = ["tests", "build"]
include_dirs = ["include"]
library_dirs = ["/usr/local/lib"]
libraries = ["mylib"]
extra_compile_args = ["-O3"]
runtime_library_dirs = ["/usr/local/lib"]

[tool.hwh.cython.compiler_directives]
boundscheck = false
wraparound = false
cdivision = true
```
