Metadata-Version: 2.4
Name: pyswig
Version: 0.2.0
Summary: Generate Swig input files from annotated header files
Author-email: Michel Gillet <michel.gillet@libesys.org>
License-Expression: MIT
Project-URL: Homepage, https://pyswig.org
Project-URL: Repository, https://gitlab.com/libesys/tools/pyswig.git
Keywords: swig,automation,wrapper,development
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Provides-Extra: contributor
Requires-Dist: anybadge>=1.0; extra == "contributor"
Requires-Dist: mypy>=1.0; extra == "contributor"
Requires-Dist: pre-commit>=4.0; extra == "contributor"
Requires-Dist: pytest>=8.0; extra == "contributor"
Requires-Dist: pytest-cov>=4.0; extra == "contributor"
Requires-Dist: ruff>=0.8; extra == "contributor"
Provides-Extra: release
Requires-Dist: build>=1.2; extra == "release"
Requires-Dist: twine>=5.0; extra == "release"
Provides-Extra: docs
Requires-Dist: sphinx>=5.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "docs"
Requires-Dist: recommonmark>=0.7; extra == "docs"
Dynamic: license-file

# PySwig

[![pipeline status](https://gitlab.com/libesys/tools/pyswig/badges/master/pipeline.svg)](https://gitlab.com/libesys/tools/pyswig/-/commits/master)

![python 3.9](https://pyswig.org/python39-badge.svg)
![python 3.10](https://pyswig.org/python310-badge.svg)
![python 3.11](https://pyswig.org/python311-badge.svg)
![python 3.12](https://pyswig.org/python312-badge.svg)

[![coverage report](https://gitlab.com/libesys/tools/pyswig/badges/master/coverage.svg)](https://pyswig.org/htmlcov)

**Simple wrapper integration** (Python × SWIG):
[integration matrix](https://pyswig.org/integration-matrix.html)
(updated after a green pipeline on `master`; preview on `develop` — see
[pages-domain.md](docs/guides/pages-domain.md)).

SWIG is a great tool to generate wrappers very easily in various scripting languages of C/C++
libraries. But if you develop a C/C++ library and its wrapper at the same time, it has a
significant flow: the necessity to create input files distinct from the source code of your
library. The more extensive the library is, the biggest issue is to have to maintain virtually two
sets of header files.

With PySwig, the source header files are annotated, allowing the automatic generation of the input
files needed by Swig. With those input files, Swig can then create the sources of the wrapper. In
this way, the maintenance effort is reduced to its minimum, since only one set of header files is
needed.

Furthermore, PySwig can also take care of calling Swig to generate the wrapper. The result is a
Python script, importing PySwig, and defining the operations to carry out. In the end, one just has
to call this Python script to generate the Swig input files and call Swig to create the wrapper
source files in one step.

## Installation

Requires **Python 3.9+** and [SWIG](https://www.swig.org/) on your PATH (or `SWIG` / `ESYS_SWIG`
environment variables).

```bash
pip install pyswig
pyswig --help
```

For wrapper development (Swig provisioning, multi-Python test runs, environment setup):

```bash
pip install pyswig-dev
pyswig-dev setup
pyswig-dev test-all
```

The `pyswig-dev` package depends on **pyswig** (same version on PyPI). See
[docs/guides/packaging.md](docs/guides/packaging.md).

The `pyswig` CLI accepts optional header paths for single-file runs; full wrapper
generation still requires a script with `FileConfig` (see Quick start below).
Useful flags: `--version`, `-q`/`--quiet`, `--run-swig`, `-l`/`--language`,
`--copy-shadow`.

For **PySwig contributors** working from a git clone:

```bash
pip install -e "packages/pyswig[contributor]" -e packages/pyswig-dev
pyswig-dev setup
```

## Documentation

- Hosted docs: [pyswig.org](https://pyswig.org/)
- Site roadmap (Sphinx → Docusaurus): [docs/guides/docs-site-roadmap.md](docs/guides/docs-site-roadmap.md)
- API reference: Sphinx under `docs/source/`
- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)

## Quick start

Configure header files with `FileConfig`, drive generation with `PySwig`, then run SWIG:

```python
import pyswig

file_config = pyswig.FileConfig()
file_config.set_input_dir("../include/simple")
file_config.set_base_inc_dir("simple")
file_config.set_source_files(["version.h", "object.h"])

pyswig_obj = pyswig.PySwig(parse_cli=False)
pyswig_obj.add_file_config(file_config)
pyswig_obj.set_module_name("simple")
pyswig_obj.set_src_output_dir("./pysimple")
pyswig_obj.set_inc_output_dir("../include/pysimplewrap")  # optional wrapper include
pyswig_obj.generate()
pyswig_obj.set_all_warnings()
pyswig_obj.set_process_cpp()
pyswig_obj.set_language("python")
pyswig_obj.run_swig()
```

See the full example in [`src/pysimple.py`](src/pysimple.py). Generated Swig files
land in [`src/pysimple/`](src/pysimple/) and `include/pysimple/simple_inc.h`; run
`python pysimple.py` from `src/` to refresh them (they are not committed).

## Development

Supported test Python versions are listed in `pyproject.toml` under
`[tool.pyswig] test-python-versions`. Simple wrapper integration tests use the pinned SWIG
versions in `[tool.pyswig] integration-swig-versions`; missing binaries are downloaded to
`.cache/swig` (Windows: portable `swigwin` zip, Linux/macOS: built from source when needed).

```bash
# One-time setup: finds uv, installs test Pythons, .venv, dev deps, pre-commit hooks
python scripts/setup_dev.py

# Run tests on every configured Python version (coverage on 3.11 only)
python scripts/test_all.py --write-badges

# Default venv only
.venv/bin/python -m pytest          # Linux/macOS
.venv\Scripts\python -m pytest      # Windows

# End-to-end simple wrapper tests (downloads/builds SWIG versions from pyproject.toml)
python -m pytest -q -m integration tests/test_integration_simple_wrapper.py

# Full integration matrix (same as CI; reads pyproject.toml)
python scripts/ci_integration_matrix.py
```

Commit messages and code style are enforced with **pre-commit** (ruff + gitlint).
See [docs/guides/commit-messages.md](docs/guides/commit-messages.md).

# Annotations

The basic principle is to add XML-like annotations in comments to various effects: to comment out a
line, or a block of code; to include some lines in the input files used by Swig; to add
automatically include files.

## Add source include file

```
//<swig_inc/>
```

Automatically add the include file to the Swig input file. As an example of usage of this
annotation, the result in the Swig input file would be:

```
//<swig_inc>
%{
#include "simple/object.h"
%}
//</swig_inc>
```



## Comment out one line

```
//<swig_out/>
```

This annotation is to comment out one line of source code in the Swig input file. See the line
below as an example one line in a header file of a library.

```
std::string &get_name();   //<swig_out/>   In C#, string are immutable
```

This same line will be transformed to the following line in the Swig input file:

```
//     std::string &get_name();    //<swig_out/>   In C#, string are immutable
```

## Commenting out a block of code

Often a block of code needs to be commented out. It can be done in this way.

```
//<swig_out>
    int m_value = 0;
    …
//</swig_out>
```

The result in the Swig input file is:

```
/* //<swig_out>
    int m_value = 0;
    …
//</swig_out> */
```

## Add code specific to Swig

Often, it’s required to add code specific to Swig to handle templates, typemaps, director, etc.
It can be done as follow:

```
/*<swig>
%apply std::string &OUTPUT …
//</swig>*/
```

It will result in the following line in a Swig input file:

```
//<swig>
%apply std::string &OUTPUT …
//</swig>
```

To add only one line, a simpler form is also possible:

```
//<swig/> %apply std::string &OUTPUT …
```

In the Swig input file, the line will look like the following:

```
%apply std::string &OUTPUT …
```




# Build script

As mentioned earlier, PySwig can also be used to automate the creation of the wrapper by directly
calling Swig. The simplest is to look at one of the examples provided in the git repo for the
wrapper of the c++ library
[simple](https://gitlab.com/libesys/tools/pyswig/-/blob/master/src/pysimple.py).

There are two Python classes to be aware of:

* **`FileConfig`** — configuration for a set of annotated source headers (input dir, output dir,
  source list, include base path).
* **`PySwig`** — orchestrates parsing annotations, writing Swig `.hh` interface files, and
  optionally invoking Swig. Use `PySwig(parse_cli=False)` when configuring everything from a script;
  omit that when driving generation from the command line.

The example script:

1. Creates one or more `FileConfig` instances and registers them on `PySwig`.
2. Sets module name, output directories, typemaps, and includes.
3. Calls `generate()` to write Swig input files from annotated headers.
4. Configures and calls `run_swig()` to produce the wrapper sources.

The lower-level **`Swig`** class locates the Swig executable and runs it with language and warning
options. **`ProcessSrcFile`** parses annotations in a single header; you rarely instantiate it
directly.
