Repository: encode/httpx

Issue #714: An open stream object is being garbage collected; call "stream.close()" explicitly
Created: 2020-01-02T15:26:54Z
I can trigger an ERROR:    An open stream object is being garbage collected; call "stream.close()" explicitly. on demand in my test suite
the trace output is just below:
DEBUG:conftest:Starting ngrok tunnel for port 5002

-------------------------------- live log setup --------------------------------
DEBUG    conftest:conftest.py:46 Starting ngrok tunnel for port 5002
DEBUG:asyncio:Using selector: EpollSelector
DEBUG    asyncio:selector_events.py:54 Using selector: EpollSelector
INFO:     Started server process [3098472]
INFO:     Uvicorn running on http://127.0.0.1:5002 (Press CTRL+C to quit)
INFO:     Waiting for application startup.
INFO:     Connected to database postgresql://postgres:********@localhost:5438/rss2inbox_test
INFO:     Application startup complete.
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE:    acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:01] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE:    load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:01] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE:    load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE:    start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE:    connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - send_headers method='GET' target='/subscriber/100' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE:    send_headers method='GET' target='/subscriber/100' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE:    send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE:    receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'4912'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'OK')
TRACE:    receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'4912'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:02] httpx.client - HTTP Request: GET https://websub.rocks/subscriber/100 "HTTP/1.1 200 OK"
DEBUG:    HTTP Request: GET https://websub.rocks/subscriber/100 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Data(<3932 bytes>)
TRACE:    receive_event event=Data(<3932 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE:    receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Data(<980 bytes>)
TRACE:    receive_event event=Data(<980 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE:    receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE:    response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - close_connection
TRACE:    close_connection
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE:    send_event event=ConnectionClosed()
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443)
TRACE:    acquire_connection origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE:    new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE [2020-01-02 12:02:02] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE:    load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:02] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE:    load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - start_connect tcp host='75d55904.ngrok.io' port=443 timeout=Timeout(timeout=5.0)
TRACE:    start_connect tcp host='75d55904.ngrok.io' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE:    connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_headers method='GET' target='/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9' headers=Headers({'host': '75d55904.ngrok.io', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE:    send_headers method='GET' target='/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9' headers=Headers({'host': '75d55904.ngrok.io', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE:    send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE:    receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE:    acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:02] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE:    load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:02] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE:    load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE:    start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE:    connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_headers method='GET' target='/blog/100/WBj716u7rareKpjbfoh9' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE:    send_headers method='GET' target='/blog/100/WBj716u7rareKpjbfoh9' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE:    send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE:    receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:03 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'2238'), (b'connection', b'keep-alive'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9>; rel="self"'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub>; rel="hub"')], http_version=b'1.1', reason=b'OK')
TRACE:    receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:03 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'2238'), (b'connection', b'keep-alive'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9>; rel="self"'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub>; rel="hub"')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:03] httpx.client - HTTP Request: GET https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
DEBUG:    HTTP Request: GET https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=Data(<2238 bytes>)
TRACE:    receive_event event=Data(<2238 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE:    receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE:    response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - close_connection
TRACE:    close_connection
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE:    send_event event=ConnectionClosed()
DEBUG:    hub_url='https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub' topic_url='https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9'
ERROR:    An open stream object is being garbage collected; call "stream.close()" explicitly.
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE:    acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:03] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE:    load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:03] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE:    load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE:    start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE:    connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_headers method='POST' target='/blog/100/WBj716u7rareKpjbfoh9/hub' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': '235', 'content-type': 'application/x-www-form-urlencoded'})
TRACE:    send_headers method='POST' target='/blog/100/WBj716u7rareKpjbfoh9/hub' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': '235', 'content-type': 'application/x-www-form-urlencoded'})
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_data data=Data(<235 bytes>)
TRACE:    send_data data=Data(<235 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE:    receive_event event=NEED_DATA
INFO:     2600:3c01::f03c:91ff:fe94:80b2:0 - "GET /callbacks/6faf64d5-ab53-403e-8349-1a6889ac2ffb?hub.mode=subscribe&hub.topic=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9&hub.challenge=O9M7grqDIEoZTBkld6bX&hub.lease_seconds=86400 HTTP/1.1" 200 OK
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Response(status_code=202, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:04 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'0'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'Accepted')
TRACE:    receive_event event=Response(status_code=202, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:04 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'0'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'Accepted')
DEBUG [2020-01-02 12:02:04] httpx.client - HTTP Request: POST https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub "HTTP/1.1 202 Accepted"
DEBUG:    HTTP Request: POST https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub "HTTP/1.1 202 Accepted"
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE:    receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE:    response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE:    release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection - close_connection
TRACE:    close_connection
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE:    send_event event=ConnectionClosed()
INFO:     93.31.210.155:0 - "GET /subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 HTTP/1.1" 200 OK
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'server', b'uvicorn'), (b'content-length', b'38'), (b'content-type', b'application/json')], http_version=b'1.1', reason=b'OK')
TRACE:    receive_event event=Response(status_code=200, headers=[(b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'server', b'uvicorn'), (b'content-length', b'38'), (b'content-type', b'application/json')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:04] httpx.client - HTTP Request: GET https://75d55904.ngrok.io/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
DEBUG:    HTTP Request: GET https://75d55904.ngrok.io/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Data(<38 bytes>)
TRACE:    receive_event event=Data(<38 bytes>)
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE:    receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE:    response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE:    release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection - close_connection
TRACE:    close_connection
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE:    send_event event=ConnectionClosed()
6faf64d5-ab53-403e-8349-1a6889ac2ffb
PASSED

the test that triggers it is below async def test100, I tried to copy most relevant code, I';m sorry it's that long....:
def get_url_from_page(content):
    htmlcontent = html.document_fromstring(content)
    link = htmlcontent.xpath("//input/@value")
    return link[0]


urls_100 = [
    "https://websub.rocks/subscriber/100",
    "https://websub.rocks/subscriber/101",
    "https://websub.rocks/subscriber/102",
    "https://websub.rocks/subscriber/103",
    "https://websub.rocks/subscriber/104",
]


@pytest.mark.asyncio
@pytest.mark.parametrize("websub_test_url", urls_100)
async def test100(websub_test_url, subscriber_server, ngrokurl_subscriber):
    response = await httpx.get(websub_test_url)
    subscribe_to_url = get_url_from_page(response.content)
    url = subscriber_app.url_path_for("subscribe")
    response = await httpx.get(
        ngrokurl_subscriber + url, params={"subscribe_to_url": subscribe_to_url}
    )
    print(response.json())
    assert response.status_code == 200

@pytest.fixture()
async def subscriber_server():
    config = Config(app=subscriber_app, port=5002)
    server = Server(config=config)
    task = asyncio.ensure_future(server.serve())
    try:
        while not server.started:
            await asyncio.sleep(0.0001)
        yield server
    finally:
        logger.debug("END SERVER")
        server.should_exit = True
        await task

class NgrokTunnel:
    def __init__(self, port: str):
        assert find_executable(
            "ngrok"
        ), "ngrok command must be installed, see https://ngrok.com/"
        self.port = port

    def start(self, ngrok_die_check_delay=0.5):
        logger.debug(f"Starting ngrok tunnel for port {self.port}")
        pattern = r"^.*addr=(?P<addr>http://localhost:(?P<port>\d+)) url=(?P<ngrokurl>https://(?P<ngroksubdomain>.*)\.ngrok\.io)$"

        self.ngrok = subprocess.Popen(
            [
                "ngrok",
                "http",
                self.port,
                "--log",
                "stdout",
            ],
            stdout=subprocess.PIPE,
            bufsize=1,
            universal_newlines=True,
        )
        found = False
        ngrokurl = None
        while not found:
            for line in self.ngrok.stdout:
                # logger.debug(line, end="")
                m = re.match(pattern, line)
                if m is not None:
                    # addr = m.group("addr")
                    # port = m.group("port")
                    ngrokurl = m.group("ngrokurl")
                    # ngroksubdomain = m.group("ngroksubdomain")
                    found = True
                    break
        # See that we don't instantly die
        time.sleep(ngrok_die_check_delay)
        assert self.ngrok.poll() is None, "ngrok terminated abrutly"
        return ngrokurl

    def stop(self):
        """Tell ngrok to tear down the tunnel.

        Stop the background tunneling process.
        """
        self.ngrok.terminate()


@pytest.fixture(scope="session", autouse=True)
def ngrokurl_subscriber():
    ngrok_subscriber = NgrokTunnel("5002")
    url = ngrok_subscriber.start()
    yield url
    ngrok_subscriber.stop()

Duplicate issue #1101: An open stream object is being garbage collected; call "stream.close()" explicitly.
Created: 2020-07-30T06:11:08Z
Checklist

[x ] The bug is reproducible against the latest release and/or master.
[x ] There are no similar issues or pull requests to fix it yet.

Describe the bug
In my case, I don't need to read responses body, so I use AsyncClient.stream functionality.
Since version 0.13 httpx has started to show the warning message: An open stream object is being garbage collected; call "stream.close()" explicitly..
To reproduce
import asyncio as aio
import httpx

client = httpx.AsyncClient()
loop = aio.get_event_loop()

async def reproduce():
    async with client.stream('GET', 'https://github.com') as res:
        print('Response:', res.status_code)

loop.run_until_complete(reproduce())
Output:
Response: 200
An open stream object is being garbage collected; call "stream.close()" explicitly.

Expected behavior
No warning messages
Environment

OS: MacOS
Python version: 3.8.0
HTTPX version: 0.13.3
Async environment: asyncio

Closing comment (2020-07-30T07:28:49Z): Hello,
I believe this is a duplicate of #714 - TL;DR: a Python bug in 3.8.0, see #714 (comment). You can try upgrading to at least 3.8.1 (latest 3.8 version is 3.8.5) and see if it removes the warning.
Thanks!