Search code examples
pythonpython-3.xdjangomanage.py

what is the difference between os.environ.setdefault() vs os.environ.putenv()


It is my understanding that both are supposed to set environmental variables. But toggling between these two in django's manage.py file leads to different outcomes.

>>> help(os.environ.putenv)
putenv(name, value, /)                                       
    Change or add an environment variable

If I edit the manage.py file and change os.environ.setdefault to os.environ.putenv, I get the following:

https://i.sstatic.net/BQknq.png

Question: Why does os.environ.setdefault work in this case, but os.environ.putenv does not work.


Solution

  • The main difference is that os.environ.setdefault treats os.environ as a python dict, while os.putenv or os.environ.putenv makes changes to the environment that affect subprocesses started with os.system(), os.popen() or os.fork() and os.execv(). The documentation for os.putenv notes the following about the relationship between os.environ and os.putenv:

    Assignments to items in os.environ are automatically translated into corresponding calls to putenv(); however, calls to putenv() don’t update os.environ, so it is actually preferable to assign to items of os.environ.

    Based on the above statement, updating the environment variables with os.putenv does not necessarily update the os.environ dictionary. Therefore, it comes down to how the environment variable in question is used. In the case of Django, the environment variable in question is accessed in the django/config/__init__.py file with the following line of code:

    settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
    

    Clearly, this line is treating os.environ as a dictionary. Since changes made using os.putenv don't affect this os.environ dictionary, django is not able to find the settings module (i.e. the settings_module variable is equal to None).

    In sum, if you want to update environment variables, it's more encompassing to use os.environ['VARIABLE'] = 'VALUE' or os.environ.setdefault. Because, as mentioned above, updating the os.environ both updates the dictionary and also calls os.putenv.