Skip to content
Snippets Groups Projects
Commit fd24f2ab authored by Frederik Hennig's avatar Frederik Hennig
Browse files

Better error messages and documentation for venv setup

parent 14792966
Branches
No related merge requests found
Pipeline #77391 passed with stages
in 6 minutes and 13 seconds
......@@ -17,6 +17,7 @@ class VenvState:
venv_dir: str | None = None
main_requirements_file: str | None = None
initialized: bool = False
populated: bool = False
user_requirements: list[list[str]] = field(default_factory=list)
user_requirements_hash: str | None = None
......@@ -86,6 +87,7 @@ def action_initialize(args):
# Reset user requirements
state.user_requirements = []
state.populated = False
def action_require(args):
......@@ -93,7 +95,14 @@ def action_require(args):
with VenvState.lock(statefile) as state:
if not state.initialized:
raise RuntimeError("Virtual environment is not initialized.")
raise RuntimeError(
"venv-require action failed: virtual environment was not initialized"
)
if state.populated:
raise RuntimeError(
"venv-require action failed: cannot add requirements after venv-populate was run"
)
state.user_requirements.append(list(args.requirements))
......@@ -103,7 +112,11 @@ def action_populate(args):
with VenvState.lock(statefile) as state:
if not state.initialized:
raise RuntimeError("Virtual environment is not initialized.")
raise RuntimeError("venv-populate action failed: virtual environment was not initialized")
if state.populated:
raise RuntimeError("venv-populate action failed: venv-populate action called twice")
h = hashlib.sha256()
for req in state.user_requirements:
h.update(bytes(";".join(str(r) for r in req), encoding="utf8"))
......@@ -124,6 +137,13 @@ def action_populate(args):
subprocess.run(install_args).check_returncode()
state.user_requirements_hash = digest
state.populated = True
def fail(*args: str):
for arg in args:
print(arg, file=sys.stderr)
exit(-1)
def main():
......@@ -159,8 +179,13 @@ def main():
parser_populate = subparsers.add_parser("populate")
parser_populate.set_defaults(func=action_populate)
args = parser.parse_args()
args.func(args)
try:
args = parser.parse_args()
args.func(args)
except RuntimeError as e:
fail(*e.args)
except subprocess.CalledProcessError as e:
fail()
if __name__ == "__main__":
......
......@@ -57,10 +57,11 @@ if( WALBERLA_CODEGEN_PRIVATE_VENV )
init
${_init_args}
RESULT_VARIABLE _lastResult
ERROR_VARIABLE _lastError
)
if( ${_lastResult} )
message( FATAL_ERROR "Codegen virtual environment setup failed" )
message( FATAL_ERROR "Codegen virtual environment setup failed:\n${_lastError}" )
endif()
set(
......@@ -133,10 +134,11 @@ function(walberla_codegen_venv_require)
--
${ARGV}
RESULT_VARIABLE _lastResult
ERROR_VARIABLE _lastError
)
if( ${_lastResult} )
message( FATAL_ERROR "venv-require: Operation failed" )
message( FATAL_ERROR ${_lastError} )
endif()
endfunction()
......@@ -150,10 +152,11 @@ function(walberla_codegen_venv_populate)
$CACHE{_WALBERLA_CODEGEN_VENV_INVOKE_MANAGER}
populate
RESULT_VARIABLE _lastResult
ERROR_VARIABLE _lastError
)
if( ${_lastResult} )
message( FATAL_ERROR "venv-populate: Operation failed" )
message( FATAL_ERROR ${_lastError} )
endif()
endfunction()
......
......@@ -38,7 +38,7 @@ examples/ForceDrivenChannel/ForceDrivenChannel
:caption: Reference
:maxdepth: 1
Python Environment <reference/PythonEnvironment>
reference/PythonEnvironment
:::
......
# Managing the Code Generator's Python Environment
# Python Environment for Code Generation
On this page, you can find information on managing, customizing, and extending the Python environment
used by the waLBerla code generation system.
The waLBerla build system will set up a [virtual Python environment][venv] inside its
build tree, and use its Python interpreter to run code generation scripts.
On this page, you can find reference information on how this Python environment can be customized.
## Using the Private Virtual Environment
## Setting the Base Interpreter
By default, `sfg-walberla` creates a new Python virtual environment within the CMake build tree,
and there installs all packages required for code generation.
This can be disabled by setting the `WALBERLA_CODEGEN_PRIVATE_VENV` CMake cache variable to `FALSE`.
WaLBerla uses [FindPython][FindPython] to locate the base Python interpreter
which will be used to create the virtual environment.
Refer to its documentation for ways to affect the discovery process.
### Install Additional Packages
## Adding Additional Packages
For projects that require external dependencies, *sfg-walberla* exposes the CMake function
`walberla_codegen_venv_install`, which can be used to install additional packages into the
code generator virtual environment;
for instance, the following invocation installs `pyyaml`:
To install additional packages into the code generation environment,
first register them in your CMake file using the `walberla_codegen_venv_require` function.
This function can be invoked multiple times to add multiple requirements.
The arguments to `walberla_codegen_venv_require` will be directly forwarded to `pip install`,
so you can include any options `pip install` understands to affect the installation.
```CMake
walberla_codegen_venv_install( pyyaml )
```
Calls to `walberla_codegen_venv_require` will only collect the set of requirements.
To perform the installation, `walberla_codegen_venv_populate` must be called after all
requirements are declared.
:::{card} Example
The arguments passed to `walberla_codegen_venv_install` are forwarded directly to `pip install`.
You can therefore use any parameters that `pip` can interpret, for instance `-e` to perform an
editable install, or `-r <requirements-file>` to install packages from a requirements file.
```CMake
# First, list requirements
walberla_codegen_venv_require( pycowsay ) # Require a single package
walberla_codegen_venv_require( -r my-requirements.txt ) # Specify a requirements file
## Using an External Virtual Environment
# Then, populate the virtual environment
walberla_codegen_venv_populate()
```
If `WALBERLA_CODEGEN_PRIVATE_VENV` is set to `FALSE`, sfg-walberla will use the Python interpreter
found in the CMake environment for running the code generators.
You can customize your Python interpreter by setting the `Python_EXECUTABLE` or `Python_ROOT_DIR` hints.
:::
:::{seealso}
[FindPython CMake Module](https://cmake.org/cmake/help/latest/module/FindPython.html)
:::{error}
It is an error for your CMake system to call
`walberla_codegen_venv_require` after `walberla_codegen_venv_populate`,
or to call `walberla_codegen_venv_populate` more than once.
:::
Sfg-walberla will check if the required packages are installed into the given external Python environment,
and raise an error if any are missing.
[venv]: https://docs.python.org/3/library/venv.html
[FindPython]: https://cmake.org/cmake/help/latest/module/FindPython.html
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment