diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 768b2da..37a90f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-latest, windows-2019, macos-13] steps: - uses: actions/checkout@v3 @@ -16,10 +16,7 @@ jobs: submodules: recursive - name: Build wheels - uses: pypa/cibuildwheel@v2.16.2 - env: - CIBW_ARCHS_MACOS: x86_64 arm64 - CIBW_TEST_SKIP: "*_arm64 *_universal2:arm64" + uses: pypa/cibuildwheel@v2.19.2 - name: Show files run: ls -lh wheelhouse diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e1d098..2cc6950 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,8 +2,8 @@ name: Release on: push: - tags: - - "v*.*.*" + branches: + - main jobs: build: diff --git a/pyproject.toml b/pyproject.toml index 79cf107..885cff2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,46 @@ requires = [ "setuptools>=42", "wheel", - "pybind11~=2.6", + "pybind11>=2.12.0", + "tomli>=0.10; python_version<'3.11'", ] build-backend = "setuptools.build_meta" + +[project] +name = "earcutx" +version = "1.0.4" +requires-python = ">=3.8" +authors = [{name = "Samuel Kogler", email = "samuel.kogler@gmail.com"}] +license = {file = "LICENSE.md"} +description = "Python bindings for the mapbox earcut C++ polygon triangulation library." +dependencies = ["numpy>=1.24.0"] + +[project.urls] +Source = "https://github.com/skogler/mapbox_earcut_python" +CSource = "https://github.com/mapbox/earcut.hpp" + +[project.readme] +file = "README.md" +content-type = "text/markdown" + +[tool.setuptools] +zip-safe = false +include-package-data = true + +[project.optional-dependencies] +test = ["pytest"] + + +[tool.cibuildwheel] +skip = "pp*" +# install the `test` extra +test-extras = ["test"] + +# Run the package tests using `pytest` +test-command = "pytest {package}/tests" + +# don't test on PyPy as it will re-build numpy +test-skip = "*_arm64 *_universal2:arm64" + +[tool.cibuildwheel.macos] +archs = ["x86_64", "arm64"] diff --git a/setup.py b/setup.py index faee1db..8916bb8 100644 --- a/setup.py +++ b/setup.py @@ -3,40 +3,44 @@ from setuptools import setup from pybind11.setup_helpers import Pybind11Extension, build_ext -FILE_DIR = os.path.dirname(os.path.abspath(__file__)) -VERSION = '1.0.1' + +def _get_version() -> str: + """ + Get the version defined in `pyproject.toml` to prevent + requiring the version to be specified in two places. + + Note that Python only introduced a TOML parser in + Python 3.11 so this requires `pip install tomli` for older + versions of Python. + """ + try: + # we could also do this with + # if `sys.version_info >= (3, 11)` + from tomllib import load + except BaseException: + # a parser with the same API from pypi + from tomli import load + + # current working directory + cwd = os.path.abspath(os.path.expanduser(os.path.dirname(__file__))) + # file-relative pyproject path + path = os.path.join(cwd, "pyproject.toml") + with open(path, "rb") as f: + pyproject = load(f) + + return pyproject["project"]["version"] + ext_modules = [ - Pybind11Extension('mapbox_earcut', - ['src/main.cpp'], - include_dirs=['include'], - define_macros = [('VERSION_INFO', VERSION)], - ), + Pybind11Extension( + "earcutx", + ["src/main.cpp"], + include_dirs=["include"], + define_macros=[("VERSION_INFO", _get_version())], + ), ] -def get_readme_contents(): - with open(os.path.join(FILE_DIR, 'README.md'), 'r') as readme_file: - return readme_file.read() - setup( - name='mapbox_earcut', - version=VERSION, - url='https://github.com/skogler/mapbox_earcut_python', - author='Samuel Kogler', - author_email='samuel.kogler@gmail.com', - description= - 'Python bindings for the mapbox earcut C++ polygon triangulation library.', - long_description=get_readme_contents(), - long_description_content_type='text/markdown', - license='ISC', ext_modules=ext_modules, - install_requires=['numpy'], - extras_require={'test': 'pytest'}, cmdclass=dict(build_ext=build_ext), - zip_safe=False, - project_urls={ - 'Source': 'https://github.com/skogler/mapbox_earcut_python', - 'Original C++ Source': 'https://github.com/mapbox/earcut.hpp', - }, - include_package_data = True ) diff --git a/src/main.cpp b/src/main.cpp index daaff82..1309f64 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,13 +77,13 @@ py::array_t triangulate(py::array_t vertices, py::array_t); #ifdef VERSION_INFO - m.attr("__version__") = MACRO_TO_STR(VERSION_INFO) ; #else m.attr("__version__") = "dev"; diff --git a/tests/test_earcut.py b/tests/test_earcut.py index 39d30e7..94fb606 100644 --- a/tests/test_earcut.py +++ b/tests/test_earcut.py @@ -1,4 +1,4 @@ -import mapbox_earcut as earcut +import earcutx import numpy as np import pytest @@ -7,10 +7,10 @@ def test_valid_triangulation_float32(): verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.float32).reshape(-1, 2) rings = np.array([3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (3, ) + assert result.shape == (3,) assert np.all(result == np.array([1, 2, 0])) @@ -18,10 +18,10 @@ def test_valid_triangulation_float64(): verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.float64).reshape(-1, 2) rings = np.array([3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (3, ) + assert result.shape == (3,) assert np.all(result == np.array([1, 2, 0])) @@ -29,23 +29,23 @@ def test_valid_triangulation_int32(): verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.int32).reshape(-1, 2) rings = np.array([3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (3, ) + assert result.shape == (3,) assert np.all(result == np.array([1, 2, 0])) def test_inverted_vertex_order(): - verts = np.array( - list(reversed([[0, 0], [1, 0], [1, 1]])), dtype=np.int32).reshape( - -1, 2) + verts = np.array(list(reversed([[0, 0], [1, 0], [1, 1]])), dtype=np.int32).reshape( + -1, 2 + ) rings = np.array([3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (3, ) + assert result.shape == (3,) assert np.all(result == np.array([1, 0, 2])) @@ -53,20 +53,20 @@ def test_no_triangles(): verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.int32).reshape(-1, 2) rings = np.array([2, 3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (0, ) + assert result.shape == (0,) def test_valid_triangulation_int64(): verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.int64).reshape(-1, 2) rings = np.array([3]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) assert result.dtype == np.uint32 - assert result.shape == (3, ) + assert result.shape == (3,) assert np.all(result == np.array([1, 2, 0])) @@ -75,7 +75,7 @@ def test_end_index_too_large(): rings = np.array([5]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_end_index_too_small(): @@ -83,7 +83,7 @@ def test_end_index_too_small(): rings = np.array([2]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_end_index_neg(): @@ -91,7 +91,7 @@ def test_end_index_neg(): rings = np.array([-1]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_rings_not_increasing(): @@ -99,7 +99,7 @@ def test_rings_not_increasing(): rings = np.array([3, 0, 3]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_rings_same(): @@ -107,7 +107,7 @@ def test_rings_same(): rings = np.array([3, 3]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_no_rings(): @@ -115,7 +115,7 @@ def test_no_rings(): rings = np.array([]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) def test_no_rings(): @@ -123,13 +123,13 @@ def test_no_rings(): rings = np.array([]) with pytest.raises(ValueError): - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float64(verts, rings) def test_empty_data(): verts = np.array([]).reshape(-1, 2) rings = np.array([]) - result = earcut.triangulate_float32(verts, rings) + result = earcutx.triangulate_float32(verts, rings) - assert result.shape == (0, ) + assert result.shape == (0,)