OGS
ApplicationsLib Namespace Reference

Namespaces

namespace  anonymous_namespace{ogs_embedded_python.cpp}
namespace  detail

Classes

struct  LinearSolverLibrarySetup
class  TestDefinition

Functions

pybind11::scoped_interpreter setupEmbeddedPython ()
void setupEmbeddedPythonVenvPaths ()

Function Documentation

◆ setupEmbeddedPython()

OGS_EXPORT_SYMBOL pybind11::scoped_interpreter ApplicationsLib::setupEmbeddedPython ( )

Sets up an embedded Python interpreter and makes sure that the OpenGeoSys Python module is not removed by the linker.

Definition at line 35 of file ogs_embedded_python.cpp.

36{
37 // Allows ogs to be interrupted by SIGINT, which otherwise is handled by
38 // python. See
39 // https://docs.python.org/3/c-api/exceptions.html#c.PyErr_CheckSignals and
40 // https://pybind11.readthedocs.io/en/stable/faq.html#how-can-i-properly-handle-ctrl-c-in-long-running-functions
41 constexpr bool init_signal_handlers = false;
42 return pybind11::scoped_interpreter{init_signal_handlers};
43}

Referenced by main().

◆ setupEmbeddedPythonVenvPaths()

OGS_EXPORT_SYMBOL void ApplicationsLib::setupEmbeddedPythonVenvPaths ( )

Checks for activated and matching virtual environment and adds it to sys.path.

Definition at line 236 of file ogs_embedded_python.cpp.

237{
238 namespace py = pybind11;
239 namespace fs = std::filesystem;
240
241 // Get embedded Python version
242 py::object const version_info =
243 py::module_::import("sys").attr("version_info");
244 int const emb_major = version_info.attr("major").cast<int>();
245 int const emb_minor = version_info.attr("minor").cast<int>();
246
247 // Check for virtual environment
248 char const* const venv = std::getenv("VIRTUAL_ENV");
249 if (venv == nullptr)
250 {
251 DBUG("No virtual environment detected (VIRTUAL_ENV not set).");
252 return;
253 }
254
255 fs::path const venv_path(venv);
256 DBUG("Virtual environment detected at: {}", venv_path.string());
257
258 // Find and validate site-packages path for the embedded interpreter
259 // version.
260 fs::path const site_packages =
261 findSitePackagesPath(venv_path, emb_major, emb_minor);
262 INFO("Using virtual environment site-packages: {}", site_packages.string());
263
264 // Add to sys.path via site.addsitedir() and not via a plain
265 // sys.path.insert(): only the former processes the .pth files of the
266 // directory. Ephemeral virtual environments created by `uv run --with ...`
267 // contain no packages at all, but merely a .pth file chaining to the
268 // directories the packages really live in. Without .pth processing not a
269 // single package of such an environment would be importable.
270 auto const sys = py::module_::import("sys");
271 py::list const sys_path = sys.attr("path");
272 std::size_t const num_paths_before = py::len(sys_path);
273
274 py::module_::import("site").attr("addsitedir")(
275 py::str(site_packages.string()));
276
277 // addsitedir() appends, but the virtual environment's packages shall take
278 // precedence over those of the embedded interpreter. Hence move the newly
279 // added paths to the front, keeping their relative order.
280 std::size_t const num_paths_after = py::len(sys_path);
281 py::list reordered_path;
282 for (std::size_t i = num_paths_before; i < num_paths_after; ++i)
283 {
284 reordered_path.append(sys_path[i]);
285 }
286 for (std::size_t i = 0; i < num_paths_before; ++i)
287 {
288 reordered_path.append(sys_path[i]);
289 }
290 sys.attr("path") = reordered_path;
291}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22

References DBUG(), and INFO().

Referenced by main().