]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Drop urllib3 in favor of public gist (#1182)
authorFlorimond Manca <florimond.manca@gmail.com>
Fri, 4 Sep 2020 20:56:36 +0000 (22:56 +0200)
committerGitHub <noreply@github.com>
Fri, 4 Sep 2020 20:56:36 +0000 (22:56 +0200)
* Drop urllib3 in favor of public gist

* Drop urllib3 coverage omit

* Drop recommendation to use urllib3 transport during Requests migration

* Add urllib3-transport to 3p pkgs

* Drop urllib3 from dependencies list in README / docs home page

Co-authored-by: Tom Christie <tom@tomchristie.com>
README.md
docs/advanced.md
docs/compatibility.md
docs/index.md
docs/third-party-packages.md
httpx/__init__.py
httpx/_transports/urllib3.py [deleted file]
scripts/coverage

index 3072daf79ea476fc257a4eab6cc094d828b45d9f..f8fe0f9b60b4606f6d8b0f14f5c302498ddd03eb 100644 (file)
--- a/README.md
+++ b/README.md
@@ -122,7 +122,6 @@ The HTTPX project relies on these excellent libraries:
 * `rfc3986` - URL parsing & normalization.
   * `idna` - Internationalized domain name support.
 * `sniffio` - Async library autodetection.
-* `urllib3` - Support for the `httpx.URLLib3Transport` class. *(Optional)*
 * `brotlipy` - Decoding for "brotli" compressed responses. *(Optional)*
 
 A huge amount of credit is due to `requests` for the API layout that
index e43ecca6dfbc0933993d52234cdab240eefb5042..b2a07df371478a18cfdaa4316acab50c8bed6bea 100644 (file)
@@ -809,6 +809,8 @@ HTTPX's `Client` also accepts a `transport` argument. This argument allows you
 to provide a custom Transport object that will be used to perform the actual
 sending of the requests.
 
+### Usage
+
 For some advanced configuration you might need to instantiate a transport
 class directly, and pass it to the client instance. The `httpcore` package
 provides a `local_address` configuration that is only available via this
@@ -850,18 +852,19 @@ do not include any default values for configuring aspects such as the
 connection pooling details, so you'll need to provide more explicit
 configuration when using this API.
 
-HTTPX also currently ships with a transport that uses the excellent
-[`urllib3` library](https://urllib3.readthedocs.io/en/latest/), which can be
-used with the sync `Client`...
+### urllib3 transport
+
+This [public gist](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e) provides a transport that uses the excellent [`urllib3` library](https://urllib3.readthedocs.io/en/latest/), and can be used with the sync `Client`...
 
 ```pycon
 >>> import httpx
->>> client = httpx.Client(transport=httpx.URLLib3Transport())
+>>> from urllib3_transport import URLLib3Transport
+>>> client = httpx.Client(transport=URLLib3Transport())
 >>> client.get("https://example.org")
 <Response [200 OK]>
 ```
 
-Note that you'll need to install the `urllib3` package to use `URLLib3Transport`.
+### Writing custom transports
 
 A transport instance must implement the Transport API defined by
 [`httpcore`](https://www.encode.io/httpcore/api/). You
index dbb8941b8b2ceb0def7a662652ddd56e273993b5..daef4994a7b9970a32d295d21c878e4e349f1a6d 100644 (file)
@@ -83,3 +83,9 @@ Besides, `httpx.Request()` does not support the `auth`, `timeout`, `allow_redire
 ## Mocking
 
 If you need to mock HTTPX the same way that test utilities like `responses` and `requests-mock` does for `requests`, see [RESPX](https://github.com/lundberg/respx).
+
+## Networking layer
+
+`requests` defers most of its HTTP networking code to the excellent [`urllib3` library](https://urllib3.readthedocs.io/en/latest/).
+
+On the other hand, HTTPX uses [HTTPCore](https://github.com/encode/httpcore) as its core HTTP networking layer, which is a different project than `urllib3`.
index 540c9bdc2d6d7245abd79d81cb2e7ca935def2af..ddea48c43f6dc11a64449cec61b07913b7bdab18 100644 (file)
@@ -114,7 +114,6 @@ The HTTPX project relies on these excellent libraries:
 * `rfc3986` - URL parsing & normalization.
   * `idna` - Internationalized domain name support.
 * `sniffio` - Async library autodetection.
-* `urllib3` - Support for the `httpx.URLLib3Transport` class. *(Optional)*
 * `brotlipy` - Decoding for "brotli" compressed responses. *(Optional)*
 
 A huge amount of credit is due to `requests` for the API layout that
index cc6a79994e4a3eabf34e0c327eaf1411ce5aca88..61e6e860ab30b83a48ffe8c901943f89becd683a 100644 (file)
@@ -23,3 +23,13 @@ An asynchronous GitHub API library. Includes [HTTPX support](https://gidgethub.r
 [GitHub](https://github.com/lundberg/respx) - [Documentation](https://lundberg.github.io/respx/)
 
 A utility for mocking out the Python HTTPX library.
+
+## Gists
+
+<!-- NOTE: this list is in alphabetical order. -->
+
+### urllib3-transport
+
+[GitHub](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e)
+
+This public gist provides an example implementation for a [custom transport](/advanced#custom-transports) implementation on top of the battle-tested [`urllib3`](https://urllib3.readthedocs.io) library.
index 38024394667bf8da11880d07d0562b5b95a47861..bfd52806efdf0269ef40b6e94fd95555199a2aa5 100644 (file)
@@ -38,7 +38,6 @@ from ._exceptions import (
 from ._models import URL, Cookies, Headers, QueryParams, Request, Response
 from ._status_codes import StatusCode, codes
 from ._transports.asgi import ASGITransport
-from ._transports.urllib3 import URLLib3ProxyTransport, URLLib3Transport
 from ._transports.wsgi import WSGITransport
 
 __all__ = [
@@ -101,8 +100,6 @@ __all__ = [
     "TransportError",
     "UnsupportedProtocol",
     "URL",
-    "URLLib3ProxyTransport",
-    "URLLib3Transport",
     "WriteError",
     "WriteTimeout",
     "WSGITransport",
diff --git a/httpx/_transports/urllib3.py b/httpx/_transports/urllib3.py
deleted file mode 100644 (file)
index c5b7af6..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-import socket
-from typing import Iterator, List, Mapping, Optional, Tuple
-
-import httpcore
-
-from .._config import create_ssl_context
-from .._content_streams import ByteStream, IteratorStream
-from .._exceptions import NetworkError, map_exceptions
-from .._types import CertTypes, VerifyTypes
-
-try:
-    import urllib3
-    from urllib3.exceptions import MaxRetryError, SSLError
-except ImportError:  # pragma: nocover
-    urllib3 = None
-
-
-class URLLib3Transport(httpcore.SyncHTTPTransport):
-    def __init__(
-        self,
-        *,
-        verify: VerifyTypes = True,
-        cert: CertTypes = None,
-        trust_env: bool = None,
-        pool_connections: int = 10,
-        pool_maxsize: int = 10,
-        pool_block: bool = False,
-    ):
-        assert (
-            urllib3 is not None
-        ), "urllib3 must be installed in order to use URLLib3Transport"
-
-        self.pool = urllib3.PoolManager(
-            ssl_context=create_ssl_context(
-                verify=verify, cert=cert, trust_env=trust_env, http2=False
-            ),
-            num_pools=pool_connections,
-            maxsize=pool_maxsize,
-            block=pool_block,
-        )
-
-    def request(
-        self,
-        method: bytes,
-        url: Tuple[bytes, bytes, Optional[int], bytes],
-        headers: List[Tuple[bytes, bytes]] = None,
-        stream: httpcore.SyncByteStream = None,
-        timeout: Mapping[str, Optional[float]] = None,
-    ) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], httpcore.SyncByteStream]:
-        headers = [] if headers is None else headers
-        stream = ByteStream(b"") if stream is None else stream
-        timeout = {} if timeout is None else timeout
-
-        urllib3_timeout = urllib3.util.Timeout(
-            connect=timeout.get("connect"), read=timeout.get("read")
-        )
-
-        chunked = False
-        content_length = 0
-        for header_key, header_value in headers:
-            header_key = header_key.lower()
-            if header_key == b"transfer-encoding":
-                chunked = header_value == b"chunked"
-            if header_key == b"content-length":
-                content_length = int(header_value.decode("ascii"))
-        body = stream if chunked or content_length else None
-
-        scheme, host, port, path = url
-        default_port = {b"http": 80, "https": 443}.get(scheme)
-        if port is None or port == default_port:
-            url_str = "%s://%s%s" % (
-                scheme.decode("ascii"),
-                host.decode("ascii"),
-                path.decode("ascii"),
-            )
-        else:
-            url_str = "%s://%s:%d%s" % (
-                scheme.decode("ascii"),
-                host.decode("ascii"),
-                port,
-                path.decode("ascii"),
-            )
-
-        with map_exceptions(
-            {
-                MaxRetryError: NetworkError,
-                SSLError: NetworkError,
-                socket.error: NetworkError,
-            }
-        ):
-            conn = self.pool.urlopen(
-                method=method.decode(),
-                url=url_str,
-                headers={
-                    key.decode("ascii"): value.decode("ascii") for key, value in headers
-                },
-                body=body,
-                redirect=False,
-                assert_same_host=False,
-                retries=0,
-                preload_content=False,
-                chunked=chunked,
-                timeout=urllib3_timeout,
-                pool_timeout=timeout.get("pool"),
-            )
-
-        def response_bytes() -> Iterator[bytes]:
-            with map_exceptions({socket.error: NetworkError}):
-                for chunk in conn.stream(4096, decode_content=False):
-                    yield chunk
-
-        status_code = conn.status
-        headers = list(conn.headers.items())
-        response_stream = IteratorStream(
-            iterator=response_bytes(), close_func=conn.release_conn
-        )
-        return (b"HTTP/1.1", status_code, conn.reason, headers, response_stream)
-
-    def close(self) -> None:
-        self.pool.clear()
-
-
-class URLLib3ProxyTransport(URLLib3Transport):
-    def __init__(
-        self,
-        *,
-        proxy_url: str,
-        proxy_headers: dict = None,
-        verify: VerifyTypes = True,
-        cert: CertTypes = None,
-        trust_env: bool = None,
-        pool_connections: int = 10,
-        pool_maxsize: int = 10,
-        pool_block: bool = False,
-    ):
-        assert (
-            urllib3 is not None
-        ), "urllib3 must be installed in order to use URLLib3ProxyTransport"
-
-        self.pool = urllib3.ProxyManager(
-            proxy_url=proxy_url,
-            proxy_headers=proxy_headers,
-            ssl_context=create_ssl_context(
-                verify=verify, cert=cert, trust_env=trust_env, http2=False
-            ),
-            num_pools=pool_connections,
-            maxsize=pool_maxsize,
-            block=pool_block,
-        )
index a476e8b278123fffe15ee70b6f190aee0d5f4a43..25a269107477d373c3802266348170d608e178d9 100755 (executable)
@@ -8,4 +8,4 @@ export SOURCE_FILES="httpx tests"
 
 set -x
 
-${PREFIX}coverage report --omit=httpx/_transports/urllib3.py --show-missing --skip-covered --fail-under=100
+${PREFIX}coverage report --show-missing --skip-covered --fail-under=100