Skip to content

Commit

Permalink
Add python packaging support
Browse files Browse the repository at this point in the history
Signed-off-by: pdmurray <peynmurray@gmail.com>
  • Loading branch information
peytondmurray committed Jul 6, 2023
1 parent 7edd8cd commit aa67f3d
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 19 deletions.
100 changes: 100 additions & 0 deletions .github/workflows/pypi_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Build and Release Python Bindings to PyPI

on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
type: string
default: ''
required: false
description: Ref to build
test_pypi:
type: boolean
description: 'Test release: publish on test.pypi.org'
default: false

jobs:
build-sdist:
name: Build sdist
runs-on: ubuntu-latest
steps:
- name:  Checkout the repo
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.tag }}

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

- name:  Install build dependencies
run: |
python -m pip install build
- name: 📦 Build the sdist
working-directory: ./openvdb/openvdb/python
run: |
python -m build --sdist
- name:  Upload artifact
uses: actions/upload-artifact@v3
with:
name: dist
path: ./openvdb/openvdb/python/dist/

build-wheels:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name:  Checkout the repo
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.tag }}


- name: Build wheels
uses: pypa/cibuildwheel@v2.12.1
with:
package-dir: ./openvdb/openvdb/python
config-file: ./openvdb/openvdb/python/pyproject.toml
env:
CIBW_ARCHS_MACOS: auto universal2

- name:  Upload artifact
uses: actions/upload-artifact@v3
with:
name: dist
path: ./openvdb/openvdb/python/dist/

publish:
name: Publish Python packages on PyPI
needs: [build-sdist, build-wheels]
runs-on: ubuntu-latest
steps:
- name:  Download artifacts
uses: actions/download-artifact@v3
with:
name: dist
path: dist

- name: 🧪 Publish to PyPI Testing
uses: pypa/gh-action-pypi-publish@release/v1
if: ${{ inputs.test_pypi }}
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
packages_dir: dist

- name: 🎉 Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
if: ${{ !inputs.test_pypi }}
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: dist
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/build/*
.DS_Store

# pyenv
.python-version
9 changes: 9 additions & 0 deletions openvdb/openvdb/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CMakeCache.txt
CMakeFiles/
Makefile
cmake_install.cmake
*.egg-info/
*.so
_skbuild/
MANIFEST.in
dist/
36 changes: 24 additions & 12 deletions openvdb/openvdb/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ if(USE_NUMPY)
list(APPEND OPENVDB_PYTHON_REQUIRED_COMPONENTS NumPy)
endif()

# scikit-build doesn't yet support FindPython, but this workaround was
# supplied by one of the scikit-build devs. See
# https://github.com/pypa/cibuildwheel/issues/727 for details.
if(SKBUILD)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
set(Python_NumPy_INCLUDE_DIR "${NUMPY_INCLUDE_DIR}")
endif()

# Make sure find_package(Python) is only ever invoked once with all required components
find_package(Python COMPONENTS ${OPENVDB_PYTHON_REQUIRED_COMPONENTS})
find_package(pybind11 ${MINIMUM_PYBIND_VERSION} REQUIRED)
Expand Down Expand Up @@ -142,33 +150,37 @@ if(NOT DEFINED PYOPENVDB_INSTALL_DIRECTORY)
get_filename_component(Python_PACKAGES_DIR ${Python_SITELIB} NAME)
set(PYOPENVDB_INSTALL_DIRECTORY
${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/${Python_PACKAGES_DIR}
CACHE STRING "The directory to install the pyopenvdb.so module."
CACHE STRING "The directory to install the _openvdb.so module."
)
endif()

pybind11_add_module(pyopenvdb ${OPENVDB_PYTHON_MODULE_SOURCE_FILES})
pybind11_add_module(_openvdb MODULE ${OPENVDB_PYTHON_MODULE_SOURCE_FILES})

target_link_libraries(pyopenvdb PUBLIC
target_link_libraries(_openvdb PUBLIC
${OPENVDB_LIB}
${OPENVDB_PYTHON_DEPS}
)

if(OPENVDB_PYTHON_WRAP_ALL_GRID_TYPES)
target_compile_definitions(pyopenvdb PRIVATE "-DPY_OPENVDB_WRAP_ALL_GRID_TYPES")
target_compile_definitions(_openvdb PRIVATE "-DPY_OPENVDB_WRAP_ALL_GRID_TYPES")
endif()
if(USE_NUMPY)
target_compile_definitions(pyopenvdb PUBLIC "-DPY_OPENVDB_USE_NUMPY")
target_compile_definitions(_openvdb PUBLIC "-DPY_OPENVDB_USE_NUMPY")
endif()
if(USE_AX)
target_link_libraries(pyopenvdb PUBLIC ${OPENVDB_AX_LIB})
target_compile_definitions(pyopenvdb PUBLIC "-DPY_OPENVDB_USE_AX")
target_link_libraries(_openvdb PUBLIC ${OPENVDB_AX_LIB})
target_compile_definitions(_openvdb PUBLIC "-DPY_OPENVDB_USE_AX")
endif()

install(TARGETS
pyopenvdb
DESTINATION
${PYOPENVDB_INSTALL_DIRECTORY}
)
if (SKBUILD)
install(TARGETS _openvdb DESTINATION openvdb)
else()
install(TARGETS
_openvdb
DESTINATION
${PYOPENVDB_INSTALL_DIRECTORY}
)
endif()

# pytest
if(OPENVDB_BUILD_PYTHON_UNITTESTS)
Expand Down
79 changes: 79 additions & 0 deletions openvdb/openvdb/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# `openvdb`

This project contains python bindings for OpenVDB.

## Installing from source

Installation using `pip` is preferred because it manages the package version
sensibly, and also automatically handles finding the correct python
installation.

### Using pip

The python bindings for OpenVDB can be installed using `pip install .`. In this
case, the build build toolchain executes in the following order:

1. The project's `pyproject.toml` is read, invoking the build backend. The
`openvdb` python bindings use `scikit-build-core` as a build backend.
`scikit-build-core` acts as [a wrapper for `cmake`][scikit-build-core].
3. `scikit-build-core` passes a sensible default set of flags which are defined
in `pyproject.toml` under `tool.scikit-build.cmake.define` to `cmake`, which
generates build files the project (ninja or GNU make).
4. `pybind11` generates the actual bindings for the project.
5. The project is built using whatever build toolchain cmake detected and
configured. A shared object file is created with the python bindings.
6. `pip` copies the resulting shared object into your python installation's
`site-packages` directory.

### Using cmake

Build files for the C++ code are generated by `cmake`, so the bindings can be
built by invoking

```bash
mkdir build
cd build
cmake ..
cmake --build .
cmake --install .
```

This will generate build files, build a shared object library, and copy it into
your python installation's `site-packages` directory, where it can be imported
directly. If you wish to target a particular version of python, this can be done
by setting [the appropriate cmake flags][cmake_flags]. `CMakeLists.txt` contains
a full listing of build options for more customization; by default the `openvdb`
package on PyPI is built with all the optional functionality enabled.

## Releasing to PyPI

Before creating an openvdb release, maintainers should be sure to update the
version string in `pyproject.toml`.

Using GitHub actions, new `openvdb` versions are published to PyPI automatically
when a new OpenVDB release is made. Releases can also published to PyPI by
triggering the "Build and Release Python Bindings to PyPI" job, and specifying a
branch/ref; if no ref is specified, the most recent commit on the given branch
is used. Publishing to PyPI requires an API token to be specified as a secret
(`PYPI_API_TOKEN`) on the repository.

If a maintainer wants to test the release process, they can do so by triggering
a workflow dispatch, and clicking the option to release to `test.pypi.org`. In
this case, a separate `TEST_PYPI_API_TOKEN` secret must be defined for the
repository. Once the release is published to the PYPI testing index, you can
install the release with

```bash
pip install -v --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ openvdb
```

This will install the `openvdb` package from test.pypi.org, but will allow
dependencies to be installed from the usual index (pypi.org).

## Contributors

Thanks to Alex Braun (@theNewFlesh) for contributing the original python
packaging for openvdb.

[scikit-build-core]: https://github.com/scikit-build/scikit-build-core
[cmake_flags]: https://cmake.org/cmake/help/latest/module/FindPython.html
1 change: 1 addition & 0 deletions openvdb/openvdb/python/openvdb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._openvdb import *
5 changes: 0 additions & 5 deletions openvdb/openvdb/python/pyOpenVDBModule.cc
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,8 @@ struct VecTypeDescr
////////////////////////////////////////


#ifdef DWA_OPENVDB
#define PY_OPENVDB_MODULE_NAME _openvdb
extern "C" { void init_openvdb(); }
#else
#define PY_OPENVDB_MODULE_NAME pyopenvdb
extern "C" { void initpyopenvdb(); }
#endif

PYBIND11_MODULE(PY_OPENVDB_MODULE_NAME, m)
{
Expand Down
42 changes: 42 additions & 0 deletions openvdb/openvdb/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[build-system]
requires = [
"scikit_build_core==0.2.1",
"pybind11==2.10.3",
"oldest-supported-numpy"
]
build-backend = "scikit_build_core.build"

[project]
name = "openvdb"
version = "10.0.1"
description= "Python bindings for OpenVDB: sparse volume data structure and tools."
dependencies = [
"numpy",
]
readme = "README.md"
authors = [
{ name = "OpenVDB Developer Team", email = "openvdb-dev@lists.aswf.io" },
]
requires-python = ">=3.7"
classifiers = [
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]

[project.urls]
homepage = "https://www.openvdb.org/"
documentation = "https://www.openvdb.org/documentation"
forum = "https://github.com/AcademySoftwareFoundation/openvdb/discussions"
repository = "https://github.com/AcademySoftwareFoundation/openvdb"
slack = "https://slack.aswf.io/"

[tool.scikit-build]
cmake.minimum-version = "3.18"

[tool.scikit-build.cmake.define]
OPENVDB_BUILD_CORE = "ON"
USE_NUMPY = "ON"
3 changes: 1 addition & 2 deletions openvdb/openvdb/python/test/TestOpenVDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
os.add_dll_directory(os.getcwd() +
'\\..\\..\\..\\..\\openvdb_ax\\openvdb_ax\\' + config)

import pyopenvdb as openvdb
import openvdb


def valueFactory(zeroValue, elemValue):
Expand Down Expand Up @@ -839,4 +839,3 @@ def testMeshConversion(self):
args = [a for a in args if a != '-t']

unittest.main(argv=args)

0 comments on commit aa67f3d

Please sign in to comment.