0
# System Integration
1
2
Forward C-level output to Python's sys.stdout/stderr streams, enabling integration with existing Python output handling systems like Jupyter notebooks, IPython, and logging frameworks.
3
4
## Capabilities
5
6
### System Stream Forwarding
7
8
Forward C-level stdout/stderr to Python sys streams without creating intermediate buffers.
9
10
```python { .api }
11
def sys_pipes(encoding='utf-8', bufsize=None):
12
"""Redirect C-level stdout/stderr to sys.stdout/stderr
13
14
Args:
15
encoding: Text encoding for output (default: 'utf-8')
16
bufsize: Pipe buffer size in bytes (default: auto-detected)
17
18
Returns:
19
Context manager that forwards C output to sys streams
20
21
Note:
22
This is useful when sys.stdout/stderr are already being forwarded
23
somewhere, e.g., in a Jupyter kernel. DO NOT USE if sys.stdout and
24
sys.stderr are not already being forwarded.
25
"""
26
```
27
28
Example usage:
29
30
```python
31
import sys
32
from wurlitzer import sys_pipes
33
34
# Ensure sys.stdout is being handled (e.g., in Jupyter)
35
with sys_pipes():
36
# C-level output will appear in the same place as Python print()
37
c_function_with_output()
38
print("This Python output and C output appear together")
39
```
40
41
### Jupyter/IPython Integration
42
43
Seamlessly integrate C-level output with Jupyter notebook cell outputs.
44
45
```python
46
from wurlitzer import sys_pipes
47
48
# In a Jupyter notebook cell
49
with sys_pipes():
50
# C library calls now appear in cell output
51
scientific_c_library.compute_results()
52
numpy_function_with_c_warnings()
53
```
54
55
### Combined with Python Output
56
57
Mix C-level and Python output in the same stream for unified logging.
58
59
```python
60
import sys
61
from wurlitzer import sys_pipes
62
63
def debug_function():
64
print("Python: Starting computation")
65
66
with sys_pipes():
67
c_computation_library.process() # C output mixed with Python
68
69
print("Python: Computation complete")
70
```
71
72
### Custom Stream Redirection
73
74
Use sys_pipes when sys.stdout/stderr have been redirected to custom handlers.
75
76
```python
77
import sys
78
from io import StringIO
79
from wurlitzer import sys_pipes
80
81
# Redirect Python sys streams
82
captured_output = StringIO()
83
original_stdout = sys.stdout
84
sys.stdout = captured_output
85
86
try:
87
with sys_pipes():
88
# Both Python and C output go to captured_output
89
print("Python output")
90
c_function_call() # C output
91
finally:
92
sys.stdout = original_stdout
93
94
all_output = captured_output.getvalue()
95
```
96
97
## Integration Patterns
98
99
### Testing Framework Integration
100
101
Integrate with testing frameworks that capture sys.stdout/stderr:
102
103
```python
104
import pytest
105
from wurlitzer import sys_pipes
106
107
def test_c_function_output(capsys):
108
with sys_pipes():
109
my_c_extension.function_under_test()
110
111
captured = capsys.readouterr()
112
assert "expected C output" in captured.out
113
```
114
115
### Logging Framework Integration
116
117
Forward C output through Python's logging system:
118
119
```python
120
import logging
121
import sys
122
from io import StringIO
123
from wurlitzer import sys_pipes
124
125
class LoggingHandler(logging.StreamHandler):
126
def __init__(self):
127
super().__init__(StringIO())
128
129
def emit(self, record):
130
# Process log records that may include C output
131
super().emit(record)
132
133
# Setup logging to capture sys output
134
logger = logging.getLogger()
135
handler = LoggingHandler()
136
logger.addHandler(handler)
137
138
# Redirect sys.stdout to logger
139
sys.stdout = handler.stream
140
141
with sys_pipes():
142
c_function_call() # Output goes through logging system
143
```
144
145
### Web Application Integration
146
147
Integrate with web frameworks where sys.stdout is redirected:
148
149
```python
150
from wurlitzer import sys_pipes
151
import flask
152
153
app = flask.Flask(__name__)
154
155
@app.route('/process')
156
def process_data():
157
output_buffer = []
158
159
with sys_pipes():
160
# C processing output captured in web context
161
result = c_data_processor.analyze(request.data)
162
163
return {"result": result, "processing_complete": True}
164
```
165
166
## Error Handling and Validation
167
168
### Stream Validation
169
170
sys_pipes includes validation to prevent infinite recursion:
171
172
```python
173
import sys
174
from wurlitzer import sys_pipes
175
176
# This will raise ValueError to prevent infinite recursion
177
try:
178
# When sys.stdout is the same as sys.__stdout__
179
with sys_pipes():
180
pass
181
except ValueError as e:
182
print(f"Cannot forward streams: {e}")
183
# Use regular pipes() instead
184
from wurlitzer import pipes
185
with pipes():
186
c_function_call()
187
```
188
189
### Fallback Patterns
190
191
Graceful degradation when sys_pipes cannot be used:
192
193
```python
194
from wurlitzer import sys_pipes, pipes
195
196
def safe_c_call():
197
try:
198
with sys_pipes():
199
return c_function_call()
200
except ValueError:
201
# Fallback to regular pipes
202
with pipes() as (out, err):
203
result = c_function_call()
204
205
# Handle captured output manually
206
stdout_content = out.read()
207
if stdout_content:
208
print(stdout_content, end='')
209
210
return result
211
```
212
213
### Thread Safety
214
215
sys_pipes is thread-safe and works correctly in multi-threaded environments:
216
217
```python
218
import threading
219
from wurlitzer import sys_pipes
220
221
def worker_thread():
222
with sys_pipes():
223
thread_specific_c_function()
224
225
# Multiple threads can safely use sys_pipes
226
threads = [threading.Thread(target=worker_thread) for _ in range(4)]
227
for t in threads:
228
t.start()
229
for t in threads:
230
t.join()
231
```