Using copy.deepcopy on os.environ in python appears broken

deep-copy, environment-variables, python

Solution

`os.environ` is of type `os._Environ`, not a list or dictionary. It is logical that a copy of an instance of `os._Environ` will modify the environment as well.

See the `os._Environ.__setitem__()` function. It stores the values in 2 places, once using `putenv()` and one to assign the key in the `self._data` dictionary.

def __setitem__(self, key, value):
    key = self.encodekey(key)
    value = self.encodevalue(value)
    self.putenv(key, value)
    self._data[key] = value

Problem

I probably just missed some bit of documentation on how os.environ or copy.deepcopy works, but it appears that copy.deepcopy doesn't work on os.environ. But if I reconstruct the os.environ into a new dictionary, it works fine. Here's my example code: ``` import copy import os tcsh_loc = '/bin/tcsh' safe_dict = {} for key in os.environ.keys(): safe_dict[key] = os.environ[key] safe_dict['SAFE_ENV'] = 'non-leaked-var' os.spawnv(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $SAFE_ENV']) os.spawnve(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $SAFE_ENV'], safe_dict) unsafe_dict = copy.deepcopy(os.environ) unsafe_dict['UNSAFE_ENV'] = 'leaked-var' os.spawnv(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $UNSAFE_ENV']) os.spawnve(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $UNSAFE_ENV'], unsafe_dict) ``` What I expect to get out is: ``` SAFE_ENV: Undefined variable. non-leaked-var UNSAFE_ENV: Undefined variable. leaked-var ``` But what I get out is: ``` SAFE_ENV: Undefined variable. non-leaked-var leaked-var leaked-var ``` Which implies that somehow the `unsafe_dict['UNSAFE_ENV'] = 'leaked-var'` assignment somehow "leaks" into os.environ, presumably from os.environ not getting deepcopied as I expected. I assume this is some kind of known behavior, but it seems really weird an undesirable to me, at least in terms of using things like os.spawnev(). I've got a clumsy workaround, but I'd be interested to understand what is going on and if there is a more elegant solution than a for loop...

Original source