@@ -32,6 +32,14 @@ def _patch_vcr_aiohttp_stubs():
3232 See: https://github.com/kevin1024/vcrpy/issues/927
3333 """
3434 try :
35+ from aiohttp import streams
36+
37+ # VCR.py imports this aiohttp internals symbol at module import time, but
38+ # newer aiohttp releases removed it. Provide a no-op compatibility shim
39+ # before importing vcr.stubs.aiohttp_stubs so test collection does not fail.
40+ if not hasattr (streams , "AsyncStreamReaderMixin" ):
41+ setattr (streams , "AsyncStreamReaderMixin" , object )
42+
3543 from vcr .stubs import aiohttp_stubs
3644 except ImportError :
3745 return
@@ -41,17 +49,55 @@ def _patch_vcr_aiohttp_stubs():
4149
4250 import asyncio
4351 import gzip
52+ import inspect
4453
45- from aiohttp import ClientConnectionError , streams
54+ from aiohttp import ClientConnectionError , ClientResponse , streams
55+ from aiohttp .helpers import TimerNoop
4656
4757 def _decompress_body (body ):
4858 """Decompress gzip body if needed."""
4959 if body and body [:2 ] == b"\x1f \x8b " :
5060 return gzip .decompress (body )
5161 return body
5262
63+ if "stream_writer" in inspect .signature (ClientResponse .__init__ ).parameters :
64+ # aiohttp 3.13 added a required stream_writer keyword argument to
65+ # ClientResponse.__init__. VCR.py's MockClientResponse still calls the
66+ # older constructor, so patch it before any cassette playback builds one.
67+ class _MockStreamWriter :
68+ output_size = 0
69+
70+ def patched_response_init (self , method , url , request_info = None ):
71+ super (aiohttp_stubs .MockClientResponse , self ).__init__ (
72+ method = method ,
73+ url = url ,
74+ writer = None ,
75+ continue100 = None ,
76+ timer = TimerNoop (),
77+ request_info = request_info ,
78+ traces = [],
79+ loop = asyncio .get_event_loop (),
80+ session = None ,
81+ stream_writer = _MockStreamWriter (),
82+ )
83+
84+ aiohttp_stubs .MockClientResponse .__init__ = patched_response_init
85+
5386 aiohttp_stubs .MockStream .set_exception = lambda self , exc : None
5487
88+ if not hasattr (aiohttp_stubs .MockStream , "iter_chunked" ):
89+ # Older aiohttp exposed iter_chunked via AsyncStreamReaderMixin. Since
90+ # that mixin is gone, VCR.py's MockStream needs the method directly for
91+ # clients that consume aiohttp responses through chunked iteration.
92+ async def iter_chunked (self , n ):
93+ while True :
94+ chunk = await self .read (n )
95+ if not chunk :
96+ break
97+ yield chunk
98+
99+ aiohttp_stubs .MockStream .iter_chunked = iter_chunked
100+
55101 async def patched_text (self , encoding = "utf-8" , errors = "strict" ):
56102 return _decompress_body (self ._body ).decode (encoding , errors = errors )
57103
0 commit comments