internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: encode/httpx

Issue:
Use IDNA 2008 instead of IDNA 2003
Using `str.encode("idna")` uses IDNA 2003 which isn't recommended for modern use. We should be using IDNA 2008 provided by the `idna` module (which is a dependency of `httpx` but I don't think we're using it anywhere?)


Discussion:

Resolving patch:
diff --git a/httpx/models.py b/httpx/models.py
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -89,16 +89,10 @@ def __init__(
         params: QueryParamTypes = None,
     ) -> None:
         if isinstance(url, str):
-            self._uri_reference = rfc3986.api.uri_reference(url)
+            self._uri_reference = rfc3986.api.iri_reference(url).encode()
         else:
             self._uri_reference = url._uri_reference
 
-        # Handle IDNA domain names.
-        if self._uri_reference.authority:
-            idna_authority = self._uri_reference.authority.encode("idna").decode("ascii")
-            if idna_authority != self._uri_reference.authority:
-                self._uri_reference = self._uri_reference.copy_with(authority=idna_authority)
-
         # Normalize scheme and domain name.
         if self.is_absolute_url:
             self._uri_reference = self._uri_reference.normalize()


Test patch:
diff --git a/tests/models/test_url.py b/tests/models/test_url.py
--- a/tests/models/test_url.py
+++ b/tests/models/test_url.py
@@ -1,13 +1,65 @@
 import pytest
+import rfc3986
 
 from httpx import URL
 from httpx.exceptions import InvalidURL
 
 
-def test_idna_url():
-    url = URL("http://中国.icom.museum:80/")
-    assert url == URL("http://xn--fiqs8s.icom.museum:80/")
-    assert url.host == "xn--fiqs8s.icom.museum"
+@pytest.mark.parametrize(
+    "given,idna,host,scheme,port",
+    [
+        (
+            "http://中国.icom.museum:80/",
+            "http://xn--fiqs8s.icom.museum:80/",
+            "xn--fiqs8s.icom.museum",
+            "http",
+            80,
+        ),
+        (
+            "http://Königsgäßchen.de",
+            "http://xn--knigsgchen-b4a3dun.de",
+            "xn--knigsgchen-b4a3dun.de",
+            "http",
+            80,
+        ),
+        ("https://faß.de", "https://xn--fa-hia.de", "xn--fa-hia.de", "https", 443),
+        (
+            "https://βόλος.com:443",
+            "https://xn--nxasmm1c.com:443",
+            "xn--nxasmm1c.com",
+            "https",
+            443,
+        ),
+        (
+            "http://ශ්‍රී.com:444",
+            "http://xn--10cl1a0b660p.com:444",
+            "xn--10cl1a0b660p.com",
+            "http",
+            444,
+        ),
+        (
+            "https://نامه‌ای.com:4433",
+            "https://xn--mgba3gch31f060k.com:4433",
+            "xn--mgba3gch31f060k.com",
+            "https",
+            4433,
+        ),
+    ],
+    ids=[
+        "http_with_port",
+        "unicode_tr46_compat",
+        "https_without_port",
+        "https_with_port",
+        "http_with_custom_port",
+        "https_with_custom_port",
+    ],
+)
+def test_idna_url(given, idna, host, scheme, port):
+    url = URL(given)
+    assert url == URL(idna)
+    assert url.host == host
+    assert url.scheme == scheme
+    assert url.port == port
 
 
 def test_url():
Repository: encode/httpx

Issue:
Origin should be (scheme, host, port) not (is_ssl, host, port)
Example: `http+unix//localhost` and `http://localhost` would currently have the same origin despite being a different scheme. Change this by using URL.scheme instead of is_ssl.


Discussion:
It's an easy change, but what about [this](https://github.com/encode/httpx/blob/master/httpx/dispatch/connection.py#L69)?

Could potentially just add `.scheme` and keep `.is_ssl` around as well:

```py
class Origin:
    """
    The URL scheme and authority information, as a comparable, hashable object.
    """

    def __init__(self, url: URLTypes) -> None:
        if not isinstance(url, URL):
            url = URL(url)
        self.scheme = url.scheme
        self.is_ssl = url.is_ssl
        self.host = url.host
        self.port = url.port

    def __eq__(self, other: typing.Any) -> bool:
        return (
            isinstance(other, self.__class__)
            and self.scheme == other.scheme
            and self.host == other.host
            and self.port == other.port
        )

    def __hash__(self) -> int:
        return hash((self.scheme, self.host, self.port))
```
Yeah we can keep the `is_ssl` parameter on the `Origin` class. Did you want to turn that mockup into a PR? :D
I was planning on it! :-)

Resolving patch:
diff --git a/httpx/dispatch/connection_pool.py b/httpx/dispatch/connection_pool.py
--- a/httpx/dispatch/connection_pool.py
+++ b/httpx/dispatch/connection_pool.py
@@ -26,10 +26,8 @@ class ConnectionStore:
     """
 
     def __init__(self) -> None:
-        self.all = {}  # type: typing.Dict[HTTPConnection, float]
-        self.by_origin = (
-            {}
-        )  # type: typing.Dict[Origin, typing.Dict[HTTPConnection, float]]
+        self.all: typing.Dict[HTTPConnection, float] = {}
+        self.by_origin: typing.Dict[Origin, typing.Dict[HTTPConnection, float]] = {}
 
     def pop_by_origin(
         self, origin: Origin, http2_only: bool = False
diff --git a/httpx/models.py b/httpx/models.py
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -233,6 +233,7 @@ class Origin:
     def __init__(self, url: URLTypes) -> None:
         if not isinstance(url, URL):
             url = URL(url)
+        self.scheme = url.scheme
         self.is_ssl = url.is_ssl
         self.host = url.host
         self.port = url.port
@@ -240,13 +241,13 @@ def __init__(self, url: URLTypes) -> None:
     def __eq__(self, other: typing.Any) -> bool:
         return (
             isinstance(other, self.__class__)
-            and self.is_ssl == other.is_ssl
+            and self.scheme == other.scheme
             and self.host == other.host
             and self.port == other.port
         )
 
     def __hash__(self) -> int:
-        return hash((self.is_ssl, self.host, self.port))
+        return hash((self.scheme, self.host, self.port))
 
 
 class QueryParams(typing.Mapping[str, str]):


Test patch:
Repository: encode/httpx

Issue:
Missing py.typed declaration?
`mypy` is complaining about not being able to find type annotations for `httpx`: 

`error: Cannot find module named 'httpx'`

I'm somewhat new to using type annotations/static type checking in Python, but from the mypy documentation [here](https://mypy.readthedocs.io/en/latest/installed_packages.html#making-pep-561-compatible-packages) it looks like there may be a missing declaration in `setup.py`?


Discussion:
Hmmm, we definitely want our type annotations to be discoverable by mypy. Do you think that this is something you'd be able to tackle? :)
Did you properly install the module via pip? 
I had an issue occurring where I installed a module via pip but my Python wasn't in my
environment variables. Preventing my IDE from locating the installed module. 

Hope this helps or makes sense :) 
It looks like we need a single `py.typed` file within our package to get mypy to recognize inline types? Am I reading that right?

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -45,6 +45,7 @@ def get_packages(package):
     long_description_content_type="text/markdown",
     author="Tom Christie",
     author_email="tom@tomchristie.com",
+    package_data={"httpx": ["py.typed"]},
     packages=get_packages("httpx"),
     install_requires=[
         "certifi",


Test patch:
Repository: encode/httpx

Issue:
Don't render Authorization, Proxy-Authorization headers, password in URLs
We could render them as `[secure]` when calling `__repr__` so that they're not exposed by logging services. Was wondering what others thought of this idea?


Discussion:
Hi, I tried to add this feature. 
In debug logging level case, this doesn't work and we will need a logging formatter. I'm not sure we should think about it.  
If this approach makes sense, we can use it.
Yeah we do the same with Starlette’s URL class. Def in favour (tho probably just repr, not str)

Resolving patch:
diff --git a/httpx/models.py b/httpx/models.py
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -210,6 +210,12 @@ def __str__(self) -> str:
     def __repr__(self) -> str:
         class_name = self.__class__.__name__
         url_str = str(self)
+        if self._uri_reference.userinfo:
+            url_str = (
+                rfc3986.urlparse(url_str)
+                .copy_with(userinfo=f"{self.username}:[secure]")
+                .unsplit()
+            )
         return f"{class_name}({url_str!r})"
 
 
@@ -489,10 +495,14 @@ def __repr__(self) -> str:
         if self.encoding != "ascii":
             encoding_str = f", encoding={self.encoding!r}"
 
-        as_dict = dict(self.items())
-        if len(as_dict) == len(self):
+        sensitive_headers = {"authorization", "proxy-authorization"}
+        as_list = [
+            (k, "[secure]" if k in sensitive_headers else v) for k, v in self.items()
+        ]
+
+        as_dict = dict(as_list)
+        if len(as_dict) == len(as_list):
             return f"{class_name}({as_dict!r}{encoding_str})"
-        as_list = self.items()
         return f"{class_name}({as_list!r}{encoding_str})"
 
 


Test patch:
diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py
--- a/tests/client/test_auth.py
+++ b/tests/client/test_auth.py
@@ -2,6 +2,7 @@
 import os
 
 from httpx import (
+    URL,
     AsyncDispatcher,
     AsyncRequest,
     AsyncResponse,
@@ -100,3 +101,20 @@ def test_trust_env_auth():
     assert response.json() == {
         "auth": "Basic ZXhhbXBsZS11c2VybmFtZTpleGFtcGxlLXBhc3N3b3Jk"
     }
+
+
+def test_auth_hidden_url():
+    url = "http://example-username:example-password@example.org/"
+    expected = "URL('http://example-username:[secure]@example.org/')"
+    assert url == URL(url)
+    assert expected == repr(URL(url))
+
+
+def test_auth_hidden_header():
+    url = "https://example.org/"
+    auth = ("example-username", "example-password")
+
+    with Client(dispatch=MockDispatch()) as client:
+        response = client.get(url, auth=auth)
+
+    assert "'authorization': '[secure]'" in str(response.request.headers)
Repository: encode/httpx

Issue:
Handle HEAD responses with Brotli decoder
Currently if you receive a response with `Content-Encoding: br` set and no body we get an error because Brotli doesn't like being called on an empty stream.


Discussion:
More generally: we should make sure not to call *any* decoder if the body is empty.

On reviewing #237 I think we *should* just call into the decoders, but that we should just make sure that all the decoder implementations correctly handle `b""` input, and all correctly return `b""` outputs in that case.

Ideally a test case for this issue would be parameterized to ensure correct behavior here from all our decoder classes.

Resolving patch:
diff --git a/httpx/decoders.py b/httpx/decoders.py
--- a/httpx/decoders.py
+++ b/httpx/decoders.py
@@ -98,8 +98,12 @@ def __init__(self) -> None:
             brotli is not None
         ), "The 'brotlipy' or 'brotli' library must be installed to use 'BrotliDecoder'"
         self.decompressor = brotli.Decompressor()
+        self.seen_data = False
 
     def decode(self, data: bytes) -> bytes:
+        if not data:
+            return b""
+        self.seen_data = True
         try:
             if hasattr(self.decompressor, "decompress"):
                 return self.decompressor.decompress(data)
@@ -108,6 +112,8 @@ def decode(self, data: bytes) -> bytes:
             raise DecodingError from exc
 
     def flush(self) -> bytes:
+        if not self.seen_data:
+            return b""
         try:
             if hasattr(self.decompressor, "finish"):
                 self.decompressor.finish()


Test patch:
diff --git a/tests/test_decoders.py b/tests/test_decoders.py
--- a/tests/test_decoders.py
+++ b/tests/test_decoders.py
@@ -4,7 +4,13 @@
 import pytest
 
 import httpx
-from httpx.decoders import TextDecoder
+from httpx.decoders import (
+    BrotliDecoder,
+    DeflateDecoder,
+    GZipDecoder,
+    IdentityDecoder,
+    TextDecoder,
+)
 
 
 def test_deflate():
@@ -79,6 +85,22 @@ def compress(body):
     assert response.read() == body
 
 
+@pytest.mark.parametrize("header_value", (b"deflate", b"gzip", b"br", b"identity"))
+def test_empty_content(header_value):
+    headers = [(b"Content-Encoding", header_value)]
+    response = httpx.Response(200, headers=headers, content=b"")
+    assert response.content == b""
+
+
+@pytest.mark.parametrize(
+    "decoder", (BrotliDecoder, DeflateDecoder, GZipDecoder, IdentityDecoder)
+)
+def test_decoders_empty_cases(decoder):
+    instance = decoder()
+    assert instance.decode(b"") == b""
+    assert instance.flush() == b""
+
+
 @pytest.mark.parametrize("header_value", (b"deflate", b"gzip", b"br"))
 def test_decoding_errors(header_value):
     headers = [(b"Content-Encoding", header_value)]
Repository: encode/httpx

Issue:
stop nox on first error
During nox is running, if it gets an error, continues running. if we add this: `nox.options.stop_on_first_error = True`, we don't overlook check errors or others before PR.


Discussion:

Resolving patch:
diff --git a/noxfile.py b/noxfile.py
--- a/noxfile.py
+++ b/noxfile.py
@@ -1,5 +1,7 @@
 import nox
 
+nox.options.stop_on_first_error = True
+
 source_files = ("httpx", "tests", "setup.py", "noxfile.py")
 
 


Test patch:
Repository: encode/httpx

Issue:
Drop NPN support
@pgjones suggested in https://github.com/encode/httpx/pull/276#discussion_r317585211 to stop using NPN to get the HTTP protocol in `.get_http_version()` on concurrency backends, and switch to ALPN-only.

(Technical notes of mine: [NPN](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04) (Next Protocol Negociation) is a TLS extension that was added as part of [SPDY](https://en.wikipedia.org/wiki/SPDY) a Google protocol whose spec eventually got merged into the HTTP/2 standard. Google announced this in 2016 in [Hello HTTP/2, good bye SPDY](https://blog.chromium.org/2015/02/hello-http2-goodbye-spdy.html), and [ALPN now replaces NPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation#History).)

I did a bit of research, and NPN removal does seem to have been on its way across the interwebs:

- [Chrome 51, 2016](https://www.chromestatus.com/feature/5767920709795840)
- [Firefox 53, 2017](https://www.fxsitecompat.dev/en-CA/docs/2017/npn-support-has-been-removed/)
- [Cloudflare, 2018](https://blog.cloudflare.com/deprecating-spdy/)
- [Safari, 2019](https://webkit.org/blog/8569/removing-legacy-spdy-protocol-support/) (macOS Mojave and iOS 12)
- [Hypercorn, 2019](https://gitlab.com/pgjones/hypercorn/merge_requests/16) (😄)

Anyone more experienced than me on HTTP protocols negociation got any thoughts on this?


Discussion:
You can add macOS to the list as well. The new `Network` module only supports ALPN.
Fair enough, that sounds like a nice little improvement.

Resolving patch:
diff --git a/httpx/concurrency/asyncio.py b/httpx/concurrency/asyncio.py
--- a/httpx/concurrency/asyncio.py
+++ b/httpx/concurrency/asyncio.py
@@ -68,8 +68,9 @@ def get_http_version(self) -> str:
             return "HTTP/1.1"
 
         ident = ssl_object.selected_alpn_protocol()
+
         if ident is None:
-            ident = ssl_object.selected_npn_protocol()
+            return "HTTP/1.1"
 
         return "HTTP/2" if ident == "h2" else "HTTP/1.1"
 
diff --git a/httpx/config.py b/httpx/config.py
--- a/httpx/config.py
+++ b/httpx/config.py
@@ -171,8 +171,6 @@ def _create_default_ssl_context(
 
         if ssl.HAS_ALPN:
             context.set_alpn_protocols(http_versions.alpn_identifiers)
-        if ssl.HAS_NPN:  # pragma: no cover
-            context.set_npn_protocols(http_versions.alpn_identifiers)
 
         if hasattr(context, "keylog_filename"):
             keylogfile = os.environ.get("SSLKEYLOGFILE")


Test patch:
Repository: encode/httpx

Issue:
Away-from-origin redirects should add a new host header
Prompted by #310

Away-from-origin redirects currently remove the `Host` header, without adding a new one.
I think we ought to be using `headers['Host'] = url.authority.encode("ascii")` instead of simply deleting the header.


Discussion:
I would like to work on this.
@gdhameeja Consider the task yours :) Thanks for taking this on!

Resolving patch:
diff --git a/httpx/middleware.py b/httpx/middleware.py
--- a/httpx/middleware.py
+++ b/httpx/middleware.py
@@ -148,7 +148,7 @@ def redirect_headers(self, request: AsyncRequest, url: URL, method: str) -> Head
             # Strip Authorization headers when responses are redirected away from
             # the origin.
             del headers["Authorization"]
-            del headers["Host"]
+            headers["Host"] = url.authority
 
         if method != request.method and method == "GET":
             # If we've switch to a 'GET' request, then strip any headers which


Test patch:
Repository: encode/httpx

Issue:
Missing py.typed declaration?
`mypy` is complaining about not being able to find type annotations for `httpx`: 

`error: Cannot find module named 'httpx'`

I'm somewhat new to using type annotations/static type checking in Python, but from the mypy documentation [here](https://mypy.readthedocs.io/en/latest/installed_packages.html#making-pep-561-compatible-packages) it looks like there may be a missing declaration in `setup.py`?


Discussion:
Hmmm, we definitely want our type annotations to be discoverable by mypy. Do you think that this is something you'd be able to tackle? :)
Did you properly install the module via pip? 
I had an issue occurring where I installed a module via pip but my Python wasn't in my
environment variables. Preventing my IDE from locating the installed module. 

Hope this helps or makes sense :) 
It looks like we need a single `py.typed` file within our package to get mypy to recognize inline types? Am I reading that right?
Basically -- that marker file plus a package_data entry seems to have done the trick. 
@andrewmwhite @sethmlarson 

Hey all, I just did `pip install httpx` to install httpx v0.7.2.

There is still no `py.typed` file in `/usr/local/lib/python3.7/site-packages/httpx/`. All of the other files, like `api.py`, `__init__.py`, etc are present, but `py.typed` isn't.

Consequently, mypy still can't find types for httpx.

From what I can tell, this PR was merged before 0.7.2 was released, so this should work in v0.7.2. If this is the case, this issue needs to be reopened.
Yep, verified this is a bug. We need to add an entry to MANIFEST.in.

@florimondmanca can we get this done before release?
@sethmlarson Sure :)

I’m curious why package_data isn’t enough to include the py.typed file, though. It has worked for me in a few other projects.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -49,6 +49,7 @@ def get_packages(package):
     package_data={"httpx": ["py.typed"]},
     packages=get_packages("httpx"),
     include_package_data=True,
+    zip_safe=False,
     install_requires=[
         "certifi",
         "chardet==3.*",


Test patch:
Repository: encode/httpx

Issue:
Releasing 0.7.3
Hi @encode/httpx-maintainers!

It’s been 21 days since 0.7.2 was released, and we’ve got [a bunch of features](https://github.com/encode/httpx/compare/0.7.2...HEAD) ready for 0.7.3 already, eg:

- Digest auth
- SSLKEYLOGFILE
- Response.elapsed
- A host of bug fixes

So regardless of what gets merged until then I think it’s time to release the next version. :)

As suggested by @sethmlarson I-cant-remember-where I’d like to take on this release. I’ll probably take the opportunity to document the release process as well - #313. 👍

Probably will do tonight.




Discussion:
Yep, definitely time to release. Maybe I'll try to get the proxy config PR in before but if not it's fine to ship without. :)
Yes, it can make it in 0.7.4 too. :)

I was wondering — what’s the policy for minor bumps? Breaking changes I guess?
I guess so? There aren't any API guarantees for 0.X under SemVer though.

Resolving patch:
diff --git a/httpx/__version__.py b/httpx/__version__.py
--- a/httpx/__version__.py
+++ b/httpx/__version__.py
@@ -1,3 +1,3 @@
 __title__ = "httpx"
 __description__ = "A next generation HTTP client, for Python 3."
-__version__ = "0.7.2"
+__version__ = "0.7.3"


Test patch:
Repository: encode/httpx

Issue:
HTTPError should be importable frop the top-level httpx package
From #365:

> `HTTPError` is not available at the top level like the other exceptions and like it was in requests. This is a somewhat common exception to catch raise_for_status, so having to add another import statement for it is a bit odd if intentional.

Put differently, `HTTPError` is missing from `httpx/__init__.py`. Adding it would allow us to do:

```python
import httpx

try:
    r = httpx.get("https://example.org")
    r.raise_for_status()
except httpx.HTTPError:
    ...
```


Discussion:
I'd like to work on this.
The issue is yours! Thanks @gdhameeja 

Resolving patch:
diff --git a/httpx/__init__.py b/httpx/__init__.py
--- a/httpx/__init__.py
+++ b/httpx/__init__.py
@@ -27,6 +27,7 @@
     ConnectTimeout,
     CookieConflict,
     DecodingError,
+    HTTPError,
     InvalidURL,
     NotRedirectResponse,
     PoolTimeout,
@@ -97,6 +98,7 @@
     "ConnectTimeout",
     "CookieConflict",
     "DecodingError",
+    "HTTPError",
     "InvalidURL",
     "NotRedirectResponse",
     "PoolTimeout",


Test patch:
diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py
--- a/tests/client/test_async_client.py
+++ b/tests/client/test_async_client.py
@@ -95,7 +95,7 @@ async def test_raise_for_status(server, backend):
             )
 
             if 400 <= status_code < 600:
-                with pytest.raises(httpx.exceptions.HTTPError) as exc_info:
+                with pytest.raises(httpx.HTTPError) as exc_info:
                     response.raise_for_status()
                 assert exc_info.value.response == response
             else:
diff --git a/tests/client/test_client.py b/tests/client/test_client.py
--- a/tests/client/test_client.py
+++ b/tests/client/test_client.py
@@ -88,7 +88,7 @@ def test_raise_for_status(server):
                 "GET", server.url.copy_with(path="/status/{}".format(status_code))
             )
             if 400 <= status_code < 600:
-                with pytest.raises(httpx.exceptions.HTTPError) as exc_info:
+                with pytest.raises(httpx.HTTPError) as exc_info:
                     response.raise_for_status()
                 assert exc_info.value.response == response
             else: