QCodeEditor: Update to current cpeditor/QCodeEditor fork, commit ed1196a
[smuview.git] / src / python / pystreamredirect.hpp
blobbea2d7ed4a49ff2b92599be1144e3eb343468624
1 /*
2 * This file is part of the SmuView project.
4 * Copyright (C) 2019-2021 Frank Stettner <frank-stettner@gmx.net>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef PYTHON_PYSTREAMREDIRECT_HPP
21 #define PYTHON_PYSTREAMREDIRECT_HPP
23 #include <iostream>
24 #include <memory>
25 #include <string>
27 #include <pybind11/pybind11.h>
29 #include <QObject>
31 #include "src/python/pystreambuf.hpp"
32 #include "src/python/smuscriptrunner.hpp"
34 using std::shared_ptr;
35 using std::string;
37 namespace py = pybind11;
39 namespace sv {
40 namespace python {
42 class __attribute__((visibility("hidden"))) PyStreamRedirect : public QObject
44 Q_OBJECT
46 public:
47 explicit PyStreamRedirect(shared_ptr<SmuScriptRunner> script_runner) :
48 script_runner_(script_runner)
50 auto sys_module = py::module::import("sys");
51 old_stdout_ = sys_module.attr("stdout");
52 old_stderr_ = sys_module.attr("stderr");
54 auto locale_module = py::module::import("locale");
55 auto default_encoding = locale_module.attr("getpreferredencoding")(false);
57 stdout_buf_ = new PyStreamBuf(
58 py::str(py::getattr(old_stdout_, "encoding", default_encoding)),
59 py::str(py::getattr(old_stdout_, "errors", py::str("strict"))));
60 auto py_stdout_buf = py::cast(
61 stdout_buf_, py::return_value_policy::reference);
62 connect(stdout_buf_, &PyStreamBuf::send_string,
63 script_runner_.get(), &SmuScriptRunner::send_py_stdout);
65 stderr_buf_ = new PyStreamBuf(
66 py::str(py::getattr(old_stderr_, "encoding", default_encoding)),
67 py::str(py::getattr(old_stderr_, "errors", py::str("backslashreplace"))));
68 auto py_stderr_buf = py::cast(
69 stderr_buf_, py::return_value_policy::reference);
70 connect(stderr_buf_, &PyStreamBuf::send_string,
71 script_runner_.get(), &SmuScriptRunner::send_py_stderr);
73 sys_module.attr("stdout") = py_stdout_buf;
74 sys_module.attr("stderr") = py_stderr_buf;
77 ~PyStreamRedirect()
79 try {
80 auto sys_module = py::module::import("sys");
81 sys_module.attr("stdout") = old_stdout_;
82 sys_module.attr("stderr") = old_stderr_;
84 catch (const py::error_already_set &) {}
86 stdout_buf_->py_close();
87 stderr_buf_->py_close();
89 disconnect(stdout_buf_, &PyStreamBuf::send_string,
90 script_runner_.get(), &SmuScriptRunner::send_py_stdout);
91 disconnect(stderr_buf_, &PyStreamBuf::send_string,
92 script_runner_.get(), &SmuScriptRunner::send_py_stderr);
95 private:
96 shared_ptr<SmuScriptRunner> script_runner_;
97 py::object old_stdout_;
98 py::object old_stderr_;
99 PyStreamBuf *stdout_buf_;
100 PyStreamBuf *stderr_buf_;
104 } // namespace python
105 } // namespace sv
107 #endif // PYTHON_PYSTREAMREDIRECT_HPP