6#include <pybind11/embed.h>
23 DBUG(
"Binding Python module OpenGeoSys.");
38 constexpr bool init_signal_handlers =
false;
39 return pybind11::scoped_interpreter{init_signal_handlers};
57 std::array<char, 256> buffer;
61 std::unique_ptr<FILE, PipeCloser> pipe(_popen(command.data(),
"r"));
63 std::unique_ptr<FILE, PipeCloser> pipe(popen(command.data(),
"r"));
68 DBUG(
"Failed to execute command: {}", command);
72 while (fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr)
74 result += buffer.data();
82 std::filesystem::path
const& venv_path)
84 namespace fs = std::filesystem;
88 python_exe = venv_path /
"Scripts" /
"python.exe";
90 python_exe = venv_path /
"bin" /
"python";
93 if (!fs::exists(python_exe))
95 DBUG(
"Python executable not found at: {}", python_exe.string());
99 std::string
const command =
"\"" + python_exe.string() +
"\" --version";
102 if (!output.has_value())
104 DBUG(
"Failed to get Python version from: {}", python_exe.string());
109 std::string_view
const out_view(output.value());
110 constexpr std::string_view prefix =
"Python ";
111 std::string_view version_part = out_view.substr(prefix.size());
112 int major = 0, minor = 0;
114 auto dot = version_part.find(
'.');
115 if (dot == std::string_view::npos)
117 DBUG(
"Failed to parse Python version from: {}", out_view);
121 auto parse = [](std::string_view sv,
int& value)
124 std::from_chars(sv.data(), sv.data() + sv.size(), value);
125 return ec == std::errc{} && ptr != sv.data();
128 if (!parse(version_part.substr(0, dot), major) ||
129 !parse(version_part.substr(dot + 1), minor))
131 DBUG(
"Failed to parse Python version from: {}", out_view);
135 DBUG(
"Detected Python version {}.{} from venv", major, minor);
136 return std::make_pair(major, minor);
141 std::filesystem::path
const& venv_path)
143 namespace fs = std::filesystem;
147 fs::path
const site_packages = venv_path /
"Lib" /
"site-packages";
151 if (!version.has_value())
154 "Failed to determine Python version of the virtual environment.");
156 fs::path
const site_packages = venv_path /
"lib" /
157 (
"python" + std::to_string(version->first) +
158 "." + std::to_string(version->second)) /
162 if (!fs::exists(site_packages))
164 OGS_FATAL(
"site-packages directory not found at '{}'",
165 site_packages.string());
168 return site_packages;
174 namespace py = pybind11;
175 namespace fs = std::filesystem;
178 py::object
const version_info =
179 py::module_::import(
"sys").attr(
"version_info");
180 int const emb_major = version_info.attr(
"major").cast<
int>();
181 int const emb_minor = version_info.attr(
"minor").cast<
int>();
184 char const*
const venv = std::getenv(
"VIRTUAL_ENV");
187 DBUG(
"No virtual environment detected (VIRTUAL_ENV not set).");
191 fs::path
const venv_path(venv);
192 DBUG(
"Virtual environment detected at: {}", venv_path.string());
194 auto const venv_version = getPythonVersionFromVenv(venv_path);
195 if (!venv_version.has_value())
198 "Failed to determine Python version from virtual environment at "
200 "Please ensure the virtual environment is valid.",
204 int const venv_major = venv_version->first;
205 int const venv_minor = venv_version->second;
208 if (venv_major != emb_major || venv_minor != emb_minor)
211 "Python version mismatch:\n"
212 " Embedded interpreter: {}.{}\n"
213 " Virtual environment: {}.{}\n"
214 "The virtual environment must use the same Python version as the "
215 "embedded interpreter.",
216 emb_major, emb_minor, venv_major, venv_minor);
220 fs::path
const site_packages = findSitePackagesPath(venv_path);
221 INFO(
"Using virtual environment site-packages: {}", site_packages.string());
224 py::list sys_path = py::module_::import(
"sys").attr(
"path");
225 sys_path.insert(0, py::str(site_packages.string()));
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
std::optional< std::string > executeCommand(std::string_view command)
Executes a command and captures its stdout output using popen.
std::optional< std::pair< int, int > > getPythonVersionFromVenv(std::filesystem::path const &venv_path)
Gets Python version by executing the venv's python executable.
std::filesystem::path findSitePackagesPath(std::filesystem::path const &venv_path)
Finds site-packages path in the virtual environment.
void setupEmbeddedPythonVenvPaths()
pybind11::scoped_interpreter setupEmbeddedPython()
void pythonBindSourceTerm(pybind11::module &m)
Creates Python bindings for the Python source term class.
void pythonBindBoundaryCondition(pybind11::module &m)
Creates Python bindings for the Python BC class.
void bheInflowpythonBindBoundaryCondition(pybind11::module &m)
Creates BHE Inflow Python bindings for the Python BC class.
PYBIND11_EMBEDDED_MODULE(OpenGeoSys, m)
Custom deleter for FILE handles from popen.
void operator()(FILE *f) const