0
# Monkey Patching
1
2
Transparent replacement of standard library modules with gevent-aware equivalents, enabling existing code to work cooperatively without modification. Monkey patching is gevent's mechanism for making synchronous code asynchronous.
3
4
## Capabilities
5
6
### Core Patching Functions
7
8
Main functions for applying monkey patches to standard library modules.
9
10
```python { .api }
11
def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True, subprocess=True, sys=False, aggressive=True, Event=True, builtins=True, signal=True, queue=True, contextvars=True, **kwargs):
12
"""
13
Patch all supported modules with gevent equivalents.
14
15
Parameters:
16
- socket: bool, patch socket module
17
- dns: bool, patch DNS functions
18
- time: bool, patch time.sleep
19
- select: bool, patch select module
20
- thread: bool, patch thread module
21
- os: bool, patch os module
22
- ssl: bool, patch ssl module
23
- subprocess: bool, patch subprocess module
24
- sys: bool, patch sys module
25
- aggressive: bool, more comprehensive patching
26
- Event: bool, patch threading.Event
27
- builtins: bool, patch builtin functions
28
- signal: bool, patch signal module
29
- queue: bool, patch queue module
30
- contextvars: bool, patch contextvars module
31
- **kwargs: additional patching options
32
33
Returns:
34
None
35
"""
36
37
def patch_socket():
38
"""
39
Patch socket module with gevent socket.
40
41
Returns:
42
None
43
"""
44
45
def patch_ssl():
46
"""
47
Patch ssl module with gevent ssl.
48
49
Returns:
50
None
51
"""
52
53
def patch_thread():
54
"""
55
Patch thread module with gevent equivalents.
56
57
Returns:
58
None
59
"""
60
61
def patch_threading():
62
"""
63
Patch threading module with gevent equivalents.
64
65
Returns:
66
None
67
"""
68
69
def patch_select():
70
"""
71
Patch select module with gevent select.
72
73
Returns:
74
None
75
"""
76
77
def patch_subprocess():
78
"""
79
Patch subprocess module with gevent subprocess.
80
81
Returns:
82
None
83
"""
84
85
def patch_os():
86
"""
87
Patch os module functions with cooperative versions.
88
89
Returns:
90
None
91
"""
92
93
def patch_time():
94
"""
95
Patch time.sleep with gevent.sleep.
96
97
Returns:
98
None
99
"""
100
101
def patch_sys():
102
"""
103
Patch sys module functions.
104
105
Returns:
106
None
107
"""
108
109
def patch_builtins():
110
"""
111
Patch builtin functions with cooperative versions.
112
113
Returns:
114
None
115
"""
116
117
def patch_signal():
118
"""
119
Patch signal module with gevent signal handling.
120
121
Returns:
122
None
123
"""
124
125
def patch_queue():
126
"""
127
Patch queue module with gevent queue.
128
129
Returns:
130
None
131
"""
132
133
def patch_dns():
134
"""
135
Patch DNS resolution functions.
136
137
Returns:
138
None
139
"""
140
```
141
142
### Utility Functions
143
144
Functions for inspecting and managing monkey patches.
145
146
```python { .api }
147
def get_original(module_name, item_name):
148
"""
149
Get original (unpatched) function or class.
150
151
Parameters:
152
- module_name: str, name of module
153
- item_name: str, name of item in module
154
155
Returns:
156
Original unpatched object
157
"""
158
159
def is_module_patched(module) -> bool:
160
"""
161
Check if module has been monkey patched.
162
163
Parameters:
164
- module: module object or string name
165
166
Returns:
167
bool, True if module is patched
168
"""
169
170
def is_object_patched(obj) -> bool:
171
"""
172
Check if specific object has been patched.
173
174
Parameters:
175
- obj: object to check
176
177
Returns:
178
bool, True if object is patched
179
"""
180
```
181
182
### Exceptions
183
184
```python { .api }
185
class MonkeyPatchWarning(Warning):
186
"""Warning raised for monkey patching issues."""
187
```
188
189
## Usage Examples
190
191
### Basic Monkey Patching
192
193
```python
194
# This should be done at the very start of your program
195
from gevent import monkey
196
monkey.patch_all()
197
198
# Now all standard library I/O is cooperative
199
import socket
200
import time
201
import threading
202
203
def blocking_function():
204
# This appears to block but actually yields to other greenlets
205
time.sleep(2)
206
207
# Socket operations are now cooperative
208
s = socket.socket()
209
s.connect(('google.com', 80))
210
s.send(b'GET / HTTP/1.1\r\nHost: google.com\r\n\r\n')
211
response = s.recv(1024)
212
s.close()
213
214
return response[:100]
215
216
# Can be used with gevent as normal
217
import gevent
218
greenlets = [gevent.spawn(blocking_function) for _ in range(10)]
219
results = [g.get() for g in greenlets]
220
print(f"Got {len(results)} responses")
221
```
222
223
### Selective Patching
224
225
```python
226
from gevent import monkey
227
228
# Only patch specific modules
229
monkey.patch_socket()
230
monkey.patch_ssl()
231
monkey.patch_time()
232
233
import socket
234
import ssl
235
import time
236
237
def selective_example():
238
# Socket and SSL are cooperative
239
context = ssl.create_default_context()
240
with socket.create_connection(('httpbin.org', 443)) as sock:
241
with context.wrap_socket(sock, server_hostname='httpbin.org') as ssock:
242
ssock.send(b'GET /get HTTP/1.1\r\nHost: httpbin.org\r\n\r\n')
243
244
# time.sleep is cooperative
245
time.sleep(0.1)
246
247
response = ssock.recv(1024)
248
return response
249
250
result = selective_example()
251
print("Response received")
252
```
253
254
### Checking Patch Status
255
256
```python
257
from gevent import monkey
258
import socket
259
import threading
260
261
def check_patches():
262
print("Before patching:")
263
print(f"Socket module patched: {monkey.is_module_patched('socket')}")
264
print(f"Threading module patched: {monkey.is_module_patched('threading')}")
265
print(f"Socket.socket patched: {monkey.is_object_patched(socket.socket)}")
266
267
# Apply patches
268
monkey.patch_all()
269
270
print("\nAfter patching:")
271
print(f"Socket module patched: {monkey.is_module_patched('socket')}")
272
print(f"Threading module patched: {monkey.is_module_patched('threading')}")
273
print(f"Socket.socket patched: {monkey.is_object_patched(socket.socket)}")
274
275
check_patches()
276
```
277
278
### Getting Original Functions
279
280
```python
281
from gevent import monkey
282
283
# Patch everything
284
monkey.patch_all()
285
286
import time
287
import socket
288
289
# Get original functions
290
original_sleep = monkey.get_original('time', 'sleep')
291
original_socket = monkey.get_original('socket', 'socket')
292
293
def mixed_example():
294
print("Using gevent sleep (cooperative)")
295
time.sleep(1) # This is now gevent.sleep
296
297
print("Using original sleep (blocking)")
298
original_sleep(1) # This is the original time.sleep
299
300
print("Using gevent socket (cooperative)")
301
gevent_sock = socket.socket() # This is gevent socket
302
303
print("Using original socket (blocking)")
304
original_sock = original_socket() # This is original socket
305
306
mixed_example()
307
```
308
309
### Patching for Existing Code
310
311
```python
312
# At the top of your main script
313
from gevent import monkey
314
monkey.patch_all()
315
316
# Now existing libraries work cooperatively
317
import requests # Uses patched socket/ssl
318
import urllib3 # Uses patched socket/ssl
319
import time # sleep is cooperative
320
321
def fetch_urls(urls):
322
"""This function can now handle many concurrent requests."""
323
import gevent
324
325
def fetch_one(url):
326
try:
327
# requests will use gevent sockets automatically
328
response = requests.get(url, timeout=5)
329
return f"{url}: {response.status_code}"
330
except Exception as e:
331
return f"{url}: Error - {e}"
332
333
# Spawn greenlets for concurrent fetching
334
greenlets = [gevent.spawn(fetch_one, url) for url in urls]
335
336
# Wait for all to complete
337
gevent.joinall(greenlets)
338
339
# Collect results
340
return [g.value for g in greenlets]
341
342
# Test with multiple URLs
343
urls = [
344
'http://httpbin.org/delay/1',
345
'http://httpbin.org/delay/2',
346
'http://httpbin.org/delay/1',
347
'http://httpbin.org/status/200',
348
'http://httpbin.org/status/404'
349
]
350
351
results = fetch_urls(urls)
352
for result in results:
353
print(result)
354
```
355
356
### Database Connection Pooling
357
358
```python
359
from gevent import monkey
360
monkey.patch_all()
361
362
import gevent
363
import time
364
import sqlite3
365
366
# Simulate a database connection pool
367
class DatabasePool:
368
def __init__(self, size=5):
369
self.connections = []
370
for i in range(size):
371
# Each connection would be a real DB connection
372
self.connections.append(f"connection_{i}")
373
self.available = list(self.connections)
374
self.in_use = []
375
376
def get_connection(self):
377
while not self.available:
378
time.sleep(0.1) # Cooperative wait
379
conn = self.available.pop()
380
self.in_use.append(conn)
381
return conn
382
383
def return_connection(self, conn):
384
if conn in self.in_use:
385
self.in_use.remove(conn)
386
self.available.append(conn)
387
388
def database_worker(worker_id, pool):
389
conn = pool.get_connection()
390
print(f"Worker {worker_id} got {conn}")
391
392
# Simulate database work
393
time.sleep(2) # This is now cooperative
394
395
print(f"Worker {worker_id} finished with {conn}")
396
pool.return_connection(conn)
397
398
return f"Worker {worker_id} completed"
399
400
# Create pool and workers
401
pool = DatabasePool(3) # Only 3 connections available
402
workers = [gevent.spawn(database_worker, i, pool) for i in range(10)]
403
404
# Wait for all workers
405
results = [w.get() for w in workers]
406
print(f"All workers completed: {len(results)}")
407
```
408
409
### Testing Patch Compatibility
410
411
```python
412
from gevent import monkey
413
import warnings
414
415
def test_patching():
416
# Capture warnings
417
with warnings.catch_warnings(record=True) as w:
418
warnings.simplefilter("always")
419
420
# Apply patches
421
monkey.patch_all()
422
423
# Check for warnings
424
if w:
425
print("Monkey patching warnings:")
426
for warning in w:
427
print(f" {warning.message}")
428
else:
429
print("No monkey patching warnings")
430
431
# Test basic functionality
432
import socket
433
import time
434
import threading
435
436
print("Testing patched modules:")
437
438
# Test socket
439
try:
440
s = socket.socket()
441
s.settimeout(1)
442
s.connect(('8.8.8.8', 53))
443
s.close()
444
print(" Socket: OK")
445
except Exception as e:
446
print(f" Socket: Error - {e}")
447
448
# Test time
449
start = time.time()
450
time.sleep(0.01)
451
elapsed = time.time() - start
452
print(f" Time.sleep: {elapsed:.3f}s (expected ~0.01s)")
453
454
# Test threading
455
try:
456
event = threading.Event()
457
event.set()
458
print(f" Threading.Event: {'OK' if event.is_set() else 'Error'}")
459
except Exception as e:
460
print(f" Threading: Error - {e}")
461
462
test_patching()
463
```