Skip to content

Commit 886751d

Browse files
committed
Add section to reference docs and minor style changes
Also added `module_local` to `add_ostream_redirect`.
1 parent f748ed7 commit 886751d

File tree

4 files changed

+57
-59
lines changed

4 files changed

+57
-59
lines changed

docs/advanced/pycpp/utilities.rst

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@ expected in Python:
2626
Capturing standard output from ostream
2727
======================================
2828

29-
Often, a library will use the streams :cpp:var:`std::cout` and
30-
:cpp:var:`std::cerr` to print, but this does not play well with Python's
31-
standard :py:obj:`sys.stdout` and :py:obj:`sys.stderr` redirection. Replacing a
32-
library's printing with :cpp:func:`py::print` may not be feasible. This can be
33-
fixed using a guard around the library function that redirects output to the
34-
corresponding python streams:
29+
Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print,
30+
but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr``
31+
redirection. Replacing a library's printing with `py::print <print>` may not
32+
be feasible. This can be fixed using a guard around the library function that
33+
redirects output to the corresponding Python streams:
3534

3635
.. code-block:: cpp
3736
38-
// At beginning of file
3937
#include <pybind11/iostream.h>
4038
4139
...
@@ -49,13 +47,13 @@ corresponding python streams:
4947
call_noisy_func();
5048
});
5149
52-
This method respects flushes on the output streams, and will flush if needed
50+
This method respects flushes on the output streams and will flush if needed
5351
when the scoped guard is destroyed. This allows the output to be redirected in
5452
real time, such as to a Jupyter notebook. The two arguments, the C++ stream and
5553
the Python output, are optional, and default to standard output if not given. An
56-
extra type, `py::scoped_estream_redirect`, is identical execpt for
57-
defaulting to the error stream; this can be useful with `py::call_guard`, which
58-
allows multiple items, but uses the default constuctor:
54+
extra type, `py::scoped_estream_redirect <scoped_estream_redirect>`, is identical
55+
except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with
56+
`py::call_guard`, which allows multiple items, but uses the default constructor:
5957

6058
.. code-block:: py
6159
@@ -64,8 +62,8 @@ allows multiple items, but uses the default constuctor:
6462
py::call_guard<py::scoped_ostream_redirect,
6563
py::scoped_estream_redirect>());
6664
67-
The redirection can also be done in python with the addition of a context
68-
manager, using the `py::add_ostream_redirect()` function:
65+
The redirection can also be done in Python with the addition of a context
66+
manager, using the `py::add_ostream_redirect() <add_ostream_redirect>` function:
6967

7068
.. code-block:: cpp
7169
@@ -79,14 +77,14 @@ creates the following context manager in Python:
7977
with ostream_redirect(stdout=True, stderr=True):
8078
noisy_function()
8179
82-
The added context manager defaults to redirecting both streams, though you can
83-
use the keyword arguments to disable one of the streams if needed.
80+
It defaults to redirecting both streams, though you can use the keyword
81+
arguments to disable one of the streams if needed.
8482

85-
.. note:
83+
.. note::
8684

87-
The above methods will not redirect direct output to file descriptors, such
85+
The above methods will not redirect C-level output to file descriptors, such
8886
as ``fprintf``. For those cases, you'll need to redirect the file
89-
descriptors either directly in C or with Python's :py:obj:`os.dup2` function
87+
descriptors either directly in C or with Python's ``os.dup2`` function
9088
in an operating-system dependent way.
9189

9290
.. _eval:

docs/changelog.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ v2.2.0 (Not yet released)
123123
7. Fixed lifetime of temporary C++ objects created in Python-to-C++ conversions.
124124
`#924 <https://github.com/pybind/pybind11/pull/924>`_.
125125

126-
* Scope guard call policy for RAII types, e.g. ``py::call_guard<py::gil_scoped_release>()``.
127-
See :ref:`call_policies` for details.
126+
* Scope guard call policy for RAII types, e.g. ``py::call_guard<py::gil_scoped_release>()``,
127+
``py::call_guard<py::scoped_ostream_redirect>()``. See :ref:`call_policies` for details.
128128
`#740 <https://github.com/pybind/pybind11/pull/740>`_.
129129

130-
* Utility for redirecting C++ streams like `std::cout`,
131-
`py::scoped_ostream_redirect`, RAII in C++;
132-
and a context manager in python. See :ref:`ostream_redirect` or
133-
`#1005 <https://github.com/pybind/pybind11/pull/1009>`_.
130+
* Utility for redirecting C++ streams to Python (e.g. ``std::cout`` ->
131+
``sys.stdout``). Scope guard ``py::scoped_ostream_redirect`` in C++ and
132+
a context manager in Python. See :ref:`ostream_redirect`.
133+
`#1009 <https://github.com/pybind/pybind11/pull/1009>`_.
134134

135135
* Improved handling of types and exceptions across module boundaries.
136136
`#915 <https://github.com/pybind/pybind11/pull/915>`_,

docs/reference.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ Embedding the interpreter
7171

7272
.. doxygenclass:: scoped_interpreter
7373

74+
Redirecting C++ streams
75+
=======================
76+
77+
.. doxygenclass:: scoped_ostream_redirect
78+
79+
.. doxygenclass:: scoped_estream_redirect
80+
81+
.. doxygenfunction:: add_ostream_redirect
82+
7483
Python build-in functions
7584
=========================
7685

include/pybind11/iostream.h

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
#pragma once
2-
31
/*
4-
pybind11/iostream -- Tools to assist with redirecting cout and cerr to Python
2+
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
53
64
Copyright (c) 2017 Henry F. Schreiner
75
86
All rights reserved. Use of this source code is governed by a
97
BSD-style license that can be found in the LICENSE file.
108
*/
119

10+
#pragma once
11+
1212
#include "pybind11.h"
1313

1414
#include <streambuf>
@@ -24,8 +24,8 @@ NAMESPACE_BEGIN(detail)
2424
class pythonbuf : public std::streambuf {
2525
private:
2626
using traits_type = std::streambuf::traits_type;
27-
char d_buffer[1024];
2827

28+
char d_buffer[1024];
2929
object pywrite;
3030
object pyflush;
3131

@@ -49,12 +49,14 @@ class pythonbuf : public std::streambuf {
4949
}
5050
return 0;
5151
}
52+
5253
public:
5354
pythonbuf(object pyostream)
5455
: pywrite(pyostream.attr("write")),
5556
pyflush(pyostream.attr("flush")) {
5657
setp(d_buffer, d_buffer + sizeof(d_buffer) - 1);
5758
}
59+
5860
/// Sync before destroy
5961
~pythonbuf() {
6062
sync();
@@ -65,37 +67,38 @@ NAMESPACE_END(detail)
6567

6668

6769
/** \rst
68-
Scoped ostream output redirect
6970
This a move-only guard that redirects output.
7071
7172
.. code-block:: cpp
7273
7374
#include <pybind11/iostream.h>
7475
75-
int main() {
76+
...
77+
78+
{
7679
py::scoped_ostream_redirect output;
7780
std::cout << "Hello, World!"; // Python stdout
7881
} // <-- return std::cout to normal
7982
80-
You can explicitly pass the c++ stream and the python object, for example to gaurd stderr instead.
83+
You can explicitly pass the c++ stream and the python object,
84+
for example to guard stderr instead.
8185
8286
.. code-block:: cpp
83-
int main() {
87+
88+
{
8489
py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
8590
std::cerr << "Hello, World!";
8691
}
8792
\endrst */
88-
8993
class scoped_ostream_redirect {
9094
protected:
91-
std::streambuf * old;
92-
std::ostream& costream;
95+
std::streambuf *old;
96+
std::ostream &costream;
9397
detail::pythonbuf buffer;
9498

9599
public:
96-
97100
scoped_ostream_redirect(
98-
std::ostream& costream = std::cout,
101+
std::ostream &costream = std::cout,
99102
object pyostream = module::import("sys").attr("stdout"))
100103
: costream(costream), buffer(pyostream) {
101104
old = costream.rdbuf(&buffer);
@@ -113,11 +116,10 @@ class scoped_ostream_redirect {
113116

114117

115118
/** \rst
116-
Scoped ostream output redirect with cerr defaults
117-
118-
This class is provided primary to make call_guards easier to make.
119+
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
120+
is provided primary to make ``py::call_guard`` easier to make.
119121
120-
.. code_block:: cpp
122+
.. code-block:: cpp
121123
122124
m.def("noisy_func", &noisy_func,
123125
py::call_guard<scoped_ostream_redirect,
@@ -127,14 +129,9 @@ class scoped_ostream_redirect {
127129
class scoped_estream_redirect : public scoped_ostream_redirect {
128130
public:
129131
scoped_estream_redirect(
130-
std::ostream& costream = std::cerr,
132+
std::ostream &costream = std::cerr,
131133
object pyostream = module::import("sys").attr("stderr"))
132134
: scoped_ostream_redirect(costream,pyostream) {}
133-
134-
scoped_estream_redirect(const scoped_estream_redirect &) = delete;
135-
scoped_estream_redirect(scoped_estream_redirect &&other) = default;
136-
scoped_estream_redirect &operator=(const scoped_estream_redirect &) = delete;
137-
scoped_estream_redirect &operator=(scoped_estream_redirect &&) = delete;
138135
};
139136

140137

@@ -148,7 +145,6 @@ class OstreamRedirect {
148145
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
149146

150147
public:
151-
152148
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
153149
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
154150

@@ -168,8 +164,8 @@ class OstreamRedirect {
168164
NAMESPACE_END(detail)
169165

170166
/** \rst
171-
This is a helper function to add a C++ redirect context manager to Python instead of using a C++ guard.
172-
To use it, add the following to your binding code:
167+
This is a helper function to add a C++ redirect context manager to Python
168+
instead of using a C++ guard. To use it, add the following to your binding code:
173169
174170
.. code-block:: cpp
175171
@@ -179,7 +175,7 @@ NAMESPACE_END(detail)
179175
180176
py::add_ostream_redirect(m, "ostream_redirect");
181177
182-
You now have a python context manager that redirects your output:
178+
You now have a Python context manager that redirects your output:
183179
184180
.. code-block:: python
185181
@@ -194,16 +190,11 @@ NAMESPACE_END(detail)
194190
m.noisy_function_with_error_printing()
195191
196192
\endrst */
197-
198193
inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::string name = "ostream_redirect") {
199-
return class_<detail::OstreamRedirect>(m, name.c_str())
194+
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
200195
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
201-
.def("__enter__", [](detail::OstreamRedirect &self) {
202-
self.enter();
203-
})
204-
.def("__exit__", [](detail::OstreamRedirect &self, args) {
205-
self.exit();
206-
});
196+
.def("__enter__", &detail::OstreamRedirect::enter)
197+
.def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); });
207198
}
208199

209200
NAMESPACE_END(PYBIND11_NAMESPACE)

0 commit comments

Comments
 (0)