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

Remove databases package from config docs #2092

Merged
merged 17 commits into from
Dec 16, 2023
Merged
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 23 additions & 44 deletions docs/config.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
Starlette encourages a strict separation of configuration from code,
following [the twelve-factor pattern][twelve-factor].

Configuration should be stored in environment variables, or in a ".env" file
Configuration should be stored in environment variables, or in a `.env` file
that is not committed to source control.

**app.py**:

```python
import databases

```python title="app.py"
from sqlalchemy import create_engine
from starlette.applications import Starlette
from starlette.config import Config
from starlette.datastructures import CommaSeparatedStrings, Secret
Expand All @@ -17,21 +14,20 @@ from starlette.datastructures import CommaSeparatedStrings, Secret
config = Config(".env")

DEBUG = config('DEBUG', cast=bool, default=False)
DATABASE_URL = config('DATABASE_URL', cast=databases.DatabaseURL)
DATABASE_URL = config('DATABASE_URL')
aminalaee marked this conversation as resolved.
Show resolved Hide resolved
SECRET_KEY = config('SECRET_KEY', cast=Secret)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=CommaSeparatedStrings)

app = Starlette(debug=DEBUG)
engine = create_engine(DATABASE_URL)
...
```

**.env**:

```shell
```shell title=".env"
# Don't commit this to source control.
# Eg. Include ".env" in your `.gitignore` file.
DEBUG=True
DATABASE_URL=postgresql://localhost/myproject
DATABASE_URL=postgresql://user:password@localhost:5432/database
SECRET_KEY=43n080musdfjt54t-09sdgr
ALLOWED_HOSTS=127.0.0.1, localhost
```
Expand All @@ -41,7 +37,7 @@ ALLOWED_HOSTS=127.0.0.1, localhost
The order in which configuration values are read is:

* From an environment variable.
* From the ".env" file.
* From the `.env` file.
* The default value given in `config`.

If none of those match, then `config(...)` will raise an error.
Expand All @@ -63,16 +59,11 @@ Secret('**********')
'98n349$%8b8-7yjn0n8y93T$23r'
```

Similarly, the `URL` class will hide any password component
aminalaee marked this conversation as resolved.
Show resolved Hide resolved
in their representations.
!!! tip

```python
>>> from myproject import settings
>>> settings.DATABASE_URL
DatabaseURL('postgresql://admin:**********@192.168.0.8/my-application')
>>> str(settings.DATABASE_URL)
'postgresql://admin:Fkjh348htGee4t3@192.168.0.8/my-application'
```
You can use `DatabaseURL` from `databases`
package [here](https://github.com/encode/databases/blob/ab5eb718a78a27afe18775754e9c0fa2ad9cd211/databases/core.py#L420)
to store database URLs and avoid leaking them in the logs.

## CommaSeparatedStrings

Expand Down Expand Up @@ -105,12 +96,10 @@ is set *after* the point that it has already been read by the configuration.
If you're using `pytest`, then you can setup any initial environment in
`tests/conftest.py`.

**tests/conftest.py**:

```python
```python title="tests/conftest.py"
from starlette.config import environ

environ['TESTING'] = 'TRUE'
environ['DEBUG'] = 'TRUE'
```

## Reading prefixed environment variables
Expand All @@ -119,6 +108,7 @@ You can namespace the environment variables by setting `env_prefix` argument.

```python title="myproject/settings.py"
import os

from starlette.config import Config

os.environ['APP_DEBUG'] = 'yes'
Expand All @@ -142,27 +132,19 @@ we can start to structure an application.
First, let's keep our settings, our database table definitions, and our
application logic separated:

**myproject/settings.py**:

```python
import databases
```python title="myproject/settings.py"
from starlette.config import Config
from starlette.datastructures import Secret

config = Config(".env")

DEBUG = config('DEBUG', cast=bool, default=False)
TESTING = config('TESTING', cast=bool, default=False)
SECRET_KEY = config('SECRET_KEY', cast=Secret)

DATABASE_URL = config('DATABASE_URL', cast=databases.DatabaseURL)
if TESTING:
DATABASE_URL = DATABASE_URL.replace(database='test_' + DATABASE_URL.database)
DATABASE_URL = config('DATABASE_URL')
aminalaee marked this conversation as resolved.
Show resolved Hide resolved
```

**myproject/tables.py**:

```python
```python title="myproject/tables.py"
import sqlalchemy

# Database table definitions.
Expand All @@ -173,13 +155,12 @@ organisations = sqlalchemy.Table(
)
```

**myproject/app.py**

```python
```python title="myproject/app.py"
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.sessions import SessionMiddleware
from starlette.routing import Route

from myproject import settings


Expand All @@ -204,16 +185,14 @@ Now let's deal with our test configuration.
We'd like to create a new test database every time the test suite runs,
and drop it once the tests complete. We'd also like to ensure

**tests/conftest.py**:

```python
```python title="tests/conftest.py"
from starlette.config import environ
from starlette.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy_utils import create_database, database_exists, drop_database

# This line would raise an error if we use it after 'settings' has been imported.
environ['TESTING'] = 'TRUE'
environ['DEBUG'] = 'TRUE'

from myproject import settings
from myproject.app import app
Expand All @@ -225,7 +204,7 @@ def setup_test_database():
"""
Create a clean test database every time the tests are run.
"""
url = str(settings.DATABASE_URL)
url = settings.DATABASE_URL
engine = create_engine(url)
assert not database_exists(url), 'Test database already exists. Aborting tests.'
create_database(url) # Create the test database.
Expand Down