poetry python build
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,3 +5,7 @@ build_warnings*.log
|
|||||||
final_build.log
|
final_build.log
|
||||||
cmake_configure.log
|
cmake_configure.log
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
|
||||||
|
dist/
|
||||||
|
build_python/
|
||||||
|
src/Python/uLib/*.so*
|
||||||
47
build_python.py
Normal file
47
build_python.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def build(setup_kwargs):
|
||||||
|
"""
|
||||||
|
Build the C++ extension using CMake.
|
||||||
|
This function is called by poetry-core during the build process.
|
||||||
|
The binary is placed directly inside the uLib directory in src/Python.
|
||||||
|
"""
|
||||||
|
# Root of the whole project where this build_extension.py is located
|
||||||
|
project_root = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# Where the extension should go
|
||||||
|
package_dir = os.path.join(project_root, "src/Python/uLib")
|
||||||
|
|
||||||
|
# Ensure package directory exists
|
||||||
|
os.makedirs(package_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Temporary build directory
|
||||||
|
build_temp = os.path.join(project_root, "build_python")
|
||||||
|
os.makedirs(build_temp, exist_ok=True)
|
||||||
|
|
||||||
|
print(f"--- Running CMake build in {build_temp} ---")
|
||||||
|
print(f"Project root: {project_root}")
|
||||||
|
print(f"Target binary dir: {package_dir}")
|
||||||
|
|
||||||
|
# CMake configuration
|
||||||
|
cmake_args = [
|
||||||
|
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={package_dir}",
|
||||||
|
f"-DPYTHON_EXECUTABLE={sys.executable}",
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DUSE_CUDA=OFF",
|
||||||
|
"-G", "Unix Makefiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Use micromamba to ensure Boost and VTK are found during the build
|
||||||
|
subprocess.check_call(["cmake", project_root] + cmake_args, cwd=build_temp)
|
||||||
|
subprocess.check_call(["cmake", "--build", ".", "--parallel", "--target", "uLib_python"], cwd=build_temp)
|
||||||
|
|
||||||
|
# Ensure the package is found by poetry during the wheel creation process.
|
||||||
|
# Return setup_kwargs for poetry-core.
|
||||||
|
return setup_kwargs
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
build({})
|
||||||
7
poetry.lock
generated
Normal file
7
poetry.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand.
|
||||||
|
package = []
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "2.1"
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
content-hash = "db9b4c08b159b17b239e26c67ead7c37b82d9f9eb06550245ae3134c095f98f7"
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "uLib"
|
||||||
|
version = "0.6.0"
|
||||||
|
description = "CMT Cosmic Muon Tomography project uLib python bindings"
|
||||||
|
authors = ["Andrea Rigoni Garola <andrea.rigoni@pd.infn.it>"]
|
||||||
|
readme = "README.md"
|
||||||
|
packages = [{ include = "uLib", from = "src/Python" }]
|
||||||
|
build = "build_python.py"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = ">=3.9"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = ["poetry-core>=2.0.0", "pybind11>=2.6.0", "cmake>=3.12"]
|
||||||
"setuptools>=42",
|
build-backend = "poetry.core.masonry.api"
|
||||||
"wheel",
|
|
||||||
"pybind11>=2.6.0",
|
|
||||||
"cmake>=3.12",
|
|
||||||
"ninja"]
|
|
||||||
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|||||||
52
setup.py
52
setup.py
@@ -1,52 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from setuptools import Extension, setup
|
|
||||||
from setuptools.command.build_ext import build_ext
|
|
||||||
|
|
||||||
class CMakeExtension(Extension):
|
|
||||||
def __init__(self, name, sourcedir=""):
|
|
||||||
Extension.__init__(self, name, sources=[])
|
|
||||||
self.sourcedir = os.path.abspath(sourcedir)
|
|
||||||
|
|
||||||
class CMakeBuild(build_ext):
|
|
||||||
def build_extension(self, ext):
|
|
||||||
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
|
|
||||||
|
|
||||||
if not extdir.endswith(os.path.sep):
|
|
||||||
extdir += os.path.sep
|
|
||||||
|
|
||||||
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug
|
|
||||||
cfg = "Debug" if debug else "Release"
|
|
||||||
|
|
||||||
cmake_args = [
|
|
||||||
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
|
|
||||||
f"-DPYTHON_EXECUTABLE={sys.executable}",
|
|
||||||
f"-DCMAKE_BUILD_TYPE={cfg}",
|
|
||||||
f"-DCMAKE_BUILD_WITH_INSTALL_RPATH=TRUE",
|
|
||||||
f"-DCMAKE_INSTALL_RPATH=$ORIGIN",
|
|
||||||
"-DUSE_CUDA=OFF",
|
|
||||||
"-G", "Unix Makefiles",
|
|
||||||
]
|
|
||||||
build_args = []
|
|
||||||
|
|
||||||
build_temp = os.path.join(self.build_temp, ext.name)
|
|
||||||
if not os.path.exists(build_temp):
|
|
||||||
os.makedirs(build_temp)
|
|
||||||
|
|
||||||
subprocess.check_call(["cmake", ext.sourcedir] + cmake_args, cwd=build_temp)
|
|
||||||
subprocess.check_call(["cmake", "--build", ".", "--target", "uLib_python"] + build_args, cwd=build_temp)
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="ulib",
|
|
||||||
version="0.6.0",
|
|
||||||
author="Andrea Rigoni Garola",
|
|
||||||
author_email="andrea.rigoni@pd.infn.it",
|
|
||||||
description="CMT Cosmic Muon Tomography project uLib python bindings",
|
|
||||||
ext_modules=[CMakeExtension("uLib_python")],
|
|
||||||
cmdclass={"build_ext": CMakeBuild},
|
|
||||||
zip_safe=False,
|
|
||||||
python_requires=">=3.6",
|
|
||||||
)
|
|
||||||
@@ -3,11 +3,11 @@ import os
|
|||||||
import unittest
|
import unittest
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import uLib_python
|
import uLib
|
||||||
|
|
||||||
class TestCoreOptions(unittest.TestCase):
|
class TestCoreOptions(unittest.TestCase):
|
||||||
def test_options(self):
|
def test_options(self):
|
||||||
opt = uLib_python.Core.Options("Test Options")
|
opt = uLib.Core.Options("Test Options")
|
||||||
|
|
||||||
# Test basic config file parsing
|
# Test basic config file parsing
|
||||||
with open("test_configuration.ini", "w") as f:
|
with open("test_configuration.ini", "w") as f:
|
||||||
@@ -18,12 +18,12 @@ class TestCoreOptions(unittest.TestCase):
|
|||||||
|
|
||||||
class TestCoreObject(unittest.TestCase):
|
class TestCoreObject(unittest.TestCase):
|
||||||
def test_object(self):
|
def test_object(self):
|
||||||
obj = uLib_python.Core.Object()
|
obj = uLib.Core.Object()
|
||||||
self.assertIsNotNone(obj)
|
self.assertIsNotN one(obj)
|
||||||
|
|
||||||
class TestCoreTimer(unittest.TestCase):
|
class TestCoreTimer(unittest.TestCase):
|
||||||
def test_timer(self):
|
def test_timer(self):
|
||||||
timer = uLib_python.Core.Timer()
|
timer = uLib.Core.Timer()
|
||||||
timer.Start()
|
timer.Start()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
val = timer.StopWatch()
|
val = timer.StopWatch()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
import unittest
|
import unittest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import uLib_python
|
import uLib
|
||||||
|
|
||||||
def vector4f0(v, target):
|
def vector4f0(v, target):
|
||||||
diff = np.array(v) - np.array(target)
|
diff = np.array(v) - np.array(target)
|
||||||
@@ -12,7 +12,7 @@ def vector4f0(v, target):
|
|||||||
|
|
||||||
class TestMathGeometry(unittest.TestCase):
|
class TestMathGeometry(unittest.TestCase):
|
||||||
def test_geometry(self):
|
def test_geometry(self):
|
||||||
Geo = uLib_python.Math.Geometry()
|
Geo = uLib.Math.Geometry()
|
||||||
|
|
||||||
Geo.SetPosition([1, 1, 1])
|
Geo.SetPosition([1, 1, 1])
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ class TestMathGeometry(unittest.TestCase):
|
|||||||
|
|
||||||
class TestMathContainerBox(unittest.TestCase):
|
class TestMathContainerBox(unittest.TestCase):
|
||||||
def test_container_box_local(self):
|
def test_container_box_local(self):
|
||||||
Cnt = uLib_python.Math.ContainerBox()
|
Cnt = uLib.Math.ContainerBox()
|
||||||
Cnt.SetOrigin([-1, -1, -1])
|
Cnt.SetOrigin([-1, -1, -1])
|
||||||
Cnt.SetSize([2, 2, 2])
|
Cnt.SetSize([2, 2, 2])
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ class TestMathContainerBox(unittest.TestCase):
|
|||||||
self.assertTrue(np.allclose(size, [2, 2, 2]))
|
self.assertTrue(np.allclose(size, [2, 2, 2]))
|
||||||
|
|
||||||
def test_container_box_global(self):
|
def test_container_box_global(self):
|
||||||
Box = uLib_python.Math.ContainerBox()
|
Box = uLib.Math.ContainerBox()
|
||||||
Box.SetPosition([1, 1, 1])
|
Box.SetPosition([1, 1, 1])
|
||||||
Box.SetSize([2, 2, 2])
|
Box.SetSize([2, 2, 2])
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ class TestMathContainerBox(unittest.TestCase):
|
|||||||
|
|
||||||
class TestMathStructuredGrid(unittest.TestCase):
|
class TestMathStructuredGrid(unittest.TestCase):
|
||||||
def test_structured_grid(self):
|
def test_structured_grid(self):
|
||||||
grid = uLib_python.Math.StructuredGrid([10, 10, 10])
|
grid = uLib.Math.StructuredGrid([10, 10, 10])
|
||||||
grid.SetSpacing([1, 1, 1])
|
grid.SetSpacing([1, 1, 1])
|
||||||
|
|
||||||
spacing = grid.GetSpacing()
|
spacing = grid.GetSpacing()
|
||||||
@@ -53,40 +53,40 @@ class TestMathStructuredGrid(unittest.TestCase):
|
|||||||
|
|
||||||
class TestMathAccumulator(unittest.TestCase):
|
class TestMathAccumulator(unittest.TestCase):
|
||||||
def test_accumulator_mean(self):
|
def test_accumulator_mean(self):
|
||||||
acc = uLib_python.Math.Accumulator_Mean_f()
|
acc = uLib.Math.Accumulator_Mean_f()
|
||||||
acc(10.0)
|
acc(10.0)
|
||||||
acc(20.0)
|
acc(20.0)
|
||||||
self.assertAlmostEqual(acc(), 15.0)
|
self.assertAlmostEqual(acc(), 15.0)
|
||||||
|
|
||||||
class TestMathNewTypes(unittest.TestCase):
|
class TestMathNewTypes(unittest.TestCase):
|
||||||
def test_eigen_vectors(self):
|
def test_eigen_vectors(self):
|
||||||
v1f = uLib_python.Math.Vector1f()
|
v1f = uLib.Math.Vector1f()
|
||||||
v3d = uLib_python.Math.Vector3d()
|
v3d = uLib.Math.Vector3d()
|
||||||
m4f = uLib_python.Math.Matrix4f()
|
m4f = uLib.Math.Matrix4f()
|
||||||
self.assertIsNotNone(v1f)
|
self.assertIsNotNone(v1f)
|
||||||
self.assertIsNotNone(v3d)
|
self.assertIsNotNone(v3d)
|
||||||
self.assertIsNotNone(m4f)
|
self.assertIsNotNone(m4f)
|
||||||
|
|
||||||
def test_ulib_vectors(self):
|
def test_ulib_vectors(self):
|
||||||
vi = uLib_python.Math.Vector_i()
|
vi = uLib.Math.Vector_i()
|
||||||
vi.append(1)
|
vi.append(1)
|
||||||
vi.append(2)
|
vi.append(2)
|
||||||
self.assertEqual(len(vi), 2)
|
self.assertEqual(len(vi), 2)
|
||||||
self.assertEqual(vi[0], 1)
|
self.assertEqual(vi[0], 1)
|
||||||
self.assertEqual(vi[1], 2)
|
self.assertEqual(vi[1], 2)
|
||||||
|
|
||||||
vf = uLib_python.Math.Vector_f()
|
vf = uLib.Math.Vector_f()
|
||||||
vf.append(1.5)
|
vf.append(1.5)
|
||||||
self.assertAlmostEqual(vf[0], 1.5)
|
self.assertAlmostEqual(vf[0], 1.5)
|
||||||
|
|
||||||
def test_homogeneous(self):
|
def test_homogeneous(self):
|
||||||
p = uLib_python.Math.HPoint3f(1.0, 2.0, 3.0)
|
p = uLib.Math.HPoint3f(1.0, 2.0, 3.0)
|
||||||
v = uLib_python.Math.HVector3f(0.0, 1.0, 0.0)
|
v = uLib.Math.HVector3f(0.0, 1.0, 0.0)
|
||||||
self.assertIsNotNone(p)
|
self.assertIsNotNone(p)
|
||||||
self.assertIsNotNone(v)
|
self.assertIsNotNone(v)
|
||||||
|
|
||||||
def test_vox_image(self):
|
def test_vox_image(self):
|
||||||
img = uLib_python.Math.VoxImage([2, 2, 2])
|
img = uLib.Math.VoxImage([2, 2, 2])
|
||||||
self.assertEqual(img.GetDims()[0], 2)
|
self.assertEqual(img.GetDims()[0], 2)
|
||||||
img.SetValue([0, 0, 0], 10.5)
|
img.SetValue([0, 0, 0], 10.5)
|
||||||
# Note: GetValue returns float, and there might be internal scaling (1.E-6 observed in code)
|
# Note: GetValue returns float, and there might be internal scaling (1.E-6 observed in code)
|
||||||
@@ -96,11 +96,11 @@ class TestMathNewTypes(unittest.TestCase):
|
|||||||
|
|
||||||
class TestMathVoxRaytracer(unittest.TestCase):
|
class TestMathVoxRaytracer(unittest.TestCase):
|
||||||
def test_raytracer(self):
|
def test_raytracer(self):
|
||||||
grid = uLib_python.Math.StructuredGrid([10, 10, 10])
|
grid = uLib.Math.StructuredGrid([10, 10, 10])
|
||||||
grid.SetSpacing([1, 1, 1])
|
grid.SetSpacing([1, 1, 1])
|
||||||
grid.SetOrigin([0, 0, 0])
|
grid.SetOrigin([0, 0, 0])
|
||||||
|
|
||||||
rt = uLib_python.Math.VoxRaytracer(grid)
|
rt = uLib.Math.VoxRaytracer(grid)
|
||||||
self.assertIsNotNone(rt)
|
self.assertIsNotNone(rt)
|
||||||
|
|
||||||
# Test TraceBetweenPoints
|
# Test TraceBetweenPoints
|
||||||
@@ -118,7 +118,7 @@ class TestMathVoxRaytracer(unittest.TestCase):
|
|||||||
self.assertGreater(elements[i].L, 0)
|
self.assertGreater(elements[i].L, 0)
|
||||||
|
|
||||||
def test_ray_data(self):
|
def test_ray_data(self):
|
||||||
data = uLib_python.Math.VoxRaytracerRayData()
|
data = uLib.Math.VoxRaytracerRayData()
|
||||||
data.SetCount(10)
|
data.SetCount(10)
|
||||||
data.SetTotalLength(5.5)
|
data.SetTotalLength(5.5)
|
||||||
self.assertEqual(data.Count(), 10)
|
self.assertEqual(data.Count(), 10)
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import uLib_python
|
import uLib
|
||||||
|
|
||||||
def test_core():
|
def test_core():
|
||||||
print("Testing Core module...")
|
print("Testing Core module...")
|
||||||
obj = uLib_python.Core.Object()
|
obj = uLib.Core.Object()
|
||||||
print("Core Object created:", obj)
|
print("Core Object created:", obj)
|
||||||
|
|
||||||
timer = uLib_python.Core.Timer()
|
timer = uLib.Core.Timer()
|
||||||
timer.Start()
|
timer.Start()
|
||||||
print("Core Timer started")
|
print("Core Timer started")
|
||||||
|
|
||||||
options = uLib_python.Core.Options("Test Options")
|
options = uLib.Core.Options("Test Options")
|
||||||
print("Core Options created:", options)
|
print("Core Options created:", options)
|
||||||
|
|
||||||
def test_math():
|
def test_math():
|
||||||
print("Testing Math module...")
|
print("Testing Math module...")
|
||||||
|
|
||||||
# Test AffineTransform
|
# Test AffineTransform
|
||||||
transform = uLib_python.Math.AffineTransform()
|
transform = uLib.Math.AffineTransform()
|
||||||
print("AffineTransform created")
|
print("AffineTransform created")
|
||||||
|
|
||||||
# Test Geometry
|
# Test Geometry
|
||||||
geom = uLib_python.Math.Geometry()
|
geom = uLib.Math.Geometry()
|
||||||
print("Geometry created")
|
print("Geometry created")
|
||||||
|
|
||||||
# Test StructuredData
|
# Test StructuredData
|
||||||
data = uLib_python.Math.StructuredData([10, 10, 10])
|
data = uLib.Math.StructuredData([10, 10, 10])
|
||||||
print("StructuredData created with dims:", data.GetDims())
|
print("StructuredData created with dims:", data.GetDims())
|
||||||
|
|
||||||
# Test Structured2DGrid
|
# Test Structured2DGrid
|
||||||
grid2d = uLib_python.Math.Structured2DGrid()
|
grid2d = uLib.Math.Structured2DGrid()
|
||||||
grid2d.SetDims([100, 100])
|
grid2d.SetDims([100, 100])
|
||||||
print("Structured2DGrid created with dims:", grid2d.GetDims())
|
print("Structured2DGrid created with dims:", grid2d.GetDims())
|
||||||
|
|
||||||
# Test TriangleMesh
|
# Test TriangleMesh
|
||||||
mesh = uLib_python.Math.TriangleMesh()
|
mesh = uLib.Math.TriangleMesh()
|
||||||
print("TriangleMesh created")
|
print("TriangleMesh created")
|
||||||
|
|
||||||
print("All tests passed successfully!")
|
print("All tests passed successfully!")
|
||||||
|
|||||||
7
src/Python/uLib/__init__.py
Normal file
7
src/Python/uLib/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
try:
|
||||||
|
from .uLib_python import Core, Math
|
||||||
|
except ImportError:
|
||||||
|
# Handle cases where the binary extension is not yet built
|
||||||
|
pass
|
||||||
|
|
||||||
|
__all__ = ["Core", "Math"]
|
||||||
Reference in New Issue
Block a user