diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 4b97e5f91..18e2f092d 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -17,8 +17,6 @@ jobs: git config --global submodule.fetchJobs 8 git config --global core.longpaths true - uses: actions/checkout@v4 - with: - submodules: recursive - name: Build wheels uses: pypa/cibuildwheel@v2.19 - uses: actions/upload-artifact@v4 @@ -31,8 +29,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - submodules: recursive - name: Build SDist run: pipx run build --sdist - name: Confirm SDist can be built diff --git a/.github/workflows/manifold.yml b/.github/workflows/manifold.yml index 2c423b6e5..83dc32ece 100644 --- a/.github/workflows/manifold.yml +++ b/.github/workflows/manifold.yml @@ -38,8 +38,6 @@ jobs: sudo apt-get install libglm-dev libgtest-dev libassimp-dev git libtbb-dev libthrust-dev pkg-config libpython3-dev lcov python -m pip install -U trimesh pytest - uses: actions/checkout@v4 - with: - submodules: recursive - uses: jwlawson/actions-setup-cmake@v2 - name: Build ${{matrix.parallel_backend}} if: matrix.parallel_backend != 'NONE' @@ -98,8 +96,6 @@ jobs: sudo apt-get -y update DEBIAN_FRONTEND=noninteractive sudo apt install -y libgtest-dev libglm-dev libassimp-dev git libtbb-dev pkg-config libpython3-dev python3 python3-distutils python3-pip - uses: actions/checkout@v4 - with: - submodules: recursive - uses: jwlawson/actions-setup-cmake@v2 - name: Build C bindings with TBB run: | @@ -124,8 +120,6 @@ jobs: sudo apt-get -y update DEBIAN_FRONTEND=noninteractive sudo apt install -y nodejs libglm-dev - uses: actions/checkout@v4 - with: - submodules: recursive - name: Setup WASM run: | # setup emscripten @@ -170,8 +164,6 @@ jobs: if: github.event.pull_request.draft == false steps: - uses: actions/checkout@v4 - with: - submodules: recursive - uses: jwlawson/actions-setup-cmake@v2 - uses: ilammy/msvc-dev-cmd@v1 - name: Build ${{matrix.parallel_backend}} @@ -203,8 +195,6 @@ jobs: container: openscad/mxe-x86_64-gui:latest steps: - uses: actions/checkout@v4 - with: - submodules: recursive - name: Build run: | mkdir build @@ -233,8 +223,6 @@ jobs: if: matrix.parallel_backend == 'TBB' run: brew install tbb onedpl - uses: actions/checkout@v4 - with: - submodules: recursive - uses: jwlawson/actions-setup-cmake@v2 - name: Build run: | @@ -257,13 +245,13 @@ jobs: timeout-minutes: 30 strategy: matrix: - variant: [none, tbb, js] + # variant: [none, tbb, js] + # disabling js variant for now + variant: [none, tbb] runs-on: ubuntu-latest if: github.event.pull_request.draft == false steps: - uses: actions/checkout@v4 - with: - submodules: recursive - uses: cachix/install-nix-action@v22 - run: nix build -L '.?submodules=1#manifold-${{matrix.variant}}' @@ -273,7 +261,5 @@ jobs: if: github.event.pull_request.draft == false steps: - uses: actions/checkout@v4 - with: - submodules: recursive - uses: cachix/install-nix-action@v22 - run: nix build -L '.?submodules=1#manifold3d' diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c682e95f..2d60ec94e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,13 @@ if(MANIFOLD_PYBIND) else() find_package(Python COMPONENTS Interpreter Development.SABIModule REQUIRED) endif() + if(Python_VERSION VERSION_GREATER_EQUAL 3.11) + set(MANIFOLD_PYBIND_STUBGEN ON) + else() + # stubgen does not support version less than 3.11 + set(MANIFOLD_PYBIND_STUBGEN OFF) + message("Python version too old, stub will not be generated") + endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index e2dfb70bc..0aa75b2d8 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -17,7 +17,8 @@ project(python) execute_process( COMMAND "${Python_EXECUTABLE}" -m nanobind --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_VERSION) -if(NB_VERSION VERSION_GREATER_EQUAL 1.8.0) +# we are fine with 2.0.0 +if(NB_VERSION VERSION_GREATER_EQUAL 2.0.0) message("Found nanobind, version ${NB_VERSION}") execute_process( COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir @@ -28,16 +29,35 @@ else() include(FetchContent) FetchContent_Declare(nanobind GIT_REPOSITORY https://github.com/wjakob/nanobind.git - GIT_TAG 8d7f1ee0621c17fa370b704b2100ffa0243d5bf # v2.0.0 + GIT_TAG 9641bb7151f04120013b812789b3ebdfa7e7324f # v2.1.0 GIT_PROGRESS TRUE ) FetchContent_MakeAvailable(nanobind) endif() + +if(NB_VERSION VERSION_LESS 2.1.0) + message("Nanobind version too old, stub will not be generated") + set(MANIFOLD_PYBIND_STUBGEN OFF) +endif() + nanobind_add_module( manifold3d NB_STATIC STABLE_ABI LTO autogen_docstrings.inl manifold3d.cpp) + +if(MANIFOLD_PYBIND_STUBGEN) + nanobind_add_stub( + manifold3d_stub + MODULE manifold3d + OUTPUT manifold3d.pyi + PYTHON_PATH $ + DEPENDS manifold3d + MARKER_FILE py.typed + PATTERN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/stub_pattern.txt + ) +endif() + target_link_libraries(manifold3d PRIVATE manifold polygon cross_section) target_compile_options(manifold3d PRIVATE ${MANIFOLD_FLAGS} -DMODULE_NAME=manifold3d) target_compile_features(manifold3d PUBLIC cxx_std_17) @@ -62,15 +82,22 @@ add_custom_command( target_include_directories(manifold3d PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if(SKBUILD) -install( - TARGETS manifold3d - LIBRARY DESTINATION ${SKBUILD_PLATLIB_DIR} - COMPONENT bindings -) + set(MANIFOLD_PYBIND_LIBDIR ${SKBUILD_PLATLIB_DIR}) else() + set(MANIFOLD_PYBIND_LIBDIR ${Python_SITEARCH}) +endif() + install( TARGETS manifold3d - LIBRARY DESTINATION ${Python_SITEARCH} + LIBRARY DESTINATION ${MANIFOLD_PYBIND_LIBDIR} COMPONENT bindings + EXCLUDE_FROM_ALL ) +if(MANIFOLD_PYBIND_STUBGEN) + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/py.typed ${CMAKE_CURRENT_BINARY_DIR}/manifold3d.pyi + DESTINATION ${MANIFOLD_PYBIND_LIBDIR} + COMPONENT bindings + EXCLUDE_FROM_ALL + ) endif() diff --git a/bindings/python/examples/bricks.py b/bindings/python/examples/bricks.py index a0d04aa1a..55501a623 100644 --- a/bindings/python/examples/bricks.py +++ b/bindings/python/examples/bricks.py @@ -84,7 +84,7 @@ def floor(length, width): ) ) if length == 1 and width > 1: - results.append(row(width - 1).rotate(0, 0, 90)) + results.append(row(width - 1).rotate((0, 0, 90))) if width == 1 and length > 1: results.append( row(length - 1).translate( diff --git a/bindings/python/examples/gyroid_module.py b/bindings/python/examples/gyroid_module.py index e8a595ae4..582084559 100644 --- a/bindings/python/examples/gyroid_module.py +++ b/bindings/python/examples/gyroid_module.py @@ -16,7 +16,7 @@ import math import numpy as np -from manifold3d import Mesh, Manifold +from manifold3d import Manifold def gyroid(x, y, z): diff --git a/bindings/python/examples/sponge.py b/bindings/python/examples/sponge.py index d0bdd7f69..203e3af8d 100644 --- a/bindings/python/examples/sponge.py +++ b/bindings/python/examples/sponge.py @@ -39,5 +39,7 @@ def run(n=1): result -= hole.rotate([0, 90, 0]) return ( - result.trim_by_plane([1, 1, 1], 0).set_properties(4, posColors).scale([100] * 3) + result.trim_by_plane([1, 1, 1], 0) + .set_properties(4, posColors) + .scale([100, 100, 100]) ) diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index 921bb899f..3b9fa503f 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -327,7 +327,8 @@ NB_MODULE(manifold3d, m) { .def("refine", &Manifold::Refine, nb::arg("n"), manifold__refine__n) .def("refine_to_length", &Manifold::RefineToLength, nb::arg("length"), manifold__refine_to_length__length) - .def("to_mesh", &Manifold::GetMeshGL, nb::arg("normal_idx") = ivec3(0), + .def("to_mesh", &Manifold::GetMeshGL, + nb::arg("normal_idx") = std::make_tuple(0, 0, 0), manifold__get_mesh_gl__normal_idx) .def("num_vert", &Manifold::NumVert, manifold__num_vert) .def("num_edge", &Manifold::NumEdge, manifold__num_edge) @@ -406,7 +407,8 @@ NB_MODULE(manifold3d, m) { .def_static("compose", &Manifold::Compose, nb::arg("manifolds"), manifold__compose__manifolds) .def_static("tetrahedron", &Manifold::Tetrahedron, manifold__tetrahedron) - .def_static("cube", &Manifold::Cube, nb::arg("size") = vec3{1, 1, 1}, + .def_static("cube", &Manifold::Cube, + nb::arg("size") = std::make_tuple(1.0, 1.0, 1.0), nb::arg("center") = false, manifold__cube__size__center) .def_static( "extrude", diff --git a/bindings/python/stub_pattern.txt b/bindings/python/stub_pattern.txt new file mode 100644 index 000000000..a549dde01 --- /dev/null +++ b/bindings/python/stub_pattern.txt @@ -0,0 +1,13 @@ +manifold3d.__prefix__: + import numpy as np + from typing import Literal, TypeVar, Union + + N = TypeVar('N', bound=np.generic) + DoubleNx2 = np.ndarray[tuple[N, Literal[2]], np.dtype[np.double]] + Doublex2 = Union[np.ndarray[tuple[Literal[2]], np.dtype[np.double]], tuple[float, float], list[float]] + Doublex3 = Union[np.ndarray[tuple[Literal[3]], np.dtype[np.double]], tuple[float, float, float], list[float]] + Double2x3 = np.ndarray[tuple[Literal[2], Literal[3]], np.dtype[np.double]] + Double3x4 = np.ndarray[tuple[Literal[3], Literal[4]], np.dtype[np.double]] + DoubleNx3 = np.ndarray[tuple[N, Literal[3]], np.dtype[np.double]] + Intx3 = Union[np.ndarray[tuple[Literal[3]], np.dtype[np.integer]], tuple[int, int, int], list[int]] + IntNx3 = np.ndarray[tuple[N, Literal[3]], np.dtype[np.integer]] diff --git a/flake.lock b/flake.lock index a9dad5445..f6676b347 100644 --- a/flake.lock +++ b/flake.lock @@ -53,11 +53,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717602782, - "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", + "lastModified": 1726937504, + "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", + "rev": "9357f4f23713673f310988025d9dc261c20e70c6", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d5379375e..15323ffc7 100644 --- a/flake.nix +++ b/flake.nix @@ -51,10 +51,6 @@ "-DBUILD_SHARED_LIBS=ON" "-DMANIFOLD_PAR=${pkgs.lib.strings.toUpper parallel-backend}" ]; - prePatch = '' - substituteInPlace bindings/python/CMakeLists.txt \ - --replace 'DESTINATION ''${Python_SITEARCH}' 'DESTINATION "${placeholder "out"}/${pkgs.python3.sitePackages}"' - ''; checkPhase = '' cd test ./manifold_test