Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
110 changes: 110 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Publish Python Package to PyPI

# This workflow uses GitHub's OIDC trusted publishing to authenticate with PyPI.
# For this to work, you must configure trusted publishers on PyPI/TestPyPI:
# 1. Go to https://test.pypi.org/ or https://pypi.org/
# 2. Navigate to your project settings → Publishing
# 3. Add a new publisher with these details:
# - Owner: alexlib
# - Repository: openptv-python
# - Workflow: publish-to-pypi.yml
# - Environment: testpypi (for TestPyPI) or pypi (for PyPI)
#
# TROUBLESHOOTING:
# If you see "invalid-publisher" error, it means the trusted publisher is not configured
# correctly on PyPI/TestPyPI. The configuration MUST match these exact values:
# - Repository owner: alexlib
# - Repository name: openptv-python
# - Workflow filename: publish-to-pypi.yml (must be exact match)
# - Environment name: testpypi or pypi (must match exactly)
#
# For detailed setup instructions, see DEPLOYMENT.md

on:
release:
types: [published]
workflow_dispatch:
inputs:
deploy_target:
description: 'Deploy to PyPI or TestPyPI'
required: true
default: 'testpypi'
type: choice
options:
- pypi
- testpypi

jobs:
build:
name: Build distribution
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine

- name: Build package
run: python -m build

- name: Check distribution
run: twine check dist/*

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

publish-to-pypi:
name: Publish to PyPI
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_target == 'pypi')
needs: [build]
runs-on: ubuntu-latest
environment:
name: pypi # This must match the environment name in PyPI's trusted publisher config
url: https://pypi.org/p/openptv-python
permissions:
id-token: write # Required for trusted publishing via OIDC

steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

publish-to-testpypi:
name: Publish to TestPyPI
if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_target == 'testpypi'
needs: [build]
runs-on: ubuntu-latest
environment:
name: testpypi # This must match the environment name in TestPyPI's trusted publisher config
url: https://test.pypi.org/p/openptv-python
permissions:
id-token: write # Required for trusted publishing via OIDC

steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/

- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/

24 changes: 24 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Python application

on:
push:
branches: [ main, simple_yaml_with_tests ]
pull_request:
branches: [ main, simple_yaml_with_tests ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
- name: Run tests
run: |
make unit-tests
66 changes: 66 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version.py
# Sphinx automatic generation of API
docs/README.md
docs/_api/
docs/_generated/

# Combined environments
ci/combined-environment-*.yml
Expand Down Expand Up @@ -473,3 +474,68 @@ $RECYCLE.BIN/
.cruft.json
/.tmp
/tmp

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*.pyc

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/




9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
PROJECT := openptv_python
CONDA := conda
CONDAFLAGS :=
UV := uv
UVFLAGS := --extra dev --upgrade
COV_REPORT := html
PYTHON ?= python

Expand All @@ -15,11 +17,16 @@ unit-tests:
type-check:
$(PYTHON) -m mypy .

env-update: uv-env-update

conda-env-update:
$(CONDA) install -y -c conda-forge conda-merge
$(CONDA) run conda-merge environment.yml ci/environment-ci.yml > ci/combined-environment-ci.yml
$(CONDA) env update $(CONDAFLAGS) -f ci/combined-environment-ci.yml

uv-env-update:
$(UV) sync $(UVFLAGS)

docker-build:
docker build -t $(PROJECT) .

Expand All @@ -30,6 +37,6 @@ template-update:
pre-commit run --all-files cruft -c .pre-commit-config-cruft.yaml

docs-build:
cp README.md docs/. && cd docs && rm -fr _api && make clean && make html
cp README.md docs/. && $(PYTHON) docs/render_native_stress_demo_include.py && cd docs && rm -fr _api && make clean && make html

# DO NOT EDIT ABOVE THIS LINE, ADD COMMANDS BELOW
67 changes: 34 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,28 @@ Python version of the OpenPTV library - this is *a work in progress*
`openptv-python` keeps the Python API as the main interface and combines three
execution modes behind that API:

- Pure Python: the reference implementation and the easiest path for reading,
debugging, and extending the code.
- Python + Numba: several hot kernels are JIT-compiled automatically on first
- **Pure Python**: the reference implementation and the easiest path for reading,
debugging, and extending the code. Always available as fallback.
- **Python + Numba**: several hot kernels are JIT-compiled automatically on first
use, so the Python implementation still benefits from acceleration.
- Native `optv` bindings: selected operations reuse the native OpenPTV
implementation when the `optv` package is available.
- **Native `optv` bindings** (default): selected operations reuse the native OpenPTV
implementation. Installed by default on supported platforms (Linux, macOS, Windows).

At the moment, automatic native delegation is implemented for image
preprocessing and full-frame target recognition. The rest of the library keeps
the same Python API and remains usable even when those native paths are not in
use.

## How this is started
If `optv` is not available on your platform, the package automatically falls back
to pure Python/Numba implementations without any configuration needed.

This work started from the https://github.com/OpenPTV/openptv/tree/pure_python branch. It's a long-standing idea to convert all the C code to Python and now it's possible with ChatGPT to save
a lot of typing time.
## How this is started

This repo is created using a *cookiecutter* and the rest of the readme describes the way to work with
this structure
This work started from the https://github.com/OpenPTV/openptv/tree/pure_python branch. It now serves as the single repository for the Python core library and the GUI layer.

## Supported Python Versions

The project currently supports Python `>=3.12,<3.14`.
The project currently supports Python `>=3.11,<3.14`.

## Installation

Expand All @@ -45,14 +44,12 @@ source .venv/bin/activate
uv sync
```

This gives you the standard runtime stack: NumPy, SciPy, Numba, and YAML
support.
This gives you the standard runtime stack: NumPy, SciPy, Numba, YAML, and the native `optv` bindings for accelerated image preprocessing and target recognition.

If you also want native `optv` delegation when bindings are available for your
platform and Python version, install the optional extra:
If you also want the GUI application, install the GUI extra:

```bash
uv sync --extra native
uv sync --extra gui
```

#### Alternative: pip
Expand All @@ -63,10 +60,10 @@ conda activate openptv-python
pip install .
```

Optional native bindings:
Optional GUI application:

```bash
pip install ".[native]"
pip install ".[gui]"
```

### Developer install
Expand All @@ -89,13 +86,10 @@ pip install -e ".[dev]"

### What gets installed

- The default install contains the runtime dependencies only.
- The optional `native` extra adds `optv` bindings for automatic native
delegation on supported platforms.
- The optional `dev` extra adds test, docs, typing, and pre-commit tooling for
contributors.
- The public API stays the same regardless of which backend extras are
installed.
- The default install includes `optv` bindings for automatic native delegation on supported platforms (Linux, macOS, Windows).
- The optional `gui` extra adds the PyPTV GUI and its runtime dependencies.
- The optional `dev` extra adds test, docs, typing, pre-commit, and GUI tooling for contributors.
- If `optv` fails to install on your platform, the package falls back to pure Python/Numba implementations automatically.

## Backend Behavior

Expand Down Expand Up @@ -150,13 +144,9 @@ Use one of the installation methods above.
uv run python - <<'PY'
import openptv_python
import numba
try:
import optv
except ImportError:
print("optv not installed; native delegation disabled")
else:
print("optv ok", optv.__version__)
import optv

print("optv ok", optv.__version__)
print("openptv_python ok")
print("numba ok", numba.__version__)
PY
Expand Down Expand Up @@ -184,17 +174,28 @@ OPENPTV_SKIP_STRESS_BENCHMARKS=1 uv run make

### Workflow for developers/contributors

For the best experience create a new conda environment (e.g. DEVELOP) with Python 3.12:
Recommended contributor workflow with `uv`:

```bash
uv venv
source .venv/bin/activate
make env-update
```

This keeps the local environment synced to the locked developer dependency set.

If you prefer the conda workflow instead:

```bash
conda create -n openptv-python -c conda-forge python=3.12
conda activate openptv-python
make conda-env-update
```

Before pushing to GitHub, use the developer install above and then run the
following commands:

1. Update conda environment: `make conda-env-update` or `uv venv` and `source .venv/bin/activate` followed by `uv sync --extra dev --upgrade`
1. Update the environment: `make env-update` by default, or `make conda-env-update` if you are using the conda workflow
1. If you are using pip instead of uv, install the editable developer environment: `pip install -e ".[dev]"`
1. Sync with the latest [template](https://github.com/ecmwf-projects/cookiecutter-conda-package) (optional): `make template-update`
1. Run quality assurance checks: `make qa`
Expand Down
9 changes: 9 additions & 0 deletions conda.recipe/conda_build_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
python:
- 3.6
- 3.7
- 3.8
- 3.9
- 3.10
- 3.11
- 3.12
- 3.13
Loading
Loading