I wrote in python a config module for getting values from the env. The env is set by the docker-compose file. I want to test the config module, so i want to unset the variables in the test before importing the module.
Code:
test_config.py:
import os
from unittest import TestCase
def test_without_env():
os.unsetenv('GITLAB_URL')
os.unsetenv('GITLAB_PROJECT_ID')
os.unsetenv('GITLAB_API_TOKEN')
os.unsetenv('JIRA_API_TOKEN')
os.unsetenv('JIRA_BOARD_ID')
os.unsetenv('JIRA_URL')
os.unsetenv('ROCKET_CHAT_API_TOKEN')
os.unsetenv('ROCKET_CHAT_USER_ID')
os.unsetenv('ROCKET_CHAT_URL')
import src.config as conf
assert conf.GITLAB_URL == 'URL'
assert conf.GITLAB_PROJECT_ID == '1234'
assert conf.GITLAB_API_TOKEN == 'TOKEN'
assert conf.JIRA_API_TOKEN == 'TOKEN'
assert conf.JIRA_BOARD_ID == '1234'
assert conf.JIRA_URL == 'URL'
assert conf.ROCKET_CHAT_API_TOKEN == 'TOKEN'
assert conf.ROCKET_CHAT_URL == 'URL'
assert conf.ROCKET_CHAT_USER_ID == 'USER_ID'
config.py:
import os
# GitLab
if 'GITLAB_URL' in os.environ: GITLAB_URL = os.environ['GITLAB_URL']
else: GITLAB_URL = 'URL'
if 'GITLAB_PROJECT_ID' in os.environ: GITLAB_PROJECT_ID = os.environ['GITLAB_PROJECT_ID']
else: GITLAB_PROJECT_ID = 1234
if 'GITLAB_API_TOKEN' in os.environ: GITLAB_API_TOKEN = os.environ['GITLAB_API_TOKEN']
else: GITLAB_API_TOKEN = 'TOKEN'
# Jira
if 'JIRA_URL' in os.environ: JIRA_URL = os.environ['JIRA_URL']
else: JIRA_URL = 'URL'
if 'JIRA_BOARD_ID' in os.environ: JIRA_BOARD_ID = os.environ['JIRA_BOARD_ID']
else: JIRA_BOARD_ID = 1234
if 'JIRA_API_TOKEN' in os.environ: JIRA_API_TOKEN = os.environ['JIRA_API_TOKEN']
else: JIRA_API_TOKEN = 'TOKEN'
# RocketChat
if 'ROCKET_CHAT_API_TOKEN' in os.environ: ROCKET_CHAT_API_TOKEN = os.environ['ROCKET_CHAT_API_TOKEN']
else: ROCKET_CHAT_API_TOKEN = 'TOKEN'
if 'ROCKET_CHAT_URL' in os.environ: ROCKET_CHAT_URL = os.environ['ROCKET_CHAT_URL']
else: ROCKET_CHAT_URL = 'URL'
if 'ROCKET_CHAT_USER_ID' in os.environ: ROCKET_CHAT_USER_ID = os.environ['ROCKET_CHAT_USER_ID']
else: ROCKET_CHAT_USER_ID = 'USER_ID'
(Values from variables and assert are changed, because of security 😀 )
Am I doing it right? Or what can i do? I think that docker is rewrite the env if it changed, just a guess…
Greetings,
DasMoorhuhn
It does not change, I tried os.unsetenv('VAR'), os.system('unset VAR') and del os.environ['VAR'].
>Solution :
You are doing it right by using os.unsetenv(‘VAR’) or del os.environ[‘VAR’], but the main issue you’re encountering is due to the fact that environment variables are loaded when a module is imported in Python. Once the module has been imported, any changes you make to the environment won’t affect the values that were set at the time of the import.
You are trying to unset the environment variables and then import the module. However, if your module is imported somewhere before the unsetting, the environment variables are already set for that instance of the module. That’s why unsetting them doesn’t seem to have any effect.
You can get around this problem by reloading the module after you’ve changed the environment. Python provides a built-in function, importlib.reload(), which you can use to reload a previously imported module. The argument must be a module object, so you must import the module first, then delete the environment variables, and then reload the module.
Here is how you could rewrite your test:
import os
from unittest import TestCase
import importlib
def test_without_env():
import src.config as conf
os.environ.pop('GITLAB_URL', None)
os.environ.pop('GITLAB_PROJECT_ID', None)
os.environ.pop('GITLAB_API_TOKEN', None)
os.environ.pop('JIRA_API_TOKEN', None)
os.environ.pop('JIRA_BOARD_ID', None)
os.environ.pop('JIRA_URL', None)
os.environ.pop('ROCKET_CHAT_API_TOKEN', None)
os.environ.pop('ROCKET_CHAT_USER_ID', None)
os.environ.pop('ROCKET_CHAT_URL', None)
importlib.reload(conf)
assert conf.GITLAB_URL == 'URL'
assert conf.GITLAB_PROJECT_ID == '1234'
assert conf.GITLAB_API_TOKEN == 'TOKEN'
assert conf.JIRA_API_TOKEN == 'TOKEN'
assert conf.JIRA_BOARD_ID == '1234'
assert conf.JIRA_URL == 'URL'
assert conf.ROCKET_CHAT_API_TOKEN == 'TOKEN'
assert conf.ROCKET_CHAT_URL == 'URL'
assert conf.ROCKET_CHAT_USER_ID == 'USER_ID'
In this code, os.environ.pop(‘VAR’, None) is used to remove the environment variable. This method removes the item with the specified key and returns the value. If the key is not found, it returns the default specified (in this case, None), so it won’t raise a KeyError if the environment variable doesn’t exist.
Then, importlib.reload(conf) is used to reload the module, re-executing the module-level code and therefore picking up the updated environment variables.
This should give you the desired result, assuming that there are no other lingering references to the old module object.