-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Open
Description
Describe the bug
Some aiohttp
tests fail when IPv6 is disabled with the kernel parameter ipv6.disable=1
.
To Reproduce
Run make
on a system with IPv6 disabled.
Expected behavior
Tests should pass.
Logs/tracebacks
Log
$ make test
============================= test session starts ==============================
platform linux -- Python 3.13.0, pytest-8.3.3, pluggy-1.5.0
codspeed: 3.0.0 (disabled, mode: walltime, timer_resolution: 1.0ns)
rootdir: aiohttp
configfile: setup.cfg
testpaths: tests/
plugins: cov-5.0.0, mock-3.14.0, codspeed-3.0.0, xdist-3.6.1
created: 16/16 workers
16 workers [3430 items]
.....................x.................x................................ [ 2%]
...........F..............................................E............. [ 4%]
........................................................................ [ 6%]
........................................................................ [ 8%]
........................................................................ [ 10%]
........................................................................ [ 12%]
.......................................x.........x...................... [ 14%]
........................................................................ [ 16%]
..........................................s.ss......................s... [ 18%]
.................................................................s...... [ 20%]
........................................................................ [ 23%]
............................................................x........... [ 25%]
........................................................................ [ 27%]
....................................................................F... [ 29%]
.............................F........................E................. [ 31%]
......E................................................................. [ 33%]
........................................................................ [ 35%]
........................................................................ [ 37%]
............................................x........................... [ 39%]
...........................................................s.s........ss [ 41%]
........................................................................ [ 43%]
.......................s................................................ [ 46%]
........................................................................ [ 48%]
...........................................................s.s.......... [ 50%]
........................................................................ [ 52%]
..................x...................................s................. [ 54%]
.................s.............................................F........ [ 56%]
........................................................................ [ 58%]
........................................................................ [ 60%]
..............................................s......................... [ 62%]
........................................................................ [ 64%]
........................................................................ [ 67%]
.....s.................................................................. [ 69%]
............s........................................................... [ 71%]
........................................................................ [ 73%]
........................................................................ [ 75%]
.x...................................................................... [ 77%]
........................................................................ [ 79%]
........................................................................ [ 81%]
........................................................................ [ 83%]
..............................s.s....................................... [ 85%]
........................................................................ [ 88%]
........................................................................ [ 90%]
........................................................................ [ 92%]
........................................................................ [ 94%]
........................................................................ [ 96%]
........................................................................ [ 98%]
................................................. [100%]
==================================== ERRORS ====================================
__________ ERROR at teardown of test_tcp_connector_interleave[pyloop] __________
[gw15] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x7fd883055940>
when = 'teardown'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
@classmethod
def from_call(
cls,
func: Callable[[], TResult],
when: Literal["collect", "setup", "call", "teardown"],
reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,
) -> CallInfo[TResult]:
"""Call func, wrapping the result in a CallInfo.
:param func:
The function to call. Called without arguments.
:type func: Callable[[], _pytest.runner.TResult]
:param when:
The phase in which the function is called.
:param reraise:
Exception or exceptions that shall propagate if raised by the
function, instead of being wrapped in the CallInfo.
"""
excinfo = None
start = timing.time()
precise_start = timing.perf_counter()
try:
> result: TResult | None = func()
cls = <class '_pytest.runner.CallInfo'>
duration = 0.12177757800236577
excinfo = <ExceptionInfo PytestUnraisableExceptionWarning('Exception ignored in: <function Connection.__del__ at 0x7fd88ab63740>...=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n') tblen=11>
func = <function call_and_report.<locals>.<lambda> at 0x7fd883055940>
precise_start = 29088.698029066
precise_stop = 29088.819806644
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
result = None
start = 1731621293.6572301
stop = 1731621293.7790093
when = 'teardown'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:341:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:242: in <lambda>
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
item = <Function test_tcp_connector_interleave[pyloop]>
kwds = {'nextitem': <Function test_tcp_connector_family_is_respected[pyloop]>}
runtest_hook = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
firstresult = False
kwargs = {'item': <Function test_tcp_connector_interleave[pyloop]>, 'nextitem': <Function test_tcp_connector_family_is_respected[pyloop]>}
self = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
firstresult = False
hook_name = 'pytest_runtest_teardown'
kwargs = {'item': <Function test_tcp_connector_interleave[pyloop]>, 'nextitem': <Function test_tcp_connector_family_is_respected[pyloop]>}
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'aiohttp/.direnv/python-3...n' from 'aiohttp/.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py'>>]
self = <_pytest.config.PytestPluginManager object at 0x7fd88be35d30>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:97: in pytest_runtest_teardown
yield from thread_exception_runtest_hook()
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:68: in thread_exception_runtest_hook
yield
cm = <_pytest.threadexception.catch_threading_exception object at 0x7fd883147e30>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:100: in pytest_runtest_teardown
yield from unraisable_exception_runtest_hook()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def unraisable_exception_runtest_hook() -> Generator[None]:
with catch_unraisable_exception() as cm:
try:
yield
finally:
if cm.unraisable:
if cm.unraisable.err_msg is not None:
err_msg = cm.unraisable.err_msg
else:
err_msg = "Exception ignored in"
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
msg += "".join(
traceback.format_exception(
cm.unraisable.exc_type,
cm.unraisable.exc_value,
cm.unraisable.exc_traceback,
)
)
> warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E pytest.PytestUnraisableExceptionWarning: Exception ignored in: <function Connection.__del__ at 0x7fd88ab63740>
E
E Traceback (most recent call last):
E File "aiohttp/aiohttp/connector.py", line 143, in __del__
E _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs)
E ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E ResourceWarning: Unclosed connection Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
cm = <_pytest.unraisableexception.catch_unraisable_exception object at 0x7fd88319b9b0>
err_msg = 'Exception ignored in'
msg = 'Exception ignored in: <function Connection.__del__ at 0x7fd88ab63740>\n\nTraceback (most recent call last):\n File "...ionKey(host=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:85: PytestUnraisableExceptionWarning
_____ ERROR at teardown of test_tcp_connector_happy_eyeballs[pyloop-0.25] ______
[gw13] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x7f0f3c5d1da0>
when = 'teardown'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
@classmethod
def from_call(
cls,
func: Callable[[], TResult],
when: Literal["collect", "setup", "call", "teardown"],
reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,
) -> CallInfo[TResult]:
"""Call func, wrapping the result in a CallInfo.
:param func:
The function to call. Called without arguments.
:type func: Callable[[], _pytest.runner.TResult]
:param when:
The phase in which the function is called.
:param reraise:
Exception or exceptions that shall propagate if raised by the
function, instead of being wrapped in the CallInfo.
"""
excinfo = None
start = timing.time()
precise_start = timing.perf_counter()
try:
> result: TResult | None = func()
cls = <class '_pytest.runner.CallInfo'>
duration = 0.14997371899880818
excinfo = <ExceptionInfo PytestUnraisableExceptionWarning('Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>...=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n') tblen=11>
func = <function call_and_report.<locals>.<lambda> at 0x7f0f3c5d1da0>
precise_start = 29097.925701192
precise_stop = 29098.075674911
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
result = None
start = 1731621302.8849025
stop = 1731621303.0348785
when = 'teardown'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:341:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:242: in <lambda>
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
item = <Function test_tcp_connector_happy_eyeballs[pyloop-0.25]>
kwds = {'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>}
runtest_hook = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
firstresult = False
kwargs = {'item': <Function test_tcp_connector_happy_eyeballs[pyloop-0.25]>, 'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>}
self = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
firstresult = False
hook_name = 'pytest_runtest_teardown'
kwargs = {'item': <Function test_tcp_connector_happy_eyeballs[pyloop-0.25]>, 'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>}
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'aiohttp/.direnv/python-3...n' from 'aiohttp/.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py'>>]
self = <_pytest.config.PytestPluginManager object at 0x7f0f46139d30>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:97: in pytest_runtest_teardown
yield from thread_exception_runtest_hook()
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:68: in thread_exception_runtest_hook
yield
cm = <_pytest.threadexception.catch_threading_exception object at 0x7f0f3c94bbf0>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:100: in pytest_runtest_teardown
yield from unraisable_exception_runtest_hook()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def unraisable_exception_runtest_hook() -> Generator[None]:
with catch_unraisable_exception() as cm:
try:
yield
finally:
if cm.unraisable:
if cm.unraisable.err_msg is not None:
err_msg = cm.unraisable.err_msg
else:
err_msg = "Exception ignored in"
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
msg += "".join(
traceback.format_exception(
cm.unraisable.exc_type,
cm.unraisable.exc_value,
cm.unraisable.exc_traceback,
)
)
> warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E pytest.PytestUnraisableExceptionWarning: Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>
E
E Traceback (most recent call last):
E File "aiohttp/aiohttp/connector.py", line 143, in __del__
E _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs)
E ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E ResourceWarning: Unclosed connection Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
cm = <_pytest.unraisableexception.catch_unraisable_exception object at 0x7f0f3c94bad0>
err_msg = 'Exception ignored in'
msg = 'Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>\n\nTraceback (most recent call last):\n File "...ionKey(host=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:85: PytestUnraisableExceptionWarning
_ ERROR at teardown of test_http_request_parser_bad_method[py-parser-pyloop-;] _
[gw13] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x7f0f3c5d3560>
when = 'teardown'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
@classmethod
def from_call(
cls,
func: Callable[[], TResult],
when: Literal["collect", "setup", "call", "teardown"],
reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,
) -> CallInfo[TResult]:
"""Call func, wrapping the result in a CallInfo.
:param func:
The function to call. Called without arguments.
:type func: Callable[[], _pytest.runner.TResult]
:param when:
The phase in which the function is called.
:param reraise:
Exception or exceptions that shall propagate if raised by the
function, instead of being wrapped in the CallInfo.
"""
excinfo = None
start = timing.time()
precise_start = timing.perf_counter()
try:
> result: TResult | None = func()
cls = <class '_pytest.runner.CallInfo'>
duration = 0.15063231300155167
excinfo = <ExceptionInfo PytestUnraisableExceptionWarning('Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>...=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n') tblen=11>
func = <function call_and_report.<locals>.<lambda> at 0x7f0f3c5d3560>
precise_start = 29098.188133088
precise_stop = 29098.338765401
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
result = None
start = 1731621303.1473334
stop = 1731621303.2979698
when = 'teardown'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:341:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/runner.py:242: in <lambda>
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
item = <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>
kwds = {'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-<]>}
runtest_hook = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
firstresult = False
kwargs = {'item': <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>, 'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-<]>}
self = <HookCaller 'pytest_runtest_teardown'>
.direnv/python-3.13/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
firstresult = False
hook_name = 'pytest_runtest_teardown'
kwargs = {'item': <Function test_http_request_parser_bad_method[py-parser-pyloop-;]>, 'nextitem': <Function test_http_request_parser_bad_method[py-parser-pyloop-<]>}
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'aiohttp/.direnv/python-3...n' from 'aiohttp/.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py'>>]
self = <_pytest.config.PytestPluginManager object at 0x7f0f46139d30>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:97: in pytest_runtest_teardown
yield from thread_exception_runtest_hook()
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/threadexception.py:68: in thread_exception_runtest_hook
yield
cm = <_pytest.threadexception.catch_threading_exception object at 0x7f0f3d372210>
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:100: in pytest_runtest_teardown
yield from unraisable_exception_runtest_hook()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def unraisable_exception_runtest_hook() -> Generator[None]:
with catch_unraisable_exception() as cm:
try:
yield
finally:
if cm.unraisable:
if cm.unraisable.err_msg is not None:
err_msg = cm.unraisable.err_msg
else:
err_msg = "Exception ignored in"
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
msg += "".join(
traceback.format_exception(
cm.unraisable.exc_type,
cm.unraisable.exc_value,
cm.unraisable.exc_traceback,
)
)
> warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E pytest.PytestUnraisableExceptionWarning: Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>
E
E Traceback (most recent call last):
E File "aiohttp/aiohttp/connector.py", line 143, in __del__
E _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs)
E ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E ResourceWarning: Unclosed connection Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
cm = <_pytest.unraisableexception.catch_unraisable_exception object at 0x7f0f3c99f1d0>
err_msg = 'Exception ignored in'
msg = 'Exception ignored in: <function Connection.__del__ at 0x7f0f44e5b740>\n\nTraceback (most recent call last):\n File "...ionKey(host=\'mocked.host\', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>\n'
.direnv/python-3.13/lib/python3.13/site-packages/_pytest/unraisableexception.py:85: PytestUnraisableExceptionWarning
=================================== FAILURES ===================================
________________ test_tcp_connector_happy_eyeballs[pyloop-None] ________________
[gw15] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
happy_eyeballs_delay = None
@pytest.mark.parametrize(
("happy_eyeballs_delay"),
[0.1, 0.25, None],
)
async def test_tcp_connector_happy_eyeballs(
loop: Any, happy_eyeballs_delay: Optional[float]
) -> None:
conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)
ip1 = "dead::beef::"
ip2 = "192.168.1.1"
ips = [ip1, ip2]
addrs_tried = []
req = ClientRequest(
"GET",
URL("https://mocked.host"),
loop=loop,
)
async def _resolve_host(host, port, traces=None):
return [
{
"hostname": host,
"host": ip,
"port": port,
"family": socket.AF_INET6 if ":" in ip else socket.AF_INET,
"proto": 0,
"flags": socket.AI_NUMERICHOST,
}
for ip in ips
]
conn._resolve_host = _resolve_host
os_error = False
connected = False
async def sock_connect(*args, **kwargs):
addr = args[1]
nonlocal os_error
addrs_tried.append(addr)
if addr[0] == ip1:
os_error = True
raise OSError
async def create_connection(*args, **kwargs):
sock: socket.socket = kwargs["sock"]
# Close the socket since we are not actually connecting
# and we don't want to leak it.
sock.close()
nonlocal connected
connected = True
tr = create_mocked_conn(loop)
pr = create_mocked_conn(loop)
return tr, pr
conn._loop.sock_connect = sock_connect
conn._loop.create_connection = create_connection
established_connection = await conn.connect(req, [], ClientTimeout())
> assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]
E AssertionError: assert [('192.168.1.1', 443)] == [('dead::beef...68.1.1', 443)]
E
E At index 0 diff: ('192.168.1.1', 443) != ('dead::beef::', 443, 0, 0)
E Right contains one more item: ('192.168.1.1', 443)
E Use -v to get more diff
_resolve_host = <function test_tcp_connector_happy_eyeballs.<locals>._resolve_host at 0x7fd883055c60>
addrs_tried = [('192.168.1.1', 443)]
conn = <aiohttp.connector.TCPConnector object at 0x7fd88303d400>
connected = True
create_connection = <function test_tcp_connector_happy_eyeballs.<locals>.create_connection at 0x7fd883055e40>
established_connection = Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
happy_eyeballs_delay = None
ip1 = 'dead::beef::'
ip2 = '192.168.1.1'
ips = ['dead::beef::', '192.168.1.1']
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
os_error = False
req = <aiohttp.client_reqrep.ClientRequest object at 0x7fd88303da90>
sock_connect = <function test_tcp_connector_happy_eyeballs.<locals>.sock_connect at 0x7fd883055d00>
tests/test_connector.py:879: AssertionError
________________ test_tcp_connector_happy_eyeballs[pyloop-0.1] _________________
[gw13] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
happy_eyeballs_delay = 0.1
@pytest.mark.parametrize(
("happy_eyeballs_delay"),
[0.1, 0.25, None],
)
async def test_tcp_connector_happy_eyeballs(
loop: Any, happy_eyeballs_delay: Optional[float]
) -> None:
conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)
ip1 = "dead::beef::"
ip2 = "192.168.1.1"
ips = [ip1, ip2]
addrs_tried = []
req = ClientRequest(
"GET",
URL("https://mocked.host"),
loop=loop,
)
async def _resolve_host(host, port, traces=None):
return [
{
"hostname": host,
"host": ip,
"port": port,
"family": socket.AF_INET6 if ":" in ip else socket.AF_INET,
"proto": 0,
"flags": socket.AI_NUMERICHOST,
}
for ip in ips
]
conn._resolve_host = _resolve_host
os_error = False
connected = False
async def sock_connect(*args, **kwargs):
addr = args[1]
nonlocal os_error
addrs_tried.append(addr)
if addr[0] == ip1:
os_error = True
raise OSError
async def create_connection(*args, **kwargs):
sock: socket.socket = kwargs["sock"]
# Close the socket since we are not actually connecting
# and we don't want to leak it.
sock.close()
nonlocal connected
connected = True
tr = create_mocked_conn(loop)
pr = create_mocked_conn(loop)
return tr, pr
conn._loop.sock_connect = sock_connect
conn._loop.create_connection = create_connection
established_connection = await conn.connect(req, [], ClientTimeout())
> assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]
E AssertionError: assert [('192.168.1.1', 443)] == [('dead::beef...68.1.1', 443)]
E
E At index 0 diff: ('192.168.1.1', 443) != ('dead::beef::', 443, 0, 0)
E Right contains one more item: ('192.168.1.1', 443)
E Use -v to get more diff
_resolve_host = <function test_tcp_connector_happy_eyeballs.<locals>._resolve_host at 0x7f0f3c5d3e20>
addrs_tried = [('192.168.1.1', 443)]
conn = <aiohttp.connector.TCPConnector object at 0x7f0f3d39d6e0>
connected = True
create_connection = <function test_tcp_connector_happy_eyeballs.<locals>.create_connection at 0x7f0f3c5d3a60>
established_connection = Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
happy_eyeballs_delay = 0.1
ip1 = 'dead::beef::'
ip2 = '192.168.1.1'
ips = ['dead::beef::', '192.168.1.1']
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
os_error = False
req = <aiohttp.client_reqrep.ClientRequest object at 0x7f0f3d3cf850>
sock_connect = <function test_tcp_connector_happy_eyeballs.<locals>.sock_connect at 0x7f0f3c5d18a0>
tests/test_connector.py:879: AssertionError
________________ test_tcp_connector_happy_eyeballs[pyloop-0.25] ________________
[gw13] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
happy_eyeballs_delay = 0.25
@pytest.mark.parametrize(
("happy_eyeballs_delay"),
[0.1, 0.25, None],
)
async def test_tcp_connector_happy_eyeballs(
loop: Any, happy_eyeballs_delay: Optional[float]
) -> None:
conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)
ip1 = "dead::beef::"
ip2 = "192.168.1.1"
ips = [ip1, ip2]
addrs_tried = []
req = ClientRequest(
"GET",
URL("https://mocked.host"),
loop=loop,
)
async def _resolve_host(host, port, traces=None):
return [
{
"hostname": host,
"host": ip,
"port": port,
"family": socket.AF_INET6 if ":" in ip else socket.AF_INET,
"proto": 0,
"flags": socket.AI_NUMERICHOST,
}
for ip in ips
]
conn._resolve_host = _resolve_host
os_error = False
connected = False
async def sock_connect(*args, **kwargs):
addr = args[1]
nonlocal os_error
addrs_tried.append(addr)
if addr[0] == ip1:
os_error = True
raise OSError
async def create_connection(*args, **kwargs):
sock: socket.socket = kwargs["sock"]
# Close the socket since we are not actually connecting
# and we don't want to leak it.
sock.close()
nonlocal connected
connected = True
tr = create_mocked_conn(loop)
pr = create_mocked_conn(loop)
return tr, pr
conn._loop.sock_connect = sock_connect
conn._loop.create_connection = create_connection
established_connection = await conn.connect(req, [], ClientTimeout())
> assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]
E AssertionError: assert [('192.168.1.1', 443)] == [('dead::beef...68.1.1', 443)]
E
E At index 0 diff: ('192.168.1.1', 443) != ('dead::beef::', 443, 0, 0)
E Right contains one more item: ('192.168.1.1', 443)
E Use -v to get more diff
_resolve_host = <function test_tcp_connector_happy_eyeballs.<locals>._resolve_host at 0x7f0f3c5d3ec0>
addrs_tried = [('192.168.1.1', 443)]
conn = <aiohttp.connector.TCPConnector object at 0x7f0f3d39e060>
connected = True
create_connection = <function test_tcp_connector_happy_eyeballs.<locals>.create_connection at 0x7f0f3c5d1c60>
established_connection = Connection<ConnectionKey(host='mocked.host', port=443, is_ssl=True, ssl=True, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
happy_eyeballs_delay = 0.25
ip1 = 'dead::beef::'
ip2 = '192.168.1.1'
ips = ['dead::beef::', '192.168.1.1']
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
os_error = False
req = <aiohttp.client_reqrep.ClientRequest object at 0x7f0f3c9e8250>
sock_connect = <function test_tcp_connector_happy_eyeballs.<locals>.sock_connect at 0x7f0f3c5d1b20>
tests/test_connector.py:879: AssertionError
_____________________ test_test_server_hostnames[::1-::1] ______________________
[gw3] linux -- Python 3.13.0 aiohttp/.direnv/python-3.13/bin/python
hostname = '::1', expected_host = '::1'
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
@pytest.mark.parametrize(
("hostname", "expected_host"),
[("127.0.0.1", "127.0.0.1"), ("localhost", "127.0.0.1"), ("::1", "::1")],
)
async def test_test_server_hostnames(hostname, expected_host, loop) -> None:
app = _create_example_app()
server = TestServer(app, host=hostname, loop=loop)
> async with server:
app = <Application 0x7f6823881220>
expected_host = '::1'
hostname = '::1'
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
server = <aiohttp.test_utils.TestServer object at 0x7f682388d440>
tests/test_test_utils.py:425:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
aiohttp/test_utils.py:226: in __aenter__
await self.start_server(loop=self._loop)
self = <aiohttp.test_utils.TestServer object at 0x7f682388d440>
aiohttp/test_utils.py:151: in start_server
_sock = self.socket_factory(self.host, self.port, family)
absolute_host = '[::1]'
family = <AddressFamily.AF_INET6: 10>
kwargs = {}
loop = <_UnixSelectorEventLoop running=False closed=False debug=False>
self = <aiohttp.test_utils.TestServer object at 0x7f682388d440>
version = 6
aiohttp/test_utils.py:89: in get_port_socket
s = socket.socket(family, socket.SOCK_STREAM)
family = <AddressFamily.AF_INET6: 10>
host = '::1'
port = 0
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <socket.socket fd=-1, family=0, type=0, proto=0>
family = <AddressFamily.AF_INET6: 10>, type = <SocketKind.SOCK_STREAM: 1>
proto = 0, fileno = None
def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
# For user code address family and type values are IntEnum members, but
# for the underlying _socket.socket they're just integers. The
# constructor of _socket.socket converts the given argument to an
# integer automatically.
if fileno is None:
if family == -1:
family = AF_INET
if type == -1:
type = SOCK_STREAM
if proto == -1:
proto = 0
> _socket.socket.__init__(self, family, type, proto, fileno)
E OSError: [Errno 97] Address family not supported by protocol
family = <AddressFamily.AF_INET6: 10>
fileno = None
proto = 0
self = <socket.socket fd=-1, family=0, type=0, proto=0>
type = <SocketKind.SOCK_STREAM: 1>
/nix/store/b5w6mr7v3mnl9s163yimdksddnwhvqyl-python3-3.13.0/lib/python3.13/socket.py:233: OSError
---------- coverage: platform linux, python 3.13.0-final-0 -----------
Name Stmts Miss Branch BrPart Cover
---------------------------------------------------------------------------
aiohttp/__init__.py 27 2 2 0 93%
aiohttp/_websocket/__init__.py 0 0 0 0 100%
aiohttp/_websocket/helpers.py 77 0 40 0 100%
aiohttp/_websocket/models.py 51 0 0 0 100%
aiohttp/_websocket/reader.py 6 0 0 0 100%
aiohttp/_websocket/reader_py.py 268 226 106 0 11%
aiohttp/_websocket/writer.py 73 0 24 0 100%
aiohttp/abc.py 103 0 66 0 100%
aiohttp/base_protocol.py 71 0 26 0 100%
aiohttp/client.py 562 12 244 5 98%
aiohttp/client_exceptions.py 156 2 46 0 99%
aiohttp/client_proto.py 164 4 66 5 96%
aiohttp/client_reqrep.py 699 4 342 9 99%
aiohttp/client_ws.py 277 5 98 4 98%
aiohttp/compression_utils.py 70 4 22 3 92%
aiohttp/connector.py 767 51 366 19 92%
aiohttp/cookiejar.py 277 6 136 1 98%
aiohttp/formdata.py 97 2 48 2 97%
aiohttp/hdrs.py 94 0 0 0 100%
aiohttp/helpers.py 468 5 182 12 97%
aiohttp/http.py 11 0 0 0 100%
aiohttp/http_exceptions.py 50 0 4 0 100%
aiohttp/http_parser.py 512 13 214 14 95%
aiohttp/http_websocket.py 6 0 0 0 100%
aiohttp/http_writer.py 140 8 60 1 94%
aiohttp/log.py 7 0 0 0 100%
aiohttp/multipart.py 625 14 280 16 96%
aiohttp/payload.py 251 0 92 3 99%
aiohttp/payload_streamer.py 31 1 4 0 97%
aiohttp/pytest_plugin.py 163 9 64 2 94%
aiohttp/resolver.py 79 1 26 1 98%
aiohttp/streams.py 388 5 144 5 98%
aiohttp/tcp_helpers.py 19 0 8 1 96%
aiohttp/test_utils.py 324 2 74 5 98%
aiohttp/tracing.py 191 0 64 0 100%
aiohttp/typedefs.py 24 0 0 0 100%
aiohttp/web.py 127 0 56 1 99%
aiohttp/web_app.py 292 1 106 1 99%
aiohttp/web_exceptions.py 157 0 10 0 100%
aiohttp/web_fileresponse.py 160 0 53 1 99%
aiohttp/web_log.py 103 0 40 0 100%
aiohttp/web_middlewares.py 59 0 24 0 100%
aiohttp/web_protocol.py 367 18 159 26 92%
aiohttp/web_request.py 446 6 218 4 98%
aiohttp/web_response.py 487 3 276 4 99%
aiohttp/web_routedef.py 100 0 12 0 100%
aiohttp/web_runner.py 213 17 66 3 92%
aiohttp/web_server.py 42 0 12 0 100%
aiohttp/web_urldispatcher.py 742 9 245 6 98%
aiohttp/web_ws.py 391 12 146 12 96%
aiohttp/worker.py 126 7 32 3 94%
tests/autobahn/test_autobahn.py 60 38 24 0 45%
tests/conftest.py 142 16 65 6 88%
tests/test_base_protocol.py 200 0 8 0 100%
tests/test_benchmarks_client.py 153 0 34 0 100%
tests/test_benchmarks_client_request.py 52 0 12 0 100%
tests/test_benchmarks_client_ws.py 66 0 18 0 100%
tests/test_benchmarks_cookiejar.py 14 0 2 0 100%
tests/test_benchmarks_http_websocket.py 71 0 24 0 100%
tests/test_benchmarks_http_writer.py 11 0 4 0 100%
tests/test_circular_imports.py 29 0 13 0 100%
tests/test_classbasedview.py 39 2 4 0 95%
tests/test_client_connection.py 94 0 14 1 99%
tests/test_client_exceptions.py 199 0 24 0 100%
tests/test_client_fingerprint.py 59 0 24 0 100%
tests/test_client_functional.py 2630 30 514 10 99%
tests/test_client_proto.py 99 0 0 0 100%
tests/test_client_request.py 843 1 128 0 99%
tests/test_client_response.py 480 5 38 1 99%
tests/test_client_session.py 593 7 127 4 98%
tests/test_client_ws.py 489 0 158 0 100%
tests/test_client_ws_functional.py 834 19 84 4 97%
tests/test_compression_utils.py 15 0 0 0 100%
tests/test_connector.py 2121 59 340 10 97%
tests/test_cookiejar.py 466 0 68 2 99%
tests/test_flowcontrol_streams.py 83 0 4 0 100%
tests/test_formdata.py 86 0 24 0 100%
tests/test_helpers.py 454 10 170 8 97%
tests/test_http_exceptions.py 109 0 10 0 100%
tests/test_http_parser.py 1106 17 218 0 98%
tests/test_http_writer.py 260 0 20 0 100%
tests/test_imports.py 40 17 16 0 59%
tests/test_loop.py 36 2 4 0 95%
tests/test_multipart.py 829 0 226 1 99%
tests/test_multipart_helpers.py 446 19 82 0 95%
tests/test_payload.py 93 3 8 0 97%
tests/test_proxy.py 325 0 110 0 100%
tests/test_proxy_functional.py 462 175 110 3 66%
tests/test_pytest_plugin.py 27 0 0 0 100%
tests/test_resolver.py 231 4 78 0 99%
tests/test_route_def.py 210 20 26 0 92%
tests/test_run_app.py 577 19 100 13 95%
tests/test_streams.py 1077 0 128 0 100%
tests/test_tcp_helpers.py 52 6 14 3 83%
tests/test_test_utils.py 274 4 76 7 97%
tests/test_tracing.py 48 0 2 0 100%
tests/test_urldispatch.py 859 12 102 1 98%
tests/test_web_app.py 453 4 56 0 99%
tests/test_web_cli.py 94 0 28 0 100%
tests/test_web_exceptions.py 179 0 38 0 100%
tests/test_web_functional.py 1605 28 206 3 98%
tests/test_web_log.py 132 2 16 0 99%
tests/test_web_middleware.py 284 3 54 2 99%
tests/test_web_request.py 513 0 34 0 100%
tests/test_web_request_handler.py 42 1 2 0 98%
tests/test_web_response.py 914 3 90 1 99%
tests/test_web_runner.py 151 9 32 0 94%
tests/test_web_sendfile.py 84 0 0 0 100%
tests/test_web_sendfile_functional.py 674 5 72 0 99%
tests/test_web_server.py 165 1 16 0 99%
tests/test_web_urldispatcher.py 524 2 82 1 99%
tests/test_web_websocket.py 444 2 82 0 99%
tests/test_web_websocket_functional.py 862 51 46 4 94%
tests/test_websocket_data_queue.py 23 0 6 0 100%
tests/test_websocket_handshake.py 152 0 26 0 100%
tests/test_websocket_parser.py 365 9 58 1 98%
tests/test_websocket_writer.py 97 0 16 0 100%
tests/test_worker.py 187 2 20 1 99%
---------------------------------------------------------------------------
TOTAL 36327 1056 8538 256 97%
============================= slowest 10 durations =============================
9.53s call tests/test_run_app.py::TestShutdown::test_shutdown_new_conn_rejected
4.01s call tests/test_run_app.py::TestShutdown::test_shutdown_pending_handler_responds
2.52s call tests/test_run_app.py::TestShutdown::test_shutdown_wait_for_handler
2.41s call tests/test_run_app.py::TestShutdown::test_shutdown_handler_cancellation_suppressed
2.02s call tests/test_client_functional.py::test_read_timeout_between_chunks[pyloop]
2.01s call tests/test_client_functional.py::test_set_cookies_max_age[pyloop]
1.82s call tests/test_pytest_plugin.py::test_aiohttp_plugin
1.62s call tests/test_run_app.py::TestShutdown::test_shutdown_timeout_handler
1.51s call tests/test_run_app.py::TestShutdown::test_shutdown_timeout_not_reached
1.40s call tests/test_circular_imports.py::test_no_warnings[aiohttp.pytest_plugin]
=========================== short test summary info ============================
SKIPPED [1] tests/test_connector.py:3054: Proactor Event loop present only in Windows
SKIPPED [1] tests/test_connector.py:3062: Proactor Event loop present only in Windows
SKIPPED [1] tests/test_connector.py:3073: Proactor Event loop present only in Windows
SKIPPED [1] tests/test_client_session.py:949: The check is applied in DEBUG mode only
SKIPPED [1] tests/test_connector.py:3271: Proactor Event loop present only in Windows
SKIPPED [1] tests/test_multipart_helpers.py:446: should raise decoding error: %82 is invalid for latin1
SKIPPED [1] tests/test_multipart_helpers.py:455: should raise decoding error: %E4 is invalid for utf-8
SKIPPED [1] tests/test_multipart_helpers.py:510: urllib.parse.unquote is tolerate to standalone % chars
SKIPPED [1] tests/test_multipart_helpers.py:519: urllib.parse.unquote is tolerate to standalone % chars
SKIPPED [1] tests/test_multipart_helpers.py:99: need more smart parser which respects quoted text
SKIPPED [1] tests/test_proxy_functional.py:386: we need to reconsider how we test this
SKIPPED [1] tests/test_proxy_functional.py:407: we need to reconsider how we test this
SKIPPED [1] tests/test_run_app.py:595: IPv6 is not available
SKIPPED [1] tests/test_resolver.py:404: aiodns <3.2.0 required
SKIPPED [1] tests/test_tcp_helpers.py:52: IPv6 is not available
SKIPPED [1] tests/test_proxy_functional.py:129: asyncio on this python supports TLS in TLS
SKIPPED [1] tests/test_web_app.py:365: The check is applied in DEBUG mode only
SKIPPED [1] tests/test_web_runner.py:121: Proactor Event loop present only in Windows
SKIPPED [1] tests/test_web_runner.py:133: Proactor Event loop present only in Windows
XFAIL tests/autobahn/test_autobahn.py::test_client
XFAIL tests/autobahn/test_autobahn.py::test_server
XFAIL tests/test_connector.py::test_del_with_scheduled_cleanup[pyloop]
XFAIL tests/test_client_functional.py::test_broken_connection[pyloop]
XFAIL tests/test_http_parser.py::test_parse_unusual_request_line[c-parser-pyloop] - Regression test for Py parser. May match C behaviour later.
XFAIL tests/test_http_parser.py::test_parse_uri_utf8[c-parser-pyloop] - reason: Not valid HTTP. Maybe update py-parser to reject later.
XFAIL tests/test_http_parser.py::test_http_request_parser_utf8_request_line[c-parser-pyloop] - Regression test for Py parser. May match C behaviour later.
XFAIL tests/test_web_functional.py::test_http10_keep_alive_default[pyloop]
ERROR tests/test_connector.py::test_tcp_connector_interleave[pyloop] - pytest...
ERROR tests/test_connector.py::test_tcp_connector_happy_eyeballs[pyloop-0.25]
ERROR tests/test_http_parser.py::test_http_request_parser_bad_method[py-parser-pyloop-;]
FAILED tests/test_connector.py::test_tcp_connector_happy_eyeballs[pyloop-None]
FAILED tests/test_connector.py::test_tcp_connector_happy_eyeballs[pyloop-0.1]
FAILED tests/test_connector.py::test_tcp_connector_happy_eyeballs[pyloop-0.25]
FAILED tests/test_test_utils.py::test_test_server_hostnames[::1-::1] - OSErro...
======= 4 failed, 3399 passed, 19 skipped, 8 xfailed, 3 errors in 57.44s =======
make: *** [Makefile:105: test] Error 1
Python Version
$ python --version
Python 3.13.0
aiohttp Version
$ python -m pip show aiohttp
Name: aiohttp
Version: 3.11.1
Summary: Async http client/server framework (asyncio)
Home-page: https://github.com/aio-libs/aiohttp
Author:
Author-email:
License: Apache 2
Location: aiohttp/.direnv/python-3.13/lib/python3.13/site-packages
Editable project location: aiohttp
Requires: aiohappyeyeballs, aiosignal, attrs, frozenlist, multidict, propcache, yarl
Required-by:
multidict Version
$ python -m pip show multidict
Name: multidict
Version: 6.1.0
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
Author-email: [email protected]
License: Apache 2
Location: aiohttp/.direnv/python-3.13/lib/python3.13/site-packages
Requires:
Required-by: aiohttp, yarl
propcache Version
$ python -m pip show propcache
Name: propcache
Version: 0.2.0
Summary: Accelerated property cache
Home-page: https://github.com/aio-libs/propcache
Author: Andrew Svetlov
Author-email: [email protected]
License: Apache-2.0
Location: aiohttp/.direnv/python-3.13/lib/python3.13/site-packages
Requires:
Required-by: aiohttp, yarl
yarl Version
$ python -m pip show yarl
Name: yarl
Version: 1.17.1
Summary: Yet another URL library
Home-page: https://github.com/aio-libs/yarl
Author: Andrew Svetlov
Author-email: [email protected]
License: Apache-2.0
Location: aiohttp/.direnv/python-3.13/lib/python3.13/site-packages
Requires: idna, multidict, propcache
Required-by: aiohttp
OS
NixOS
Related component
Server, Client
Additional context
No response
Code of Conduct
- I agree to follow the aio-libs Code of Conduct