⚙️ Unified environment variable and settings management for FastAPI and beyond 🚀
Unified environment variable and settings management for FastAPI and beyond
fastenv [fæst iː ən v] 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:
setuptools
has come around. PEP 621 defined how to store package metadata and dependencies in pyproject.toml. Why don’t we use the metadata from our pyproject.toml files in our Python applications?The source code is 100% type-annotated and unit-tested.
For additional background on the project, see www.bws.bio/projects/fastenv.
Install fastenv into a virtual environment:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install fastenv
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 fastenv in your FastAPI app:
from contextlib import asynccontextmanager
from typing import AsyncIterator, TypedDict
import fastenv
from fastapi import FastAPI, Request
class LifespanState(TypedDict):
settings: fastenv.DotEnv
@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[LifespanState]:
"""Configure app lifespan.
https://fastapi.tiangolo.com/advanced/events/
https://www.starlette.io/lifespan/
"""
settings = await fastenv.load_dotenv(".env")
lifespan_state: LifespanState = {"settings": settings}
yield lifespan_state
app = FastAPI(lifespan=lifespan)
@app.get("/settings")
async def get_settings(request: Request) -> dict[str, str]:
settings = request.state.settings
return dict(settings)
Documentation is built with Material for MkDocs, deployed on Vercel, and available at fastenv.bws.bio and fastenv.vercel.app.
python3 -m pip install mkdocs-material && mkdocs build --site-dir public
public
(default)Vercel site configuration is specified in vercel.json.