Skip to content

Commit 8da6fbe

Browse files
Add gaurds to redirect C++'s stdout/stderr streams to python's stdout/stderr streams (#68)
C++'s stdout/stderr and Python's stdout/stderr streams are two different streams.. normally this is not a problem but colab ignores C++'s streams. To make colab see C++'s streams they need to be redirected to Python's streams if the statement `py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>()` is added to a function's definition then its stdout/stderr gets redirected. I do that for the decoding methods for simplex and tesseract. so statements like with `verbose=True` will have their stdout redirected ```py3 >> tesseract_dec.decode(...) len(pq) = 0 num_pq_pushed = 1 num_detectors = 3 max_num_detectors = 65538 cost = 6.811496946171 activated_errors = activated_detectors = 19, 20, 25, activated_errors = 880, activated_detectors = Decoding complete. Cost: 6.811496946171 num_pq_pushed = 100 ``` I also added a context manager that can be used to do this from inside python ```py3 import tesseract_decoder with tesseract_decoder.ostream_redirect(stdout=..., stderr=...): # since the call happens inside the context manager its streams get captured a_function_whose_stdout_isnot_redirected() ```
1 parent f78ce8a commit 8da6fbe

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed

src/simplex.pybind.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef _SIMPLEX_PYBIND_H
1616
#define _SIMPLEX_PYBIND_H
1717

18+
#include <pybind11/iostream.h>
1819
#include <pybind11/operators.h>
1920
#include <pybind11/pybind11.h>
2021
#include <pybind11/stl.h>
@@ -63,7 +64,8 @@ void add_simplex_module(py::module& root) {
6364
.def_readwrite("end_time_to_errors", &SimplexDecoder::end_time_to_errors)
6465
.def_readonly("low_confidence_flag", &SimplexDecoder::low_confidence_flag)
6566
.def("init_ilp", &SimplexDecoder::init_ilp)
66-
.def("decode_to_errors", &SimplexDecoder::decode_to_errors, py::arg("detections"))
67+
.def("decode_to_errors", &SimplexDecoder::decode_to_errors, py::arg("detections"),
68+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>())
6769
.def(
6870
"get_observables_from_errors",
6971
[](SimplexDecoder& self, const std::vector<size_t>& predicted_errors) {
@@ -88,6 +90,7 @@ void add_simplex_module(py::module& root) {
8890
}
8991
return result;
9092
},
91-
py::arg("detections"));
93+
py::arg("detections"),
94+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>());
9295
}
9396
#endif

src/tesseract.pybind.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "tesseract.pybind.h"
1616

17+
#include <pybind11/iostream.h>
1718
#include <pybind11/pybind11.h>
1819

1920
#include "common.pybind.h"
@@ -23,8 +24,18 @@
2324

2425
PYBIND11_MODULE(tesseract_decoder, tesseract) {
2526
py::module::import("stim");
27+
2628
add_common_module(tesseract);
2729
add_utils_module(tesseract);
2830
add_simplex_module(tesseract);
2931
add_tesseract_module(tesseract);
32+
33+
// Adds a context manager to the python library that can be used to redirect C++'s stdout/stderr
34+
// to python's stdout/stderr at run time like
35+
// with tesseract_decoder.ostream_redirect(stdout=..., stderr=...):
36+
// do_work()
37+
// This is only needed if the C++ function's stdout/stderr is not redirected to python's
38+
// stdout/stderr using the py::call_guard<py::scoped_ostream_redirect,
39+
// py::scoped_estream_redirect>() statement.
40+
py::add_ostream_redirect(tesseract, "ostream_redirect");
3041
}

src/tesseract.pybind.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef _TESSERACT_PYBIND_H
1616
#define _TESSERACT_PYBIND_H
1717

18+
#include <pybind11/iostream.h>
1819
#include <pybind11/operators.h>
1920
#include <pybind11/pybind11.h>
2021
#include <pybind11/stl.h>
@@ -71,11 +72,13 @@ void add_tesseract_module(py::module& root) {
7172
.def(py::init<TesseractConfig>(), py::arg("config"))
7273
.def("decode_to_errors",
7374
py::overload_cast<const std::vector<uint64_t>&>(&TesseractDecoder::decode_to_errors),
74-
py::arg("detections"))
75+
py::arg("detections"),
76+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>())
7577
.def("decode_to_errors",
7678
py::overload_cast<const std::vector<uint64_t>&, size_t, size_t>(
7779
&TesseractDecoder::decode_to_errors),
78-
py::arg("detections"), py::arg("det_order"), py::arg("det_beam"))
80+
py::arg("detections"), py::arg("det_order"), py::arg("det_beam"),
81+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>())
7982
.def(
8083
"get_observables_from_errors",
8184
[](TesseractDecoder& self, const std::vector<size_t>& predicted_errors) {
@@ -100,7 +103,8 @@ void add_tesseract_module(py::module& root) {
100103
}
101104
return result;
102105
},
103-
py::arg("detections"))
106+
py::arg("detections"),
107+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>())
104108
.def_readwrite("low_confidence_flag", &TesseractDecoder::low_confidence_flag)
105109
.def_readwrite("predicted_errors_buffer", &TesseractDecoder::predicted_errors_buffer)
106110
.def_readwrite("errors", &TesseractDecoder::errors);

0 commit comments

Comments
 (0)