βοΈ fastenv π¶
Unified environment variable and settings management for FastAPI and beyond
Description¶
fastenv /fΓ¦st iΛ Ιn viΛ/ is a Python package for managing environment variables and application settings.
Environment variables are key-value pairs provided to the operating system with syntax like VARIABLE_NAME=value. Collections of environment variables are stored in files commonly named .env and called "dotenv" files. The Python standard library os module provides tools for reading environment variables, such as os.getenv("VARIABLE_NAME"), but only handles strings, and doesn't include tools for file I/O. Additional logic is therefore needed to load environment variables from files before they can be read by Python, and to convert variables from strings to other Python types.
This project aims to:
- Replace the aging python-dotenv project with a similar, but more intuitive API, and modern syntax and tooling.
- Implement asynchronous file I/O. Reading and writing files can be done asynchronously with packages like AnyIO.
- Implement asynchronous object storage integration. Dotenv files are commonly kept in cloud object storage, but environment variable management packages typically don't integrate with object storage clients. Additional logic is therefore required to download
.envfiles from object storage prior to loading environment variables. This project aims to integrate with S3-compatible object storage, with a focus on downloading and uploading file objects. - Read settings from TOML. It's all about
pyproject.tomlnow. The Python community has pushed PEP 517 build tooling and PEP 518 build requirements forward, and evensetuptoolshas come around. PEP 621 defined how to store package metadata and dependencies inpyproject.toml. The Starlette integration makes this metadata available as application settings. - Unify settings management for FastAPI. FastAPI depends on Pydantic and Starlette. Pydantic and Starlette provide different APIs for loading environment variables and configuring application settings. When configuring a FastAPI application, the Pydantic integration and Starlette integration provide these settings APIs backed by a shared fastenv dotenv parser.
The source code is 100% type-annotated and unit-tested.
For additional background on the project, see www.bws.bio/projects/fastenv.
Quickstart¶
Install fastenv with Pydantic settings support and FastAPI into a virtual environment:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install 'fastenv[settings]' fastapi
Then start a REPL session and try it out:
.venv β― python
# instantiate a DotEnv with a variable
import fastenv
dotenv = fastenv.DotEnv("EXAMPLE_VARIABLE=example_value")
# add a variable with dictionary syntax
dotenv["ANOTHER_VARIABLE"] = "another_value"
# delete a variable
del dotenv["ANOTHER_VARIABLE"]
# add a variable by calling the instance
dotenv("I_THINK_FASTENV_IS=awesome")
# {'I_THINK_FASTENV_IS': 'awesome'}
# return a dict of the variables in the DotEnv instance
dict(dotenv)
# {'EXAMPLE_VARIABLE': 'example_value', 'I_THINK_FASTENV_IS': 'awesome'}
# save the DotEnv instance to a file
import anyio
anyio.run(fastenv.dump_dotenv, dotenv)
# Path('/path/to/this/dir/.env')
Use a Pydantic settings model in your FastAPI app to load the .env file created above:
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import TypedDict
from fastapi import FastAPI, Request
from fastenv import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")
example_variable: str
i_think_fastenv_is: str
debug: bool = False
class LifespanState(TypedDict):
settings: Settings
@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncGenerator[LifespanState]:
"""Configure app lifespan.
https://fastapi.tiangolo.com/advanced/events/
https://starlette.dev/lifespan/
"""
settings = await Settings.load()
lifespan_state: LifespanState = {"settings": settings}
yield lifespan_state
app = FastAPI(lifespan=lifespan)
@app.get("/settings")
async def get_settings(request: Request) -> Settings:
return request.state.settings
The model loads files asynchronously and validates settings at startup without changing the process environment. Environment variables override file values, and DEBUG=true overrides the boolean default. FastAPI serializes the model returned by /settings as JSON:
{
"example_variable": "example_value",
"i_think_fastenv_is": "awesome",
"debug": false
}
Documentation¶
Documentation is built with Zensical, deployed to Vercel using the Vercel project configuration in vercel.json, and available at fastenv.bws.bio and fastenv.vercel.app.