Metadata-Version: 2.4
Name: xstrumodeler
Version: 0.0.4
Summary: Python bindings for the xstrucore structural cross-section modeler
Author: Luigi Luis Paone
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Project-URL: Repository, https://gitlab.com/luigi_paone/xstrumodeler
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# xstrumodeler

Python bindings (Boost.Python) for the `xstrucore` cross-section modeler.

The repository is self-contained:

| Path                   | Content                                                  |
|------------------------|----------------------------------------------------------|
| `boost-wrap.cpp`       | Boost.Python module definition (`xstrumodeler`)          |
| `lib/coreobj/`         | core objects library (functions, units, keys, ...)       |
| `lib/xstrucore/`       | structural section modeler library                       |
| `src/xstrumodeler/`    | Python package; the compiled module is installed here    |

Boost 1.88 is downloaded automatically at configure time (CMake `FetchContent`)
and Boost.Python is compiled statically into the module, so no system Boost is
required. The wheel depends only on the C++ runtime.

## Requirements

- Python >= 3.10 (with headers)
- a C++17 compiler:
  - Linux: GCC or Clang (`g++`)
  - Windows: Visual Studio 2022 Build Tools with the
    *Desktop development with C++* workload
- network access on first build (≈100 MB Boost download)

CMake is provided by `scikit-build-core` if not installed.

## Build

```sh
pip wheel . -w dist          # build a wheel
pip install .                # or install directly
```

```python
from xstrumodeler import xstrumodeler
modeler = xstrumodeler.XStruModeler()
```

### Faster rebuilds (development)

By default pip builds in a temporary directory, so every build downloads
Boost again and recompiles everything (about a minute). To reuse a build
directory, install the build tools once and disable build isolation:

```sh
pip install "scikit-build-core>=0.11" ninja
pip install --no-build-isolation . -Cbuild-dir=build/{wheel_tag}
```

Following builds only recompile the changed files (seconds).
Build isolation must be off: with it, pip uses a different temporary `ninja`
on each run and the build directory is discarded.

### Offline build

Download and extract
[boost-1.88.0-cmake.tar.xz](https://github.com/boostorg/boost/releases/download/boost-1.88.0/boost-1.88.0-cmake.tar.xz)
then:

```sh
pip wheel . -w dist -Ccmake.define.FETCHCONTENT_SOURCE_DIR_BOOST=/path/to/boost-1.88.0
```

### Plain CMake (development)

```sh
cmake -S . -B build
cmake --build build -j
PYTHONPATH=build python -c "import xstrumodeler; print(xstrumodeler.XStruModeler())"
```

Here the compiled module is imported directly (`import xstrumodeler`),
while the installed package is `from xstrumodeler import xstrumodeler`.

### Wheels for all Python versions (like CI)

```sh
pipx run cibuildwheel --platform linux     # requires Docker
pipx run cibuildwheel --platform windows   # on Windows
```

Wheels are written to `wheelhouse/`. Locally cibuildwheel uses its default
manylinux image, so Linux wheels may be tagged `manylinux_2_28` instead of
the `manylinux_2_34` built by CI.

## Releasing

GitLab CI builds the sdist, manylinux_2_34 wheels (cp310–cp314) and Windows
wheels (`cibuildwheel`):

- on pushes to `master` and merge requests that change build files
  (sources, CMake, `pyproject.toml`, CI), or from *Run pipeline* in the
  GitLab UI: build only, to catch problems before a release;
- on version tags: it also checks that the tag matches `version` in
  `pyproject.toml` and, if every build succeeds, uploads them all:

| Tag          | Upload to                                                  |
|--------------|------------------------------------------------------------|
| `vX.Y.ZrcN`  | [TestPyPI](https://test.pypi.org/project/xstrumodeler/)    |
| `vX.Y.Z`     | [PyPI](https://pypi.org/project/xstrumodeler/)             |

Uploads use [Trusted Publishing](https://docs.pypi.org/trusted-publishers/):
no token is stored in GitLab.

Release steps:

1. Set `version = "X.Y.ZrcN"` in `pyproject.toml`, commit, push, then
   `git tag vX.Y.ZrcN && git push origin vX.Y.ZrcN`.
2. Check the release candidate:
   `pip install -i https://test.pypi.org/simple/ xstrumodeler==X.Y.ZrcN`.
3. Set `version = "X.Y.Z"` in `pyproject.toml` and `CITATION.cff`, commit,
   push, then `git tag vX.Y.Z && git push origin vX.Y.Z`.

A version can be uploaded only once: if a release fails after uploading,
use the next rc number.

One-time setup:

- PyPI → `xstrumodeler` → Settings → Publishing → add a GitLab publisher:
  namespace `luigi_paone`, project `xstrumodeler`, pipeline file
  `.gitlab-ci.yml`, environment `pypi`.
- TestPyPI → Account → Publishing → add a pending publisher with the same
  values, project name `xstrumodeler`, environment `testpypi`.
- GitLab → Settings → Repository → Protected tags: `v*`, Maintainers only.

## Provenance

Extracted from the [exagon](https://gitlab.com/luigi_paone/exagon) repository
(commit `5455d2d`) with history preserved: `src/app/xstrumodeler` → repository
root, `src/lib/coreobj` and `src/lib/xstrucore` → `lib/`. The copies in
`lib/` are now independent from exagon; changes are not synchronized
automatically.

## License

Licensed under the [Apache License, Version 2.0](LICENSE). Redistributions
must retain the [NOTICE](NOTICE) file. If you use xstrumodeler in published
work, please cite it as described in [CITATION.cff](CITATION.cff).

Boost is distributed under the Boost Software License, Version 1.0.
