Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
pybindings.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
18#include "shambase/print.hpp"
19#include "shambase/string.hpp"
21#include "shamcmdopt/tty.hpp"
22#include <pybind11/eval.h>
23#include <pybind11/iostream.h>
24#include <pybind11/pybind11.h>
25#include <string_view>
26#include <exception>
27#include <memory>
28#include <stdexcept>
29
30// Before we used to redirect std::cout to python stdout but this creates deadlocks
31// in adaptive cpp, hence the use of python printing functions
32
34void py_func_printer_normal(std::string_view s) {
35 using namespace pybind11;
36 py::print(s, "end"_a = "");
37}
38
40void py_func_printer_ln(std::string_view s) {
41 using namespace pybind11;
42 py::print(s);
43}
44
47
56std::unique_ptr<std::vector<fct_sig>> static_init_shamrock_pybind;
57
60 if (!bool(static_init_shamrock_pybind)) {
61 static_init_shamrock_pybind = std::make_unique<std::vector<fct_sig>>();
62 }
63
64 static_init_shamrock_pybind->push_back(std::move(fct));
65}
66
67void register_py_to_sham_print(py::module &m) {
68
69 struct wrapper_io {
70 int _fileno;
71 wrapper_io(int fileno) : _fileno(fileno) {}
72 void write(py::object &buffer) { shambase::print(buffer.cast<std::string>()); }
73 void flush() { shambase::flush(); }
74 bool isatty() { return shamcmdopt::is_a_tty(); }
75 int fileno() { return _fileno; }
76 };
77
78 py::class_<wrapper_io>(m, "wrapper_io")
79 .def(py::init<int>())
80 .def("write", &wrapper_io::write)
81 .def("flush", &wrapper_io::flush)
82 .def("isatty", &wrapper_io::isatty)
83 .def("fileno", &wrapper_io::fileno);
84
85 m.def("hook_stdout", [&]() {
86 try {
87 auto sys = py::module::import("sys");
88
89 py::exec(R"(
90 class PyStdWrapper:
91 def __init__(self, backend):
92 self.backend = backend
93 def write(self, text):
94 self.backend.write(text)
95 def flush(self):
96 self.backend.flush()
97 def isatty(self):
98 return self.backend.isatty()
99 def fileno(self):
100 return self.backend.fileno()
101 )");
102
103 py::object py_wrapper_class = py::globals()["PyStdWrapper"];
104
105 py::object backend_out = py::cast(wrapper_io(1));
106 py::object backend_err = py::cast(wrapper_io(2));
107 py::object stdout_wrapper = py_wrapper_class(backend_out);
108 py::object stderr_wrapper = py_wrapper_class(backend_err);
109
110 sys.attr("stdout") = stdout_wrapper;
111 sys.attr("stderr") = stderr_wrapper;
112
113 } catch (std::exception &e) {
115 }
116 });
117}
118
119namespace shambindings {
120
121 enum { None = 0, Lib = 1, Embed = 2 } init_state = None;
122
123 template<bool is_lib_mode>
124 void init(py::module &m) {
125
126 m.attr("__doc__") = R"doc(Python bindings for Shamrock)doc";
127
128 if (is_lib_mode) {
131 }
132
134 for (auto fct : *static_init_shamrock_pybind) {
135 fct(m);
136 }
137 }
138
139 if (is_lib_mode) {
140 init_state = Lib;
141 } else {
142 init_state = Embed;
143 }
144 }
145
146 void init_lib(py::module &m) { shambindings::init<true>(m); }
147
148 void init_embed(py::module &m, bool hook_stdout) {
149 shambindings::init<false>(m);
150 if (hook_stdout) {
151 register_py_to_sham_print(m);
152 m.attr("hook_stdout")();
153 }
154 }
155
157 if (init_state != Lib) {
159 shambase::format(
160 "python bindings not initialized as lib mode, current mode = {}",
161 i32(init_state)),
162 loc);
163 }
164 }
165
167 if (init_state != Embed) {
169 shambase::format(
170 "python bindings not initialized as embed mode, current mode = {}",
171 i32(init_state)),
172 loc);
173 }
174 }
175
176} // namespace shambindings
std::int32_t i32
32 bit integer
This header file contains utility functions related to exception handling in the code.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
void print(std::string_view sv)
Prints a string to the console.
Definition print.cpp:30
void flush()
Flushes the output buffer.
Definition print.cpp:44
void change_printer(void(*func_printer_normal)(std::string_view), void(*func_printer_ln)(std::string_view), void(*func_flush_func)())
Changes the behavior of the print, println and flush functions.
Definition print.cpp:52
bool is_a_tty()
Test if current terminal is a tty.
Definition tty.cpp:31
Pybind11 include and definitions.
std::function< void(py::module &)> fct_sig
alias to pybind11 namespace
std::unique_ptr< std::vector< fct_sig > > static_init_shamrock_pybind
Statically initialized python module init function list We use a unique pointer to ensure that the ve...
void py_func_printer_normal(std::string_view s)
With pybind we print using python out stream.
void py_func_flush_func()
Python print performs already a flush so we need nothing here.
void register_pybind_init_func(fct_sig fct)
Add a python module init function to the init list.
void py_func_printer_ln(std::string_view s)
With pybind we print using python out stream.
void expect_init_embed(SourceLocation loc=SourceLocation{})
Expect python bindings to be initialized as embed mode, throws if not.
void init_embed(py::module &m, bool hook_stdout=true)
Init python bindings and register them to Python API.
void expect_init_lib(SourceLocation loc=SourceLocation{})
Expect python bindings to be initialized as lib mode, throws if not.
void init_lib(py::module &m)
Init python bindings and register them to Python API.
provide information about the source location
This file contains tty info getters.