Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to run uvicorn programatically #1525

Merged
merged 5 commits into from Jun 20, 2022
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 39 additions & 3 deletions docs/index.md
Expand Up @@ -196,9 +196,25 @@ For more information, see the [settings documentation](settings.md).

### Running programmatically

To run uvicorn directly from your application...
There are several ways to run uvicorn directly from your application.

**example.py**:
#### `uvicorn.run`

If you're looking for a programmatic equivalent of the `uvicorn` command line interface, use `uvicorn.run()`:

```python
Kludex marked this conversation as resolved.
Show resolved Hide resolved
import uvicorn

async def app(scope, receive, send):
...

if __name__ == "__main__":
uvicorn.run("main:app", port=5000, log_level="info")
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`uvicorn.run` accepts the following arguments:

* `app`: Either an ASGI application, or (as shown above) an import string to the target ASGI application. The latter is required if using auto-reload or multiple workers.
* `**kwargs`: Keyword arguments that mirror command line options (see [Settings](/settings.md)): `--host <str>` becomes `host=<str>`, `--log-level <str>` becomes `log_level=<str>`, etc.

(I think this kind of info is valuable in docs, but maybe we might want to kick off an API Reference page for this kind of thing. I'm OK if we defer this bit from this PR.)

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We improved the uvicorn.run type annotation, so we can have autocomplete on it:

uvicorn/uvicorn/main.py

Lines 445 to 492 in b1a4582

def run(
app: typing.Union[ASGIApplication, str],
*,
host: str = "127.0.0.1",
port: int = 8000,
uds: typing.Optional[str] = None,
fd: typing.Optional[int] = None,
loop: LoopSetupType = "auto",
http: HTTPProtocolType = "auto",
ws: WSProtocolType = "auto",
ws_max_size: int = 16777216,
ws_ping_interval: float = 20.0,
ws_ping_timeout: float = 20.0,
ws_per_message_deflate: bool = True,
lifespan: LifespanType = "auto",
interface: InterfaceType = "auto",
debug: bool = False,
reload: bool = False,
reload_dirs: typing.Optional[typing.List[str]] = None,
reload_includes: typing.Optional[typing.List[str]] = None,
reload_excludes: typing.Optional[typing.List[str]] = None,
reload_delay: float = 0.25,
workers: typing.Optional[int] = None,
env_file: typing.Optional[str] = None,
log_config: typing.Optional[typing.Union[dict, str]] = None,
log_level: typing.Optional[str] = None,
access_log: bool = True,
proxy_headers: bool = True,
server_header: bool = True,
date_header: bool = True,
forwarded_allow_ips: typing.Optional[str] = None,
root_path: str = "",
limit_concurrency: typing.Optional[int] = None,
backlog: int = 2048,
limit_max_requests: typing.Optional[int] = None,
timeout_keep_alive: int = 5,
ssl_keyfile: typing.Optional[str] = None,
ssl_certfile: typing.Optional[str] = None,
ssl_keyfile_password: typing.Optional[str] = None,
ssl_version: int = int(SSL_PROTOCOL_VERSION),
ssl_cert_reqs: int = int(ssl.CERT_NONE),
ssl_ca_certs: typing.Optional[str] = None,
ssl_ciphers: str = "TLSv1",
headers: typing.Optional[typing.List[typing.Tuple[str, str]]] = None,
use_colors: typing.Optional[bool] = None,
app_dir: typing.Optional[str] = None,
factory: bool = False,
) -> None:

I'll not apply this for now. An API reference would be fine by me.


#### `Config` and `Server` instances

For more control over configuration and server lifecycle, use `uvicorn.Config` and `uvicorn.Server`:

```python
import uvicorn
Expand All @@ -207,7 +223,27 @@ async def app(scope, receive, send):
...

if __name__ == "__main__":
uvicorn.run("example:app", host="127.0.0.1", port=5000, log_level="info")
config = uvicorn.Config("main:app", port=5000, log_level="info")
server = uvicorn.Server(config)
server.run()
```

If you'd like to run Uvicorn from an already running async environment, use `uvicorn.Server.serve()` instead:

```python
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```python
main.py
```python

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to say this is the name of the file, I'll approve it without this change but we have too many people not understanding how the app string works

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added on the first file here.

import asyncio
import uvicorn

async def app(scope, receive, send):
...

async def main():
config = uvicorn.Config("main:app", port=5000, log_level="info")
server = uvicorn.Server(config)
await server.serve()

if __name__ == "__main__":
asyncio.run(main())
```

### Running with Gunicorn
Expand Down