import json import os from configparser import ConfigParser from pathlib import Path from typing import Any CONFIG_DEFAULTS = { 'SQLALCHEMY_TRACK_MODIFICATIONS': False } CONFIG_PREFIXES = ['SMIDGEN_', 'SQLALCHEMY_'] STRIPPED_PREFIXES = ['SMIDGEN_'] def read_from_file() -> dict: """Read the configuration file and return the values in a dictionary""" config_file = Path(__file__).parent / '..' / 'codesmidgen.cfg' if not config_file.exists(): return {} config_parser = ConfigParser() config_parser.read(config_file) config: dict[str, Any] = {} for option in config_parser.options('codesmidgen'): config[option.upper()] = config_parser.get('codesmidgen', option) return config def read_from_envvars() -> dict: """Read the configuration from environment variables""" config: dict[str, Any] = {} for key in sorted(os.environ): if not any([key.startswith(prefix) for prefix in CONFIG_PREFIXES]): continue value = os.environ[key] try: value = json.loads(value) except Exception: # If the value is not JSON parseable, just leave it as a string pass for prefix in STRIPPED_PREFIXES: key = key.replace(prefix, '') # Check if there are any "nested" values if '__' not in key: config[key] = value continue # Navigate the nested values and build the structure *parents, child = key.split('__') item = config for parent in parents: if parent not in item: item[parent] = {} item = item[parent] item[child] = value return config def get_config() -> dict: """Read configuration from files, environment variables, etc.""" config = {} config.update(CONFIG_DEFAULTS) config.update(read_from_file()) config.update(read_from_envvars()) return config