classification
Title: os.getenv() not updated after external module uses C putenv()
Type: behavior Stage:
Components: Library (Lib) Versions: Python 2.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: BreamoreBoy, draghuram, jason.coombs, loewis, pythonmeister, robert.ancell
Priority: normal Keywords:

Created on 2007-09-13 07:22 by robert.ancell, last changed 2010-09-18 13:35 by BreamoreBoy.

Files
File name Uploaded Description Edit
environmodule.c robert.ancell, 2007-09-14 04:42
Messages (12)
msg55881 - (view) Author: Robert Ancell (robert.ancell) Date: 2007-09-13 07:22
The Python os.getenv() function accesses an Python dictionary which is
mirroring the process environment. This dictionary is populated when the
interpreter starts and updated when os.environ.__setitem__() or
os.putenv() are called. However if the python program imports an
extension module that uses the system putenv() then the changes cannot
be accessed using the Python standard library.

This has been a problem for us as we have created Python bindings to an
existing C based library that modifies the environment dynamically (not
the best design decision...). The workaround we are using is to create
our own wrapper to the system (Solaris/Linux) getenv().

A potential solution could be to make environ a class where
os.environ.__setitem__() calls putenv(), os.environ.__getitem__() calls
getenv() and os.environ.keys()/items()/iter*() uses **environ (or other
appropriate system call). This does however have undefined issues on how
the environment behaves on various systems (memory leaks etc).
msg55883 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2007-09-13 07:35
I can't see a bug here. If you want the current C library value of the
environment variable, just use os.getenv, not os.environ.
msg55884 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2007-09-13 07:49
Ignore my comment - I see now that you are talking about os.getenv.
msg55893 - (view) Author: Raghuram Devarakonda (draghuram) Date: 2007-09-13 16:20
On 9/13/07, Robert Ancell <report@bugs.python.org> wrote:

> The Python os.getenv() function accesses an Python dictionary which is
> mirroring the process environment. This dictionary is populated when the
> interpreter starts and updated when os.environ.__setitem__() or
> os.putenv() are called. However if the python program imports an

As per the document and my simple test (on Linux), os.putenv() does
not update os.environ. I think, it should update it.
msg55894 - (view) Author: Stefan Sonnenberg-Carstens (pythonmeister) Date: 2007-09-13 17:43
> As per the document and my simple test (on Linux), os.putenv() does
> not update os.environ. I think, it should update it.
What would be the benefit ?
msg55895 - (view) Author: Raghuram Devarakonda (draghuram) Date: 2007-09-13 17:58
> Stefan Sonnenberg-Carstens added the comment:
>
> > As per the document and my simple test (on Linux), os.putenv() does
> > not update os.environ. I think, it should update it.
> What would be the benefit ?

Symmetrical behaviour. When os.getenv() returns the value from
os.environ, one would expect, os.putenv to store the value there (At
least, I did). On the other hand, it is also ok for both os.getenv and
os.putenv get/set the environment directly instead of going through
os.environ. I am sure there was some reason for the current behaviour
of os.putenv. Perhaps, because putenv is supposedly not available on
all platforms?

Any way, I think the OP was asking to always "get" the value
dynamically when ever os.environ['VAR'] or os.getenv['VAR'] is done. I
don't see any problem with that approach. How ever, if it is
considered backwards incompatible, I guess an optional parameter can
be added to os.getenv.
msg55897 - (view) Author: Stefan Sonnenberg-Carstens (pythonmeister) Date: 2007-09-13 19:45
I'd like to see perl/ruby behaviour:
an dict (os.environ), nothing more (perl %ENV,ruby $ENV).
Get rid of setenv/putenv at all.
3.0a1 has even more:
There is os.environ (a dict), os.[put|get]env() and os.environ.putenv()
msg55905 - (view) Author: Robert Ancell (robert.ancell) Date: 2007-09-14 00:20
draghuram, unfortunately while os.putenv() can be fixed to be
symmetrical any putenv call from a C module cannot, for example:

If you make an extension:
#include <stdlib.h>
PyObject *putenvC(PyObject *module, PyObject *args)
{
    int result;

    if (!PyArg_ParseTuple(args, ""))
        return 0;

    result = putenv("FOO=BAR");

    return Py_BuildValue("i", result);
}

The following behaviour will occur:
$ python
>>> import putenv
>>> putenv.putenvC()
>>> assert(os.getenv('FOO') == None)
>>> assert(os.environ.get('FOO') == None)

This is because the os.environ dictionary will never be updated:
From Lib/os.py:
def getenv(key, default=None):
    """Get an environment variable, return None if it doesn't exist.
    The optional second argument can specify an alternate default."""
    return environ.get(key, default)
msg55907 - (view) Author: Robert Ancell (robert.ancell) Date: 2007-09-14 04:42
I've attached proof-of-concept showing how os.environ would ideally
work. It'll only work in Posix, etc etc.

Reading into it more there are a lot of general issues with environments
and memory allocation which is why I suspect Python doesn't use
putenv... See putenv(3) for details.

Compile with:
gcc -shared -o environmodule.so -g -Wall -I /usr/include/python2.5
environmodule.c
msg55912 - (view) Author: Raghuram Devarakonda (draghuram) Date: 2007-09-14 15:37
> Robert Ancell added the comment:
>
> draghuram, unfortunately while os.putenv() can be fixed to be
> symmetrical any putenv call from a C module cannot, for example:

Hi Robert, I understood the problem from your very first report. I
brought up putenv() not updating os.environ only because you mentioned
in the original report that it does. All you need is a way to get the
current value of an environment variable. The situation is a bit
complicated since a cache is in the picture (os.environ). I would
suggest that you bring up the topic for discussion on python-dev and
once a consensus is reached, some one can come up with a patch (I can
try).
msg81660 - (view) Author: Jason R. Coombs (jason.coombs) * (Python committer) Date: 2009-02-11 19:47
As a workaround, could you use ctypes to pull the environment back into
the python context?  For example:

http://paste.turbogears.org/paste/34734
msg116776 - (view) Author: Mark Lawrence (BreamoreBoy) Date: 2010-09-18 13:35
Can someone please comment on whether or not this issue is still valid.
History
Date User Action Args
2010-09-18 13:35:38BreamoreBoysetresolution: postponed ->

messages: + msg116776
nosy: + BreamoreBoy
2009-02-11 19:47:20jason.coombssetnosy: + jason.coombs
messages: + msg81660
2007-09-18 12:24:54jafosetpriority: normal
resolution: postponed
2007-09-14 15:37:33draghuramsetmessages: + msg55912
2007-09-14 04:42:18robert.ancellsetfiles: + environmodule.c
messages: + msg55907
2007-09-14 00:20:26robert.ancellsetmessages: + msg55905
2007-09-13 19:45:01pythonmeistersetmessages: + msg55897
2007-09-13 17:58:13draghuramsetmessages: + msg55895
2007-09-13 17:43:52pythonmeistersetnosy: + pythonmeister
messages: + msg55894
2007-09-13 16:20:30draghuramsetmessages: + msg55893
2007-09-13 15:56:48draghuramsetnosy: + draghuram
2007-09-13 07:49:42loewissetmessages: + msg55884
2007-09-13 07:35:46loewissetnosy: + loewis
messages: + msg55883
2007-09-13 07:22:07robert.ancellcreate