Skip to content

Commit ea70e0e

Browse files
committed
Add demo notebook
1 parent a3be844 commit ea70e0e

File tree

1 file changed

+224
-0
lines changed

1 file changed

+224
-0
lines changed

Demo.ipynb

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Capturing C-level stdout/stderr with `wurlitzer`\n",
8+
"\n",
9+
"Sometimes in Python you are calling some C code.\n",
10+
"Sometimes that C code makes calls to `printf`,\n",
11+
"or otherwise writes to the stdout/stderr of the process."
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 1,
17+
"metadata": {
18+
"collapsed": false
19+
},
20+
"outputs": [],
21+
"source": [
22+
"import ctypes\n",
23+
"libc = ctypes.CDLL(None)\n",
24+
"\n",
25+
"try:\n",
26+
" c_stderr_p = ctypes.c_void_p.in_dll(libc, 'stderr')\n",
27+
"except ValueError:\n",
28+
" # libc.stdout is has a funny name on OS X\n",
29+
" c_stderr_p = ctypes.c_void_p.in_dll(libc, '__stderrp')\n",
30+
"\n",
31+
"\n",
32+
"def printf(msg):\n",
33+
" \"\"\"Call C printf\"\"\"\n",
34+
" libc.printf((msg + '\\n').encode('utf8'))\n",
35+
"\n",
36+
"def printf_err(msg):\n",
37+
" \"\"\"Cal C fprintf on stderr\"\"\"\n",
38+
" libc.fprintf(c_stderr_p, (msg + '\\n').encode('utf8'))"
39+
]
40+
},
41+
{
42+
"cell_type": "markdown",
43+
"metadata": {},
44+
"source": [
45+
"IPython forwards the Python-level `sys.stdout` and `sys.stderr`,\n",
46+
"but it leaves the process-level file descriptors that C code will write to untouched.\n",
47+
"That means that in a context like this notebook, these functions will print to the terminal, because they are not captured:"
48+
]
49+
},
50+
{
51+
"cell_type": "code",
52+
"execution_count": 2,
53+
"metadata": {
54+
"collapsed": true
55+
},
56+
"outputs": [],
57+
"source": [
58+
"printf(\"Hello?\")\n",
59+
"printf_err(\"Stderr? Anybody?\")"
60+
]
61+
},
62+
{
63+
"cell_type": "markdown",
64+
"metadata": {},
65+
"source": [
66+
"With wurlitzer, we can capture these C-level functions:"
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": 3,
72+
"metadata": {
73+
"collapsed": true
74+
},
75+
"outputs": [],
76+
"source": [
77+
"from wurlitzer import pipes, sys_pipes, STDOUT, PIPE"
78+
]
79+
},
80+
{
81+
"cell_type": "code",
82+
"execution_count": 4,
83+
"metadata": {
84+
"collapsed": true
85+
},
86+
"outputs": [],
87+
"source": [
88+
"with pipes() as (stdout, stderr):\n",
89+
" printf(\"Hello, stdout!\")\n",
90+
" printf_err(\"Hello, stderr!\")"
91+
]
92+
},
93+
{
94+
"cell_type": "markdown",
95+
"metadata": {},
96+
"source": [
97+
"and redisplay them if we like:"
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": 5,
103+
"metadata": {
104+
"collapsed": false
105+
},
106+
"outputs": [
107+
{
108+
"name": "stdout",
109+
"output_type": "stream",
110+
"text": [
111+
"Hello, stdout!\n"
112+
]
113+
},
114+
{
115+
"name": "stderr",
116+
"output_type": "stream",
117+
"text": [
118+
"Hello, stderr!\n"
119+
]
120+
}
121+
],
122+
"source": [
123+
"import sys\n",
124+
"sys.stdout.write(stdout.read())\n",
125+
"sys.stderr.write(stderr.read())"
126+
]
127+
},
128+
{
129+
"cell_type": "markdown",
130+
"metadata": {},
131+
"source": [
132+
"Some tools, such as the IPython kernel for Jupyter,\n",
133+
"capture the Python-level `sys.stdout` and `sys.stderr` and forward them somewhere.\n",
134+
"In the case of Jupyter, this is over a network socket, so that it ends up in the browser.\n",
135+
"\n",
136+
"If we know that's going on, we can easily hook up the C outputs to the Python-forwarded ones with a single call:"
137+
]
138+
},
139+
{
140+
"cell_type": "code",
141+
"execution_count": 6,
142+
"metadata": {
143+
"collapsed": false
144+
},
145+
"outputs": [
146+
{
147+
"name": "stdout",
148+
"output_type": "stream",
149+
"text": [
150+
"Hello from C, 0!\n",
151+
"Hello from C, 1!\n",
152+
"Hello from C, 2!\n",
153+
"Hello from C, 3!\n",
154+
"Hello from C, 4!\n"
155+
]
156+
}
157+
],
158+
"source": [
159+
"import time\n",
160+
"\n",
161+
"with sys_pipes():\n",
162+
" for i in range(5):\n",
163+
" time.sleep(1)\n",
164+
" printf(\"Hello from C, %i!\" % i)\n"
165+
]
166+
},
167+
{
168+
"cell_type": "markdown",
169+
"metadata": {},
170+
"source": [
171+
"We can also capture the pipes to any writeable streams, such as a `StringIO` object:"
172+
]
173+
},
174+
{
175+
"cell_type": "code",
176+
"execution_count": 7,
177+
"metadata": {
178+
"collapsed": false
179+
},
180+
"outputs": [
181+
{
182+
"name": "stdout",
183+
"output_type": "stream",
184+
"text": [
185+
"Hello, stdout!\n",
186+
"Hello, stderr!\n",
187+
"\n"
188+
]
189+
}
190+
],
191+
"source": [
192+
"import io\n",
193+
"\n",
194+
"stdout = io.StringIO()\n",
195+
"with pipes(stdout=stdout, stderr=STDOUT):\n",
196+
" printf(\"Hello, stdout!\")\n",
197+
" printf_err(\"Hello, stderr!\")\n",
198+
"\n",
199+
"print(stdout.getvalue())"
200+
]
201+
}
202+
],
203+
"metadata": {
204+
"kernelspec": {
205+
"display_name": "Python 3",
206+
"language": "python",
207+
"name": "python3"
208+
},
209+
"language_info": {
210+
"codemirror_mode": {
211+
"name": "ipython",
212+
"version": 3
213+
},
214+
"file_extension": ".py",
215+
"mimetype": "text/x-python",
216+
"name": "python",
217+
"nbconvert_exporter": "python",
218+
"pygments_lexer": "ipython3",
219+
"version": "3.5.1"
220+
}
221+
},
222+
"nbformat": 4,
223+
"nbformat_minor": 1
224+
}

0 commit comments

Comments
 (0)