I was looking for the solution and was surprised to see so little on this topic.
Coming from .net experience I could not find suitable & simple solution to avoid storing production credentials in source control.
What I came with so far and satisfied with how it worked.
This is the solution structure:
|-- lib
|-- configuration.py
|-- main.py
|-- appconfig.development.py
|-- appconfig.production.py
First, created a config file template configuration.py
:
from dataclasses import dataclass
from typing import Optional
@dataclass
class Connection:
server: str
database: str
user: str
password: str
port: Optional[str] = None
# connection config
pg_connection: Connection
# email
email_from: str
error_emails: list[str]
smtp_server: str
smtp_port: int
smtp_user: str
smtp_password: str
Then, in the specific config file, assign values.
For example appconfig.development.py
:
import lib.configuration as config
config.pg_connection=config.Connection(
server='my.postgres.server',
port=12345,
database='db',
user='user',
password='pass'
)
config.error_emails = "[email protected]"
config.email_from = "[email protected]"
config.smtp_server = 'smtp.sendgrid.net'
config.smtp_port = 587
config.smtp_user = 'any'
config.smtp_password = 'any'
Finally, load the config in the main at first convenience, better at startup:
# load config name from ENV environment variable, default to development
env = os.environ.get('ENV', 'development')
logging.info("loading configuration for %s", env)
spec = importlib.util.spec_from_file_location(
name="doesnotmatter", # anything without dots
location="appconfig." + env + ".py",
)
my_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(my_module)
After loading, the configuration can be used in any module like that:
import lib.configuration as appconfig
msg = EmailMessage()
msg['From'] = appconfig.email_from
msg['To'] = ", ".join(appconfig.error_emails)
server = smtplib.SMTP(appconfig.smtp_server, appconfig.smtp_port)
server.login(appconfig.smtp_user, appconfig.smtp_password)
server.send_message(msg)