Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pytest fails, cannot bind to address :7000 #26

Open
bertsky opened this issue May 2, 2023 · 0 comments
Open

pytest fails, cannot bind to address :7000 #26

bertsky opened this issue May 2, 2023 · 0 comments

Comments

@bertsky
Copy link
Member

bertsky commented May 2, 2023

In #25 I am running pytest from a container. I understand I cannot spawn new containers there. As pytest does not have CLI settings to remove entire files, I just rm the related files from the local copy of tests. The idea is to run at least native SSH tests and non-networking parts.

However, I get this result:

output

============================= test session starts ==============================
platform linux -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0 -- /usr/local/ocrd-monitor/.nox/pytest/bin/python
cachedir: .pytest_cache
rootdir: /usr/local/ocrd-monitor
configfile: pyproject.toml
plugins: anyio-3.6.2, asyncio-0.21.0, clarity-1.0.1
asyncio: mode=Mode.STRICT
collecting ... collected 53 items

tests/ocrdbrowser/test_launch.py::test__workspace__launch__spawns_new_ocrd_browser PASSED [  1%]
tests/ocrdbrowser/test_launch.py::test__workspace__launch_for_different_owners__both_processes_running PASSED [  3%]
tests/ocrdbrowser/test_launch.py::test__workspace__launch_for_same_owner_and_workspace__does_not_start_new_process PASSED [  5%]
tests/ocrdbrowser/test_websocketchannel.py::test__channel__losing_connection_while_communicating__raises_channel_closed[send] FAILED [  7%]
tests/ocrdbrowser/test_websocketchannel.py::test__channel__losing_connection_while_communicating__raises_channel_closed[receive] FAILED [  9%]
tests/ocrdbrowser/test_workspace.py::test__a_workspace_with_mets_xml_is_valid PASSED [ 11%]
tests/ocrdbrowser/test_workspace.py::test__a_nested_workspace__is_valid PASSED [ 13%]
tests/ocrdbrowser/test_workspace.py::test__a_workspace_without_mets_xml_is_invalid PASSED [ 15%]
tests/ocrdbrowser/test_workspace.py::test__list_workspaces__returns_valid_workspaces PASSED [ 16%]
tests/ocrdmonitor/test_jobs.py::test__parsing_a_ocrd_job_file_for_completed_job__returns_ocrdjob_with_a_return_code PASSED [ 18%]
tests/ocrdmonitor/test_jobs.py::test__parsing_a_ocrd_job_file_for_running_job__returns_ocrdjob_with_a_process_id PASSED [ 20%]
tests/ocrdmonitor/test_processstatus.py::test__parsing_psoutput__returns_list_of_process_status PASSED [ 22%]
tests/ocrdmonitor/test_processstatus.py::test__parsing_psoutput_with_error__returns_empty_list[] PASSED [ 24%]
tests/ocrdmonitor/test_processstatus.py::test__parsing_psoutput_with_error__returns_empty_list[error: list of session leaders OR effective group names must follow -g] PASSED [ 26%]
tests/ocrdmonitor/test_processstatus.py::test__parsing_psoutput_with_error__returns_empty_list[error: unknown user-defined format specifier] PASSED [ 28%]
tests/ocrdmonitor/test_readlogs.py::test__given_a_path__reads_logs[path0] PASSED [ 30%]
tests/ocrdmonitor/test_readlogs.py::test__given_a_path__reads_logs[path1] PASSED [ 32%]
tests/ocrdmonitor/test_readlogs.py::test__given_a_dir_path_with_log_file__has_logs_is_true PASSED [ 33%]
tests/ocrdmonitor/test_readlogs.py::test__given_a_dir_path_without_log_file__has_logs_is_false PASSED [ 35%]
tests/ocrdmonitor/test_readlogs.py::test__given_a_file_path__has_logs_is_true PASSED [ 37%]
tests/ocrdmonitor/test_redirect.py::test__redirect_for_empty_url_returns_server_address PASSED [ 39%]
tests/ocrdmonitor/test_redirect.py::test__redirect_to_file_in_workspace__returns_server_slash_file[file.js-http://example.com:8080] PASSED [ 41%]
tests/ocrdmonitor/test_redirect.py::test__redirect_to_file_in_workspace__returns_server_slash_file[file.js-http://example.com:8080/] PASSED [ 43%]
tests/ocrdmonitor/test_redirect.py::test__redirect_to_file_in_workspace__returns_server_slash_file[/file.js-http://example.com:8080] PASSED [ 45%]
tests/ocrdmonitor/test_redirect.py::test__redirect_to_file_in_workspace__returns_server_slash_file[/file.js-http://example.com:8080/] PASSED [ 47%]
tests/ocrdmonitor/test_redirect.py::test__redirect_from_workspace__returns_server_address PASSED [ 49%]
tests/ocrdmonitor/test_redirect.py::test__redirect_with_workspace__is_a_match PASSED [ 50%]
tests/ocrdmonitor/test_redirect.py::test__an_empty_path__does_not_match PASSED [ 52%]
tests/ocrdmonitor/test_redirect.py::test__a_path_starting_with_workspace__is_a_match PASSED [ 54%]
tests/ocrdmonitor/server/test_job_endpoint.py::test__given_a_completed_ocrd_job__the_job_endpoint_lists_it_in_a_table[0-SUCCESS] PASSED [ 56%]
tests/ocrdmonitor/server/test_job_endpoint.py::test__given_a_completed_ocrd_job__the_job_endpoint_lists_it_in_a_table[1-FAILURE] PASSED [ 58%]
tests/ocrdmonitor/server/test_job_endpoint.py::test__given_a_running_ocrd_job__the_job_endpoint_lists_it_with_resource_consumption PASSED [ 60%]
tests/ocrdmonitor/server/test_settings.py::test__can_parse_env PASSED    [ 62%]
tests/ocrdmonitor/server/test_settings.py::test__browser_settings__produces_matching_factory_for_selected_mode[native-SubProcessOcrdBrowserFactory] PASSED [ 64%]
tests/ocrdmonitor/server/test_settings.py::test__browser_settings__produces_matching_factory_for_selected_mode[docker-DockerOcrdBrowserFactory] PASSED [ 66%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__workspaces__shows_the_workspace_names_starting_from_workspace_root PASSED [ 67%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__passes_full_workspace_path_to_ocrdbrowser[BrowserSpy-BrowserSpy] PASSED [ 69%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__passes_full_workspace_path_to_ocrdbrowser[BrowserSpy-BrowserFake] PASSED [ 71%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__passes_full_workspace_path_to_ocrdbrowser[BrowserFake-BrowserSpy] PASSED [ 73%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__passes_full_workspace_path_to_ocrdbrowser[BrowserFake-BrowserFake] PASSED [ 75%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__assigns_and_tracks_session_id[BrowserSpy] PASSED [ 77%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browse_workspace__assigns_and_tracks_session_id[BrowserFake] PASSED [ 79%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__opened_workspace__when_socket_disconnects_on_broadway_side__shuts_down_browser[BrowserSpy] PASSED [ 81%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__opened_workspace__when_socket_disconnects_on_broadway_side__shuts_down_browser[BrowserFake] PASSED [ 83%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__starts_new_browser[BrowserSpy-BrowserSpy] PASSED [ 84%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__starts_new_browser[BrowserSpy-BrowserFake] PASSED [ 86%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__starts_new_browser[BrowserFake-BrowserSpy] FAILED [ 88%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__starts_new_browser[BrowserFake-BrowserFake] FAILED [ 90%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__viewing_proxies_requests_to_browser[BrowserSpy] PASSED [ 92%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__disconnected_workspace__when_opening_again__viewing_proxies_requests_to_browser[BrowserFake] FAILED [ 94%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browsed_workspace_is_ready__when_pinging__returns_ok[BrowserSpy] PASSED [ 96%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browsed_workspace_is_ready__when_pinging__returns_ok[BrowserFake] FAILED [ 98%]
tests/ocrdmonitor/server/test_workspace_endpoint.py::test__browsed_workspace_not_ready__when_pinging__returns_bad_gateway PASSED [100%]

=================================== FAILURES ===================================
_ test__channel__losing_connection_while_communicating__raises_channel_closed[send] _

comm_function = <function send at 0x7f567d46a340>

    @pytest.mark.asyncio
    @pytest.mark.integration
    @pytest.mark.parametrize("comm_function", [send, receive])
    async def test__channel__losing_connection_while_communicating__raises_channel_closed(
        comm_function: CommunicationFunction,
    ) -> None:
        server = broadway_fake("")
        await asyncio.to_thread(server.launch)
    
        sut = HttpBrowserClient("http://localhost:7000")
        with pytest.raises(ChannelClosed):
>           async with sut.open_channel() as channel:

tests/ocrdbrowser/test_websocketchannel.py:34: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
ocrdbrowser/_client.py:30: in __aenter__
    self._open_connection = await self._connection
.nox/pytest/lib/python3.11/site-packages/websockets/legacy/client.py:655: in __await_impl_timeout__
    return await self.__await_impl__()
.nox/pytest/lib/python3.11/site-packages/websockets/legacy/client.py:659: in __await_impl__
    _transport, _protocol = await self._create_connection()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_UnixSelectorEventLoop running=False closed=False debug=False>
protocol_factory = functools.partial(<class 'websockets.legacy.client.WebSocketClientProtocol'>, logger=None, origin=None, extensions=[<w...queue=32, read_limit=65536, write_limit=65536, host='localhost', port=7000, secure=False, legacy_recv=False, loop=None)
host = 'localhost', port = 7000

    async def create_connection(
            self, protocol_factory, host=None, port=None,
            *, ssl=None, family=0,
            proto=0, flags=0, sock=None,
            local_addr=None, server_hostname=None,
            ssl_handshake_timeout=None,
            ssl_shutdown_timeout=None,
            happy_eyeballs_delay=None, interleave=None):
        """Connect to a TCP server.
    
        Create a streaming transport connection to a given internet host and
        port: socket family AF_INET or socket.AF_INET6 depending on host (or
        family if specified), socket type SOCK_STREAM. protocol_factory must be
        a callable returning a protocol instance.
    
        This method is a coroutine which will try to establish the connection
        in the background.  When successful, the coroutine returns a
        (transport, protocol) pair.
        """
        if server_hostname is not None and not ssl:
            raise ValueError('server_hostname is only meaningful with ssl')
    
        if server_hostname is None and ssl:
            # Use host as default for server_hostname.  It is an error
            # if host is empty or not set, e.g. when an
            # already-connected socket was passed or when only a port
            # is given.  To avoid this error, you can pass
            # server_hostname='' -- this will bypass the hostname
            # check.  (This also means that if host is a numeric
            # IP/IPv6 address, we will attempt to verify that exact
            # address; this will probably fail, but it is possible to
            # create a certificate for a specific IP address, so we
            # don't judge it here.)
            if not host:
                raise ValueError('You must set server_hostname '
                                 'when using ssl without a host')
            server_hostname = host
    
        if ssl_handshake_timeout is not None and not ssl:
            raise ValueError(
                'ssl_handshake_timeout is only meaningful with ssl')
    
        if ssl_shutdown_timeout is not None and not ssl:
            raise ValueError(
                'ssl_shutdown_timeout is only meaningful with ssl')
    
        if sock is not None:
            _check_ssl_socket(sock)
    
        if happy_eyeballs_delay is not None and interleave is None:
            # If using happy eyeballs, default to interleave addresses by family
            interleave = 1
    
        if host is not None or port is not None:
            if sock is not None:
                raise ValueError(
                    'host/port and sock can not be specified at the same time')
    
            infos = await self._ensure_resolved(
                (host, port), family=family,
                type=socket.SOCK_STREAM, proto=proto, flags=flags, loop=self)
            if not infos:
                raise OSError('getaddrinfo() returned empty list')
    
            if local_addr is not None:
                laddr_infos = await self._ensure_resolved(
                    local_addr, family=family,
                    type=socket.SOCK_STREAM, proto=proto,
                    flags=flags, loop=self)
               if not laddr_infos:
                    raise OSError('getaddrinfo() returned empty list')
            else:
                laddr_infos = None
    
            if interleave:
                infos = _interleave_addrinfos(infos, interleave)
    
            exceptions = []
            if happy_eyeballs_delay is None:
                # not using happy eyeballs
                for addrinfo in infos:
                    try:
                        sock = await self._connect_sock(
                            exceptions, addrinfo, laddr_infos)
                        break
                    except OSError:
                        continue
            else:  # using happy eyeballs
                sock, _, _ = await staggered.staggered_race(
                    (functools.partial(self._connect_sock,
                                       exceptions, addrinfo, laddr_infos)
                     for addrinfo in infos),
                    happy_eyeballs_delay, loop=self)
    
            if sock is None:
                exceptions = [exc for sub in exceptions for exc in sub]
                try:
                    if len(exceptions) == 1:
                        raise exceptions[0]
                    else:
                        # If they all have the same str(), raise one.
                        model = str(exceptions[0])
                        if all(str(exc) == model for exc in exceptions):
                            raise exceptions[0]
                        # Raise a combined exception so the user can see all
                        # the various error messages.
>                       raise OSError('Multiple exceptions: {}'.format(
                            ', '.join(str(exc) for exc in exceptions)))
E                           OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 7000), [Errno 99] Cannot assign requested address

../lib/python3.11/asyncio/base_events.py:1093: OSError
----------------------------- Captured stderr call -----------------------------
INFO:     Started server process [78]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
ERROR:    [Errno 99] error while attempting to bind on address ('::1', 7000, 0, 0): cannot assign requested address
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
_ test__channel__losing_connection_while_communicating__raises_channel_closed[receive] _

comm_function = <function receive at 0x7f567d46a3e0>

    @pytest.mark.asyncio
    @pytest.mark.integration
    @pytest.mark.parametrize("comm_function", [send, receive])
    async def test__channel__losing_connection_while_communicating__raises_channel_closed(
        comm_function: CommunicationFunction,
    ) -> None:
        server = broadway_fake("")
        await asyncio.to_thread(server.launch)
    
        sut = HttpBrowserClient("http://localhost:7000")
        with pytest.raises(ChannelClosed):
>           async with sut.open_channel() as channel:

tests/ocrdbrowser/test_websocketchannel.py:34: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
ocrdbrowser/_client.py:30: in __aenter__
    self._open_connection = await self._connection
.nox/pytest/lib/python3.11/site-packages/websockets/legacy/client.py:655: in __await_impl_timeout__
    return await self.__await_impl__()
.nox/pytest/lib/python3.11/site-packages/websockets/legacy/client.py:659: in __await_impl__
    _transport, _protocol = await self._create_connection()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_UnixSelectorEventLoop running=False closed=False debug=False>
protocol_factory = functools.partial(<class 'websockets.legacy.client.WebSocketClientProtocol'>, logger=None, origin=None, extensions=[<w...queue=32, read_limit=65536, write_limit=65536, host='localhost', port=7000, secure=False, legacy_recv=False, loop=None)
host = 'localhost', port = 7000

    async def create_connection(
            self, protocol_factory, host=None, port=None,
            *, ssl=None, family=0,
            proto=0, flags=0, sock=None,
            local_addr=None, server_hostname=None,
            ssl_handshake_timeout=None,
            ssl_shutdown_timeout=None,
            happy_eyeballs_delay=None, interleave=None):
        """Connect to a TCP server.
    
        Create a streaming transport connection to a given internet host and
        port: socket family AF_INET or socket.AF_INET6 depending on host (or
        family if specified), socket type SOCK_STREAM. protocol_factory must be
        a callable returning a protocol instance.
    
        This method is a coroutine which will try to establish the connection
        in the background.  When successful, the coroutine returns a
        (transport, protocol) pair.
        """
        if server_hostname is not None and not ssl:
            raise ValueError('server_hostname is only meaningful with ssl')
    
        if server_hostname is None and ssl:
            # Use host as default for server_hostname.  It is an error
            # if host is empty or not set, e.g. when an
            # already-connected socket was passed or when only a port
            # is given.  To avoid this error, you can pass
            # server_hostname='' -- this will bypass the hostname
            # check.  (This also means that if host is a numeric
            # IP/IPv6 address, we will attempt to verify that exact
            # address; this will probably fail, but it is possible to
            # create a certificate for a specific IP address, so we
            # don't judge it here.)
            if not host:
                raise ValueError('You must set server_hostname '
                                 'when using ssl without a host')
            server_hostname = host
    
        if ssl_handshake_timeout is not None and not ssl:
            raise ValueError(
                'ssl_handshake_timeout is only meaningful with ssl')
    
        if ssl_shutdown_timeout is not None and not ssl:
            raise ValueError(
                'ssl_shutdown_timeout is only meaningful with ssl')
    
        if sock is not None:
            _check_ssl_socket(sock)
    
        if happy_eyeballs_delay is not None and interleave is None:
            # If using happy eyeballs, default to interleave addresses by family
            interleave = 1
    
        if host is not None or port is not None:
            if sock is not None:
                raise ValueError(
                    'host/port and sock can not be specified at the same time')
   
            infos = await self._ensure_resolved(
                (host, port), family=family,
                type=socket.SOCK_STREAM, proto=proto, flags=flags, loop=self)
            if not infos:
                raise OSError('getaddrinfo() returned empty list')
    
            if local_addr is not None:
                laddr_infos = await self._ensure_resolved(
                    local_addr, family=family,
                    type=socket.SOCK_STREAM, proto=proto,
                    flags=flags, loop=self)
                if not laddr_infos:
                    raise OSError('getaddrinfo() returned empty list')
            else:
                laddr_infos = None
    
            if interleave:
                infos = _interleave_addrinfos(infos, interleave)
    
            exceptions = []
            if happy_eyeballs_delay is None:
                # not using happy eyeballs
                for addrinfo in infos:
                    try:
                        sock = await self._connect_sock(
                            exceptions, addrinfo, laddr_infos)
                        break
                    except OSError:
                        continue
            else:  # using happy eyeballs
                sock, _, _ = await staggered.staggered_race(
                    (functools.partial(self._connect_sock,
                                       exceptions, addrinfo, laddr_infos)
                     for addrinfo in infos),
                    happy_eyeballs_delay, loop=self)
    
            if sock is None:
                exceptions = [exc for sub in exceptions for exc in sub]
                try:
                    if len(exceptions) == 1:
                        raise exceptions[0]
                    else:
                        # If they all have the same str(), raise one.
                        model = str(exceptions[0])
                        if all(str(exc) == model for exc in exceptions):
                            raise exceptions[0]
                        # Raise a combined exception so the user can see all
                        # the various error messages.
>                       raise OSError('Multiple exceptions: {}'.format(
                            ', '.join(str(exc) for exc in exceptions)))
E                           OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 7000), [Errno 99] Cannot assign requested address

../lib/python3.11/asyncio/base_events.py:1093: OSError
----------------------------- Captured stderr call -----------------------------
INFO:     Started server process [82]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
ERROR:    [Errno 99] error while attempting to bind on address ('::1', 7000, 0, 0): cannot assign requested address
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
_ test__disconnected_workspace__when_opening_again__starts_new_browser[BrowserFake-BrowserSpy] _
anyio._backends._asyncio.ExceptionGroup: 2 exceptions were raised in the task group:
----------------------------
Traceback (most recent call last):
  File "/usr/local/ocrd-monitor/.nox/pytest/lib/python3.11/site-packages/anyio/_core/_sockets.py", line 164, in try_connect
    stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/ocrd-monitor/.nox/pytest/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 1691, in connect_tcp
    await get_running_loop().create_connection(
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1085, in create_connection
    raise exceptions[0]
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1069, in create_connection
    sock = await self._connect_sock(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 973, in _connect_sock
    await self.sock_connect(sock, address)
  File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 634, in sock_connect
    return await fut
           ^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 642, in _sock_connect
    sock.connect(address)
OSError: [Errno 99] Cannot assign requested address
----------------------------
Traceback (most recent call last):
  File "/usr/local/ocrd-monitor/.nox/pytest/lib/python3.11/site-packages/anyio/_core/_sockets.py", line 164, in try_connect
    stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/ocrd-monitor/.nox/pytest/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 1691, in connect_tcp
    await get_running_loop().create_connection(
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1085, in create_connection
    raise exceptions[0]
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1069, in create_connection
    sock = await self._connect_sock(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 973, in _connect_sock
    await self.sock_connect(sock, address)
  File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 634, in sock_connect
    return await fut
           ^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 674, in _sock_connect_cb
    raise OSError(err, f'Connect call failed {address}')
ConnectionRefusedError: [Errno 111] Connect call failed ('127.0.0.1', 7000)

The above exception was the direct cause of the following exception:

map = {<class 'TimeoutError'>: <class 'httpcore.ConnectTimeout'>, <class 'OSError'>: <class 'httpcore.ConnectError'>, <class 'anyio.BrokenResourceError'>: <class 'httpcore.ConnectError'>}

    @contextlib.contextmanager
    def map_exceptions(map: ExceptionMapping) -> Iterator[None]:
        try:
>           yield

.nox/pytest/lib/python3.11/site-packages/httpcore/_exceptions.py:10: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpcore.backends.asyncio.AsyncIOBackend object at 0x7f567c925850>
host = 'localhost', port = 7000, timeout = 5.0, local_address = None

    async def connect_tcp(
        self,
        host: str,
        port: int,
        timeout: typing.Optional[float] = None,
        local_address: typing.Optional[str] = None,
    ) -> AsyncNetworkStream:
        exc_map = {
            TimeoutError: ConnectTimeout,
            OSError: ConnectError,
            anyio.BrokenResourceError: ConnectError,
        }
        with map_exceptions(exc_map):
            with anyio.fail_after(timeout):
>               stream: anyio.abc.ByteStream = await anyio.connect_tcp(
                    remote_host=host,
                    remote_port=port,
                    local_host=local_address,
                )

.nox/pytest/lib/python3.11/site-packages/httpcore/backends/asyncio.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

remote_host = 'localhost', remote_port = 7000

    async def connect_tcp(
        remote_host: IPAddressType,
        remote_port: int,
        *,
        local_host: Optional[IPAddressType] = None,
        tls: bool = False,
        ssl_context: Optional[ssl.SSLContext] = None,
        tls_standard_compatible: bool = True,
        tls_hostname: Optional[str] = None,
        happy_eyeballs_delay: float = 0.25,
    ) -> Union[SocketStream, TLSStream]:
        """
        Connect to a host using the TCP protocol.
    
        This function implements the stateless version of the Happy Eyeballs algorithm (RFC 6555).
        If ``address`` is a host name that resolves to multiple IP addresses, each one is tried until
        one connection attempt succeeds. If the first attempt does not connected within 250
        milliseconds, a second attempt is started using the next address in the list, and so on.
        On IPv6 enabled systems, an IPv6 address (if available) is tried first.
    
        When the connection has been established, a TLS handshake will be done if either
        ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``.
    
        :param remote_host: the IP address or host name to connect to
        :param remote_port: port on the target host to connect to
        :param local_host: the interface address or name to bind the socket to before connecting
        :param tls: ``True`` to do a TLS handshake with the connected stream and return a
            :class:`~anyio.streams.tls.TLSStream` instead
        :param ssl_context: the SSL context object to use (if omitted, a default context is created)
        :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake before closing
            the stream and requires that the server does this as well. Otherwise,
            :exc:`~ssl.SSLEOFError` may be raised during reads from the stream.
            Some protocols, such as HTTP, require this option to be ``False``.
            See :meth:`~ssl.SSLContext.wrap_socket` for details.
        :param tls_hostname: host name to check the server certificate against (defaults to the value
            of ``remote_host``)
        :param happy_eyeballs_delay: delay (in seconds) before starting the next connection attempt
        :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream
        :raises OSError: if the connection attempt fails
    
        """
        # Placed here due to https://github.com/python/mypy/issues/7057
        connected_stream: Optional[SocketStream] = None
    
        async def try_connect(remote_host: str, event: Event) -> None:
            nonlocal connected_stream
            try:
                stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
            except OSError as exc:
                oserrors.append(exc)
                return
            else:
                if connected_stream is None:
                    connected_stream = stream
                    tg.cancel_scope.cancel()
                else:
                    await stream.aclose()
            finally:
                event.set()
    
        asynclib = get_asynclib()
        local_address: Optional[IPSockAddrType] = None
        family = socket.AF_UNSPEC
        if local_host:
            gai_res = await getaddrinfo(str(local_host), None)
            family, *_, local_address = gai_res[0]
    
        target_host = str(remote_host)
        try:
            addr_obj = ip_address(remote_host)
        except ValueError:
            # getaddrinfo() will raise an exception if name resolution fails
            gai_res = await getaddrinfo(
                target_host, remote_port, family=family, type=socket.SOCK_STREAM
            )
    
            # Organize the list so that the first address is an IPv6 address (if available) and the
            # second one is an IPv4 addresses. The rest can be in whatever order.
            v6_found = v4_found = False
            target_addrs: List[Tuple[socket.AddressFamily, str]] = []
            for af, *rest, sa in gai_res:
                if af == socket.AF_INET6 and not v6_found:
                    v6_found = True
                    target_addrs.insert(0, (af, sa[0]))
                elif af == socket.AF_INET and not v4_found and v6_found:
                    v4_found = True
                    target_addrs.insert(1, (af, sa[0]))
                else:
                    target_addrs.append((af, sa[0]))
        else:
            if isinstance(addr_obj, IPv6Address):
                target_addrs = [(socket.AF_INET6, addr_obj.compressed)]
            else:
                target_addrs = [(socket.AF_INET, addr_obj.compressed)]
    
        oserrors: List[OSError] = []
        async with create_task_group() as tg:
            for i, (af, addr) in enumerate(target_addrs):
                event = Event()
                tg.start_soon(try_connect, addr, event)
                with move_on_after(happy_eyeballs_delay):
                    await event.wait()
    
        if connected_stream is None:
            cause = oserrors[0] if len(oserrors) == 1 else asynclib.ExceptionGroup(oserrors)
>           raise OSError("All connection attempts failed") from cause
E           OSError: All connection attempts failed

.nox/pytest/lib/python3.11/site-packages/anyio/_core/_sockets.py:222: OSError

During handling of the above exception, another exception occurred:

    @contextlib.contextmanager
    def map_httpcore_exceptions() -> typing.Iterator[None]:
        try:
>           yield

.nox/pytest/lib/python3.11/site-packages/httpx/_transports/default.py:60: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
...

@bertsky bertsky linked a pull request Jun 20, 2023 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant