From 5c09ea94e804a78016c3fff9f317c233bcd05a05 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Tue, 19 Nov 2024 22:20:33 -0800 Subject: [PATCH] bump dependencies, overhaul build action (#21) * move from setup.py to pyproject.toml * clean and modernize github actions * update dependencies to latest [ci build] * rename build action * dont use system python on macos action [ci build] * add scipy for tests [ci build] * minor * wait to bump for now [ci build] Co-authored-by: Ben Pedigo --- .github/workflows/build.yml | 109 -------------------- .github/workflows/cibuildwheel_config.toml | 8 ++ .github/workflows/publish.yml | 79 +++++++++++++++ .github/workflows/test_build.yml | 53 ++++++++++ .github/workflows/test_linux.yml | 2 +- .github/workflows/test_macos.yml | 9 +- deps/geometry-central | 2 +- deps/pybind11 | 2 +- pyproject.toml | 33 ++++++ setup.py | 111 --------------------- 10 files changed, 180 insertions(+), 228 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/cibuildwheel_config.toml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test_build.yml create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 64b6d65..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Build - -# Run on the main branch and on tags (note conditional below) -on: - push: - branches: - - master - tags: - - v* - pull_request: - branches: - - master - -jobs: - build_wheels: - - # Only run if the commit message contains '[ci build]' OR always run if it's a tag - # This will not respect the tag if it appears in a pull request commit message. Those builds always show up as 'synchronize' events, and there is no easy way to get the corresponding commit messages. We instead pull the PR title to check for tags. - # More info here: https://github.community/t/accessing-commit-message-in-pull-request-event/17158/13 - if: "contains(toJSON(github.event.commits.*.message), '[ci build]') || contains(toJSON(github.event.pull_request.title), '[ci build]') || contains(github.ref, 'refs/tags')" - - strategy: - matrix: - include: - - runs-on: ubuntu-latest - cibw-arch: manylinux_x86_64 - - runs-on: ubuntu-latest - cibw-arch: manylinux_i686 - - runs-on: macos-latest - cibw-arch: macosx_x86_64 - - runs-on: macos-latest - cibw-arch: macosx_arm64 - - runs-on: macos-latest - cibw-arch: macosx_universal2 - - runs-on: windows-latest - cibw-arch: win_amd64 - - runs-on: windows-latest - cibw-arch: win32 - python-arch: x86 - - name: Wheels • ${{ matrix.cibw-arch }} - runs-on: ${{ matrix.runs-on }} - - env: - CIBW_BUILD_VERBOSITY: 3 - CIBW_BEFORE_BUILD_LINUX : "yum remove -y cmake && python -m pip install cmake" - - steps: - - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.7' - - - name: Install cibuildwheel - run: | - python -m pip install cibuildwheel==2.13.1 - - - - name: Package source distribution - if: runner.os == 'Linux' - run: | - python setup.py sdist -d wheelhouse --formats=gztar - - - name: Configure cibuildwheel - shell: bash - run: | - CMAKE_ARCH="${{ matrix.cibw-arch == 'win32' && '-A Win32' || '' }}" - CMAKE_OSX_ARCHITECTURES=${{ matrix.cibw-arch == 'macosx_x86_64' && 'x86_64' || matrix.cibw-arch == 'macosx_arm64' && 'arm64' || matrix.cibw-arch == 'macosx_universal2' && '"arm64;x86_64"' || '' }} - echo "CIBW_ARCHS_MACOS=x86_64 arm64 universal2" >> $GITHUB_ENV - echo "CIBW_BUILD=*-${{ matrix.cibw-arch }}" >> $GITHUB_ENV - echo "CIBW_ENVIRONMENT_MACOS=CMAKE_OSX_ARCHITECTURES=\"$CMAKE_OSX_ARCHITECTURES\"" >> $GITHUB_ENV - - - name: Build wheels - run: | - python -m cibuildwheel --output-dir wheelhouse - - # Upload binaries to github - - uses: actions/upload-artifact@v2 - with: - path: | - ./wheelhouse/*.whl - ./wheelhouse/*.tar.gz - - # Push the resulting binaries to pypi on a tag starting with 'v' - upload_pypi: - needs: [build_wheels] - runs-on: ubuntu-latest - # upload to PyPI on every tag starting with 'v' - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') - # alternatively, to publish when a GitHub Release is created, use the following rule: - # if: github.event_name == 'release' && github.event.action == 'published' - steps: - - uses: actions/download-artifact@v2 - with: - name: artifact - path: dist - - - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} - skip_existing: true - # To test: repository_url: https://test.pypi.org/legacy/ - diff --git a/.github/workflows/cibuildwheel_config.toml b/.github/workflows/cibuildwheel_config.toml new file mode 100644 index 0000000..f48d4c2 --- /dev/null +++ b/.github/workflows/cibuildwheel_config.toml @@ -0,0 +1,8 @@ +[tool.cibuildwheel] +skip = "cp36-*" # scikit-build-core requires >=3.7 +build-verbosity = 3 + +[tool.cibuildwheel.linux] +before-all = [ + "yum remove -y cmake", +] \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..ebbf477 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,79 @@ +name: Build and Publish + +# NOTE: build logic is duplicated here and in test_build.yml + +# Run on the main branch for commits only +on: + push: + branches: + - master + +jobs: + build_wheels: + + # only run if the most recent commit contains '[ci publish]' + if: "contains(github.event.head_commit.message, '[ci publish]')" + + strategy: + matrix: + # macos-13 is an intel runner, macos-14 is apple silicon + os: [ubuntu-latest, windows-latest, macos-13, macos-14] + + name: Build wheels ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Package source distribution + if: runner.os == 'Linux' + run: | + python -m pip install build + python -m build --sdist + + - name: Run cibuildwheel + uses: pypa/cibuildwheel@v2.21 + with: + config-file: ".github/workflows/cibuildwheel_config.toml" + + # Upload binaries to the github artifact store + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.os }} + path: | + ./wheelhouse/*.whl + ./wheelhouse/*.tar.gz + overwrite: true + + # Push the resulting binaries to pypi on a tag starting with 'v' + upload_pypi: + name: Upload release to PyPI + + # only run if the most recent commit contains '[ci publish]' + if: "contains(github.event.head_commit.message, '[ci publish]')" + + needs: [build_wheels] + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/robust-laplacian/ + permissions: # we authenticate via PyPI's 'trusted publisher' workflow, this permission is required + id-token: write + steps: + - name: Download built wheels artifact # downloads from the jobs storage from the previous step + uses: actions/download-artifact@v4.1.7 + with: + # omitting the `name: ` field downloads all artifacts from this workflow + path: dist + + - name: List downloaded files from artifact + run: ls dist | cat # piping through cat prints one per line + + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # To test: repository_url: https://test.pypi.org/legacy/ + diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml new file mode 100644 index 0000000..b7a75f0 --- /dev/null +++ b/.github/workflows/test_build.yml @@ -0,0 +1,53 @@ +name: Test Build + +# NOTE: build logic is duplicated here and in publish.yml + +# Run on the master branch commit push and PRs to master (note conditional below) +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build_wheels: + + # Only run if the commit message contains '[ci build]' + if: "contains(toJSON(github.event.commits.*.message), '[ci build]') || contains(toJSON(github.event.pull_request.title), '[ci build]')" + + strategy: + fail-fast: false + matrix: + # macos-13 is an intel runner, macos-14 is apple silicon + os: [ubuntu-latest, windows-latest, macos-13, macos-14] + + name: Build wheels ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Package source distribution + if: runner.os == 'Linux' + run: | + python -m pip install build + python -m build --sdist + + - name: Run cibuildwheel + uses: pypa/cibuildwheel@v2.21 + with: + config-file: ".github/workflows/cibuildwheel_config.toml" + + # Upload binaries to the github artifact store + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.os }} + path: | + ./wheelhouse/*.whl + ./wheelhouse/*.tar.gz + overwrite: true \ No newline at end of file diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index 5e65742..ee6290e 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-python@v2 name: Install Python with: - python-version: '3.7' + python-version: '3.9' - name: install python packages run: python3 -m pip install numpy scipy diff --git a/.github/workflows/test_macos.yml b/.github/workflows/test_macos.yml index 4defe3a..59b6cd6 100644 --- a/.github/workflows/test_macos.yml +++ b/.github/workflows/test_macos.yml @@ -15,11 +15,10 @@ jobs: with: submodules: 'recursive' - # Use system python on mac; 3.9 seems to be available and this way there aren't multiple versions floating around - #- uses: actions/setup-python@v2 - #name: Install Python - #with: - #python-version: '3.7' + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.9' - name: install python packages run: python3 -m pip install numpy scipy diff --git a/deps/geometry-central b/deps/geometry-central index 4aba049..70c859e 160000 --- a/deps/geometry-central +++ b/deps/geometry-central @@ -1 +1 @@ -Subproject commit 4aba04964b6d3aa594520555f9fe54b07bad101f +Subproject commit 70c859ec3b58fe597c0063673a74082654e9c5aa diff --git a/deps/pybind11 b/deps/pybind11 index 8a099e4..a2e59f0 160000 --- a/deps/pybind11 +++ b/deps/pybind11 @@ -1 +1 @@ -Subproject commit 8a099e44b3d5f85b20f05828d919d2332a8de841 +Subproject commit a2e59f0e7065404b44dfe92a28aca47ba1378dc4 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..612aaae --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,33 @@ +[project] +name = "robust_laplacian" +version = "0.2.8" +description = "Robust Laplace matrices for meshes and point clouds" +readme = "README.md" +license.file = "LICENSE" +authors = [ + { name = "Nicholas Sharp", email = "nmwsharp@gmail.com" }, +] +maintainers = [ + { name = "Nicholas Sharp", email = "nmwsharp@gmail.com" }, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] +requires-python = ">=3.7" + +dependencies = [ + "numpy", +] + +[project.urls] +Homepage = "https://github.com/nmwsharp/robust-laplacians-py" + +[build-system] +requires = ["scikit-build-core"] +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +build.verbose = true +logging.level = "INFO" \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index ed3559a..0000000 --- a/setup.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import re -import sys -import platform -import subprocess - -import setuptools -from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext -from distutils.version import LooseVersion - -__version__ = '0.2.7' - -class CMakeExtension(Extension): - def __init__(self, name, sourcedir='', exclude_arch=False): - Extension.__init__(self, name, sources=[]) - self.sourcedir = os.path.abspath(sourcedir) - self.exclude_arch = exclude_arch - - -class CMakeBuild(build_ext): - def run(self): - try: - out = subprocess.check_output(['cmake', '--version']) - except OSError: - raise RuntimeError("CMake must be installed to build the following extensions: " + - ", ".join(e.name for e in self.extensions)) - - if platform.system() == "Windows": - cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) - if cmake_version < '3.1.0': - raise RuntimeError("CMake >= 3.1.0 is required on Windows") - - for ext in self.extensions: - self.build_extension(ext) - - def build_extension(self, ext): - extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) - cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, - '-DPYTHON_EXECUTABLE=' + sys.executable] - - cfg = 'Debug' if self.debug else 'Release' - build_args = ['--config', cfg] - - if platform.system() == "Windows": - cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] - if not ext.exclude_arch: - if sys.maxsize > 2**32: - cmake_args += ['-A', 'x64'] - else: - cmake_args += ['-A', 'Win32'] - build_args += ['--', '/m'] - else: - cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] - build_args += ['--', '-j3'] - - if self.distribution.verbose > 0: - cmake_args += ['-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'] - - - env = os.environ.copy() - env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), - self.distribution.get_version()) - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) - - if(self.distribution.verbose > 0): - print("Running cmake configure command: " + " ".join(['cmake', ext.sourcedir] + cmake_args)) - subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) - - if(self.distribution.verbose > 0): - print("Running cmake build command: " + " ".join(['cmake', '--build', '.'] + build_args)) - subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) - -def main(): - - with open('README.md') as f: - long_description = f.read() - - # Applies to windows only. - # Normally, we set cmake's -A option to specify 64 bit platform when need (and /m for build), - # but these are errors with non-visual-studio generators. CMake does not seem to have an idiomatic - # way to disable, so we expose an option here. A more robust solution would auto-detect based on the - # generator. Really, this option might be better titled "exclude visual-studio-settings-on-windows" - if "--exclude-arch" in sys.argv: - exclude_arch = True - sys.argv.remove('--exclude-arch') - else: - exclude_arch = False - - setup( - name='robust_laplacian', - version=__version__, - author='Nicholas Sharp', - author_email='nsharp@cs.cmu.edu', - url='https://github.com/nmwsharp/robust-laplacians-py', - description='Robust Laplace matrices for meshes and point clouds', - long_description=long_description, - long_description_content_type='text/markdown', - license="MIT", - package_dir = {'': 'src'}, - packages=setuptools.find_packages(where="src"), - ext_modules=[CMakeExtension('.')], - install_requires=['numpy','scipy'], - cmdclass=dict(build_ext=CMakeBuild), - zip_safe=False, - test_suite="test", - ) - -if __name__ == "__main__": - main()