fixturify 0.1.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. fixturify/__init__.py +21 -0
  2. fixturify/_utils/__init__.py +7 -0
  3. fixturify/_utils/_constants.py +10 -0
  4. fixturify/_utils/_fixture_discovery.py +165 -0
  5. fixturify/_utils/_path_resolver.py +135 -0
  6. fixturify/http_d/__init__.py +80 -0
  7. fixturify/http_d/_config.py +214 -0
  8. fixturify/http_d/_decorator.py +267 -0
  9. fixturify/http_d/_exceptions.py +153 -0
  10. fixturify/http_d/_fixture_discovery.py +33 -0
  11. fixturify/http_d/_matcher.py +372 -0
  12. fixturify/http_d/_mock_context.py +154 -0
  13. fixturify/http_d/_models.py +205 -0
  14. fixturify/http_d/_patcher.py +524 -0
  15. fixturify/http_d/_player.py +222 -0
  16. fixturify/http_d/_recorder.py +1350 -0
  17. fixturify/http_d/_stubs/__init__.py +8 -0
  18. fixturify/http_d/_stubs/_aiohttp.py +220 -0
  19. fixturify/http_d/_stubs/_connection.py +478 -0
  20. fixturify/http_d/_stubs/_httpcore.py +269 -0
  21. fixturify/http_d/_stubs/_tornado.py +95 -0
  22. fixturify/http_d/_utils.py +194 -0
  23. fixturify/json_assert/__init__.py +13 -0
  24. fixturify/json_assert/_actual_saver.py +67 -0
  25. fixturify/json_assert/_assert.py +173 -0
  26. fixturify/json_assert/_comparator.py +183 -0
  27. fixturify/json_assert/_diff_formatter.py +265 -0
  28. fixturify/json_assert/_normalizer.py +83 -0
  29. fixturify/object_mapper/__init__.py +5 -0
  30. fixturify/object_mapper/_deserializers/__init__.py +19 -0
  31. fixturify/object_mapper/_deserializers/_base.py +186 -0
  32. fixturify/object_mapper/_deserializers/_dataclass.py +52 -0
  33. fixturify/object_mapper/_deserializers/_plain.py +55 -0
  34. fixturify/object_mapper/_deserializers/_pydantic_v1.py +38 -0
  35. fixturify/object_mapper/_deserializers/_pydantic_v2.py +41 -0
  36. fixturify/object_mapper/_deserializers/_sqlalchemy.py +72 -0
  37. fixturify/object_mapper/_deserializers/_sqlmodel.py +43 -0
  38. fixturify/object_mapper/_detectors/__init__.py +5 -0
  39. fixturify/object_mapper/_detectors/_type_detector.py +186 -0
  40. fixturify/object_mapper/_serializers/__init__.py +19 -0
  41. fixturify/object_mapper/_serializers/_base.py +260 -0
  42. fixturify/object_mapper/_serializers/_dataclass.py +55 -0
  43. fixturify/object_mapper/_serializers/_plain.py +49 -0
  44. fixturify/object_mapper/_serializers/_pydantic_v1.py +49 -0
  45. fixturify/object_mapper/_serializers/_pydantic_v2.py +49 -0
  46. fixturify/object_mapper/_serializers/_sqlalchemy.py +70 -0
  47. fixturify/object_mapper/_serializers/_sqlmodel.py +54 -0
  48. fixturify/object_mapper/mapper.py +256 -0
  49. fixturify/read_d/__init__.py +5 -0
  50. fixturify/read_d/_decorator.py +193 -0
  51. fixturify/read_d/_fixture_loader.py +88 -0
  52. fixturify/sql_d/__init__.py +7 -0
  53. fixturify/sql_d/_config.py +30 -0
  54. fixturify/sql_d/_decorator.py +373 -0
  55. fixturify/sql_d/_driver_registry.py +133 -0
  56. fixturify/sql_d/_executor.py +82 -0
  57. fixturify/sql_d/_fixture_discovery.py +55 -0
  58. fixturify/sql_d/_phase.py +10 -0
  59. fixturify/sql_d/_strategies/__init__.py +11 -0
  60. fixturify/sql_d/_strategies/_aiomysql.py +63 -0
  61. fixturify/sql_d/_strategies/_aiosqlite.py +29 -0
  62. fixturify/sql_d/_strategies/_asyncpg.py +34 -0
  63. fixturify/sql_d/_strategies/_base.py +118 -0
  64. fixturify/sql_d/_strategies/_mysql.py +70 -0
  65. fixturify/sql_d/_strategies/_psycopg.py +35 -0
  66. fixturify/sql_d/_strategies/_psycopg2.py +40 -0
  67. fixturify/sql_d/_strategies/_registry.py +109 -0
  68. fixturify/sql_d/_strategies/_sqlite.py +33 -0
  69. fixturify-0.1.9.dist-info/METADATA +122 -0
  70. fixturify-0.1.9.dist-info/RECORD +71 -0
  71. fixturify-0.1.9.dist-info/WHEEL +4 -0
@@ -0,0 +1,524 @@
1
+ """Patcher builder for HTTP client mocking.
2
+
3
+ Uses unittest.mock.patch.object to patch HTTP clients at various levels:
4
+ - http.client (covers requests, urllib3, httplib2, boto3)
5
+ - httpcore (covers httpx sync and async)
6
+ - aiohttp (async HTTP client)
7
+ - tornado (async HTTP client)
8
+ """
9
+
10
+ import contextlib
11
+ from typing import TYPE_CHECKING, Dict, Iterator, Type
12
+ from unittest import mock
13
+
14
+ if TYPE_CHECKING:
15
+ from ._mock_context import HttpMockContext
16
+
17
+
18
+ # Save original classes at import time for force_reset()
19
+ _originals: Dict[str, object] = {}
20
+
21
+
22
+ def _save_originals():
23
+ """Save original HTTP classes for later restoration."""
24
+ import http.client as httplib
25
+ _originals["httplib.HTTPConnection"] = httplib.HTTPConnection
26
+ _originals["httplib.HTTPSConnection"] = httplib.HTTPSConnection
27
+
28
+ # urllib3 has its own connection classes
29
+ try:
30
+ import urllib3.connection
31
+ _originals["urllib3.HTTPConnection"] = urllib3.connection.HTTPConnection
32
+ _originals["urllib3.HTTPSConnection"] = urllib3.connection.HTTPSConnection
33
+ except ImportError:
34
+ pass
35
+
36
+ # urllib3 connection pools have ConnectionCls attribute
37
+ try:
38
+ from urllib3.connectionpool import HTTPConnectionPool, HTTPSConnectionPool
39
+ _originals["urllib3.HTTPConnectionPool.ConnectionCls"] = HTTPConnectionPool.ConnectionCls
40
+ _originals["urllib3.HTTPSConnectionPool.ConnectionCls"] = HTTPSConnectionPool.ConnectionCls
41
+ except ImportError:
42
+ pass
43
+
44
+ # Also check requests.packages.urllib3 (bundled version)
45
+ try:
46
+ import requests.packages.urllib3.connection as req_urllib3_conn
47
+ _originals["requests.urllib3.HTTPConnection"] = req_urllib3_conn.HTTPConnection
48
+ _originals["requests.urllib3.HTTPSConnection"] = req_urllib3_conn.HTTPSConnection
49
+ except ImportError:
50
+ pass
51
+
52
+ try:
53
+ from requests.packages.urllib3.connectionpool import (
54
+ HTTPConnectionPool as ReqHTTPConnectionPool,
55
+ HTTPSConnectionPool as ReqHTTPSConnectionPool,
56
+ )
57
+ _originals["requests.urllib3.HTTPConnectionPool.ConnectionCls"] = ReqHTTPConnectionPool.ConnectionCls
58
+ _originals["requests.urllib3.HTTPSConnectionPool.ConnectionCls"] = ReqHTTPSConnectionPool.ConnectionCls
59
+ except ImportError:
60
+ pass
61
+
62
+ try:
63
+ import httpcore
64
+ _originals["httpcore.ConnectionPool.handle_request"] = (
65
+ httpcore.ConnectionPool.handle_request
66
+ )
67
+ _originals["httpcore.AsyncConnectionPool.handle_async_request"] = (
68
+ httpcore.AsyncConnectionPool.handle_async_request
69
+ )
70
+ except ImportError:
71
+ pass
72
+
73
+ try:
74
+ import aiohttp.client
75
+ _originals["aiohttp.ClientSession._request"] = (
76
+ aiohttp.client.ClientSession._request
77
+ )
78
+ except ImportError:
79
+ pass
80
+
81
+ try:
82
+ import tornado.simple_httpclient
83
+ _originals["tornado.SimpleAsyncHTTPClient.fetch_impl"] = (
84
+ tornado.simple_httpclient.SimpleAsyncHTTPClient.fetch_impl
85
+ )
86
+ except ImportError:
87
+ pass
88
+
89
+ try:
90
+ import tornado.curl_httpclient
91
+ _originals["tornado.CurlAsyncHTTPClient.fetch_impl"] = (
92
+ tornado.curl_httpclient.CurlAsyncHTTPClient.fetch_impl
93
+ )
94
+ except ImportError:
95
+ pass
96
+
97
+ # httplib2 uses SCHEME_TO_CONNECTION dict
98
+ try:
99
+ import httplib2
100
+ _originals["httplib2.SCHEME_TO_CONNECTION"] = dict(httplib2.SCHEME_TO_CONNECTION)
101
+ except ImportError:
102
+ pass
103
+
104
+ # botocore has its own connection classes
105
+ try:
106
+ import botocore.awsrequest
107
+ _originals["botocore.AWSHTTPConnectionPool.ConnectionCls"] = (
108
+ botocore.awsrequest.AWSHTTPConnectionPool.ConnectionCls
109
+ )
110
+ _originals["botocore.AWSHTTPSConnectionPool.ConnectionCls"] = (
111
+ botocore.awsrequest.AWSHTTPSConnectionPool.ConnectionCls
112
+ )
113
+ except ImportError:
114
+ pass
115
+
116
+
117
+ # Save originals at module load
118
+ _save_originals()
119
+
120
+
121
+ @contextlib.contextmanager
122
+ def force_reset():
123
+ """
124
+ Context manager that temporarily restores original HTTP classes.
125
+
126
+ Used when making real HTTP requests (e.g., in record mode) to avoid
127
+ infinite recursion through our patched classes.
128
+ """
129
+ import http.client as httplib
130
+
131
+ patchers = []
132
+
133
+ # Always restore http.client
134
+ patchers.append(mock.patch.object(
135
+ httplib, "HTTPConnection", _originals["httplib.HTTPConnection"]
136
+ ))
137
+ patchers.append(mock.patch.object(
138
+ httplib, "HTTPSConnection", _originals["httplib.HTTPSConnection"]
139
+ ))
140
+
141
+ # Restore urllib3 if available
142
+ if "urllib3.HTTPConnection" in _originals:
143
+ import urllib3.connection
144
+ patchers.append(mock.patch.object(
145
+ urllib3.connection, "HTTPConnection",
146
+ _originals["urllib3.HTTPConnection"]
147
+ ))
148
+ patchers.append(mock.patch.object(
149
+ urllib3.connection, "HTTPSConnection",
150
+ _originals["urllib3.HTTPSConnection"]
151
+ ))
152
+
153
+ # Restore urllib3 ConnectionCls
154
+ if "urllib3.HTTPConnectionPool.ConnectionCls" in _originals:
155
+ from urllib3.connectionpool import HTTPConnectionPool, HTTPSConnectionPool
156
+ patchers.append(mock.patch.object(
157
+ HTTPConnectionPool, "ConnectionCls",
158
+ _originals["urllib3.HTTPConnectionPool.ConnectionCls"]
159
+ ))
160
+ patchers.append(mock.patch.object(
161
+ HTTPSConnectionPool, "ConnectionCls",
162
+ _originals["urllib3.HTTPSConnectionPool.ConnectionCls"]
163
+ ))
164
+
165
+ # Restore requests.packages.urllib3 if available
166
+ if "requests.urllib3.HTTPConnection" in _originals:
167
+ import requests.packages.urllib3.connection as req_urllib3_conn
168
+ patchers.append(mock.patch.object(
169
+ req_urllib3_conn, "HTTPConnection",
170
+ _originals["requests.urllib3.HTTPConnection"]
171
+ ))
172
+ patchers.append(mock.patch.object(
173
+ req_urllib3_conn, "HTTPSConnection",
174
+ _originals["requests.urllib3.HTTPSConnection"]
175
+ ))
176
+
177
+ # Restore requests.packages.urllib3 ConnectionCls
178
+ if "requests.urllib3.HTTPConnectionPool.ConnectionCls" in _originals:
179
+ from requests.packages.urllib3.connectionpool import (
180
+ HTTPConnectionPool as ReqHTTPConnectionPool,
181
+ HTTPSConnectionPool as ReqHTTPSConnectionPool,
182
+ )
183
+ patchers.append(mock.patch.object(
184
+ ReqHTTPConnectionPool, "ConnectionCls",
185
+ _originals["requests.urllib3.HTTPConnectionPool.ConnectionCls"]
186
+ ))
187
+ patchers.append(mock.patch.object(
188
+ ReqHTTPSConnectionPool, "ConnectionCls",
189
+ _originals["requests.urllib3.HTTPSConnectionPool.ConnectionCls"]
190
+ ))
191
+
192
+ # Restore httplib2 if available
193
+ if "httplib2.SCHEME_TO_CONNECTION" in _originals:
194
+ import httplib2
195
+ patchers.append(mock.patch.dict(
196
+ httplib2.SCHEME_TO_CONNECTION,
197
+ _originals["httplib2.SCHEME_TO_CONNECTION"],
198
+ clear=True
199
+ ))
200
+
201
+ # Restore botocore if available
202
+ if "botocore.AWSHTTPConnectionPool.ConnectionCls" in _originals:
203
+ import botocore.awsrequest
204
+ patchers.append(mock.patch.object(
205
+ botocore.awsrequest.AWSHTTPConnectionPool, "ConnectionCls",
206
+ _originals["botocore.AWSHTTPConnectionPool.ConnectionCls"]
207
+ ))
208
+ patchers.append(mock.patch.object(
209
+ botocore.awsrequest.AWSHTTPSConnectionPool, "ConnectionCls",
210
+ _originals["botocore.AWSHTTPSConnectionPool.ConnectionCls"]
211
+ ))
212
+
213
+ # Restore httpcore if available
214
+ if "httpcore.ConnectionPool.handle_request" in _originals:
215
+ import httpcore
216
+ patchers.append(mock.patch.object(
217
+ httpcore.ConnectionPool, "handle_request",
218
+ _originals["httpcore.ConnectionPool.handle_request"]
219
+ ))
220
+ patchers.append(mock.patch.object(
221
+ httpcore.AsyncConnectionPool, "handle_async_request",
222
+ _originals["httpcore.AsyncConnectionPool.handle_async_request"]
223
+ ))
224
+
225
+ # Restore aiohttp if available
226
+ if "aiohttp.ClientSession._request" in _originals:
227
+ import aiohttp.client
228
+ patchers.append(mock.patch.object(
229
+ aiohttp.client.ClientSession, "_request",
230
+ _originals["aiohttp.ClientSession._request"]
231
+ ))
232
+
233
+ # Restore tornado if available
234
+ if "tornado.SimpleAsyncHTTPClient.fetch_impl" in _originals:
235
+ import tornado.simple_httpclient
236
+ patchers.append(mock.patch.object(
237
+ tornado.simple_httpclient.SimpleAsyncHTTPClient, "fetch_impl",
238
+ _originals["tornado.SimpleAsyncHTTPClient.fetch_impl"]
239
+ ))
240
+
241
+ if "tornado.CurlAsyncHTTPClient.fetch_impl" in _originals:
242
+ import tornado.curl_httpclient
243
+ patchers.append(mock.patch.object(
244
+ tornado.curl_httpclient.CurlAsyncHTTPClient, "fetch_impl",
245
+ _originals["tornado.CurlAsyncHTTPClient.fetch_impl"]
246
+ ))
247
+
248
+ # Start all patchers
249
+ for patcher in patchers:
250
+ patcher.start()
251
+
252
+ try:
253
+ yield
254
+ finally:
255
+ # Stop all patchers in reverse order
256
+ for patcher in reversed(patchers):
257
+ patcher.stop()
258
+
259
+
260
+ class PatcherBuilder:
261
+ """
262
+ Builds mock.patch objects for all HTTP clients.
263
+
264
+ The key insight is that we create dynamic subclasses of our stub classes
265
+ with the mock_context attribute set. This allows the stubs to access
266
+ the mock context without using thread-local storage or context variables.
267
+ """
268
+
269
+ def __init__(self, mock_context: "HttpMockContext"):
270
+ """
271
+ Initialize the patcher builder.
272
+
273
+ Args:
274
+ mock_context: The HttpMockContext to use for recording/playback
275
+ """
276
+ self._mock_context = mock_context
277
+ self._class_cache: Dict[Type, Type] = {}
278
+
279
+ def build(self) -> Iterator[mock._patch]:
280
+ """
281
+ Yield all patches to apply.
282
+
283
+ Each patch is a context manager that can be entered/exited.
284
+ """
285
+ yield from self._httplib_patches()
286
+ yield from self._urllib3_patches()
287
+ yield from self._httplib2_patches()
288
+ yield from self._botocore_patches()
289
+ yield from self._httpcore_patches()
290
+ yield from self._aiohttp_patches()
291
+ yield from self._tornado_patches()
292
+
293
+ def _get_stub_with_context(self, stub_class: Type) -> Type:
294
+ """
295
+ Create a subclass of stub_class with mock_context attribute set.
296
+
297
+ This is the key mechanism for passing context to stubs without
298
+ using thread-local storage. Each test gets its own subclass
299
+ with its own mock_context.
300
+
301
+ Args:
302
+ stub_class: The stub class to subclass
303
+
304
+ Returns:
305
+ A new class with mock_context set to self._mock_context
306
+ """
307
+ if stub_class not in self._class_cache:
308
+ # Create dynamic subclass with mock_context attribute
309
+ self._class_cache[stub_class] = type(
310
+ stub_class.__name__,
311
+ (stub_class,),
312
+ {"mock_context": self._mock_context}
313
+ )
314
+ return self._class_cache[stub_class]
315
+
316
+ def _httplib_patches(self) -> Iterator[mock._patch]:
317
+ """
318
+ Patches for http.client (stdlib).
319
+
320
+ This covers most HTTP libraries:
321
+ - requests (uses urllib3 which uses http.client)
322
+ - urllib3 (uses http.client)
323
+ - httplib2 (uses http.client)
324
+ - boto3/botocore (uses urllib3)
325
+ """
326
+ import http.client as httplib
327
+ from ._stubs._connection import MockHTTPConnection, MockHTTPSConnection
328
+
329
+ yield mock.patch.object(
330
+ httplib, "HTTPConnection",
331
+ self._get_stub_with_context(MockHTTPConnection)
332
+ )
333
+ yield mock.patch.object(
334
+ httplib, "HTTPSConnection",
335
+ self._get_stub_with_context(MockHTTPSConnection)
336
+ )
337
+
338
+ def _urllib3_patches(self) -> Iterator[mock._patch]:
339
+ """
340
+ Patches for urllib3 connection classes.
341
+
342
+ urllib3 imports HTTPConnection at module load time, so we need
343
+ to patch its own connection module in addition to http.client.
344
+
345
+ This also covers requests, which uses urllib3 under the hood.
346
+ """
347
+ from ._stubs._connection import MockHTTPConnection, MockHTTPSConnection
348
+
349
+ mock_http = self._get_stub_with_context(MockHTTPConnection)
350
+ mock_https = self._get_stub_with_context(MockHTTPSConnection)
351
+
352
+ # Patch urllib3.connection
353
+ try:
354
+ import urllib3.connection
355
+ yield mock.patch.object(
356
+ urllib3.connection, "HTTPConnection", mock_http
357
+ )
358
+ yield mock.patch.object(
359
+ urllib3.connection, "HTTPSConnection", mock_https
360
+ )
361
+ except ImportError:
362
+ pass
363
+
364
+ # Patch urllib3 connection pool ConnectionCls
365
+ try:
366
+ from urllib3.connectionpool import HTTPConnectionPool, HTTPSConnectionPool
367
+ yield mock.patch.object(
368
+ HTTPConnectionPool, "ConnectionCls", mock_http
369
+ )
370
+ yield mock.patch.object(
371
+ HTTPSConnectionPool, "ConnectionCls", mock_https
372
+ )
373
+ except ImportError:
374
+ pass
375
+
376
+ # Patch requests.packages.urllib3.connection (bundled urllib3)
377
+ try:
378
+ import requests.packages.urllib3.connection as req_urllib3_conn
379
+ yield mock.patch.object(
380
+ req_urllib3_conn, "HTTPConnection", mock_http
381
+ )
382
+ yield mock.patch.object(
383
+ req_urllib3_conn, "HTTPSConnection", mock_https
384
+ )
385
+ except ImportError:
386
+ pass
387
+
388
+ # Patch requests.packages.urllib3 connection pool ConnectionCls
389
+ try:
390
+ from requests.packages.urllib3.connectionpool import (
391
+ HTTPConnectionPool as ReqHTTPConnectionPool,
392
+ HTTPSConnectionPool as ReqHTTPSConnectionPool,
393
+ )
394
+ yield mock.patch.object(
395
+ ReqHTTPConnectionPool, "ConnectionCls", mock_http
396
+ )
397
+ yield mock.patch.object(
398
+ ReqHTTPSConnectionPool, "ConnectionCls", mock_https
399
+ )
400
+ except ImportError:
401
+ pass
402
+
403
+ def _httplib2_patches(self) -> Iterator[mock._patch]:
404
+ """
405
+ Patches for httplib2 connection classes.
406
+
407
+ httplib2 uses SCHEME_TO_CONNECTION dict to look up connection classes.
408
+ We patch this dict to use our mock classes.
409
+ """
410
+ from ._stubs._connection import MockHTTPConnection, MockHTTPSConnection
411
+
412
+ mock_http = self._get_stub_with_context(MockHTTPConnection)
413
+ mock_https = self._get_stub_with_context(MockHTTPSConnection)
414
+
415
+ try:
416
+ import httplib2
417
+ # Patch the scheme-to-connection mapping
418
+ yield mock.patch.dict(
419
+ httplib2.SCHEME_TO_CONNECTION,
420
+ {"http": mock_http, "https": mock_https}
421
+ )
422
+ except ImportError:
423
+ pass
424
+
425
+ def _botocore_patches(self) -> Iterator[mock._patch]:
426
+ """
427
+ Patches for botocore (boto3) connection classes.
428
+
429
+ botocore has its own connection pool classes that use
430
+ AWSHTTPConnection and AWSHTTPSConnection.
431
+ """
432
+ from ._stubs._connection import MockHTTPConnection, MockHTTPSConnection
433
+
434
+ mock_http = self._get_stub_with_context(MockHTTPConnection)
435
+ mock_https = self._get_stub_with_context(MockHTTPSConnection)
436
+
437
+ try:
438
+ import botocore.awsrequest
439
+ yield mock.patch.object(
440
+ botocore.awsrequest.AWSHTTPConnectionPool, "ConnectionCls", mock_http
441
+ )
442
+ yield mock.patch.object(
443
+ botocore.awsrequest.AWSHTTPSConnectionPool, "ConnectionCls", mock_https
444
+ )
445
+ except ImportError:
446
+ pass
447
+
448
+ def _httpcore_patches(self) -> Iterator[mock._patch]:
449
+ """
450
+ Patches for httpcore.
451
+
452
+ This covers:
453
+ - httpx (sync and async)
454
+ - FastAPI TestClient (uses httpx internally)
455
+ """
456
+ try:
457
+ import httpcore
458
+ except ImportError:
459
+ return
460
+
461
+ from ._stubs._httpcore import make_sync_handler, make_async_handler
462
+
463
+ yield mock.patch.object(
464
+ httpcore.ConnectionPool, "handle_request",
465
+ make_sync_handler(self._mock_context)
466
+ )
467
+ yield mock.patch.object(
468
+ httpcore.AsyncConnectionPool, "handle_async_request",
469
+ make_async_handler(self._mock_context)
470
+ )
471
+
472
+ def _aiohttp_patches(self) -> Iterator[mock._patch]:
473
+ """
474
+ Patches for aiohttp.
475
+
476
+ aiohttp is an async HTTP client that doesn't use http.client.
477
+ """
478
+ try:
479
+ import aiohttp.client
480
+ except ImportError:
481
+ return
482
+
483
+ from ._stubs._aiohttp import make_aiohttp_request_handler
484
+
485
+ yield mock.patch.object(
486
+ aiohttp.client.ClientSession, "_request",
487
+ make_aiohttp_request_handler(self._mock_context)
488
+ )
489
+
490
+ def _tornado_patches(self) -> Iterator[mock._patch]:
491
+ """
492
+ Patches for tornado HTTP clients.
493
+
494
+ Tornado has multiple HTTP client implementations.
495
+ """
496
+ from ._stubs._tornado import make_tornado_fetch_handler
497
+
498
+ # SimpleAsyncHTTPClient
499
+ try:
500
+ import tornado.simple_httpclient
501
+ original = _originals.get(
502
+ "tornado.SimpleAsyncHTTPClient.fetch_impl",
503
+ tornado.simple_httpclient.SimpleAsyncHTTPClient.fetch_impl
504
+ )
505
+ yield mock.patch.object(
506
+ tornado.simple_httpclient.SimpleAsyncHTTPClient, "fetch_impl",
507
+ make_tornado_fetch_handler(self._mock_context, original)
508
+ )
509
+ except ImportError:
510
+ pass
511
+
512
+ # CurlAsyncHTTPClient
513
+ try:
514
+ import tornado.curl_httpclient
515
+ original = _originals.get(
516
+ "tornado.CurlAsyncHTTPClient.fetch_impl",
517
+ tornado.curl_httpclient.CurlAsyncHTTPClient.fetch_impl
518
+ )
519
+ yield mock.patch.object(
520
+ tornado.curl_httpclient.CurlAsyncHTTPClient, "fetch_impl",
521
+ make_tornado_fetch_handler(self._mock_context, original)
522
+ )
523
+ except ImportError:
524
+ pass