Skip to content

Commit e544baa

Browse files
authored
Merge pull request #52 from jbweston/feature/stderr
show output to stderr
2 parents 443b633 + 7e13cc6 commit e544baa

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

doc/source/index.rst

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ much richer output than mere text; plots, for example:
5656
from matplotlib import pyplot
5757
%matplotlib inline
5858

59-
x = np.linspace(0, 2 * np.pi)
59+
x = np.linspace(1E-3, 2 * np.pi)
6060

6161
pyplot.plot(x, np.sin(x) / x)
6262
pyplot.plot(x, np.cos(x))
@@ -155,16 +155,40 @@ a list of error types; if an error is raised that is not in the list then execut
155155
:raises: KeyError, ValueError
156156

157157
a = {'hello': 'world!'}
158-
a['jello']
158+
a['hello']
159159

160160
produces:
161161

162162
.. jupyter-execute::
163163
:raises: KeyError, ValueError
164164

165165
a = {'hello': 'world!'}
166-
a['jello']
166+
a['hello']
167167

168+
Additionally, any output sent to the ``stderr`` stream of a cell will result in jupyter-sphinx
169+
raising an exception. This behaviour can be suppressed (and the ``stderr`` stream printed as regular
170+
output) by providing the ``stderr`` option::
171+
172+
.. jupyter-execute::
173+
:stderr:
174+
175+
import sys
176+
177+
print("hello, world!", file=sys.stderr)
178+
179+
produces:
180+
181+
.. jupyter-execute::
182+
:stderr:
183+
184+
import sys
185+
186+
print("hello, world!", file=sys.stderr)
187+
188+
.. warning::
189+
190+
Note that output written to ``stderr`` is not displayed any differently than output written
191+
to ``stdout``.
168192

169193
Controlling the execution environment
170194
-------------------------------------

jupyter_sphinx/execute.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class JupyterCell(Directive):
147147
'hide-output': directives.flag,
148148
'code-below': directives.flag,
149149
'raises': csv_option,
150+
'stderr': directives.flag,
150151
}
151152

152153
def run(self):
@@ -180,6 +181,7 @@ def run(self):
180181
hide_output=('hide-output' in self.options),
181182
code_below=('code-below' in self.options),
182183
raises=self.options.get('raises'),
184+
stderr=('stderr' in self.options),
183185
)]
184186

185187

@@ -291,6 +293,15 @@ def apply(self):
291293
raise ExtensionError('Cell raised uncaught exception:\n{}'
292294
.format('\n'.join(errors[0]['traceback'])))
293295

296+
# Raise error if cells print to stderr
297+
for node, cell in zip(nodes, notebook.cells):
298+
stderr = [output for output in cell.outputs
299+
if output['output_type'] == 'stream'
300+
and output['name'] == 'stderr']
301+
if stderr and not node.attributes['stderr']:
302+
raise ExtensionError('Cell printed to stderr:\n{}'
303+
.format(stderr[0]['text']))
304+
294305
# Highlight the code cells now that we know what language they are
295306
for node in nodes:
296307
source = node.children[0]
@@ -379,7 +390,6 @@ def cell_output_to_nodes(cell, data_priority, dir):
379390
output_type = output['output_type']
380391
if (
381392
output_type == 'stream'
382-
and output['name'] == 'stdout'
383393
):
384394
to_add.append(docutils.nodes.literal_block(
385395
text=output['text'],

tests/test_execute.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def test_raises(doctree):
155155
'''
156156
tree = doctree(source)
157157
cell, = tree.traverse(JupyterCellNode)
158-
'ValueError' in cell.children[1].rawsource
158+
assert 'ValueError' in cell.children[1].rawsource
159159

160160
source = '''
161161
.. jupyter-execute::
@@ -165,7 +165,7 @@ def test_raises(doctree):
165165
'''
166166
tree = doctree(source)
167167
cell, = tree.traverse(JupyterCellNode)
168-
'ValueError' in cell.children[1].rawsource
168+
assert 'ValueError' in cell.children[1].rawsource
169169

170170

171171
def test_widgets(doctree):
@@ -191,3 +191,38 @@ def test_javascript(doctree):
191191
node, = list(tree.traverse(raw))
192192
text, = node.children
193193
assert 'world' in text
194+
195+
196+
def test_stdout(doctree):
197+
source = """
198+
.. jupyter-execute::
199+
200+
print('hello world')
201+
"""
202+
tree = doctree(source)
203+
cell, = tree.traverse(JupyterCellNode)
204+
assert len(cell.children) == 2
205+
assert cell.children[1].rawsource.strip() == "hello world"
206+
207+
208+
def test_stderr(doctree):
209+
source = """
210+
.. jupyter-execute::
211+
212+
import sys
213+
print('hello world', file=sys.stderr)
214+
"""
215+
with pytest.raises(ExtensionError):
216+
tree = doctree(source)
217+
218+
source = """
219+
.. jupyter-execute::
220+
:stderr:
221+
222+
import sys
223+
print('hello world', file=sys.stderr)
224+
"""
225+
tree = doctree(source)
226+
cell, = tree.traverse(JupyterCellNode)
227+
assert len(cell.children) == 2
228+
assert cell.children[1].rawsource.strip() == "hello world"

0 commit comments

Comments
 (0)