diff --git a/src/httpcore2/docs/async.md b/docs/httpcore2/async.md similarity index 87% rename from src/httpcore2/docs/async.md rename to docs/httpcore2/async.md index cd7866df..9926dc1f 100644 --- a/src/httpcore2/docs/async.md +++ b/docs/httpcore2/async.md @@ -13,13 +13,13 @@ Launching concurrent async tasks is far more resource efficient than spawning mu If you're using async with [Python's stdlib `asyncio` support](https://docs.python.org/3/library/asyncio.html), install the optional dependencies using: ```shell -pip install 'httpcore[asyncio]' +pip install 'httpcore2[asyncio]' ``` Alternatively, if you're working with [the Python `trio` package](https://trio.readthedocs.io/en/stable/): ```shell -pip install 'httpcore[trio]' +pip install 'httpcore2[trio]' ``` We highly recommend `trio` for async support. The `trio` project [pioneered the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency), and has a more carefully constrained API against which to work from. @@ -29,21 +29,21 @@ We highly recommend `trio` for async support. The `trio` project [pioneered the When using async support, you need make sure to use an async connection pool class: ```python -# The async variation of `httpcore.ConnectionPool` -async with httpcore.AsyncConnectionPool() as http: +# The async variation of `httpcore2.ConnectionPool` +async with httpcore2.AsyncConnectionPool() as http: ... ``` ### Sending requests -Sending requests with the async version of `httpcore` requires the `await` keyword: +Sending requests with the async version of `httpcore2` requires the `await` keyword: ```python import asyncio -import httpcore +import httpcore2 async def main(): - async with httpcore.AsyncConnectionPool() as http: + async with httpcore2.AsyncConnectionPool() as http: response = await http.request("GET", "https://www.example.com/") @@ -65,11 +65,11 @@ For example: ```python import asyncio -import httpcore +import httpcore2 async def main(): - async with httpcore.AsyncConnectionPool() as http: + async with httpcore2.AsyncConnectionPool() as http: async with http.stream("GET", "https://www.example.com/") as response: async for chunk in response.aiter_stream(): print(f"Downloaded: {chunk}") @@ -80,10 +80,10 @@ asyncio.run(main()) ### Pool lifespans -When using `httpcore` in an async environment it is strongly recommended that you instantiate and use connection pools using the context managed style: +When using `httpcore2` in an async environment it is strongly recommended that you instantiate and use connection pools using the context managed style: ```python -async with httpcore.AsyncConnectionPool() as http: +async with httpcore2.AsyncConnectionPool() as http: ... ``` @@ -93,7 +93,7 @@ If you do want to use a connection pool without this style then you'll need to e ```python try: - http = httpcore.AsyncConnectionPool() + http = httpcore2.AsyncConnectionPool() ... finally: await http.aclose() @@ -117,7 +117,7 @@ Let's take a look at sending several outgoing HTTP requests concurrently, using ```python import asyncio -import httpcore +import httpcore2 import time @@ -126,7 +126,7 @@ async def download(http, year): async def main(): - async with httpcore.AsyncConnectionPool() as http: + async with httpcore2.AsyncConnectionPool() as http: started = time.time() # Here we use `asyncio.gather()` in order to run several tasks concurrently... tasks = [download(http, year) for year in range(2000, 2020)] @@ -146,7 +146,7 @@ asyncio.run(main()) Trio is [an alternative async library](https://trio.readthedocs.io/en/stable/), designed around the [the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency). ```python -import httpcore +import httpcore2 import trio import time @@ -156,7 +156,7 @@ async def download(http, year): async def main(): - async with httpcore.AsyncConnectionPool() as http: + async with httpcore2.AsyncConnectionPool() as http: started = time.time() async with trio.open_nursery() as nursery: for year in range(2000, 2020): @@ -178,7 +178,7 @@ AnyIO is an [asynchronous networking and concurrency library](https://anyio.read The `anyio` library is designed around the [the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency), and brings many of the same correctness and usability benefits that Trio provides, while interoperating with existing `asyncio` libraries. ```python -import httpcore +import httpcore2 import anyio import time @@ -188,7 +188,7 @@ async def download(http, year): async def main(): - async with httpcore.AsyncConnectionPool() as http: + async with httpcore2.AsyncConnectionPool() as http: started = time.time() async with anyio.create_task_group() as task_group: for year in range(2000, 2020): @@ -207,9 +207,9 @@ anyio.run(main) # Reference -## `httpcore.AsyncConnectionPool` +## `httpcore2.AsyncConnectionPool` -::: httpcore.AsyncConnectionPool +::: httpcore2.AsyncConnectionPool handler: python rendering: show_source: False diff --git a/src/httpcore2/docs/connection-pools.md b/docs/httpcore2/connection-pools.md similarity index 90% rename from src/httpcore2/docs/connection-pools.md rename to docs/httpcore2/connection-pools.md index cb461a98..1203aabe 100644 --- a/src/httpcore2/docs/connection-pools.md +++ b/docs/httpcore2/connection-pools.md @@ -1,15 +1,15 @@ # Connection Pools -While the top-level API provides convenience functions for working with `httpcore`, +While the top-level API provides convenience functions for working with `httpcore2`, in practice you'll almost always want to take advantage of the connection pooling functionality that it provides. To do so, instantiate a pool instance, and use it to send requests: ```python -import httpcore +import httpcore2 -http = httpcore.ConnectionPool() +http = httpcore2.ConnectionPool() r = http.request("GET", "https://www.example.com/") print(r) @@ -21,11 +21,11 @@ Connection pools support the same `.request()` and `.stream()` APIs [as describe We can observe the benefits of connection pooling with a simple script like so: ```python -import httpcore +import httpcore2 import time -http = httpcore.ConnectionPool() +http = httpcore2.ConnectionPool() for counter in range(5): started = time.time() response = http.request("GET", "https://www.example.com/") @@ -52,7 +52,7 @@ The connection pool instance is also the main point of configuration. Let's take ### SSL configuration * `ssl_context`: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` + If not specified, the default `httpcore2.default_ssl_context()` will be used. ### Pooling configuration @@ -93,20 +93,20 @@ Working with a single global instance isn't a bad idea for many use case, since # This is perfectly fine for most purposes. # The connection pool will automatically be closed when it is garbage collected, # or when the Python interpreter exits. -http = httpcore.ConnectionPool() +http = httpcore2.ConnectionPool() ``` However, to be more explicit around the resource usage, we can use the connection pool within a context manager: ```python -with httpcore.ConnectionPool() as http: +with httpcore2.ConnectionPool() as http: ... ``` Or else close the pool explicitly: ```python -http = httpcore.ConnectionPool() +http = httpcore2.ConnectionPool() try: ... finally: @@ -115,7 +115,7 @@ finally: ## Thread and task safety -Connection pools are designed to be thread-safe. Similarly, when using `httpcore` in an async context connection pools are task-safe. +Connection pools are designed to be thread-safe. Similarly, when using `httpcore2` in an async context connection pools are task-safe. This means that you can have a single connection pool instance shared by multiple threads. @@ -123,9 +123,9 @@ This means that you can have a single connection pool instance shared by multipl # Reference -## `httpcore.ConnectionPool` +## `httpcore2.ConnectionPool` -::: httpcore.ConnectionPool +::: httpcore2.ConnectionPool handler: python rendering: show_source: False diff --git a/src/httpcore2/docs/connections.md b/docs/httpcore2/connections.md similarity index 55% rename from src/httpcore2/docs/connections.md rename to docs/httpcore2/connections.md index 0ca21556..8ad87b39 100644 --- a/src/httpcore2/docs/connections.md +++ b/docs/httpcore2/connections.md @@ -6,23 +6,23 @@ TODO # Reference -## `httpcore.HTTPConnection` +## `httpcore2.HTTPConnection` -::: httpcore.HTTPConnection +::: httpcore2.HTTPConnection handler: python rendering: show_source: False -## `httpcore.HTTP11Connection` +## `httpcore2.HTTP11Connection` -::: httpcore.HTTP11Connection +::: httpcore2.HTTP11Connection handler: python rendering: show_source: False -## `httpcore.HTTP2Connection` +## `httpcore2.HTTP2Connection` -::: httpcore.HTTP2Connection +::: httpcore2.HTTP2Connection handler: python rendering: show_source: False diff --git a/docs/httpcore2/exceptions.md b/docs/httpcore2/exceptions.md new file mode 100644 index 00000000..fa85fd1b --- /dev/null +++ b/docs/httpcore2/exceptions.md @@ -0,0 +1,18 @@ +# Exceptions + +The following exceptions may be raised when sending a request: + +* `httpcore2.TimeoutException` + * `httpcore2.PoolTimeout` + * `httpcore2.ConnectTimeout` + * `httpcore2.ReadTimeout` + * `httpcore2.WriteTimeout` +* `httpcore2.NetworkError` + * `httpcore2.ConnectError` + * `httpcore2.ReadError` + * `httpcore2.WriteError` +* `httpcore2.ProtocolError` + * `httpcore2.RemoteProtocolError` + * `httpcore2.LocalProtocolError` +* `httpcore2.ProxyError` +* `httpcore2.UnsupportedProtocol` diff --git a/src/httpcore2/docs/extensions.md b/docs/httpcore2/extensions.md similarity index 86% rename from src/httpcore2/docs/extensions.md rename to docs/httpcore2/extensions.md index 7a24a418..0dd4b584 100644 --- a/src/httpcore2/docs/extensions.md +++ b/docs/httpcore2/extensions.md @@ -1,6 +1,6 @@ # Extensions -The request/response API used by `httpcore` is kept deliberately simple and explicit. +The request/response API used by `httpcore2` is kept deliberately simple and explicit. The `Request` and `Response` models are pretty slim wrappers around this core API: @@ -24,7 +24,7 @@ Well... almost. There is a maxim in Computer Science that *"All non-trivial abstractions, to some degree, are leaky"*. When an expression is leaky, it's important that it ought to at least leak only in well-defined places. -In order to handle cases that don't otherwise fit inside this core abstraction, `httpcore` requests and responses have 'extensions'. These are a dictionary of optional additional information. +In order to handle cases that don't otherwise fit inside this core abstraction, `httpcore2` requests and responses have 'extensions'. These are a dictionary of optional additional information. Let's expand on our request/response abstraction... @@ -49,7 +49,7 @@ Let's expand on our request/response abstraction... Several extensions are supported both on the request: ```python -r = httpcore.request( +r = httpcore2.request( "GET", "https://www.example.com", extensions={"timeout": {"connect": 5.0}} @@ -59,7 +59,7 @@ r = httpcore.request( And on the response: ```python -r = httpcore.request("GET", "https://www.example.com") +r = httpcore2.request("GET", "https://www.example.com") print(r.extensions["http_version"]) # When using HTTP/1.1 on the client side, the server HTTP response @@ -79,7 +79,7 @@ For example: ```python # Timeout if a connection takes more than 5 seconds to established, or if # we are blocked waiting on the connection pool for more than 10 seconds. -r = httpcore.request( +r = httpcore2.request( "GET", "https://www.example.com", extensions={"timeout": {"connect": 5.0, "pool": 10.0}} @@ -89,19 +89,19 @@ r = httpcore.request( ### `"trace"` The trace extension allows a callback handler to be installed to monitor the internal -flow of events within `httpcore`. The simplest way to explain this is with an example: +flow of events within `httpcore2`. The simplest way to explain this is with an example: ```python -import httpcore +import httpcore2 def log(event_name, info): print(event_name, info) -r = httpcore.request("GET", "https://www.example.com/", extensions={"trace": log}) +r = httpcore2.request("GET", "https://www.example.com/", extensions={"trace": log}) # connection.connect_tcp.started {'host': 'www.example.com', 'port': 443, 'local_address': None, 'timeout': None} -# connection.connect_tcp.complete {'return_value': } +# connection.connect_tcp.complete {'return_value': } # connection.start_tls.started {'ssl_context': , 'server_hostname': b'www.example.com', 'timeout': None} -# connection.start_tls.complete {'return_value': } +# connection.start_tls.complete {'return_value': } # http11.send_request_headers.started {'request': } # http11.send_request_headers.complete {'return_value': None} # http11.send_request_body.started {'request': } @@ -120,7 +120,7 @@ The `event_name` and `info` arguments here will be one of the following: * `{event_type}.{event_name}.complete`, `{"return_value": <...>}` * `{event_type}.{event_name}.failed`, `{"exception": <...>}` -Note that when using the async variant of `httpcore` the handler function passed to `"trace"` must be an `async def ...` function. +Note that when using the async variant of `httpcore2` the handler function passed to `"trace"` must be an `async def ...` function. The following event types are currently exposed... @@ -147,7 +147,7 @@ The following event types are currently exposed... * `"http2.receive_response_body"` * `"http2.response_closed"` -The exact set of trace events may be subject to change across different versions of `httpcore`. If you need to rely on a particular set of events it is recommended that you pin installation of the package to a fixed version. +The exact set of trace events may be subject to change across different versions of `httpcore2`. If you need to rely on a particular set of events it is recommended that you pin installation of the package to a fixed version. ### `"sni_hostname"` @@ -158,7 +158,7 @@ For example: ``` python headers = {"Host": "www.encode.io"} extensions = {"sni_hostname": "www.encode.io"} -response = httpcore.request( +response = httpcore2.request( "GET", "https://185.199.108.153", headers=headers, @@ -180,7 +180,7 @@ For example: ```python extensions = {"target": b"www.encode.io:443"} -response = httpcore.request( +response = httpcore2.request( "CONNECT", "http://your-tunnel-proxy.com", headers=headers, @@ -238,18 +238,18 @@ A proxy CONNECT request using the network stream: # CONNECT http://www.example.com HTTP/1.1 url = "http://127.0.0.1:8080" extensions = {"target: "http://www.example.com"} -with httpcore.stream("CONNECT", url, extensions=extensions) as response: +with httpcore2.stream("CONNECT", url, extensions=extensions) as response: network_stream = response.extensions["network_stream"] # Upgrade to an SSL stream... network_stream = network_stream.start_tls( - ssl_context=httpcore.default_ssl_context(), + ssl_context=httpcore2.default_ssl_context(), hostname=b"www.example.com", ) # Manually send an HTTP request over the network stream, and read the response... # - # For a more complete example see the httpcore `TunnelHTTPConnection` implementation. + # For a more complete example see the httpcore2 `TunnelHTTPConnection` implementation. network_stream.write(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") data = network_stream.read() print(data) @@ -260,7 +260,7 @@ with httpcore.stream("CONNECT", url, extensions=extensions) as response: Using the `wsproto` package to handle a websockets session: ```python -import httpcore +import httpcore2 import wsproto import os import base64 @@ -273,7 +273,7 @@ headers = { b"Sec-WebSocket-Key": base64.b64encode(os.urandom(16)), b"Sec-WebSocket-Version": b"13" } -with httpcore.stream("GET", url, headers=headers) as response: +with httpcore2.stream("GET", url, headers=headers) as response: if response.status != 101: raise Exception("Failed to upgrade to websockets", response) @@ -304,7 +304,7 @@ with httpcore.stream("GET", url, headers=headers) as response: The network stream abstraction also allows access to various low-level information that may be exposed by the underlying socket: ```python -response = httpcore.request("GET", "https://www.example.com") +response = httpcore2.request("GET", "https://www.example.com") network_stream = response.extensions["network_stream"] client_addr = network_stream.get_extra_info("client_addr") @@ -316,7 +316,7 @@ print("Server address", server_addr) The socket SSL information is also available through this interface, although you need to ensure that the underlying connection is still open, in order to access it... ```python -with httpcore.stream("GET", "https://www.example.com") as response: +with httpcore2.stream("GET", "https://www.example.com") as response: network_stream = response.extensions["network_stream"] ssl_object = network_stream.get_extra_info("ssl_object") diff --git a/src/httpcore2/docs/http2.md b/docs/httpcore2/http2.md similarity index 74% rename from src/httpcore2/docs/http2.md rename to docs/httpcore2/http2.md index f136a95d..6ebb2767 100644 --- a/src/httpcore2/docs/http2.md +++ b/docs/httpcore2/http2.md @@ -10,20 +10,20 @@ For a comprehensive guide to HTTP/2 you may want to check out "[HTTP2 Explained] ## Enabling HTTP/2 -When using the `httpcore` client, HTTP/2 support is not enabled by default, because HTTP/1.1 is a mature, battle-hardened transport layer, and our HTTP/1.1 implementation may be considered the more robust option at this point in time. It is possible that a future version of `httpcore` may enable HTTP/2 support by default. +When using the `httpcore2` client, HTTP/2 support is not enabled by default, because HTTP/1.1 is a mature, battle-hardened transport layer, and our HTTP/1.1 implementation may be considered the more robust option at this point in time. It is possible that a future version of `httpcore2` may enable HTTP/2 support by default. If you're issuing highly concurrent requests you might want to consider trying out our HTTP/2 support. You can do so by first making sure to install the optional HTTP/2 dependencies... ```shell -pip install 'httpcore[http2]' +pip install 'httpcore2[http2]' ``` And then instantiating a connection pool with HTTP/2 support enabled: ```python -import httpcore +import httpcore2 -pool = httpcore.ConnectionPool(http2=True) +pool = httpcore2.ConnectionPool(http2=True) ``` We can take a look at the difference in behaviour by issuing several outgoing requests in parallel. @@ -31,7 +31,7 @@ We can take a look at the difference in behaviour by issuing several outgoing re Start out by using a standard HTTP/1.1 connection pool: ```python -import httpcore +import httpcore2 import concurrent.futures import time @@ -41,7 +41,7 @@ def download(http, year): def main(): - with httpcore.ConnectionPool() as http: + with httpcore2.ConnectionPool() as http: started = time.time() with concurrent.futures.ThreadPoolExecutor(max_workers=10) as threads: for year in range(2000, 2020): @@ -75,7 +75,7 @@ We can see that the connection pool required a number of connections in order to If we now upgrade our connection pool to support HTTP/2: ```python -with httpcore.ConnectionPool(http2=True) as http: +with httpcore2.ConnectionPool(http2=True) as http: ... ``` @@ -97,9 +97,9 @@ Enabling HTTP/2 support on the client does not *necessarily* mean that your requ You can determine which version of the HTTP protocol was used by examining the `"http_version"` response extension. ```python -import httpcore +import httpcore2 -pool = httpcore.ConnectionPool(http2=True) +pool = httpcore2.ConnectionPool(http2=True) response = pool.request("GET", "https://www.example.com/") # Should be one of b"HTTP/2", b"HTTP/1.1", b"HTTP/1.0", or b"HTTP/0.9". @@ -116,13 +116,13 @@ Robust servers need to support both HTTP/2 and HTTP/1.1 capable clients, and so Generally the method used is for the server to advertise if it has HTTP/2 support during the part of the SSL connection handshake. This is known as ALPN - "Application Layer Protocol Negotiation". -Most browsers only provide HTTP/2 support over HTTPS connections, and this is also the default behaviour that `httpcore` provides. If you enable HTTP/2 support you should still expect to see HTTP/1.1 connections for any `http://` URLs. +Most browsers only provide HTTP/2 support over HTTPS connections, and this is also the default behaviour that `httpcore2` provides. If you enable HTTP/2 support you should still expect to see HTTP/1.1 connections for any `http://` URLs. ### HTTP/2 over HTTP Servers can optionally also support HTTP/2 over HTTP by supporting the `Upgrade: h2c` header. -This mechanism is not supported by `httpcore`. It requires an additional round-trip between the client and server, and also requires any request body to be sent twice. +This mechanism is not supported by `httpcore2`. It requires an additional round-trip between the client and server, and also requires any request body to be sent twice. ### Prior Knowledge @@ -131,14 +131,14 @@ If you know in advance that the server you are communicating with will support H This is managed by disabling HTTP/1.1 support on the connection pool: ```python -pool = httpcore.ConnectionPool(http1=False, http2=True) +pool = httpcore2.ConnectionPool(http1=False, http2=True) ``` ## Request & response headers Because HTTP/2 frames the requests and responses somewhat differently to HTTP/1.1, there is a difference in some of the headers that are used. -In order for the `httpcore` library to support both HTTP/1.1 and HTTP/2 transparently, the HTTP/1.1 style is always used throughout the API. Any differences in header styles are only mapped onto HTTP/2 at the internal network layer. +In order for the `httpcore2` library to support both HTTP/1.1 and HTTP/2 transparently, the HTTP/1.1 style is always used throughout the API. Any differences in header styles are only mapped onto HTTP/2 at the internal network layer. ## Request headers @@ -146,16 +146,16 @@ The following pseudo-headers are used by HTTP/2 in the request: * `:method` - The request method. * `:path` - Taken from the URL of the request. -* `:authority` - Equivalent to the `Host` header in HTTP/1.1. In `httpcore` this is represented using the request `Host` header, which is automatically populated from the request URL if no `Host` header is explicitly included. +* `:authority` - Equivalent to the `Host` header in HTTP/1.1. In `httpcore2` this is represented using the request `Host` header, which is automatically populated from the request URL if no `Host` header is explicitly included. * `:scheme` - Taken from the URL of the request. -These pseudo-headers are included in `httpcore` as part of the `request.method` and `request.url` attributes, and through the `request.headers["Host"]` header. *They are not exposed directly by their psuedo-header names.* +These pseudo-headers are included in `httpcore2` as part of the `request.method` and `request.url` attributes, and through the `request.headers["Host"]` header. *They are not exposed directly by their psuedo-header names.* The one other difference to be aware of is the `Transfer-Encoding: chunked` header. In HTTP/2 this header is never used, since streaming data is framed using a different mechanism. -In `httpcore` the `Transfer-Encoding: chunked` header is always used to represent the presence of a streaming body on the request, and is automatically populated if required. However the header is only sent if the underlying connection ends up being HTTP/1.1, and is omitted if the underlying connection ends up being HTTP/2. +In `httpcore2` the `Transfer-Encoding: chunked` header is always used to represent the presence of a streaming body on the request, and is automatically populated if required. However the header is only sent if the underlying connection ends up being HTTP/1.1, and is omitted if the underlying connection ends up being HTTP/2. ## Response headers @@ -163,4 +163,4 @@ The following pseudo-header is used by HTTP/2 in the response: * `:status` - The response status code. -In `httpcore` this *is represented by the `response.status` attribute, rather than being exposed as a psuedo-header*. +In `httpcore2` this *is represented by the `response.status` attribute, rather than being exposed as a psuedo-header*. diff --git a/src/httpcore2/docs/index.md b/docs/httpcore2/index.md similarity index 78% rename from src/httpcore2/docs/index.md rename to docs/httpcore2/index.md index 6505febe..96af14c9 100644 --- a/src/httpcore2/docs/index.md +++ b/docs/httpcore2/index.md @@ -1,7 +1,7 @@ # HTTPCore -[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions) -[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/) +[![Test Suite](https://github.com/pydantic/httpx2/workflows/Test%20Suite/badge.svg)](https://github.com/pydantic/httpx2/actions) +[![Package version](https://badge.fury.io/py/httpcore2.svg)](https://pypi.org/project/httpcore2/) > *Do one thing, and do it well.* @@ -28,19 +28,19 @@ Some things HTTP Core does do: For HTTP/1.1 only support, install with: ```shell -pip install httpcore +pip install httpcore2 ``` For HTTP/1.1 and HTTP/2 support, install with: ```shell -pip install httpcore[http2] +pip install httpcore2[http2] ``` For SOCKS proxy support, install with: ```shell -pip install httpcore[socks] +pip install httpcore2[socks] ``` ## Example @@ -48,9 +48,9 @@ pip install httpcore[socks] Let's check we're able to send HTTP requests: ```python -import httpcore +import httpcore2 -response = httpcore.request("GET", "https://www.example.com/") +response = httpcore2.request("GET", "https://www.example.com/") print(response) # diff --git a/docs/httpcore2/logging.md b/docs/httpcore2/logging.md new file mode 100644 index 00000000..122e9b47 --- /dev/null +++ b/docs/httpcore2/logging.md @@ -0,0 +1,41 @@ +# Logging + +If you need to inspect the internal behaviour of `httpcore2`, you can use Python's standard logging to output debug level information. + +For example, the following configuration... + +```python +import logging +import httpcore2 + +logging.basicConfig( + format="%(levelname)s [%(asctime)s] %(name)s - %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.DEBUG +) + +httpcore2.request('GET', 'https://www.example.com') +``` + +Will send debug level output to the console, or wherever `stdout` is directed too... + +``` +DEBUG [2023-01-09 14:44:00] httpcore2.connection - connect_tcp.started host='www.example.com' port=443 local_address=None timeout=None +DEBUG [2023-01-09 14:44:00] httpcore2.connection - connect_tcp.complete return_value= +DEBUG [2023-01-09 14:44:00] httpcore2.connection - start_tls.started ssl_context= server_hostname='www.example.com' timeout=None +DEBUG [2023-01-09 14:44:00] httpcore2.connection - start_tls.complete return_value= +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - send_request_headers.started request= +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - send_request_headers.complete +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - send_request_body.started request= +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - send_request_body.complete +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - receive_response_headers.started request= +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Age', b'572646'), (b'Cache-Control', b'max-age=604800'), (b'Content-Type', b'text/html; charset=UTF-8'), (b'Date', b'Mon, 09 Jan 2023 14:44:00 GMT'), (b'Etag', b'"3147526947+ident"'), (b'Expires', b'Mon, 16 Jan 2023 14:44:00 GMT'), (b'Last-Modified', b'Thu, 17 Oct 2019 07:18:26 GMT'), (b'Server', b'ECS (nyb/1D18)'), (b'Vary', b'Accept-Encoding'), (b'X-Cache', b'HIT'), (b'Content-Length', b'1256')]) +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - receive_response_body.started request= +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - receive_response_body.complete +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - response_closed.started +DEBUG [2023-01-09 14:44:00] httpcore2.http11 - response_closed.complete +DEBUG [2023-01-09 14:44:00] httpcore2.connection - close.started +DEBUG [2023-01-09 14:44:00] httpcore2.connection - close.complete +``` + +The exact formatting of the debug logging may be subject to change across different versions of `httpcore2`. If you need to rely on a particular format it is recommended that you pin installation of the package to a fixed version. diff --git a/src/httpcore2/docs/network-backends.md b/docs/httpcore2/network-backends.md similarity index 76% rename from src/httpcore2/docs/network-backends.md rename to docs/httpcore2/network-backends.md index fbb6bfdb..169b5364 100644 --- a/src/httpcore2/docs/network-backends.md +++ b/docs/httpcore2/network-backends.md @@ -1,6 +1,6 @@ # Network Backends -The API layer at which `httpcore` interacts with the network is described as the network backend. Various backend implementations are provided, allowing `httpcore` to handle networking in different runtime contexts. +The API layer at which `httpcore2` interacts with the network is described as the network backend. Various backend implementations are provided, allowing `httpcore2` to handle networking in different runtime contexts. ## Working with network backends @@ -11,9 +11,9 @@ Typically you won't need to specify a network backend, as a default will automat First we're making a standard HTTP request, using a connection pool: ```python -import httpcore +import httpcore2 -with httpcore.ConnectionPool() as http: +with httpcore2.ConnectionPool() as http: response = http.request('GET', 'https://www.example.com') print(response) ``` @@ -21,23 +21,23 @@ with httpcore.ConnectionPool() as http: We can also have the same behavior, but be explicit with our selection of the network backend: ```python -import httpcore +import httpcore2 -network_backend = httpcore.SyncBackend() -with httpcore.ConnectionPool(network_backend=network_backend) as http: +network_backend = httpcore2.SyncBackend() +with httpcore2.ConnectionPool(network_backend=network_backend) as http: response = http.request('GET', 'https://www.example.com') print(response) ``` -The `httpcore.SyncBackend()` implementation handles the opening of TCP connections, and operations on the socket stream, such as reading, writing, and closing the connection. +The `httpcore2.SyncBackend()` implementation handles the opening of TCP connections, and operations on the socket stream, such as reading, writing, and closing the connection. We can get a better understanding of this by using a network backend to send a basic HTTP/1.1 request directly: ```python -import httpcore +import httpcore2 # Create an SSL context using 'certifi' for the certificates. -ssl_context = httpcore.default_ssl_context() +ssl_context = httpcore2.default_ssl_context() # A basic HTTP/1.1 request as a plain bytestring. request = b'\r\n'.join([ @@ -49,7 +49,7 @@ request = b'\r\n'.join([ ]) # Open a TCP stream and upgrade it to SSL. -network_backend = httpcore.SyncBackend() +network_backend = httpcore2.SyncBackend() network_stream = network_backend.connect_tcp("www.example.com", 443) network_stream = network_stream.start_tls(ssl_context, server_hostname="www.example.com") @@ -73,32 +73,32 @@ while True: If we're working with an `async` codebase, then we need to select a different backend. -The `httpcore.AnyIOBackend` is suitable for usage if you're running under `asyncio`. This is a networking backend implemented using [the `anyio` package](https://anyio.readthedocs.io/en/3.x/). +The `httpcore2.AnyIOBackend` is suitable for usage if you're running under `asyncio`. This is a networking backend implemented using [the `anyio` package](https://anyio.readthedocs.io/en/3.x/). ```python -import httpcore +import httpcore2 import asyncio async def main(): - network_backend = httpcore.AnyIOBackend() - async with httpcore.AsyncConnectionPool(network_backend=network_backend) as http: + network_backend = httpcore2.AnyIOBackend() + async with httpcore2.AsyncConnectionPool(network_backend=network_backend) as http: response = await http.request('GET', 'https://www.example.com') print(response) asyncio.run(main()) ``` -The `AnyIOBackend` will work when running under either `asyncio` or `trio`. However, if you're working with async using the [`trio` framework](https://trio.readthedocs.io/en/stable/), then we recommend using the `httpcore.TrioBackend`. +The `AnyIOBackend` will work when running under either `asyncio` or `trio`. However, if you're working with async using the [`trio` framework](https://trio.readthedocs.io/en/stable/), then we recommend using the `httpcore2.TrioBackend`. This will give you the same kind of networking behavior you'd have using `AnyIOBackend`, but there will be a little less indirection so it will be marginally more efficient and will present cleaner tracebacks in error cases. ```python -import httpcore +import httpcore2 import trio async def main(): - network_backend = httpcore.TrioBackend() - async with httpcore.AsyncConnectionPool(network_backend=network_backend) as http: + network_backend = httpcore2.TrioBackend() + async with httpcore2.AsyncConnectionPool(network_backend=network_backend) as http: response = await http.request('GET', 'https://www.example.com') print(response) @@ -113,16 +113,16 @@ These backends accept a list of bytes, and return network stream interfaces that Here's an example of mocking a simple HTTP/1.1 response... ```python -import httpcore +import httpcore2 -network_backend = httpcore.MockBackend([ +network_backend = httpcore2.MockBackend([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) -with httpcore.ConnectionPool(network_backend=network_backend) as http: +with httpcore2.ConnectionPool(network_backend=network_backend) as http: response = http.request("GET", "https://example.com/") print(response.extensions['http_version']) print(response.status) @@ -134,7 +134,7 @@ Mocking a HTTP/2 response is more complex, since it uses a binary format... ```python import hpack import hyperframe.frame -import httpcore +import httpcore2 content = [ hyperframe.frame.SettingsFrame().serialize(), @@ -155,8 +155,8 @@ content = [ # Note that we instantiate the mock backend with an `http2=True` argument. # This ensures that the mock network stream acts as if the `h2` ALPN flag has been set, # and causes the connection pool to interact with the connection using HTTP/2. -network_backend = httpcore.MockBackend(content, http2=True) -with httpcore.ConnectionPool(network_backend=network_backend) as http: +network_backend = httpcore2.MockBackend(content, http2=True) +with httpcore2.ConnectionPool(network_backend=network_backend) as http: response = http.request("GET", "https://example.com/") print(response.extensions['http_version']) print(response.status) @@ -176,10 +176,10 @@ You can use this to provide advanced networking functionality such as: Here's an example that records the network response to a file on disk: ```python -import httpcore +import httpcore2 -class RecordingNetworkStream(httpcore.NetworkStream): +class RecordingNetworkStream(httpcore2.NetworkStream): def __init__(self, record_file, stream): self.record_file = record_file self.stream = stream @@ -210,13 +210,13 @@ class RecordingNetworkStream(httpcore.NetworkStream): return self.stream.get_extra_info(info) -class RecordingNetworkBackend(httpcore.NetworkBackend): +class RecordingNetworkBackend(httpcore2.NetworkBackend): """ A custom network backend that records network responses. """ def __init__(self, record_file): self.record_file = record_file - self.backend = httpcore.SyncBackend() + self.backend = httpcore2.SyncBackend() def connect_tcp( self, @@ -243,13 +243,13 @@ class RecordingNetworkBackend(httpcore.NetworkBackend): # Once you make the request, the raw HTTP/1.1 response will be available -# in the 'network-recording' file. +# in the 'network-recording' file. # # Try switching to `http2=True` to see the difference when recording HTTP/2 binary network traffic, # or add `headers={'Accept-Encoding': 'gzip'}` to see HTTP content compression. with open("network-recording", "wb") as record_file: network_backend = RecordingNetworkBackend(record_file) - with httpcore.ConnectionPool(network_backend=network_backend) as http: + with httpcore2.ConnectionPool(network_backend=network_backend) as http: response = http.request("GET", "https://www.example.com/") print(response) ``` @@ -260,20 +260,20 @@ with open("network-recording", "wb") as record_file: ### Networking Backends -* `httpcore.SyncBackend` -* `httpcore.AnyIOBackend` -* `httpcore.TrioBackend` +* `httpcore2.SyncBackend` +* `httpcore2.AnyIOBackend` +* `httpcore2.TrioBackend` ### Mock Backends -* `httpcore.MockBackend` -* `httpcore.MockStream` -* `httpcore.AsyncMockBackend` -* `httpcore.AsyncMockStream` +* `httpcore2.MockBackend` +* `httpcore2.MockStream` +* `httpcore2.AsyncMockBackend` +* `httpcore2.AsyncMockStream` ### Base Interface -* `httpcore.NetworkBackend` -* `httpcore.NetworkStream` -* `httpcore.AsyncNetworkBackend` -* `httpcore.AsyncNetworkStream` +* `httpcore2.NetworkBackend` +* `httpcore2.NetworkStream` +* `httpcore2.AsyncNetworkBackend` +* `httpcore2.AsyncNetworkStream` diff --git a/src/httpcore2/docs/proxies.md b/docs/httpcore2/proxies.md similarity index 57% rename from src/httpcore2/docs/proxies.md rename to docs/httpcore2/proxies.md index 492ea86f..75198dc3 100644 --- a/src/httpcore2/docs/proxies.md +++ b/docs/httpcore2/proxies.md @@ -1,21 +1,21 @@ # Proxies -The `httpcore` package provides support for HTTP proxies, using either "HTTP Forwarding" or "HTTP Tunnelling". Forwarding is a proxy mechanism for sending requests to `http` URLs via an intermediate proxy. Tunnelling is a proxy mechanism for sending requests to `https` URLs via an intermediate proxy. +The `httpcore2` package provides support for HTTP proxies, using either "HTTP Forwarding" or "HTTP Tunnelling". Forwarding is a proxy mechanism for sending requests to `http` URLs via an intermediate proxy. Tunnelling is a proxy mechanism for sending requests to `https` URLs via an intermediate proxy. Sending requests via a proxy is very similar to sending requests using a standard connection pool: ```python -import httpcore +import httpcore2 -proxy = httpcore.Proxy("http://127.0.0.1:8080/") -pool = httpcore.ConnectionPool(proxy=proxy) +proxy = httpcore2.Proxy("http://127.0.0.1:8080/") +pool = httpcore2.ConnectionPool(proxy=proxy) r = proxy.request("GET", "https://www.example.com/") print(r) # ``` -You can test the `httpcore` proxy support, using the Python [`proxy.py`](https://pypi.org/project/proxy.py/) tool: +You can test the `httpcore2` proxy support, using the Python [`proxy.py`](https://pypi.org/project/proxy.py/) tool: ```shell pip install proxy.py @@ -29,88 +29,88 @@ Requests will automatically use either forwarding or tunnelling, depending on if Proxy authentication can be included in the initial configuration: ```python -import httpcore +import httpcore2 # A `Proxy-Authorization` header will be included on the initial proxy connection. -proxy = httpcore.Proxy( +proxy = httpcore2.Proxy( url="http://127.0.0.1:8080/", auth=("", "") ) -pool = httpcore.ConnectionPool(proxy=proxy) +pool = httpcore2.ConnectionPool(proxy=proxy) ``` Custom headers can also be included: ```python -import httpcore +import httpcore2 import base64 # Construct and include a `Proxy-Authorization` header. auth = base64.b64encode(b":") -proxy = httpcore.Proxy( +proxy = httpcore2.Proxy( url="http://127.0.0.1:8080/", headers={"Proxy-Authorization": b"Basic " + auth} ) -pool = httpcore.ConnectionPool(proxy=proxy) +pool = httpcore2.ConnectionPool(proxy=proxy) ``` ## Proxy SSL -The `httpcore` package also supports HTTPS proxies for http and https destinations. +The `httpcore2` package also supports HTTPS proxies for http and https destinations. HTTPS proxies can be used in the same way that HTTP proxies are. ```python -proxy = httpcore.Proxy(url="https://127.0.0.1:8080/") +proxy = httpcore2.Proxy(url="https://127.0.0.1:8080/") ``` Also, when using HTTPS proxies, you may need to configure the SSL context, which you can do with the `ssl_context` argument. ```python import ssl -import httpcore +import httpcore2 proxy_ssl_context = ssl.create_default_context() proxy_ssl_context.check_hostname = False -proxy = httpcore.Proxy( +proxy = httpcore2.Proxy( url='https://127.0.0.1:8080/', ssl_context=proxy_ssl_context ) -pool = httpcore.ConnectionPool(proxy=proxy) +pool = httpcore2.ConnectionPool(proxy=proxy) ``` ## HTTP Versions -If you use proxies, keep in mind that the `httpcore` package only supports proxies to HTTP/1.1 servers. +If you use proxies, keep in mind that the `httpcore2` package only supports proxies to HTTP/1.1 servers. ## SOCKS proxy support -The `httpcore` package also supports proxies using the SOCKS5 protocol. +The `httpcore2` package also supports proxies using the SOCKS5 protocol. -Make sure to install the optional dependency using `pip install 'httpcore[socks]'`. +Make sure to install the optional dependency using `pip install 'httpcore2[socks]'`. The `SOCKSProxy` class should be using instead of a standard connection pool: ```python -import httpcore +import httpcore2 # Note that the SOCKS port is 1080. -proxy = httpcore.Proxy(url="socks5://127.0.0.1:1080/") -pool = httpcore.ConnectionPool(proxy=proxy) +proxy = httpcore2.Proxy(url="socks5://127.0.0.1:1080/") +pool = httpcore2.ConnectionPool(proxy=proxy) r = pool.request("GET", "https://www.example.com/") ``` Authentication via SOCKS is also supported: ```python -import httpcore +import httpcore2 -proxy = httpcore.Proxy( +proxy = httpcore2.Proxy( url="socks5://127.0.0.1:1080/", auth=("", ""), ) -pool = httpcore.ConnectionPool(proxy=proxy) +pool = httpcore2.ConnectionPool(proxy=proxy) r = pool.request("GET", "https://www.example.com/") ``` @@ -118,9 +118,9 @@ r = pool.request("GET", "https://www.example.com/") # Reference -## `httpcore.Proxy` +## `httpcore2.Proxy` -::: httpcore.Proxy +::: httpcore2.Proxy handler: python rendering: show_source: False diff --git a/src/httpcore2/docs/quickstart.md b/docs/httpcore2/quickstart.md similarity index 68% rename from src/httpcore2/docs/quickstart.md rename to docs/httpcore2/quickstart.md index e43b0596..c63a1d19 100644 --- a/src/httpcore2/docs/quickstart.md +++ b/docs/httpcore2/quickstart.md @@ -1,15 +1,15 @@ # Quickstart -For convenience, the `httpcore` package provides a couple of top-level functions that you can use for sending HTTP requests. You probably don't want to integrate against functions if you're writing a library that uses `httpcore`, but you might find them useful for testing `httpcore` from the command-line, or if you're writing a simple script that doesn't require any of the connection pooling or advanced configuration that `httpcore` offers. +For convenience, the `httpcore2` package provides a couple of top-level functions that you can use for sending HTTP requests. You probably don't want to integrate against functions if you're writing a library that uses `httpcore2`, but you might find them useful for testing `httpcore2` from the command-line, or if you're writing a simple script that doesn't require any of the connection pooling or advanced configuration that `httpcore2` offers. ## Sending a request We'll start off by sending a request... ```python -import httpcore +import httpcore2 -response = httpcore.request("GET", "https://www.example.com/") +response = httpcore2.request("GET", "https://www.example.com/") print(response) # @@ -26,17 +26,17 @@ print(response.content) Request headers may be included either in a dictionary style, or as a list of two-tuples. ```python -import httpcore +import httpcore2 import json -headers = {'User-Agent': 'httpcore'} -r = httpcore.request('GET', 'https://httpbin.org/headers', headers=headers) +headers = {'User-Agent': 'httpcore2'} +r = httpcore2.request('GET', 'https://httpbin.org/headers', headers=headers) print(json.loads(r.content)) # { # 'headers': { # 'Host': 'httpbin.org', -# 'User-Agent': 'httpcore', +# 'User-Agent': 'httpcore2', # 'X-Amzn-Trace-Id': 'Root=1-616ff5de-5ea1b7e12766f1cf3b8e3a33' # } # } @@ -53,10 +53,10 @@ The `Host` header will always be automatically included in any outgoing request, A request body can be included either as bytes... ```python -import httpcore +import httpcore2 import json -r = httpcore.request('POST', 'https://httpbin.org/post', content=b'Hello, world') +r = httpcore2.request('POST', 'https://httpbin.org/post', content=b'Hello, world') print(json.loads(r.content)) # { @@ -78,11 +78,11 @@ print(json.loads(r.content)) Or as an iterable that returns bytes... ```python -import httpcore +import httpcore2 import json with open("hello-world.txt", "rb") as input_file: - r = httpcore.request('POST', 'https://httpbin.org/post', content=input_file) + r = httpcore2.request('POST', 'https://httpbin.org/post', content=input_file) print(json.loads(r.content)) # { @@ -109,14 +109,14 @@ The `Transfer-Encoding: chunked` header is the mechanism that HTTP/1.1 uses for ## Streaming responses -When using the `httpcore.request()` function, the response body will automatically be read to completion, and made available in the `response.content` attribute. +When using the `httpcore2.request()` function, the response body will automatically be read to completion, and made available in the `response.content` attribute. -Sometimes you may be dealing with large responses and not want to read the entire response into memory. The `httpcore.stream()` function provides a mechanism for sending a request and dealing with a streaming response: +Sometimes you may be dealing with large responses and not want to read the entire response into memory. The `httpcore2.stream()` function provides a mechanism for sending a request and dealing with a streaming response: ```python -import httpcore +import httpcore2 -with httpcore.stream('GET', 'https://example.com') as response: +with httpcore2.stream('GET', 'https://example.com') as response: for chunk in response.iter_stream(): print(f"Downloaded: {chunk}") ``` @@ -124,20 +124,20 @@ with httpcore.stream('GET', 'https://example.com') as response: Here's a more complete example that demonstrates downloading a response: ```python -import httpcore +import httpcore2 -with httpcore.stream('GET', 'https://speed.hetzner.de/100MB.bin') as response: +with httpcore2.stream('GET', 'https://speed.hetzner.de/100MB.bin') as response: with open("download.bin", "wb") as output_file: for chunk in response.iter_stream(): output_file.write(chunk) ``` -The `httpcore.stream()` API also allows you to *conditionally* read the response... +The `httpcore2.stream()` API also allows you to *conditionally* read the response... ```python -import httpcore +import httpcore2 -with httpcore.stream('GET', 'https://example.com') as response: +with httpcore2.stream('GET', 'https://example.com') as response: content_length = [int(v) for k, v in response.headers if k.lower() == b'content-length'][0] if content_length > 100_000_000: raise Exception("Response too large.") @@ -148,16 +148,16 @@ with httpcore.stream('GET', 'https://example.com') as response: # Reference -## `httpcore.request()` +## `httpcore2.request()` -::: httpcore.request +::: httpcore2.request handler: python rendering: show_source: False -## `httpcore.stream()` +## `httpcore2.stream()` -::: httpcore.stream +::: httpcore2.stream handler: python rendering: show_source: False diff --git a/src/httpcore2/docs/requests-responses-urls.md b/docs/httpcore2/requests-responses-urls.md similarity index 61% rename from src/httpcore2/docs/requests-responses-urls.md rename to docs/httpcore2/requests-responses-urls.md index 7919a54c..f4e8fb74 100644 --- a/src/httpcore2/docs/requests-responses-urls.md +++ b/docs/httpcore2/requests-responses-urls.md @@ -4,27 +4,27 @@ TODO ## Requests -Request instances in `httpcore` are deliberately simple, and only include the essential information required to represent an HTTP request. +Request instances in `httpcore2` are deliberately simple, and only include the essential information required to represent an HTTP request. Properties on the request are plain byte-wise representations. ```python ->>> request = httpcore.Request("GET", "https://www.example.com/") +>>> request = httpcore2.Request("GET", "https://www.example.com/") >>> request.method b"GET" >>> request.url -httpcore.URL(scheme=b"https", host=b"www.example.com", port=None, target=b"/") +httpcore2.URL(scheme=b"https", host=b"www.example.com", port=None, target=b"/") >>> request.headers [(b'Host', b'www.example.com')] >>> request.stream - + ``` The interface is liberal in the types that it accepts, but specific in the properties that it uses to represent them. For example, headers may be specified as a dictionary of strings, but internally are represented as a list of `(byte, byte)` tuples. ```python >>> headers = {"User-Agent": "custom"} ->>> request = httpcore.Request("GET", "https://www.example.com/", headers=headers) +>>> request = httpcore2.Request("GET", "https://www.example.com/", headers=headers) >>> request.headers [(b'Host', b'www.example.com'), (b"User-Agent", b"custom")] @@ -40,23 +40,23 @@ The interface is liberal in the types that it accepts, but specific in the prope # Reference -## `httpcore.Request` +## `httpcore2.Request` -::: httpcore.Request +::: httpcore2.Request handler: python rendering: show_source: False -## `httpcore.Response` +## `httpcore2.Response` -::: httpcore.Response +::: httpcore2.Response handler: python rendering: show_source: False -## `httpcore.URL` +## `httpcore2.URL` -::: httpcore.URL +::: httpcore2.URL handler: python rendering: show_source: False diff --git a/mkdocs.yml b/mkdocs.yml index 2e1654a3..9829a244 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -48,6 +48,19 @@ nav: - Third Party Packages: 'third_party_packages.md' - Contributing: 'contributing.md' - Code of Conduct: 'code_of_conduct.md' + - httpcore2: + - Introduction: 'httpcore2/index.md' + - Quickstart: 'httpcore2/quickstart.md' + - Requests, Responses, and URLs: 'httpcore2/requests-responses-urls.md' + - Connection Pools: 'httpcore2/connection-pools.md' + - Connections: 'httpcore2/connections.md' + - Proxies: 'httpcore2/proxies.md' + - HTTP/2: 'httpcore2/http2.md' + - Async Support: 'httpcore2/async.md' + - Network Backends: 'httpcore2/network-backends.md' + - Extensions: 'httpcore2/extensions.md' + - Logging: 'httpcore2/logging.md' + - Exceptions: 'httpcore2/exceptions.md' plugins: - mkdocstrings: diff --git a/src/httpcore2/docs/exceptions.md b/src/httpcore2/docs/exceptions.md deleted file mode 100644 index 63ef3f28..00000000 --- a/src/httpcore2/docs/exceptions.md +++ /dev/null @@ -1,18 +0,0 @@ -# Exceptions - -The following exceptions may be raised when sending a request: - -* `httpcore.TimeoutException` - * `httpcore.PoolTimeout` - * `httpcore.ConnectTimeout` - * `httpcore.ReadTimeout` - * `httpcore.WriteTimeout` -* `httpcore.NetworkError` - * `httpcore.ConnectError` - * `httpcore.ReadError` - * `httpcore.WriteError` -* `httpcore.ProtocolError` - * `httpcore.RemoteProtocolError` - * `httpcore.LocalProtocolError` -* `httpcore.ProxyError` -* `httpcore.UnsupportedProtocol` diff --git a/src/httpcore2/docs/logging.md b/src/httpcore2/docs/logging.md deleted file mode 100644 index 8db85875..00000000 --- a/src/httpcore2/docs/logging.md +++ /dev/null @@ -1,41 +0,0 @@ -# Logging - -If you need to inspect the internal behaviour of `httpcore`, you can use Python's standard logging to output debug level information. - -For example, the following configuration... - -```python -import logging -import httpcore - -logging.basicConfig( - format="%(levelname)s [%(asctime)s] %(name)s - %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - level=logging.DEBUG -) - -httpcore.request('GET', 'https://www.example.com') -``` - -Will send debug level output to the console, or wherever `stdout` is directed too... - -``` -DEBUG [2023-01-09 14:44:00] httpcore.connection - connect_tcp.started host='www.example.com' port=443 local_address=None timeout=None -DEBUG [2023-01-09 14:44:00] httpcore.connection - connect_tcp.complete return_value= -DEBUG [2023-01-09 14:44:00] httpcore.connection - start_tls.started ssl_context= server_hostname='www.example.com' timeout=None -DEBUG [2023-01-09 14:44:00] httpcore.connection - start_tls.complete return_value= -DEBUG [2023-01-09 14:44:00] httpcore.http11 - send_request_headers.started request= -DEBUG [2023-01-09 14:44:00] httpcore.http11 - send_request_headers.complete -DEBUG [2023-01-09 14:44:00] httpcore.http11 - send_request_body.started request= -DEBUG [2023-01-09 14:44:00] httpcore.http11 - send_request_body.complete -DEBUG [2023-01-09 14:44:00] httpcore.http11 - receive_response_headers.started request= -DEBUG [2023-01-09 14:44:00] httpcore.http11 - receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Age', b'572646'), (b'Cache-Control', b'max-age=604800'), (b'Content-Type', b'text/html; charset=UTF-8'), (b'Date', b'Mon, 09 Jan 2023 14:44:00 GMT'), (b'Etag', b'"3147526947+ident"'), (b'Expires', b'Mon, 16 Jan 2023 14:44:00 GMT'), (b'Last-Modified', b'Thu, 17 Oct 2019 07:18:26 GMT'), (b'Server', b'ECS (nyb/1D18)'), (b'Vary', b'Accept-Encoding'), (b'X-Cache', b'HIT'), (b'Content-Length', b'1256')]) -DEBUG [2023-01-09 14:44:00] httpcore.http11 - receive_response_body.started request= -DEBUG [2023-01-09 14:44:00] httpcore.http11 - receive_response_body.complete -DEBUG [2023-01-09 14:44:00] httpcore.http11 - response_closed.started -DEBUG [2023-01-09 14:44:00] httpcore.http11 - response_closed.complete -DEBUG [2023-01-09 14:44:00] httpcore.connection - close.started -DEBUG [2023-01-09 14:44:00] httpcore.connection - close.complete -``` - -The exact formatting of the debug logging may be subject to change across different versions of `httpcore`. If you need to rely on a particular format it is recommended that you pin installation of the package to a fixed version. \ No newline at end of file diff --git a/src/httpcore2/docs/table-of-contents.md b/src/httpcore2/docs/table-of-contents.md deleted file mode 100644 index 5dc9a10b..00000000 --- a/src/httpcore2/docs/table-of-contents.md +++ /dev/null @@ -1,49 +0,0 @@ -# API Reference - -* Quickstart - * `httpcore.request()` - * `httpcore.stream()` -* Requests, Responses, and URLs - * `httpcore.Request` - * `httpcore.Response` - * `httpcore.URL` -* Connection Pools - * `httpcore.ConnectionPool` -* Proxies - * `httpcore.Proxy` -* Connections - * `httpcore.HTTPConnection` - * `httpcore.HTTP11Connection` - * `httpcore.HTTP2Connection` -* Async Support - * `httpcore.AsyncConnectionPool` - * `httpcore.AsyncHTTPConnection` - * `httpcore.AsyncHTTP11Connection` - * `httpcore.AsyncHTTP2Connection` -* Network Backends - * Sync - * `httpcore.backends.sync.SyncBackend` - * `httpcore.backends.mock.MockBackend` - * Async - * `httpcore.backends.auto.AutoBackend` - * `httpcore.backends.asyncio.AsyncioBackend` - * `httpcore.backends.trio.TrioBackend` - * `httpcore.backends.mock.AsyncMockBackend` - * Base interfaces - * `httpcore.backends.base.NetworkBackend` - * `httpcore.backends.base.AsyncNetworkBackend` -* Exceptions - * `httpcore.TimeoutException` - * `httpcore.PoolTimeout` - * `httpcore.ConnectTimeout` - * `httpcore.ReadTimeout` - * `httpcore.WriteTimeout` - * `httpcore.NetworkError` - * `httpcore.ConnectError` - * `httpcore.ReadError` - * `httpcore.WriteError` - * `httpcore.ProtocolError` - * `httpcore.RemoteProtocolError` - * `httpcore.LocalProtocolError` - * `httpcore.ProxyError` - * `httpcore.UnsupportedProtocol` diff --git a/src/httpcore2/mkdocs.yml b/src/httpcore2/mkdocs.yml deleted file mode 100644 index 9f4200ba..00000000 --- a/src/httpcore2/mkdocs.yml +++ /dev/null @@ -1,36 +0,0 @@ -site_name: HTTPCore -site_description: A minimal HTTP client for Python. -site_url: https://www.encode.io/httpcore/ - -repo_name: encode/httpcore -repo_url: https://github.com/encode/httpcore/ - -nav: - - Introduction: 'index.md' - - Quickstart: 'quickstart.md' - - Connection Pools: 'connection-pools.md' - - Proxies: 'proxies.md' - - HTTP/2: 'http2.md' - - Async Support: 'async.md' - - Network Backends: 'network-backends.md' - - Extensions: 'extensions.md' - - Logging: 'logging.md' - - Exceptions: 'exceptions.md' - -theme: - name: "material" - -plugins: - - search - - mkdocstrings: - default_handler: python - watch: - - httpcore - handlers: - python: - members_order: - - "source" - -markdown_extensions: - - codehilite: - css_class: highlight