You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/deployment.md
+11-21Lines changed: 11 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,12 +3,10 @@ Deployment
3
3
4
4
Depending on your setup and preferences, there are multiple ways to run Emmett applications. In this chapter, we'll try to document the most common ones.
5
5
6
-
If you want to use an ASGI server not listed in this section, please refer to its documentation, remembering that your Emmett application object is the actual ASGI application (following spec version 3.0).
7
-
8
6
Included server
9
7
---------------
10
8
11
-
*Changed in version 2.5*
9
+
*Changed in version 2.7*
12
10
13
11
Emmett comes with [Granian](https://github.com/emmett-framework/granian) as its HTTP server. In order to run your application in production you can just use the included `serve` command:
14
12
@@ -22,35 +20,27 @@ You can inspect all the available options of the `serve` command using the `--he
| backpressure || Maximum number of requests to process concurrently |
32
33
| ssl-certfile || Path to SSL certificate file |
33
34
| ssl-keyfile || Path to SSL key file |
34
35
35
-
Uvicorn
36
-
-------
37
-
38
-
*Changed in version 2.5*
39
-
40
-
In case you want to stick with a more popular option, Emmett also comes with included support for [Uvicorn](https://github.com/encode/uvicorn).
41
-
42
-
You can just use the `emmett[uvicorn]` extra during installation and rely on the `uvicorn` command to serve your application.
43
-
44
-
Gunicorn
45
-
--------
46
-
47
-
The included server might suit most of the common demands, but whenever you need additional features, you can use [Gunicorn](https://gunicorn.org).
36
+
Other ASGI servers
37
+
------------------
48
38
49
-
Emmett includes a Gunicorn worker class allowing you to run ASGI applications with the Emmett's environment, while also giving you Gunicorn's fully-featured process management:
Since an Emmett application object is also an [ASGI](https://asgi.readthedocs.io/en/latest/) application, you can serve your project with any [ASGI compliant server](https://asgi.readthedocs.io/en/latest/implementations.html#servers).
52
42
53
-
This allows you to increase or decrease the number of worker processes on the fly, restart worker processes gracefully, or perform server upgrades without downtime.
43
+
To serve your project with such servers, just refer to the specific server documentation an point it to your application object.
Copy file name to clipboardExpand all lines: docs/installation.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ Installation
4
4
5
5
So, how do you get Emmett on your computer quickly? There are many ways you could do that, but the most kick-ass method is virtualenv, so let’s have a look at that first.
6
6
7
-
You will need Python version 3.8 or higher in order to get Emmett working.
7
+
You will need Python version 3.9 or higher in order to get Emmett working.
The `Pipe`'s methods we saw until now are commonly handled by Emmett on all the routes you define, without distinction between routes handling requests and routes handling websockets.
241
241
242
-
But since handling the former or the latter ones make a great difference in terms of *flow*, `Pipe`s objects also have two dedicated methods for websockets only, and in particular:
242
+
But since handling the former or the latter ones make a great difference in terms of *flow*, `Pipe`s objects also have one dedicated method for requests and two dedicated methods for websockets only, in particular:
243
243
244
+
- on\_stream
244
245
- on\_receive
245
246
- on\_send
246
247
247
-
These two methods accepts only one argument: the message; and they will be called sequentially when receiving or sending messages. Here is an example:
248
+
The `on_stream` method accepts no arguments and it will be called sequentially when a [response stream](./response#streaming-responses) starts. Here is an example:
249
+
250
+
```python
251
+
from emmett import response
252
+
253
+
classMyStreamPipe(Pipe):
254
+
defon_stream(self):
255
+
response.headers["x-my-stream"] ="true"
256
+
```
257
+
258
+
The `on_receive` and `on_send` methods accept only one argument instead: the message. These methods will be called sequentially when receiving or sending messages. Here is an example:
248
259
249
260
```python
250
261
classWSPipe(Pipe):
@@ -284,6 +295,7 @@ To summarize, here is the complete table of methods available on Emmett pipes:
284
295
| pipe | pipe\_request | pipe\_ws |
285
296
| on\_pipe\_success |||
286
297
| on\_pipe\_failure |||
298
+
|| on\_stream ||
287
299
||| on\_receive |
288
300
||| on\_send |
289
301
@@ -356,7 +368,7 @@ from emmett import Injector
356
368
classDateInjector(Injector):
357
369
namespace ="dates"
358
370
359
-
defpretty(d):
371
+
defpretty(self, d):
360
372
# your prettydate code
361
373
362
374
app.injectors = [DateInjector()]
@@ -376,7 +388,7 @@ You can also expose all the contents of your injectors without specifying the na
Copy file name to clipboardExpand all lines: docs/response.md
+67-1Lines changed: 67 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -114,6 +114,8 @@ async def response_aiter():
114
114
return response.wrap_aiter(aiterator())
115
115
```
116
116
117
+
> **Note:** both `wrap_iter` and `wrap_aiter` perform the iteration outside of the [pipeline](./pipeline). Whenever you need to stream contents and keep the pipeline open or use the global context, you should use the [stream utilities](#streaming-responses) instead.
118
+
117
119
### File responses
118
120
119
121
You can produce responses from file using two different methods in Emmett:
@@ -129,10 +131,74 @@ async def file(name):
129
131
130
132
@app.route("/io/<name:str>")
131
133
asyncdefio(name):
132
-
withopen(f"assets/{name}", "r") as f:
134
+
withopen(f"assets/{name}", "rb") as f:
133
135
return response.wrap_io(f)
134
136
```
135
137
138
+
Streaming responses
139
+
-------------------
140
+
141
+
*New in version 2.7*
142
+
143
+
Emmett `Response` object provides a `stream` awaitable method in order to stream content from a generator while keeping the [pipeline](./pipeline) open:
144
+
145
+
```python
146
+
asyncdefiterator():
147
+
for _ inrange(3):
148
+
yieldb"hello"
149
+
150
+
@app.route()
151
+
asyncdefresponse_stream():
152
+
response.status =200
153
+
returnawait response.stream(iterator())
154
+
```
155
+
156
+
### Streaming utilities
157
+
158
+
On top of the `Response.stream` method, Emmett also provides a `StreamPipe` pipe and a `stream` decorator, so you can define your route function as the generator:
159
+
160
+
```python
161
+
from emmett.tools import StreamPipe, stream
162
+
163
+
# the following routes behave the same
164
+
@app.route(pipeline=[StreamPipe()])
165
+
asyncdefstream_1():
166
+
for _ inrange(3):
167
+
yieldb"hello"
168
+
169
+
@app.route()
170
+
@stream()
171
+
asyncdefstream_2():
172
+
for _ inrange(3):
173
+
yieldb"hello"
174
+
```
175
+
176
+
As you can't change the `Response` object directly in the route anymore, both `StreamPipe` and `stream` accept the same parameters to do so, specifically:
177
+
178
+
| parameter | type | default |
179
+
| --- | --- | --- |
180
+
| status |`int`| 200 |
181
+
| headers |`dict[str, str]`|`{}`|
182
+
| cookies |`dict[str, Any]`|`{}`|
183
+
184
+
> **Note:** while `status` will overwrite the existing value, both `headers` and `cookies` will be merged on top of the existing `Response` ones.
185
+
186
+
### Server-Sent Events
187
+
188
+
Emmett also provides some specific utilities to stream [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events):
189
+
190
+
```python
191
+
from emmett.tools import sse
192
+
193
+
@app.route()
194
+
@sse()
195
+
asyncdefsse_stream():
196
+
for _ inrange(3):
197
+
yield sse.Event(data={"msg": "hello"})
198
+
```
199
+
200
+
The `sse` decorator is based on the `stream` one but already configures some headers for you, like the `content-type` and caching. You can still use the same parameters of the `stream` decorator to customise the response.
Copy file name to clipboardExpand all lines: docs/upgrading.md
+38Lines changed: 38 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,44 @@ Just as a remind, you can update Emmett using *pip*:
13
13
$ pip install -U emmett
14
14
```
15
15
16
+
Version 2.7
17
+
-----------
18
+
19
+
Emmett 2.7 introduces some changes you should be aware of, and some new features you might be interested into.
20
+
21
+
This release drops support for Python 3.8.
22
+
23
+
### Breaking changes
24
+
25
+
#### Serve command arguments
26
+
27
+
As Emmett 2.7 updates the minimum [Granian](https://github.com/emmett-framework/granian) dependency version, the previous `threading-mode` argument of the `serve` command is now moved to `runtime-mode`.
28
+
In case you specified this argument in previous Emmett versions, please update your code using the following conversion table:
29
+
30
+
| previous value | new value |
31
+
| --- | --- |
32
+
|`--threading-mode runtime`|`--runtime-mode mt`|
33
+
|`--threading-mode workers`|`--runtime-mode st`|
34
+
35
+
The serve command also includes some new params you might want to use. Please check the [relevant chapter](./deployment#included-server) of the documentation for more information.
36
+
37
+
#### Removed uvicorn extra dependency
38
+
39
+
Prior to 2.7, Emmett provided the `uvicorn` extra dependency. Given the additional work required to keep such dependency extras in sync with other projects release cycles, we no longer offer this facility.
40
+
41
+
You can still use Uvicorn to serve your Emmett application, you simply need to manage that dependency yourself. See also the [deployment chapter](./deployment) of the documentation.
42
+
43
+
#### Uvloop is now an optional dependency
44
+
45
+
Emmett 2.7 doesn't require [uvloop](https://github.com/MagicStack/uvloop) anymore. This dependency is now optional and gated under the `uvloop` extra. If you want to keep using uvloop, you can add it to your project dependencies or switch your Emmett dependency spec to `emmett[uvloop]`.
0 commit comments