diff --git a/.github/environment.yml b/.github/environment.yml index c12722d8..5a4905c7 100644 --- a/.github/environment.yml +++ b/.github/environment.yml @@ -2,7 +2,7 @@ name: testenv channels: - conda-forge dependencies: - - scikit-build + - scikit-build-core - numpy - compilers - pybind11 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc5c8969..65f01ff3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,60 +35,30 @@ jobs: with: repository: PDAL/python-plugins path: ./plugins + ref: main - name: Setup micromamba uses: conda-incubator/setup-miniconda@v3 with: miniforge-variant: Mambaforge miniforge-version: latest + python-version: ${{ matrix.python-version }} use-mamba: true auto-update-conda: true environment-file: .github/environment.yml - name: Install python-pdal - run: pip install . + run: | + pip install -vv . --no-deps --no-build-isolation - name: Install python-pdal-plugins working-directory: ./plugins - run: pip install . + run: pip install -vv . --no-deps --no-build-isolation - name: Test run: | - export PDAL_DRIVER_PATH=$(python -c "import os, skbuild; print(os.path.join('plugins', skbuild.constants.SKBUILD_DIR(), 'cmake-build'))") + export PDAL_DRIVER_PATH=$(python -m pdal --pdal-plugin-path) + echo $PDAL_DRIVER_PATH pdal --drivers --debug py.test -v test/ - - name: Build source distribution - if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' - run: python setup.py sdist - - - name: Upload distribution(s) - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.os }}-py${{ matrix.python-version }} - path: ./dist/* - - publish: - runs-on: ubuntu-latest - needs: [build] - - steps: - - name: Download distributions - uses: actions/download-artifact@v3 - with: - path: ./artifacts - - - name: Move artifacts to dist - run: | - mkdir dist - find ./artifacts -type f -exec mv {} ./dist \; - tree ./dist - - - name: Publish package - uses: pypa/gh-action-pypi-publish@release/v1 - if: github.event_name == 'release' && github.event.action == 'published' - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} - packages_dir: ./dist - verbose: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..6b55754a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,44 @@ +name: Release + +on: + release: + types: + - published + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + pypi-publish: + name: Upload release to PyPI + runs-on: ubuntu-latest + environment: + name: release + url: https://pypi.org/p/pdal-plugins + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + strategy: + fail-fast: true + + steps: + - uses: actions/checkout@v3 + - name: Setup micromamba + uses: conda-incubator/setup-miniconda@v3 + with: + miniforge-variant: Mambaforge + miniforge-version: latest + use-mamba: true + python-version: ${{ matrix.python-version }} + auto-update-conda: true + environment-file: .github/environment.yml + + - name: Install dependencies + shell: bash -l {0} + run: | + python -m pip install build pipx twine + pipx run build --sdist + + - name: Publish package distributions to PyPI + if: github.event_name == 'release' && github.event.action == 'published' + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index b45f0c35..8c2860ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.11.0) -project(pdal-python) +project(pdal-python VERSION) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -23,17 +23,17 @@ endif() find_package(Python3 COMPONENTS Interpreter ${DEVELOPMENT_COMPONENT} NumPy REQUIRED) # find PDAL. Require 2.1+ -find_package(PDAL 2.5 REQUIRED) +find_package(PDAL 2.6 REQUIRED) # find PyBind11 find_package(pybind11 REQUIRED) set(extension "libpdalpython") pybind11_add_module(${extension} MODULE - pdal/PyArray.cpp - pdal/PyPipeline.cpp - pdal/StreamableExecutor.cpp - pdal/libpdalpython.cpp + src/pdal/PyArray.cpp + src/pdal/PyPipeline.cpp + src/pdal/StreamableExecutor.cpp + src/pdal/libpdalpython.cpp ) target_include_directories(${extension} PRIVATE ${Python3_NumPy_INCLUDE_DIRS}) target_link_libraries(${extension} PRIVATE ${PDAL_LIBRARIES}) diff --git a/README.rst b/README.rst index 1a2d9de6..77915dda 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,8 @@ Additionally, you can use it to fetch `schema`_ and `metadata`_ from PDAL operat Installation -------------------------------------------------------------------------------- +**Note** The PDAL Python bindings require the PDAL base library installed. Source code can be found at https://pdal.io and `GitHub `__. + PyPI ................................................................................ @@ -307,8 +309,8 @@ USE-CASE : Take a LiDAR map, create a mesh from the ground points, split into ti Requirements ================================================================================ -* PDAL 2.5+ +* PDAL 2.6+ * Python >=3.9 * Pybind11 (eg :code:`pip install pybind11[global]`) * Numpy (eg :code:`pip install numpy`) -* scikit-build (eg :code:`pip install scikit-build`) +* scikit-build-core (eg :code:`pip install scikit-build-core`) diff --git a/pyproject.toml b/pyproject.toml index db01ea67..419a8b08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,69 @@ +[project] +name = "pdal" +description = "Point cloud data processing" +readme = "README.rst" +requires-python = ">=3.9" +license = {file = "LICENSE.txt"} +keywords = ["point", "cloud", "spatial"] +authors = [ + {email = "howard@hobu.co"}, + {name = "Howard Butler"} +] +maintainers = [ + {name = "Howard Butler", email = "howard@hobu.co"} +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: GIS", +] + +dependencies = [ + "numpy" +] + +dynamic = ["version"] + +[project.optional-dependencies] +test = [ + "pandas", + "meshio" +] + +[tool.setuptools] +package-dir = {"" = "src"} +zip-safe = false + +[project.urls] +homepage = "https://pdal.io" +documentation = "https://pdal.io" +repository = "https://github.com/PDAL/Python" +changelog = "https://github.com/PDAL/python/blob/main/README.rst" + [build-system] -requires = ["scikit-build", "cmake>=3.11", "ninja", "numpy", "pybind11[global]"] +requires = ["scikit-build-core >= 0.9", "numpy", "pybind11[global]"] +build-backend = "scikit_build_core.build" + + +[tool.scikit-build] +build-dir = "build/{wheel_tag}" +sdist.exclude = [".github"] +sdist.cmake = true +cmake.build-type = "Release" +sdist.include = [ + "src", + "CMakeLists.txt" +] +cmake.verbose = false +logging.level = "ERROR" + +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "src/pdal/__init__.py" diff --git a/setup.py b/setup.py.off similarity index 100% rename from setup.py rename to setup.py.off diff --git a/pdal/PyArray.cpp b/src/pdal/PyArray.cpp similarity index 100% rename from pdal/PyArray.cpp rename to src/pdal/PyArray.cpp diff --git a/pdal/PyArray.hpp b/src/pdal/PyArray.hpp similarity index 100% rename from pdal/PyArray.hpp rename to src/pdal/PyArray.hpp diff --git a/pdal/PyDimension.hpp b/src/pdal/PyDimension.hpp similarity index 100% rename from pdal/PyDimension.hpp rename to src/pdal/PyDimension.hpp diff --git a/pdal/PyPipeline.cpp b/src/pdal/PyPipeline.cpp similarity index 100% rename from pdal/PyPipeline.cpp rename to src/pdal/PyPipeline.cpp diff --git a/pdal/PyPipeline.hpp b/src/pdal/PyPipeline.hpp similarity index 100% rename from pdal/PyPipeline.hpp rename to src/pdal/PyPipeline.hpp diff --git a/pdal/StreamableExecutor.cpp b/src/pdal/StreamableExecutor.cpp similarity index 100% rename from pdal/StreamableExecutor.cpp rename to src/pdal/StreamableExecutor.cpp diff --git a/pdal/StreamableExecutor.hpp b/src/pdal/StreamableExecutor.hpp similarity index 100% rename from pdal/StreamableExecutor.hpp rename to src/pdal/StreamableExecutor.hpp diff --git a/pdal/__init__.py b/src/pdal/__init__.py similarity index 94% rename from pdal/__init__.py rename to src/pdal/__init__.py index 1f05ff3d..7ba4fad7 100644 --- a/pdal/__init__.py +++ b/src/pdal/__init__.py @@ -1,5 +1,5 @@ -__version__ = "3.3.0" __all__ = ["Pipeline", "Stage", "Reader", "Filter", "Writer", "dimensions", "info"] +__version__ = '3.4.0' from . import libpdalpython from .drivers import inject_pdal_drivers diff --git a/src/pdal/__main__.py b/src/pdal/__main__.py new file mode 100644 index 00000000..f45f3151 --- /dev/null +++ b/src/pdal/__main__.py @@ -0,0 +1,77 @@ +import sys +import os +import pathlib + +import distutils.ccompiler +so_ext = distutils.ccompiler.new_compiler().shared_lib_extension +import sysconfig + +import argparse + +import pdal + +from . import __version__ + +__all__ = ["main"] + + +def __dir__() -> list[str]: + return __all__ + + +def print_driver_path(args): + print (os.environ['PDAL_DRIVER_PATH']) + +def print_plugin_path(args): + purelib = sysconfig.get_paths()["purelib"]+os.path.sep+"pdal" + + if sys.platform == "linux" or sys.platform == "linux2": + suffix = 'so' + purelib = purelib + os.path.sep + "pdal" + elif sys.platform == "darwin": + suffix = 'dylib' + purelib = purelib + os.path.sep + "pdal" + elif sys.platform == "win32": + suffix = 'dll' + purelib = purelib + os.path.sep + "bin" + + for f in pathlib.Path(purelib).glob(f'*.{suffix}'): + if 'pdal' in str(f.name): + if 'numpy' in str(f.name) or 'python' in str(f.name): + print (purelib) + return # we are done + +def print_version(args): + info = pdal.drivers.libpdalpython.getInfo() + pdal_version = info.version + plugin = info.plugin + debug = info.debug + + line = '----------------------------------------------------------------------------------------------------------------------------\n' + version = f'PDAL version {pdal_version}\nPython bindings version {__version__}\n' + plugin = f"Environment-set PDAL_DRIVER_PATH: {os.environ['PDAL_DRIVER_PATH']}" + output = f'{line}{version}{plugin}\n{line}\n{debug}' + print (output) + + +def main() -> None: + header = f"PDAL Python bindings {__version__} on Python {sys.version}" + + parser = argparse.ArgumentParser(description=header) + parser.add_argument('--pdal-driver-path', action='store_true', + help='print PDAL_DRIVER_PATH including Python plugin locations') + parser.add_argument('--pdal-plugin-path', action='store_true', + help='print location of PDAL Python plugins') + + args = parser.parse_args() + + if args.pdal_driver_path: + print_driver_path(args) + elif args.pdal_plugin_path: + print_plugin_path(args) + else: + print_version(args) + + +if __name__ == "__main__": + main() diff --git a/pdal/drivers.py b/src/pdal/drivers.py similarity index 100% rename from pdal/drivers.py rename to src/pdal/drivers.py diff --git a/pdal/libpdalpython.cpp b/src/pdal/libpdalpython.cpp similarity index 100% rename from pdal/libpdalpython.cpp rename to src/pdal/libpdalpython.cpp diff --git a/pdal/pipeline.py b/src/pdal/pipeline.py similarity index 100% rename from pdal/pipeline.py rename to src/pdal/pipeline.py