Python Use Config Files
Description
One of the easiest ways you can differentiate between environments with python apps is to create yml files in the application’s directory and set an environmental variable as the environment. I haven’t gotten around to re-writing all my applications (Function Apps), but I plan to do this soon.
To Resolve:
-
Create your regular
.env
file as follows like:1
STAGE=production
- If using a Function App, just set the environmental variable in the Application Settings blade and then do like usual
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
def import_creds(): ''' Gets secrets from Azure Keyvault as an application Secret values are stored in the Function App under Configuration Example of how to call from main(): keyvault_creds = import_creds() logging.info(f"client_id: { keyvault_creds['client_id'] }") logging.info(f"client_secret: { keyvault_creds['client_secret'] }") logging.info(f"tenant: { keyvault_creds['tenant'] }") logging.info(f"vault_name: { keyvault_creds['vault_name'] }") ''' try: creds = {} creds["client_id"] = os.environ["client_id"] creds["client_secret"] = os.environ["client_secret"] creds["tenant"] = os.environ["tenant"] creds["vault_name"] = os.environ["vault_name"] except KeyError: logging.error("Unable to get env vars") except Exception as e: logging.error(f"Generic Catch: {str(e)}") return creds
-
But this time, set a config file in the directory called
.dev.config.yaml
with the contents of:1 2 3 4 5 6 7 8 9 10
servers: - host-a.domain.com - host-b.domain.com - networks: - 10.20.20.0 - 10.30.30.30 endpoints: - service_now: https://myendpoint-dev.com - key: dev-adcd1234567890
- Also create a
.prod.config.yaml
in the same directory with the values of:
1 2 3 4 5 6 7 8 9 10
servers: - host-c.domain.com - host-d.domain.com - networks: - 10.20.20.0 - 10.30.30.30 endpoints: - service_now: https://myendpoint-prod.com - key: prod-adcd1234567890
- Then, either in its own file like
config.py
or inside yourhelpers.py
, import them:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
import os import sys from pathlib import Path import yaml from dotenv import load_dotenv load_dotenv() try: APP_ENV = os.getenv('STAGE', 'development') except Exception as e: print(f"Unable to get environmental variable: {STAGE}") exit(1) CONFIG_FILES = { 'development': '.dev.config.yaml', 'production': '.prod.config.yaml', } try: conf_file = Path(__file__).parent.joinpath(CONFIG_FILES[APP_ENV]) except KeyError: print(f"Environment config file not found. Provided: '{APP_ENV}'. Accepted: {CONFIG_FILES}") sys.exit(1) with open(conf_file, 'r') as f: CONFIG = yaml.safe_load(f)
- Also create a
-
Make sure your
requirements.txt
includes the following1 2
PyYAML==5.3.1 python-dotenv==0.14.0
-
Now, in your main code, just call the same config regardless of the environment. For example, in a
main.py
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
from config import CONFIG servers = CONFIG['servers'] print(servers) # ['host-c.domain.com', 'host-d.domain.com', {'networks': ['10.20.20.0', '10.30.30.30']}] print(servers[0]) # host-c.domain.com print(servers[1]) # host-d.domain.com print(servers[2]['networks']) # ['10.20.20.0', '10.30.30.30'] print(servers[2]['networks'][0]) # 10.20.20.0 endpoints = CONFIG['endpoints'] print(endpoints) # [{'service_now': 'https://myendpoint-dev.com'}, {'key': 'dev-adcd1234567890'}] sn = CONFIG['endpoints'][0]['service_now'] print(sn) # https://myendpoint-dev.com key = CONFIG['endpoints'][1]['key'] print(key) # dev-adcd1234567890
Comments