Aller au contenu

Configuration

Starlette encourage une séparation stricte de la configuration du code selon le modèle des douze éléments.

Les configurations doivent être stockées dans des variables d'environnement ou dans des fichiers .env qui ne sont pas soumis au contrôle du code source.

de sqlalchemy import create_engine
de starlette.applications import Starlette
depuis starlette.config import Config
de starlette.datastructures import CommaSeparatedStructures, Secret

# Config sera lu à partir de variables environnementales et/ou de fichiers ".env".
config = Config(".env")

DEBUG = config('DEBUG', cast=bool, default=False)
DATABASE_URL = config('DATABASE_URL')
SECRET_KEY = config('SECRET_KEY', cast=Secret)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=CommaSeparatedStrings)

app = Starlette(débogage =DEBUG)
engine = create_engine(DATABASE_URL)
...


# Don't commit this to source control.
# Eg. Include ".env" dans votre fichier `.gitignore`
DEBUG= vrai
DATABASE_URL=postgresql://user:password@localhost:5432/database
SECRET_KEY=43n080musdfjt54t-09sdgr
ALLOWED_HOSTS=127.0.0.1, localhost

Configurer les priorités

L'ordre de lecture des valeurs de configuration est:

  • variables d'environnement.
  • à partir d'un fichier .env
  • Valeur par défaut donnée dans config.

Si aucun de ces éléments ne correspond, alors config(...) va déclencher une erreur.

Le secret

Pour les clés sensibles, la classe Secret est utile car elle aide à minimiser les cas où sa valeur détenue peut être divulguée dans le backtracking ou d'autres introspections de code.

Pour obtenir la valeur d'une instance de Secret, vous devez la convertir explicitement en chaîne de caractères. vous ne devez le faire que lorsque vous utilisez cette valeur.

>>> de myproject import settings
>>> settings.SECRET_KEY
Secret('***************)
>>> str(settings.SECRET_KEY)
'98n349$%8b8-7yjn0n8y93T$23r'

Indice

Vous pouvez utiliser DatabaseURL de databases paquet ici Pour stocker les URLs de base et les laisser dans les logs.

Strings séparés par des virgules

Le type CommaSeparatedStrings est utile pour contenir plusieurs contenus dans une seule clé de configuration.

>>> de myproject import settings
>>> print(settings.ALLOWED_HOSTS)
CommaSeparatedStrings(['127.0.0.1','localhost'])
>>> print(list(settings.ALLOWED_HOSTS))
['127.0.0.1','localhost']
>>> print(len(settings.ALLOWED_HOSTS))
2
>>> print(settings.ALLOWED_HOSTS[0])
'127.0.0.1'

Lire ou modifier l'environnement

Dans certains cas, vous voudrez peut-être lire ou modifier les variables d'environnement par programme, ce qui est particulièrement utile dans les tests, où vous voudrez peut-être remplacer des clés spécifiques dans votre environnement.

Au lieu de lire ou d'écrire à partir de os.environ, vous devriez utiliser l'instance environ de Starlette. cette instance est mappée sur le os.environ standard et vous offre une protection supplémentaire en générant une erreur si elle est définie après que la configuration a déjà lu une variable d'environnement.

Si vous utilisez pytest, vous pouvez configurer n'importe quel environnement initial dans tests/conftest.py.

de starlette.config import environ

environ ['DEBUG'] = 'TRU'.

Lire une variable d'environnement avec un préfixe

Vous pouvez diviser l'espace de noms des variables d'environnement en définissant le paramètre env_prefix.

Importer les OS

depuis starlette.config import Config

os.environ ['APP_DEBUG'] = ' oui '
os.environ ['ENVIRONMENT'] = 'dev'

config = Config(env_prefix ='APP_')

DEBUG = config('DEBUG') # lookups APP_DEBUG, returns "yes"
ENVIRONMENT = config('ENVIRONMENT') # lookups APP_ENVIRONMENT, raises KeyError as variable is not defined

Un exemple complet

Construire de grandes applications peut être complexe-vous devez séparer correctement la configuration et le code, isoler la base de données pendant les tests, utiliser des bases de données de test et de production distinctes, etc.

Ici, nous allons regarder un exemple complet qui montre comment nous pouvons commencer à construire une application.

Tout d'abord, séparons nos paramètres, nos définitions de tables de base de données et notre logique d'application:

depuis starlette.config import Config
de starlette.datastructures import Secret

config = Config(".env")

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

DATABASE_URL = config('DATABASE_URL')


Import sqlalchemy

#Définitions de table de base.
metadata = sqlalchemy.MetaData()

organisations = sqlalchemy.Table(
    ...
)


de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.sessions import SessionMiddleware
de starlette.routing Route d'importation

de myproject import settings


async def homepage(request):
    ...

routes = [
    Route("/", endpoint=homepage)
]

middleware = [
    Middleware(
        SessionMiddleware,
        secret_key=settings.SECRET_KEY,
    )
]

app = Starlette(débogage =settings.DEBUG, routes=routes, middleware=middleware)

Nous allons maintenant nous occuper de notre configuration de test. nous voulons créer une nouvelle base de données de test chaque fois que la suite de tests est exécutée et la supprimer une fois le test terminé. nous voulons également nous assurer que nous sommes sûrs que

de starlette.config import environ
depuis starlette.testclient import TestClient
de sqlalchemy import create_engine
from sqlalchemy_utils import create_database, database_exists, drop_database

#Cette ligne aurait pu causer une erreur si nous l'avions utilisée après que les « paramètres » aient été importés.
environ ['DEBUG'] = 'TRU'.

de myproject import settings
depuis myproject.app import app
de myproject.tables import metadata


@pytest.fixture(autouse=True, scope="session")
def setup_test_database():
    """
    Créer une base de test propre à chaque fois que les tests sont en cours d'exécution.
    """
    url = settings.DATABASE_URL
    engine = create_engine(url)
    assert not database_exists(url),« Test database déjà existants.
    create_database(URL)             #Créer la base de test.
    metadata.create_all(engine)      #Créez les tables.
    Yield, le                            #Exécutez les tests.
    drop_database(URL)               # Drop la base de test.


@pytest.fixture()
def client()
    """
    Faites une fixation « client » disponible pour tester les cas.
    """
    # Our fixture est créé avec un gestionnaire de contexte.
    # application lifespan runs pour tous les cas de test.
    avec TestClient(app) comme test_client:
        yield test_client