File indexing completed on 2025-01-18 10:17:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <pybind11/iostream.h>
0011
0012 #include "pybind11_tests.h"
0013
0014 #include <atomic>
0015 #include <iostream>
0016 #include <mutex>
0017 #include <string>
0018 #include <thread>
0019
0020 void noisy_function(const std::string &msg, bool flush) {
0021
0022 std::cout << msg;
0023 if (flush) {
0024 std::cout << std::flush;
0025 }
0026 }
0027
0028 void noisy_funct_dual(const std::string &msg, const std::string &emsg) {
0029 std::cout << msg;
0030 std::cerr << emsg;
0031 }
0032
0033
0034
0035
0036 struct TestThread {
0037 TestThread() : stop_{false} {
0038 auto thread_f = [this] {
0039 static std::mutex cout_mutex;
0040 while (!stop_) {
0041 {
0042
0043
0044
0045
0046
0047
0048 const std::lock_guard<std::mutex> lock(cout_mutex);
0049 std::cout << "x" << std::flush;
0050 }
0051 std::this_thread::sleep_for(std::chrono::microseconds(50));
0052 }
0053 };
0054 t_ = new std::thread(std::move(thread_f));
0055 }
0056
0057 ~TestThread() { delete t_; }
0058
0059 void stop() { stop_ = true; }
0060
0061 void join() const {
0062 py::gil_scoped_release gil_lock;
0063 t_->join();
0064 }
0065
0066 void sleep() {
0067 py::gil_scoped_release gil_lock;
0068 std::this_thread::sleep_for(std::chrono::milliseconds(50));
0069 }
0070
0071 std::thread *t_{nullptr};
0072 std::atomic<bool> stop_;
0073 };
0074
0075 TEST_SUBMODULE(iostream, m) {
0076
0077 add_ostream_redirect(m);
0078
0079
0080
0081 m.def("captured_output_default", [](const std::string &msg) {
0082 py::scoped_ostream_redirect redir;
0083 std::cout << msg << std::flush;
0084 });
0085
0086 m.def("captured_output", [](const std::string &msg) {
0087 py::scoped_ostream_redirect redir(std::cout, py::module_::import("sys").attr("stdout"));
0088 std::cout << msg << std::flush;
0089 });
0090
0091 m.def("guard_output",
0092 &noisy_function,
0093 py::call_guard<py::scoped_ostream_redirect>(),
0094 py::arg("msg"),
0095 py::arg("flush") = true);
0096
0097 m.def("captured_err", [](const std::string &msg) {
0098 py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));
0099 std::cerr << msg << std::flush;
0100 });
0101
0102 m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true);
0103
0104 m.def("dual_guard",
0105 &noisy_funct_dual,
0106 py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(),
0107 py::arg("msg"),
0108 py::arg("emsg"));
0109
0110 m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; });
0111
0112 m.def("raw_err", [](const std::string &msg) { std::cerr << msg << std::flush; });
0113
0114 m.def("captured_dual", [](const std::string &msg, const std::string &emsg) {
0115 py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout"));
0116 py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr"));
0117 std::cout << msg << std::flush;
0118 std::cerr << emsg << std::flush;
0119 });
0120
0121 py::class_<TestThread>(m, "TestThread")
0122 .def(py::init<>())
0123 .def("stop", &TestThread::stop)
0124 .def("join", &TestThread::join)
0125 .def("sleep", &TestThread::sleep);
0126 }