Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Unset env variable from inside of an docker container using python

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading