Skip to content

Commit

Permalink
First version of infrastructure for Python wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
gipert committed Dec 28, 2024
1 parent a535d00 commit 9f39f02
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 34 deletions.
74 changes: 69 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# CMake generated
/include/RMGConfig.hh
/python/remage/cpp_utils.py
/docs/Doxyfile
/docs/conf.py

/docs/_build
/docs/_doxygen
/docs/api
Expand All @@ -24,13 +27,74 @@ bookmarkFile

compile_commands.json

# junk
*.DS_Store
# editors
*~
*.swp
*.swo
.mypy_cache
__pycache__
*.dat

# python

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# setuptools_scm
python/*/_version.py

# ruff
.ruff_cache/

# OS specific stuff
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
16 changes: 15 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(
remage
VERSION 0.5.0
VERSION 0.5.0 # TODO: get this dynamically
DESCRIPTION "Simulation framework for HPGe-based experiments"
LANGUAGES C CXX) # C is needed for Geant4's HDF5 support

Expand Down Expand Up @@ -175,6 +175,20 @@ message(STATUS "CMAKE_CXX_STANDARD is c++" ${CMAKE_CXX_STANDARD})

add_subdirectory(src)

# let's now look for python, needed for the remage python wrapper and tests
find_package(Python3 REQUIRED COMPONENTS Interpreter)

execute_process(
COMMAND "${Python3_EXECUTABLE}" -m venv --help
RESULT_VARIABLE VENV_AVAILABLE
OUTPUT_QUIET ERROR_QUIET)

if(NOT VENV_AVAILABLE EQUAL 0)
message(FATAL_ERROR "Python3 is installed, but the 'venv' module is missing.")
endif()

add_subdirectory(python)

option(RMG_BUILD_DOCS "Build remage documentation" OFF)
if(RMG_BUILD_DOCS)
add_subdirectory(docs)
Expand Down
3 changes: 3 additions & 0 deletions cmake/cpp_utils.py.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from __future__ import annotations

REMAGE_CPP_EXE_PATH = "@REMAGE_CPP_EXE_PATH@"
11 changes: 6 additions & 5 deletions docs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ add_custom_command(
OUTPUT ${DOXYGEN_INDEX_FILE}
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
DEPENDS ${DOXYFILE_IN} ${REMAGE_PUBLIC_HEADERS}
MAIN_DEPENDENCY ${DOXYFILE_OUT}
COMMENT "Running Doxygen")
MAIN_DEPENDENCY ${DOXYFILE_OUT})

add_custom_target(
doxygen ALL
Expand Down Expand Up @@ -65,11 +64,13 @@ add_custom_command(
WORKING_DIRECTORY ${SPHINX_SOURCE}
DEPENDS ${SPHINX_SOURCES} ${SPHINX_IMAGES} ${DOXYGEN_INDEX_FILE}
MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in
COMMENT "Generating Sphinx docs")
${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in)

# Nice named target so we can run the job easily
add_custom_target(sphinx ALL DEPENDS ${SPHINX_INDEX_FILE})
add_custom_target(
sphinx ALL
DEPENDS ${SPHINX_INDEX_FILE}
COMMENT "Generating Sphinx docs")

# Add an install target to install the docs
include(GNUInstallDirs)
Expand Down
13 changes: 8 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"

[project]
name = "pyremage"
name = "remage"
authors = [
{ name = "Luigi Pertoldi", email = "[email protected]" },
]
Expand Down Expand Up @@ -45,6 +45,9 @@ dev = [
"pytest-cov >=3",
]

[project.scripts]
remage = "remage.cli:remage_cli"

[project.urls]
Homepage = "https://github.com/legend-exp/remage"
"Bug Tracker" = "https://github.com/legend-exp/remage/issues"
Expand All @@ -53,8 +56,10 @@ Changelog = "https://github.com/legend-exp/remage/releases"

[tool.hatch]
version.source = "vcs"
build.hooks.vcs.version-file = "python/_version.py"
metadata.path = "python/"
build.hooks.vcs.version-file = "python/remage/_version.py"

[tool.hatch.build.targets.wheel]
packages = ["python/remage"]

[tool.hatch.envs.default]
features = ["test"]
Expand Down Expand Up @@ -106,8 +111,6 @@ ignore = [
"ISC001", # Conflicts with formatter
]
isort.required-imports = ["from __future__ import annotations"]
# Uncomment if using a _compat.typing backport
# typing-modules = ["pyremage._compat.typing"]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["T20"]
Expand Down
63 changes: 63 additions & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# get the output name of the remage-cli target (set in src/CMakeLists.txt)
get_target_property(REMAGE_CPP_OUTPUT_NAME remage-cli-cpp OUTPUT_NAME)

# construct the full path to the built executable
set(REMAGE_CPP_EXE_PATH "${CMAKE_BINARY_DIR}/${REMAGE_CPP_OUTPUT_NAME}")

# configure cpp_utils.py.in with the dynamically derived path
configure_file("${PROJECT_SOURCE_DIR}/cmake/cpp_utils.py.in"
"${CMAKE_CURRENT_SOURCE_DIR}/remage/cpp_utils.py" @ONLY)

# create the virtual environment with python-venv
# also install the uv package manager
set(VENV_DIR "${CMAKE_BINARY_DIR}/python_venv")

add_custom_command(
OUTPUT "${VENV_DIR}/bin/activate"
COMMAND "${PYTHON_EXECUTABLE}" -m venv "${VENV_DIR}"
COMMAND "${VENV_DIR}/bin/python" -m pip install --upgrade pip
COMMAND "${VENV_DIR}/bin/python" -m pip install uv)

add_custom_target(
python-virtualenv
DEPENDS "${VENV_DIR}/bin/activate"
COMMENT "Configuring Python virtual environment in ${VENV_DIR}")

# install the remage wrapper package into the virtual environment with uv
add_custom_command(
OUTPUT "${VENV_DIR}/bin/remage"
COMMAND "${VENV_DIR}/bin/python" -m uv pip install "${CMAKE_SOURCE_DIR}"
DEPENDS python-virtualenv)

add_custom_target(
remage-cli ALL
DEPENDS "${VENV_DIR}/bin/remage"
COMMENT "Installing remage Python wrapper into the virtual environment")

# store the path to the remage executable, needed later in tests
set_target_properties(remage-cli PROPERTIES PYEXE_PATH "${VENV_DIR}/bin/remage")

# install section

# construct the full path to the installed executable
set(REMAGE_CPP_EXE_PATH
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${REMAGE_CPP_OUTPUT_NAME}")

configure_file("${PROJECT_SOURCE_DIR}/cmake/cpp_utils.py.in"
"${CMAKE_CURRENT_SOURCE_DIR}/remage/cpp_utils.py" @ONLY)

# install the package into the install prefix with the existing uv installation
add_custom_command(
OUTPUT "${CMAKE_INSTALL_PREFIX}/bin/remage"
COMMAND "${VENV_DIR}/bin/python" -m uv pip install --prefix "${CMAKE_INSTALL_PREFIX}"
"${CMAKE_SOURCE_DIR}")

add_custom_target(
install-remage-cli
DEPENDS "${CMAKE_INSTALL_PREFIX}/bin/remage"
COMMENT "Installing remage Python wrapper")

# hack the install process to also install the remage wrapper
install(
CODE "execute_process(COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target install-remage-cli)"
)
1 change: 1 addition & 0 deletions python/remage/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from __future__ import annotations
32 changes: 32 additions & 0 deletions python/remage/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

import argparse
import subprocess
import sys

from .cpp_utils import REMAGE_CPP_EXE_PATH

# NOTE: when uv/pip installs the package and creates the executable for the cli,
# it hardcodes the path to the current python executable (e.g. the one of the
# virtualenv) in the script's shebang


def remage_cli():
parser = argparse.ArgumentParser(
prog="remage", description="remage's command-line interface"
)

# global options
parser.add_argument(
"--version", action="store_true", help="""Print remage version and exit"""
)

args = parser.parse_args()

cmdline = [REMAGE_CPP_EXE_PATH]
if args.version:
cmdline += ["--version"]

result = subprocess.run(cmdline, check=False)

sys.exit(result.returncode)
8 changes: 4 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ set_property(
PROPERTY COMPATIBLE_INTERFACE_STRING remage_MAJOR_VERSION)

# executable for CLI
add_executable(remage-cli ${_root}/src/remage.cc)
target_link_libraries(remage-cli PUBLIC remage)
set_target_properties(remage-cli PROPERTIES OUTPUT_NAME remage)
add_executable(remage-cli-cpp ${_root}/src/remage.cc)
target_link_libraries(remage-cli-cpp PUBLIC remage)
set_target_properties(remage-cli-cpp PROPERTIES OUTPUT_NAME remage-cpp)

# executable for dumping all docs
add_executable(remage-doc-dump-cli EXCLUDE_FROM_ALL ${_root}/src/remage-doc-dump.cc)
Expand Down Expand Up @@ -192,7 +192,7 @@ install(
PATTERN "EcoMug" EXCLUDE)

# install CLI binaries
install(TARGETS remage-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS remage-cli-cpp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(RMG_HAS_HDF5)
install(TARGETS remage-to-lh5 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
3 changes: 2 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ project(remage-tests)

add_subdirectory(basics)
add_subdirectory(confinement)
add_subdirectory(output)
add_subdirectory(internals)
add_subdirectory(output)
add_subdirectory(python)
add_subdirectory(vertex)
8 changes: 4 additions & 4 deletions tests/basics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ set(_macros_extra run-2nbb.mac)
set(_macros_vis vis-co60.mac vis-2nbb.mac)

foreach(_mac ${_macros} ${_macros_extra} ${_macros_vis})
add_test(NAME basics/${_mac} COMMAND remage-cli -g gdml/main.gdml -- macros/${_mac})
add_test(NAME basics/${_mac} COMMAND remage-cli-cpp -g gdml/main.gdml -- macros/${_mac})
endforeach()

foreach(_mac ${_macros})
add_test(NAME basics-mt/${_mac} COMMAND remage-cli -g gdml/main.gdml -t 2 macros/${_mac})
add_test(NAME basics-mt/${_mac} COMMAND remage-cli-cpp -g gdml/main.gdml -t 2 macros/${_mac})
set_tests_properties(basics-mt/${_mac} PROPERTIES LABELS mt)
endforeach()

Expand All @@ -29,7 +29,7 @@ endif()

if(BxDecay0_THREADSAFE)
foreach(_mac ${_macros_extra})
add_test(NAME basics-mt/${_mac} COMMAND remage-cli -g gdml/main.gdml -t 2 macros/${_mac})
add_test(NAME basics-mt/${_mac} COMMAND remage-cli-cpp -g gdml/main.gdml -t 2 macros/${_mac})
set_tests_properties(basics-mt/${_mac} PROPERTIES LABELS "mt extra")
endforeach()

Expand All @@ -49,6 +49,6 @@ set_tests_properties(${_macros_vis} PROPERTIES SKIP_REGULAR_EXPRESSION "couldn't
# further specific tests.

# expect two overlaps from this prepared geometry.
add_test(NAME basics/overlaps.mac COMMAND remage-cli -- macros/overlaps.mac)
add_test(NAME basics/overlaps.mac COMMAND remage-cli-cpp -- macros/overlaps.mac)
set_tests_properties(basics/overlaps.mac PROPERTIES PASS_REGULAR_EXPRESSION
"GeomVol1002.*GeomVol1002")
8 changes: 4 additions & 4 deletions tests/confinement/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ set(_macros complex-volume.mac geometrical.mac native-surface.mac geometrical-an
geometrical-or-physical.mac native-volume.mac)

foreach(_mac ${_macros})
add_test(NAME confinement/${_mac} COMMAND remage-cli -g gdml/geometry.gdml -o test-out.root --
macros/${_mac})
add_test(NAME confinement/${_mac} COMMAND remage-cli-cpp -g gdml/geometry.gdml -o test-out.root
-- macros/${_mac})

add_test(NAME confinement-mt/${_mac} COMMAND remage-cli -g gdml/geometry.gdml -t 2 -o
add_test(NAME confinement-mt/${_mac} COMMAND remage-cli-cpp -g gdml/geometry.gdml -t 2 -o
test-out.root -- macros/${_mac})
set_tests_properties(confinement-mt/${_mac} PROPERTIES LABELS mt)

add_test(NAME confinement-vis/${_mac}
COMMAND remage-cli -g gdml/geometry.gdml -o test-out.root -- macros/_vis.mac
COMMAND remage-cli-cpp -g gdml/geometry.gdml -o test-out.root -- macros/_vis.mac
macros/${_mac} macros/_vis-export.mac)
set_tests_properties(confinement-vis/${_mac} PROPERTIES LABELS vis)
set_tests_properties(confinement-vis/${_mac} PROPERTIES SKIP_REGULAR_EXPRESSION
Expand Down
7 changes: 4 additions & 3 deletions tests/output/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ endforeach()
set(_macros ntuple-per-det.mac ntuple-per-det-vol.mac ntuple-flat.mac)

foreach(_mac ${_macros})
add_test(NAME output/hdf5-${_mac} COMMAND ./run-test-hdf5.sh $<TARGET_FILE:remage-cli>
add_test(NAME output/hdf5-${_mac} COMMAND ./run-test-hdf5.sh $<TARGET_FILE:remage-cli-cpp>
${_visit_hdf5} ${_remage_to_lh5} ${_mac})
add_test(NAME output/root-${_mac} COMMAND ./run-test-root.sh $<TARGET_FILE:remage-cli> ${_mac})
add_test(NAME output/root-${_mac} COMMAND ./run-test-root.sh $<TARGET_FILE:remage-cli-cpp>
${_mac})
endforeach()

list(TRANSFORM _macros PREPEND "output/hdf5-" OUTPUT_VARIABLE _macros_hdf5)
set_tests_properties(${_macros_hdf5} PROPERTIES LABELS extra DEPENDS output/build-test-visit-hdf5)

# SPECIAL TESTS
add_test(NAME output/th228-chain COMMAND ./run-test-th228-chain.py $<TARGET_FILE:remage-cli>)
add_test(NAME output/th228-chain COMMAND ./run-test-th228-chain.py $<TARGET_FILE:remage-cli-cpp>)

# Geant4 <= 11.0.3 is deleting non-empty HDF5 files after a successful run, so disable the tests.
if(Geant4_VERSION VERSION_LESS "11.0.4" OR NOT RMG_HAS_HDF5)
Expand Down
3 changes: 3 additions & 0 deletions tests/python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
get_target_property(REMAGE_PYEXE remage-cli PYEXE_PATH)

add_test(NAME python/cli COMMAND "${REMAGE_PYEXE}" --help)
Loading

0 comments on commit 9f39f02

Please sign in to comment.