Skip to content

Commit d084fec

Browse files
committed
Add replacement version of aiohappyeyeballs.start_connection
1 parent 462abab commit d084fec

File tree

5 files changed

+58
-6
lines changed

5 files changed

+58
-6
lines changed

Diff for: README.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,14 @@ def event_loop():
111111
loop.close()
112112
```
113113

114-
### Integration with pytest-aiohttp
114+
### Integration with aiohappyeyeballs
115+
116+
Unfortunately `aiohappyeyeballs.start_connection` doesn't work out of the box
117+
because it relies on creating a real socket. I've created a replacement
118+
`async_solipsism.aiohappyeyeballs_start_connection` that can be used to
119+
replace it. See the aiohttp section below for example code.
120+
121+
### Integration with aiohttp
115122

116123
A little extra work is required to work with aiohttp's test utilities, but it
117124
is possible. The example below requires at least aiohttp 3.8.0.
@@ -127,6 +134,12 @@ def event_loop_policy():
127134
return async_solipsism.EventLoopPolicy()
128135

129136

137+
@pytest.fixture(autouse=True)
138+
def mock_start_connection(monkeypatch):
139+
monkeypatch.setattr("aiohappyeyeballs.start_connection",
140+
async_solipsism.aiohappyeyeballs_start_connection)
141+
142+
130143
def socket_factory(host, port, family):
131144
return async_solipsism.ListenSocket((host, port))
132145

@@ -174,6 +187,10 @@ Calling functions that are not supported will generally raise
174187

175188
## Changelog
176189

190+
### 0.7
191+
192+
- Add a replacement function for `aiohappyeyeballs.start_connection`.
193+
177194
### 0.6
178195

179196
- Drop support for Python 3.6 and 3.7, which have reached end of life.

Diff for: pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ authors = [
1111
]
1212
requires-python = ">=3.8"
1313
classifiers = [
14-
"Development Status :: 3 - Alpha",
14+
"Development Status :: 5 - Production/Stable",
1515
"Framework :: AsyncIO",
1616
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
1717
"Topic :: Software Development :: Testing :: Mocking",

Diff for: src/async_solipsism/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
from .socket import * # noqa
2020
from .loop import * # noqa
2121

22-
__version__ = '0.6'
22+
__version__ = '0.7'

Diff for: src/async_solipsism/loop.py

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2020, 2022 Bruce Merry
1+
# Copyright 2020, 2022, 2024 Bruce Merry
22
#
33
# This file is part of async-solipsism.
44
#
@@ -24,7 +24,7 @@
2424
from .exceptions import SolipsismError
2525

2626

27-
__all__ = ('EventLoop', 'EventLoopPolicy', 'stream_pairs')
27+
__all__ = ('EventLoop', 'EventLoopPolicy', 'aiohappyeyeballs_start_connection', 'stream_pairs')
2828

2929

3030
class EventLoop(asyncio.selector_events.BaseSelectorEventLoop):
@@ -133,6 +133,27 @@ async def create_server(
133133
**kwargs
134134
)
135135

136+
async def aiohappyeyeballs_start_connection(self,
137+
addr_infos,
138+
*,
139+
local_addr_infos=None,
140+
happy_eyeballs_delay=None,
141+
interleave=None):
142+
for addr_info in addr_infos:
143+
addr = addr_info[4]
144+
addr = _socket._normalise_ipv6_sockaddr(addr)
145+
if addr in self.__listening_sockets:
146+
listener = self.__listening_sockets[addr]
147+
if local_addr_infos:
148+
local_addr_info = local_addr_infos[0]
149+
else:
150+
port = self.__next_port
151+
self.__next_port += 1
152+
local_addr_info = ('::1', port, 0, 0)
153+
sock = await listener.make_connection(local_addr_info)
154+
return sock
155+
raise ConnectionRefusedError('No socket listening on requested addresses')
156+
136157
async def connect_read_pipe(self, protocol_factory, pipe):
137158
raise SolipsismError("connect_read_pipe is not supported")
138159

@@ -207,3 +228,17 @@ async def stream_pairs(capacity=None):
207228
streams1 = await asyncio.open_connection(sock=sock1)
208229
streams2 = await asyncio.open_connection(sock=sock2)
209230
return streams1, streams2
231+
232+
233+
async def aiohappyeyeballs_start_connection(addr_infos,
234+
*,
235+
local_addr_infos=None,
236+
happy_eyeballs_delay=None,
237+
interleave=None,
238+
loop=None):
239+
if loop is None:
240+
loop = asyncio.get_running_loop()
241+
return await loop.aiohappyeyeballs_start_connection(addr_infos,
242+
local_addr_infos=local_addr_infos,
243+
happy_eyeballs_delay=happy_eyeballs_delay,
244+
interleave=interleave)

Diff for: src/async_solipsism/socket.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def gettimeout(self):
120120

121121
def setblocking(self, flag):
122122
if flag:
123-
raise SolipsismError('Socket only support non-blocking operation')
123+
raise SolipsismError('Socket only supports non-blocking operation')
124124

125125
def setsockopt(self, level, optname, value, optlen=None):
126126
key = (level, optname)

0 commit comments

Comments
 (0)