For all my projects, I load all env variables at the start and check that all the expected keys exist as described by an .env.example
file following the dotenv-safe approach.
However, the env variables are strings, which have to be manually cast whenever they're used inside the Python code. This is annoying and error-prone. I'd like to use the information from the .env.example
file to cast the env variables and get Python typing support in my IDE (VS Code). How do I do that?
env.example
PORT: int
SSL: boolean
Python Ideal Behavior
# Set the env in some way (doesn't matter)
import os
os.environment["SSL"] = "0"
os.environment["PORT"] = "99999"
env = type_env()
if not env["SSL"]: # <-- I'd like this to be cast to boolean and typed as a boolean
print("Connecting w/o SSL!")
if 65535 < env["PORT"]: # <-- I'd like this to be cast to int and typed as an int
print("Invalid port!")
In this code example, what would the type_env()
function look like assuming it only supported boolean
, int
, float
, and str
?
It's not too hard to do the casting as shown in e.g. https://stackoverflow.com/a/11781375/1452257, but it's unclear to me how to get it working with typing support.
I will suggest using pydantic.
From StackOverflow pydantic tag info
Pydantic is a library for data validation and settings management based on Python type hinting (PEP484) and variable annotations (PEP526). It allows for defining schemas in Python for complex structures.
let's assume that you have a file with your SSL
and PORT
envs:
with open('.env', 'w') as fp:
fp.write('PORT=5000\nSSL=0')
then you can use:
from pydantic import BaseSettings
class Settings(BaseSettings):
PORT : int
SSL : bool
class Config:
env_file = '.env'
config = Settings()
print(type(config.SSL), config.SSL)
print(type(config.PORT), config.PORT)
# <class 'bool'> False
# <class 'int'> 5000
with your code:
env = Settings()
if not env.SSL:
print("Connecting w/o SSL!")
if 65535 < env.PORT:
print("Invalid port!")
output:
Connecting w/o SSL!