-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Infrastructure for Python wrapper (#210)
* First version of infrastructure for Python wrapper * Bug fix and suppress pip/uv/doxygen/sphinx outputs * just sys.argv instead of argparse * use the python wrapper in tests * Update documentation
- Loading branch information
Showing
18 changed files
with
268 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,33 @@ your GitHub username): | |
$ git clone [email protected]:yourusername/remage.git | ||
``` | ||
|
||
## That `remage` executable... | ||
|
||
To enhance _remage_'s capabilities without requiring complex C++ code, we | ||
implemented a Python wrapper. This wrapper handles input preprocessing, invokes | ||
the `remage-cpp` executable, and performs output postprocessing. While this | ||
approach slightly complicates the build system, it significantly reduces the | ||
amount of code to write and maintain. | ||
|
||
The C++ code resides in the `src` directory, with the `remage-cpp` executable | ||
built from `src/remage.cc`. The Python code is organized as a package under the | ||
`python` directory, where the `cli.py` module provides the _remage_ command-line | ||
interface. | ||
|
||
At build time, CMake compiles `remage-cpp` and installs the Python package in | ||
the build area. The Python package and its dependencies (see `pyproject.toml`) | ||
are installed into a virtual environment, ensuring an isolated environment with | ||
all required dependencies. The Python wrapper is configured to use the | ||
`remage-cpp` executable from the build area. | ||
|
||
This setup is replicated during installation, targeting the install prefix. A | ||
key advantage of this approach is enabling the use of the _remage_ executable in | ||
unit tests, which run on _remage_ from the build area. | ||
|
||
Information about the C++ part of _remage_ is forwarded to the Python wrapper | ||
via the `cmake/cpp_config.py.in` file, which is configured by CMake at build | ||
time and moved into the package source folder. | ||
|
||
## Installing dependencies | ||
|
||
```{include} _dependencies.md | ||
|
@@ -35,6 +62,10 @@ $ cmake -DCMAKE_INSTALL_PREFIX=<optional prefix> .. | |
$ make install | ||
``` | ||
|
||
```{tip} | ||
A list of available Make targets can be printed by running `make help`. | ||
``` | ||
|
||
## Code style | ||
|
||
A set of [pre-commit](https://pre-commit.com) hooks is configured to make sure | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ requires = ["hatchling", "hatch-vcs"] | |
build-backend = "hatchling.build" | ||
|
||
[project] | ||
name = "pyremage" | ||
name = "remage" | ||
authors = [ | ||
{ name = "Luigi Pertoldi", email = "[email protected]" }, | ||
] | ||
|
@@ -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" | ||
|
@@ -53,8 +56,13 @@ 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.build.targets.wheel.force-include] | ||
"python/remage/cpp_config.py" = "remage/cpp_config.py" | ||
|
||
[tool.hatch.envs.default] | ||
features = ["test"] | ||
|
@@ -106,8 +114,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"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# List here manually all source files. Using GLOB is bad, see: | ||
# https://cmake.org/cmake/help/latest/command/file.html?highlight=Note#filesystem | ||
|
||
set(_r ${PROJECT_SOURCE_DIR}) | ||
|
||
set(PYTHON_SOURCES ${_r}/cmake/cpp_config.py.in ${_r}/python/remage/__init__.py | ||
${_r}/python/remage/cli.py ${_r}/pyproject.toml) | ||
|
||
# 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) | ||
|
||
# 1) construct the full path to the built executable | ||
set(REMAGE_CPP_EXE_PATH ${CMAKE_BINARY_DIR}/src/${REMAGE_CPP_OUTPUT_NAME}) | ||
|
||
# configure cpp_config.py.in for the build area with the dynamically derived path | ||
configure_file( | ||
${PROJECT_SOURCE_DIR}/cmake/cpp_config.py.in | ||
${CMAKE_CURRENT_BINARY_DIR}/cpp_config.build.py # temporary location | ||
@ONLY) | ||
|
||
# 2) construct the full path to the installed executable | ||
set(REMAGE_CPP_EXE_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${REMAGE_CPP_OUTPUT_NAME}) | ||
|
||
# configure cpp_config.py.in for the install area | ||
configure_file( | ||
${PROJECT_SOURCE_DIR}/cmake/cpp_config.py.in | ||
${CMAKE_CURRENT_BINARY_DIR}/cpp_config.install.py # temporary location | ||
@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/uv | ||
COMMAND ${Python3_EXECUTABLE} -m venv ${VENV_DIR} | ||
COMMAND ${VENV_DIR}/bin/python -m pip -q install --no-warn-script-location --upgrade pip | ||
COMMAND ${VENV_DIR}/bin/python -m pip -q install --no-warn-script-location uv | ||
COMMENT "Configuring Python virtual environment") | ||
|
||
add_custom_target(python-virtualenv DEPENDS ${VENV_DIR}/bin/uv) | ||
|
||
# install the remage wrapper package into the virtual environment with uv (build area) | ||
# 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 | ||
add_custom_command( | ||
OUTPUT ${VENV_DIR}/bin/remage | ||
COMMAND | ||
cp | ||
${CMAKE_CURRENT_BINARY_DIR}/cpp_config.build.py # now we want to use the cpp_config for the build area | ||
${CMAKE_CURRENT_SOURCE_DIR}/remage/cpp_config.py | ||
COMMAND ${VENV_DIR}/bin/python -m uv -q pip install --reinstall ${CMAKE_SOURCE_DIR} | ||
DEPENDS python-virtualenv ${PYTHON_SOURCES} | ||
COMMENT "Installing remage Python wrapper into the virtual environment") | ||
|
||
add_custom_target(remage-cli ALL DEPENDS ${VENV_DIR}/bin/remage) | ||
|
||
# store the path to the remage executable, needed later in tests (that must work in the build area) | ||
set_target_properties(remage-cli PROPERTIES PYEXE_PATH ${VENV_DIR}/bin/remage) | ||
|
||
# install section | ||
|
||
# install the package into the install prefix with the existing uv installation | ||
add_custom_command( | ||
OUTPUT ${CMAKE_INSTALL_PREFIX}/bin/remage | ||
COMMAND | ||
cp | ||
${CMAKE_CURRENT_BINARY_DIR}/cpp_config.install.py # now we want to use the cpp_config for the install area | ||
${CMAKE_CURRENT_SOURCE_DIR}/remage/cpp_config.py | ||
COMMAND ${VENV_DIR}/bin/python -m uv -q pip install --reinstall --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)" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from __future__ import annotations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from __future__ import annotations | ||
|
||
import subprocess | ||
import sys | ||
|
||
from .cpp_config import REMAGE_CPP_EXE_PATH | ||
|
||
|
||
def remage_cli(): | ||
result = subprocess.run([REMAGE_CPP_EXE_PATH] + sys.argv[1:], check=False) | ||
sys.exit(result.returncode) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from __future__ import annotations | ||
|
||
REMAGE_CPP_EXE_PATH = "/home/gipert/sw/src/legend/remage/build/src/remage-cpp" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.