miketheman / pytest-socket

Pytest Plugin to disable socket calls during tests

Home Page:https://pypi.org/project/pytest-socket/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

0.7.0: test suite fails

kloczek opened this issue · comments

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix> using 'installer` module
  • run pytest with $PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>
  • build is performed in env which is cut off from access to the public network (pytest is executed with -m "not network")
Here is pytest output:
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-socket-0.7.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-socket-0.7.0-2.fc35
.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra -m 'not network'
============================= test session starts ==============================
platform linux -- Python 3.8.18, pytest-8.0.0, pluggy-1.3.0
rootdir: /home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0
plugins: socket-0.7.0, anyio-4.2.0, httpbin-2.0.0
collected 31 items / 3 errors

==================================== ERRORS ====================================
_____________________ ERROR collecting tests/test_async.py _____________________
ImportError while importing test module '/home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0/tests/test_async.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.8/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_async.py:2: in <module>
    from tests.common import assert_socket_blocked
E   ModuleNotFoundError: No module named 'tests'
__________________ ERROR collecting tests/test_precedence.py ___________________
ImportError while importing test module '/home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0/tests/test_precedence.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.8/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_precedence.py:4: in <module>
    from tests.common import assert_socket_blocked
E   ModuleNotFoundError: No module named 'tests'
____________________ ERROR collecting tests/test_socket.py _____________________
ImportError while importing test module '/home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0/tests/test_socket.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.8/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_socket.py:4: in <module>
    from tests.common import assert_socket_blocked
E   ModuleNotFoundError: No module named 'tests'
=========================== short test summary info ============================
ERROR tests/test_async.py
ERROR tests/test_precedence.py
ERROR tests/test_socket.py
!!!!!!!!!!!!!!!!!!! Interrupted: 3 errors during collection !!!!!!!!!!!!!!!!!!!!
============================== 3 errors in 0.14s ===============================
List of installed modules in build env:
Package                   Version
------------------------- ---------
anyio                     4.2.0
asynctest                 0.13.0
attrs                     23.2.0
blinker                   1.6.2
Brotli                    1.1.0
build                     1.0.3
certifi                   2023.7.22
charset-normalizer        3.3.2
click                     8.1.7
cppclean                  0.13
decorator                 5.1.1
distro                    1.9.0
dnf                       4.19.0
exceptiongroup            1.1.3
flasgger                  0.9.7.1
Flask                     3.0.2
gpg                       1.23.2
greenlet                  3.0.3
h11                       0.14.0
httpbin                   0.10.1
httpcore                  1.0.0
httpx                     0.25.2
idna                      3.6
importlib_metadata        7.0.1
importlib_resources       6.1.1
iniconfig                 2.0.0
installer                 0.7.0
itsdangerous              2.1.2
Jinja2                    3.1.3
jsonschema                4.19.1
jsonschema-specifications 2023.7.1
libdnf                    0.73.0
MarkupSafe                2.1.3
mistune                   2.0.5
packaging                 23.2
pkgutil_resolve_name      1.3.10
pluggy                    1.3.0
poetry-core               1.9.0
pyproject_hooks           1.0.0
pytest                    8.0.0
pytest-httpbin            2.0.0
python-dateutil           2.8.2
PyYAML                    6.0.1
referencing               0.30.2
requests                  2.31.0
rpds-py                   0.18.0
six                       1.16.0
sniffio                   1.3.0
starlette                 0.37.1
tomli                     2.0.1
typing_extensions         4.9.0
urllib3                   1.26.18
Werkzeug                  3.0.1
wheel                     0.42.0
zipp                      3.17.0

Please let me know if you need more details or want me to perform some diagnostics.

After apply #309 pytest passes scanning unit and ..

still fails in one unit with
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-socket-0.7.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-socket-0.7.0-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra -m 'not network'
============================= test session starts ==============================
platform linux -- Python 3.8.18, pytest-8.0.0, pluggy-1.3.0
rootdir: /home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0
plugins: socket-0.7.0, anyio-4.2.0, httpbin-2.0.0
collected 65 items

tests/test_async.py .F                                                   [  3%]
tests/test_combinations.py ..                                            [  6%]
tests/test_doctest.py .                                                  [  7%]
tests/test_precedence.py ..........                                      [ 23%]
tests/test_restrict_hosts.py ............................                [ 66%]
tests/test_socket.py ......................                              [100%]

=================================== FAILURES ===================================
_______________________________ test_httpx_fails _______________________________

testdir = <Testdir local('/tmp/pytest-of-tkloczko/pytest-148/test_httpx_fails0')>

    @unix_sockets_only
    def test_httpx_fails(testdir):
        testdir.makepyfile(
            """
            import pytest
            import httpx


            @pytest.fixture(autouse=True)
            def anyio_backend():
                return "asyncio"

            async def test_httpx():
                async with httpx.AsyncClient() as client:
                    await client.get("http://www.example.com/")
            """
        )
        result = testdir.runpytest("--disable-socket", "--allow-unix-socket")
>       assert_socket_blocked(result)

/home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0/tests/test_async.py:53:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

result = <RunResult ret=ExitCode.TESTS_FAILED len(stdout.lines)=155 len(stderr.lines)=0 duration=0.50s>
passed = 0, skipped = 0, failed = 1

    def assert_socket_blocked(result, passed=0, skipped=0, failed=1):
        """
        Uses built in methods to test for common failure scenarios.
        Usually we only test for a single failure,
        but sometimes we want to test for multiple conditions,
        so we can pass in the expected counts.
        """
        result.assert_outcomes(passed=passed, skipped=skipped, failed=failed)
>       result.stdout.fnmatch_lines(
            "*Socket*Blocked*Error: A test tried to use socket.socket.*"
        )
E       Failed: nomatch: '*Socket*Blocked*Error: A test tried to use socket.socket.*'
E           and: '============================= test session starts =============================='
E           and: 'platform linux -- Python 3.8.18, pytest-8.0.0, pluggy-1.3.0'
E           and: 'rootdir: /tmp/pytest-of-tkloczko/pytest-148/test_httpx_fails0'
E           and: 'plugins: socket-0.7.0, anyio-4.2.0, httpbin-2.0.0'
E           and: 'collected 1 item'
E           and: ''
E           and: 'test_httpx_fails.py F                                                    [100%]'
E           and: ''
E           and: '=================================== FAILURES ==================================='
E           and: '__________________________________ test_httpx __________________________________'
E           and: ''
E           and: "map = {<class 'TimeoutError'>: <class 'httpcore.ConnectTimeout'>, <class 'OSError'>: <class 'httpcore.ConnectError'>, <class 'anyio.BrokenResourceError'>: <class 'httpcore.ConnectError'>}"
E           and: ''
E           and: '    @contextlib.contextmanager'
E           and: '    def map_exceptions(map: ExceptionMapping) -> Iterator[None]:'
E           and: '        try:'
E           and: '>           yield'
E           and: ''
E           and: '/usr/lib/python3.8/site-packages/httpcore/_exceptions.py:10: '
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: '/usr/lib/python3.8/site-packages/httpcore/_backends/anyio.py:114: in connect_tcp'
E           and: '    stream: anyio.abc.ByteStream = await anyio.connect_tcp('
E           and: '/usr/lib/python3.8/site-packages/anyio/_core/_sockets.py:195: in connect_tcp'
E           and: '    gai_res = await getaddrinfo('
E           and: '/usr/lib/python3.8/site-packages/anyio/_core/_sockets.py:573: in getaddrinfo'
E           and: '    gai_res = await get_async_backend().getaddrinfo('
E           and: '/usr/lib/python3.8/site-packages/anyio/_backends/_asyncio.py:2360: in getaddrinfo'
E           and: '    return await get_running_loop().getaddrinfo('
E           and: '/usr/lib64/python3.8/asyncio/base_events.py:825: in getaddrinfo'
E           and: '    return await self.run_in_executor('
E           and: '/usr/lib64/python3.8/concurrent/futures/thread.py:57: in run'
E           and: '    result = self.fn(*self.args, **self.kwargs)'
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: ''
E           and: "host = b'www.example.com', port = 80, family = <AddressFamily.AF_UNSPEC: 0>"
E           and: 'type = <SocketKind.SOCK_STREAM: 1>, proto = 0, flags = 0'
E           and: ''
E           and: '    def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):'
E           and: '        """Resolve host and port into list of address info entries.'
E           and: '    '
E           and: '        Translate the host/port argument into a sequence of 5-tuples that contain'
E           and: '        all the necessary arguments for creating a socket connected to that service.'
E           and: '        host is a domain name, a string representation of an IPv4/v6 address or'
E           and: "        None. port is a string service name such as 'http', a numeric port number or"
E           and: '        None. By passing None as the value of host and port, you can pass NULL to'
E           and: '        the underlying C API.'
E           and: '    '
E           and: '        The family, type and proto arguments can be optionally specified in order to'
E           and: '        narrow the list of addresses returned. Passing zero as a value for each of'
E           and: '        these arguments selects the full range of results.'
E           and: '        """'
E           and: '        # We override this function since we want to translate the numeric family'
E           and: '        # and socket type values to enum constants.'
E           and: '        addrlist = []'
E           and: '>       for res in _socket.getaddrinfo(host, port, family, type, proto, flags):'
E           and: 'E       socket.gaierror: [Errno -2] Name or service not known'
E           and: ''
E           and: '/usr/lib64/python3.8/socket.py:918: gaierror'
E           and: ''
E           and: 'The above exception was the direct cause of the following exception:'
E           and: ''
E           and: '    @contextlib.contextmanager'
E           and: '    def map_httpcore_exceptions() -> typing.Iterator[None]:'
E           and: '        try:'
E           and: '>           yield'
E           and: ''
E           and: '/usr/lib/python3.8/site-packages/httpx/_transports/default.py:66: '
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: '/usr/lib/python3.8/site-packages/httpx/_transports/default.py:366: in handle_async_request'
E           and: '    resp = await self._pool.handle_async_request(req)'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_async/connection_pool.py:262: in handle_async_request'
E           and: '    raise exc'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_async/connection_pool.py:245: in handle_async_request'
E           and: '    response = await connection.handle_async_request(request)'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:99: in handle_async_request'
E           and: '    raise exc'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:76: in handle_async_request'
E           and: '    stream = await self._connect(request)'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:124: in _connect'
E           and: '    stream = await self._network_backend.connect_tcp(**kwargs)'
E           and: '/usr/lib/python3.8/site-packages/httpcore/_backends/auto.py:30: in connect_tcp'
E           and: '    return await self._backend.connect_tcp('
E           and: '/usr/lib/python3.8/site-packages/httpcore/_backends/anyio.py:121: in connect_tcp'
E           and: '    stream._raw_socket.setsockopt(*option)  # type: ignore[attr-defined] # pragma: no cover'
E           and: '/usr/lib64/python3.8/contextlib.py:131: in __exit__'
E           and: '    self.gen.throw(type, value, traceback)'
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: ''
E           and: "map = {<class 'TimeoutError'>: <class 'httpcore.ConnectTimeout'>, <class 'OSError'>: <class 'httpcore.ConnectError'>, <class 'anyio.BrokenResourceError'>: <class 'httpcore.ConnectError'>}"
E           and: ''
E           and: '    @contextlib.contextmanager'
E           and: '    def map_exceptions(map: ExceptionMapping) -> Iterator[None]:'
E           and: '        try:'
E           and: '            yield'
E           and: '        except Exception as exc:  # noqa: PIE786'
E           and: '            for from_exc, to_exc in map.items():'
E           and: '                if isinstance(exc, from_exc):'
E           and: '>                   raise to_exc(exc) from exc'
E           and: 'E                   httpcore.ConnectError: [Errno -2] Name or service not known'
E           and: ''
E           and: '/usr/lib/python3.8/site-packages/httpcore/_exceptions.py:14: ConnectError'
E           and: ''
E           and: 'The above exception was the direct cause of the following exception:'
E           and: ''
E           and: '    async def test_httpx():'
E           and: '        async with httpx.AsyncClient() as client:'
E           and: '>           await client.get("http://www.example.com/")'
E           and: ''
E           and: 'test_httpx_fails.py:11: '
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1757: in get'
E           and: '    return await self.request('
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1530: in request'
E           and: '    return await self.send(request, auth=auth, follow_redirects=follow_redirects)'
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1617: in send'
E           and: '    response = await self._send_handling_auth('
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1645: in _send_handling_auth'
E           and: '    response = await self._send_handling_redirects('
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1682: in _send_handling_redirects'
E           and: '    response = await self._send_single_request(request)'
E           and: '/usr/lib/python3.8/site-packages/httpx/_client.py:1719: in _send_single_request'
E           and: '    response = await transport.handle_async_request(request)'
E           and: '/usr/lib/python3.8/site-packages/httpx/_transports/default.py:366: in handle_async_request'
E           and: '    resp = await self._pool.handle_async_request(req)'
E           and: '/usr/lib64/python3.8/contextlib.py:131: in __exit__'
E           and: '    self.gen.throw(type, value, traceback)'
E           and: '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ '
E           and: ''
E           and: '    @contextlib.contextmanager'
E           and: '    def map_httpcore_exceptions() -> typing.Iterator[None]:'
E           and: '        try:'
E           and: '            yield'
E           and: '        except Exception as exc:'
E           and: '            mapped_exc = None'
E           and: '    '
E           and: '            for from_exc, to_exc in HTTPCORE_EXC_MAP.items():'
E           and: '                if not isinstance(exc, from_exc):'
E           and: '                    continue'
E           and: '                # We want to map to the most specific exception we can find.'
E           and: '                # Eg if `exc` is an `httpcore.ReadTimeout`, we want to map to'
E           and: '                # `httpx.ReadTimeout`, not just `httpx.TimeoutException`.'
E           and: '                if mapped_exc is None or issubclass(to_exc, mapped_exc):'
E           and: '                    mapped_exc = to_exc'
E           and: '    '
E           and: '            if mapped_exc is None:  # pragma: no cover'
E           and: '                raise'
E           and: '    '
E           and: '            message = str(exc)'
E           and: '>           raise mapped_exc(message) from exc'
E           and: 'E           httpx.ConnectError: [Errno -2] Name or service not known'
E           and: ''
E           and: '/usr/lib/python3.8/site-packages/httpx/_transports/default.py:83: ConnectError'
E           and: '=========================== short test summary info ============================'
E           and: 'FAILED test_httpx_fails.py::test_httpx - httpx.ConnectError: [Errno -2] Name ...'
E           and: '============================== 1 failed in 0.42s ==============================='
E       remains unmatched: '*Socket*Blocked*Error: A test tried to use socket.socket.*'

/home/tkloczko/rpmbuild/BUILD/pytest-socket-0.7.0/tests/common.py:14: Failed
----------------------------- Captured stdout call -----------------------------
============================= test session starts ==============================
platform linux -- Python 3.8.18, pytest-8.0.0, pluggy-1.3.0
rootdir: /tmp/pytest-of-tkloczko/pytest-148/test_httpx_fails0
plugins: socket-0.7.0, anyio-4.2.0, httpbin-2.0.0
collected 1 item

test_httpx_fails.py F                                                    [100%]

=================================== FAILURES ===================================
__________________________________ test_httpx __________________________________

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

/usr/lib/python3.8/site-packages/httpcore/_exceptions.py:10:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.8/site-packages/httpcore/_backends/anyio.py:114: in connect_tcp
    stream: anyio.abc.ByteStream = await anyio.connect_tcp(
/usr/lib/python3.8/site-packages/anyio/_core/_sockets.py:195: in connect_tcp
    gai_res = await getaddrinfo(
/usr/lib/python3.8/site-packages/anyio/_core/_sockets.py:573: in getaddrinfo
    gai_res = await get_async_backend().getaddrinfo(
/usr/lib/python3.8/site-packages/anyio/_backends/_asyncio.py:2360: in getaddrinfo
    return await get_running_loop().getaddrinfo(
/usr/lib64/python3.8/asyncio/base_events.py:825: in getaddrinfo
    return await self.run_in_executor(
/usr/lib64/python3.8/concurrent/futures/thread.py:57: in run
    result = self.fn(*self.args, **self.kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

host = b'www.example.com', port = 80, family = <AddressFamily.AF_UNSPEC: 0>
type = <SocketKind.SOCK_STREAM: 1>, proto = 0, flags = 0

    def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
        """Resolve host and port into list of address info entries.

        Translate the host/port argument into a sequence of 5-tuples that contain
        all the necessary arguments for creating a socket connected to that service.
        host is a domain name, a string representation of an IPv4/v6 address or
        None. port is a string service name such as 'http', a numeric port number or
        None. By passing None as the value of host and port, you can pass NULL to
        the underlying C API.

        The family, type and proto arguments can be optionally specified in order to
        narrow the list of addresses returned. Passing zero as a value for each of
        these arguments selects the full range of results.
        """
        # We override this function since we want to translate the numeric family
        # and socket type values to enum constants.
        addrlist = []
>       for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
E       socket.gaierror: [Errno -2] Name or service not known

/usr/lib64/python3.8/socket.py:918: gaierror

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

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

/usr/lib/python3.8/site-packages/httpx/_transports/default.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.8/site-packages/httpx/_transports/default.py:366: in handle_async_request
    resp = await self._pool.handle_async_request(req)
/usr/lib/python3.8/site-packages/httpcore/_async/connection_pool.py:262: in handle_async_request
    raise exc
/usr/lib/python3.8/site-packages/httpcore/_async/connection_pool.py:245: in handle_async_request
    response = await connection.handle_async_request(request)
/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:99: in handle_async_request
    raise exc
/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:76: in handle_async_request
    stream = await self._connect(request)
/usr/lib/python3.8/site-packages/httpcore/_async/connection.py:124: in _connect
    stream = await self._network_backend.connect_tcp(**kwargs)
/usr/lib/python3.8/site-packages/httpcore/_backends/auto.py:30: in connect_tcp
    return await self._backend.connect_tcp(
/usr/lib/python3.8/site-packages/httpcore/_backends/anyio.py:121: in connect_tcp
    stream._raw_socket.setsockopt(*option)  # type: ignore[attr-defined] # pragma: no cover
/usr/lib64/python3.8/contextlib.py:131: in __exit__
    self.gen.throw(type, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

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
        except Exception as exc:  # noqa: PIE786
            for from_exc, to_exc in map.items():
                if isinstance(exc, from_exc):
>                   raise to_exc(exc) from exc
E                   httpcore.ConnectError: [Errno -2] Name or service not known

/usr/lib/python3.8/site-packages/httpcore/_exceptions.py:14: ConnectError

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

    async def test_httpx():
        async with httpx.AsyncClient() as client:
>           await client.get("http://www.example.com/")

test_httpx_fails.py:11:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.8/site-packages/httpx/_client.py:1757: in get
    return await self.request(
/usr/lib/python3.8/site-packages/httpx/_client.py:1530: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/usr/lib/python3.8/site-packages/httpx/_client.py:1617: in send
    response = await self._send_handling_auth(
/usr/lib/python3.8/site-packages/httpx/_client.py:1645: in _send_handling_auth
    response = await self._send_handling_redirects(
/usr/lib/python3.8/site-packages/httpx/_client.py:1682: in _send_handling_redirects
    response = await self._send_single_request(request)
/usr/lib/python3.8/site-packages/httpx/_client.py:1719: in _send_single_request
    response = await transport.handle_async_request(request)
/usr/lib/python3.8/site-packages/httpx/_transports/default.py:366: in handle_async_request
    resp = await self._pool.handle_async_request(req)
/usr/lib64/python3.8/contextlib.py:131: in __exit__
    self.gen.throw(type, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    @contextlib.contextmanager
    def map_httpcore_exceptions() -> typing.Iterator[None]:
        try:
            yield
        except Exception as exc:
            mapped_exc = None

            for from_exc, to_exc in HTTPCORE_EXC_MAP.items():
                if not isinstance(exc, from_exc):
                    continue
                # We want to map to the most specific exception we can find.
                # Eg if `exc` is an `httpcore.ReadTimeout`, we want to map to
                # `httpx.ReadTimeout`, not just `httpx.TimeoutException`.
                if mapped_exc is None or issubclass(to_exc, mapped_exc):
                    mapped_exc = to_exc

            if mapped_exc is None:  # pragma: no cover
                raise

            message = str(exc)
>           raise mapped_exc(message) from exc
E           httpx.ConnectError: [Errno -2] Name or service not known

/usr/lib/python3.8/site-packages/httpx/_transports/default.py:83: ConnectError
=========================== short test summary info ============================
FAILED test_httpx_fails.py::test_httpx - httpx.ConnectError: [Errno -2] Name ...
============================== 1 failed in 0.42s ===============================
=========================== short test summary info ============================
FAILED tests/test_async.py::test_httpx_fails - Failed: nomatch: '*Socket*Bloc...
======================== 1 failed, 64 passed in 12.80s =========================

Seems related to #43 (stale, autoclosed) where there is desire to disable getaddrinfo(). - which as you show in the most recent output is being attempted.

In your scenario of no network access, even a hostname lookup will fail.

I have no such requirements as of yet, and would be happy to review a changeset that merges cleanly.

The proposed changes in #309 are undesirable, as the change to the import paths to a top-level common package can conflict with the https://pypi.org/project/common/ package. They should rather be either relative to the root.

n your scenario of no network access, even a hostname lookup will fail.

Actually that output was from build env which had access to DNS server with full public network access 🤔

Then that's even further confusing, since the error surfaced shows a failure to lookup www.example.com - can you verify that the DNS server used can look up that address?

$ host www.example.com
Host www.example.com not found: 3(NXDOMAIN)

That is from whole UK.

Second thing: many distributions build infras are intentionally cut off from access to the public network during prod packages build. Already many packages are anticipating that supporting pytest mark network allowing execute pytesst -m 'not network' allowing in such scenario skip unts execution which needs public network access.
It would be really good to support such convention 🤔

This issue is stale because it has been open for 90 days with no activity.

This issue was closed because it has been inactive for 30 days since being marked as stale.

Issue still is not resolved 🤔