How to write DRY code when setting variable names from string literals?

Viewed 56

In short, is there a pythonic way to write SETTING_A = os.environ['SETTING_A']?

I want to provide a module environment.py from which I can import constants that are read from environment variables.

Approach 1:
import os

try:
    SETTING_A = os.environ['SETTING_A']
    SETTING_B = os.environ['SETTING_B']
    SETTING_C = os.environ['SETTING_C']
except KeyError as e:
    raise EnvironmentError(f'env var {e} is not defined')
Approach 2
import os

vs = ('SETTING_A', 'SETTING_B', 'SETTING_C')

try:
    for v in vs:
        locals()[v] = os.environ[v]
except KeyError as e:
    raise EnvironmentError(f'env var {e} is not defined')

Approach 1 repeats the names of the variables, approach 2 manipulates locals and it's harder to see what constants will be importable from the module.

Is there a best practice to this problem?

2 Answers

Use python-decouple to set environment variables.

pip install python-decouple

Now you can create a .ini or .env file and store your variables there.

.env

SETTING_A=os.environ['SETTING_A'] 
SETTING_B=os.environ['SETTING_B']
SETTING_C=os.environ['SETTING_C']

Now in your settings file you can import the env variables and use them.

from decouple import config

setting_a = config('SETTING_A')
setting_b = config('SETTING_B')
setting_c = config('SETTING_C')

Note that while setting your env variables you shouldn't leave gap with "=" and you should use config('') to load them.

You can also use pydantic to achieve this

from pydantic import BaseSettings

class _Settings(BaseSettings):
    SETTING_A: str
    SETTING_B: str
    SETTING_C: str

class SettingsHandler:
    @classmethod
    def generate(cls):

        root_dir = os.path.dirname(os.path.abspath(__file__))
        _file_path = f"{root_dir}/local.env"

        if os.path.exists(ini_file_path):
            return _Settings(_env_file=ini_file_path, _env_file_encoding="utf-8")

        return _Settings()

SETTINGS = SettingsHandler.generate()

Now you can use this SETTINGS object. Sample usage is written below

print(SETTINGS.SETTING_A)
print(SETTINGS.SETTING_B)
print(SETTINGS.SETTING_C)

Sample env file

SETTING_A="value_of_setting_a"
SETTING_B="value_of_setting_b"
SETTING_C="value_of_setting_c"
Related