Skip to content

Commit e5debd4

Browse files
authored
Merge pull request #1 from encode/september-2020-report
September 2020 report
2 parents 1ff8541 + 99e4e40 commit e5debd4

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

reports/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ title: "Monthly Reports"
77

88
## 2020
99

10+
* [September 2020](september-2020)
1011
* [August 2020](august-2020)
1112
* [July 2020](july-2020)
1213
* [June 2020](june-2020)

reports/september-2020.md

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
---
2+
layout: reports
3+
title: "September 2020"
4+
---
5+
6+
# Django REST framework
7+
8+
## 3.12 Release
9+
10+
Django REST framework 3.12 has finally been released.
11+
12+
There's a host of smaller issues resolved in this, plus a few headline features
13+
around schema generation.
14+
15+
See the [release announcement](https://www.django-rest-framework.org/community/3.12-announcement/)
16+
for details.
17+
18+
## 3.11.2 Security release
19+
20+
We've also issued a security release, in version 3.11.2.
21+
22+
This release resolves a potential XSS issue in the browsable API.
23+
24+
# HTTPX
25+
26+
We're continuing to work towards a 1.0 release.
27+
28+
Our latest release of 0.15 brings with it a number of new features,
29+
including the following...
30+
31+
## Using Request and Response instances directly
32+
33+
We've improved support for being able to use `Request` and `Response` instances
34+
as stand-alone models. For example...
35+
36+
```python
37+
# Create a response instance, with JSON content.
38+
response = Response(200, json={"hello, world!"})
39+
```
40+
41+
This work will allow you use request and response instances in more contexts.
42+
43+
For example, it becomes easier to unit test authentication classes. It's also
44+
allow us to work towards providing a mock transport handler for stubbing
45+
46+
## Support for event hooks
47+
48+
HTTPX allows you to register "event hooks" with the client, that are called
49+
every time a particular type of event takes place.
50+
51+
There are currently two event hooks:
52+
53+
* `request` - Called once a request is about to be sent. Passed the `request` instance.
54+
* `response` - Called once the response has been returned. Passed the `response` instance.
55+
56+
These allow you to install client-wide functionality such as logging and monitoring.
57+
58+
```python
59+
def log_request(request):
60+
print(f"Request event hook: {request.method} {request.url} - Waiting for response")
61+
62+
def log_response(response):
63+
request = response.request
64+
print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
65+
66+
client = httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]})
67+
```
68+
69+
You can also use these hooks to install response processing code, such as this
70+
example, which creates a client instance that always raises `httpx.HTTPStatusError`
71+
on 4xx and 5xx responses.
72+
73+
```python
74+
def raise_on_4xx_5xx(response):
75+
response.raise_for_status()
76+
77+
client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})
78+
```
79+
80+
Event hooks must always be set as a *list of callables*, and you may register
81+
multiple event hooks for each type of event.
82+
83+
As well as being able to set event hooks on instantiating the client, there
84+
is also an `.event_hooks` property, that allows you to inspect and modify
85+
the installed hooks.
86+
87+
```python
88+
client = httpx.Client()
89+
client.event_hooks['request'] = [log_request]
90+
client.event_hooks['response'] = [log_response, raise_on_4xx_5xx]
91+
```
92+
93+
## Support for authentication flows which require I/O
94+
95+
Our authentication API already supports authentication classes which make one
96+
or multiple requests, and which work equally with both `Client` and `AsyncClient`.
97+
98+
However if you need to perform I/O within an authentication class, things become
99+
more complex, as thread-blocking I/O should not be performed within an async
100+
context, and async I/O cannot be performed within a sync context.
101+
102+
We've [now added support for authentication classes which require I/O](https://www.python-httpx.org/advanced/#customizing-authentication),
103+
allowing developers to support *either* the sync I/O case, *or* the
104+
async I/O case, *or* both cases.
105+
106+
## Support for Curio
107+
108+
The `AsyncClient` now supports [the curio async framework](https://github.com/dabeaz/curio).
109+
110+
When working with async, the `httpx` client will autodetect if you're in an
111+
`asyncio`, `trio`, or `curio` context, and everything will *just work*...
112+
113+
```python
114+
import curio
115+
import httpx
116+
117+
async def main():
118+
async with httpx.AsyncClient() as client:
119+
r = await client.get("https://www.httpbin.org/json")
120+
print(r.status_code)
121+
print(r.json())
122+
123+
curio.run(main)
124+
```
125+
126+
## Monitoring download progress
127+
128+
When performing a large download you'll sometimes want to monitor the ongoing
129+
progress, by periodically comparing how many bytes have been downloaded against
130+
the `Content-Length` header included in the response.
131+
132+
This is actually more awkward to do than might be expected at first, because
133+
HTTP supports compression on responses, and clients such as `httpx`, `requests`,
134+
and `urllib3` will transparently handle the decompression for you when iterating
135+
over the response bytes.
136+
137+
We now provide [access to the underlying number of bytes that have been read from
138+
the response body](https://www.python-httpx.org/advanced/#monitoring-download-progress),
139+
allowing for accurate download progress monitoring.
140+
141+
## HTTPX command line client
142+
143+
We've released [a beta version of an `httpx` command line client](https://github.com/encode/httpx-cli)...
144+
145+
```shell
146+
$ pip install httpx-cli
147+
$ httpx https://www.httpbin.org/json
148+
HTTP/1.1 200 OK
149+
date: Fri, 02 Oct 2020 15:08:10 GMT
150+
content-type: application/json
151+
content-length: 429
152+
connection: keep-alive
153+
server: gunicorn/19.9.0
154+
access-control-allow-origin: *
155+
access-control-allow-credentials: true
156+
157+
{
158+
"slideshow": {
159+
"author": "Yours Truly",
160+
"date": "date of publication",
161+
"slides": [
162+
{
163+
"title": "Wake up to WonderWidgets!",
164+
"type": "all"
165+
},
166+
{
167+
"items": [
168+
"Why <em>WonderWidgets</em> are great",
169+
"Who <em>buys</em> WonderWidgets"
170+
],
171+
"title": "Overview",
172+
"type": "all"
173+
}
174+
],
175+
"title": "Sample Slide Show"
176+
}
177+
}
178+
```
179+
180+
## HTTP header casing
181+
182+
Our underlying HTTP transport uses the fantastically engineered [`h11` library](https://github.com/python-hyper/h11)
183+
for it's HTTP/1.1 support. Because the HTTP spec mandates that header names
184+
must be treated as case-insensitive, the `h11` library has historically taken
185+
a nice simple approach, and simply normalized header names by always lowercasing
186+
them.
187+
188+
However, there are plenty of non-compliant bits of HTTP infrastructure in the
189+
wild, so in *some* cases you really do want to be able to preserve the
190+
header casing used.
191+
192+
We've now got a [pull request against `h11`](https://github.com/python-hyper/h11/pull/104) that:
193+
194+
* Continues to support the existing `h11` API without modification.
195+
* While preserving HTTP header casing.
196+
* With minimal performance implications.
197+
198+
---
199+
200+
Thanks as ever to all our sponsors, contributors, and users,
201+
202+
&mdash; Tom Christie, 2nd October, 2020.

0 commit comments

Comments
 (0)