summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/os.rst43
-rw-r--r--Doc/whatsnew/3.9.rst8
-rw-r--r--Lib/os.py32
-rw-r--r--Lib/test/test_os.py4
-rw-r--r--Lib/test/test_posix.py1
-rw-r--r--Misc/NEWS.d/next/Build/2020-01-23-03-05-13.bpo-39395.RoArIZ.rst2
-rw-r--r--Misc/NEWS.d/next/Library/2020-01-23-03-05-41.bpo-39395.4dda42.rst2
-rw-r--r--Modules/clinic/posixmodule.c.h10
-rw-r--r--Modules/posixmodule.c83
-rwxr-xr-xconfigure6
-rw-r--r--configure.ac6
-rw-r--r--pyconfig.h.in9
12 files changed, 52 insertions, 154 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index de3e560..f59423c 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -111,9 +111,9 @@ process and user.
to the environment made after this time are not reflected in ``os.environ``,
except for changes made by modifying ``os.environ`` directly.
- If the platform supports the :func:`putenv` function, this mapping may be used
- to modify the environment as well as query the environment. :func:`putenv` will
- be called automatically when the mapping is modified.
+ This mapping may be used to modify the environment as well as query the
+ environment. :func:`putenv` will be called automatically when the mapping
+ is modified.
On Unix, keys and values use :func:`sys.getfilesystemencoding` and
``'surrogateescape'`` error handler. Use :data:`environb` if you would like
@@ -130,14 +130,10 @@ process and user.
cause memory leaks. Refer to the system documentation for
:c:func:`putenv`.
- If :func:`putenv` is not provided, a modified copy of this mapping may be
- passed to the appropriate process-creation functions to cause child processes
- to use a modified environment.
-
- If the platform supports the :func:`unsetenv` function, you can delete items in
- this mapping to unset environment variables. :func:`unsetenv` will be called
- automatically when an item is deleted from ``os.environ``, and when
- one of the :meth:`pop` or :meth:`clear` methods is called.
+ You can delete items in this mapping to unset environment variables.
+ :func:`unsetenv` will be called automatically when an item is deleted from
+ ``os.environ``, and when one of the :meth:`pop` or :meth:`clear` methods is
+ called.
.. data:: environb
@@ -439,17 +435,18 @@ process and user.
changes to the environment affect subprocesses started with :func:`os.system`,
:func:`popen` or :func:`fork` and :func:`execv`.
- .. availability:: most flavors of Unix, Windows.
+ Assignments to items in ``os.environ`` are automatically translated into
+ corresponding calls to :func:`putenv`; however, calls to :func:`putenv`
+ don't update ``os.environ``, so it is actually preferable to assign to items
+ of ``os.environ``.
.. note::
On some platforms, including FreeBSD and Mac OS X, setting ``environ`` may
- cause memory leaks. Refer to the system documentation for putenv.
+ cause memory leaks. Refer to the system documentation for :c:func:`putenv`.
- When :func:`putenv` is supported, assignments to items in ``os.environ`` are
- automatically translated into corresponding calls to :func:`putenv`; however,
- calls to :func:`putenv` don't update ``os.environ``, so it is actually
- preferable to assign to items of ``os.environ``.
+ .. versionchanged:: 3.9
+ The function is now always available.
.. function:: setegid(egid)
@@ -638,15 +635,13 @@ process and user.
environment affect subprocesses started with :func:`os.system`, :func:`popen` or
:func:`fork` and :func:`execv`.
- When :func:`unsetenv` is supported, deletion of items in ``os.environ`` is
- automatically translated into a corresponding call to :func:`unsetenv`; however,
- calls to :func:`unsetenv` don't update ``os.environ``, so it is actually
- preferable to delete items of ``os.environ``.
-
- .. availability:: most flavors of Unix, Windows.
+ Deletion of items in ``os.environ`` is automatically translated into a
+ corresponding call to :func:`unsetenv`; however, calls to :func:`unsetenv`
+ don't update ``os.environ``, so it is actually preferable to delete items of
+ ``os.environ``.
.. versionchanged:: 3.9
- The function is now also available on Windows.
+ The function is now always available and is also available on Windows.
.. _os-newstreams:
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 751562e..a4c4266 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -227,6 +227,10 @@ descriptors.
The :func:`os.unsetenv` function is now also available on Windows.
(Contributed by Victor Stinner in :issue:`39413`.)
+The :func:`os.putenv` and :func:`os.unsetenv` functions are now always
+available.
+(Contributed by Victor Stinner in :issue:`39395`.)
+
poplib
------
@@ -331,6 +335,10 @@ Build and C API Changes
Python 3.0, it has been ignored and unused.
(Contributed by Jeroen Demeyer in :issue:`36974`.)
+* On non-Windows platforms, the :c:func:`setenv` and :c:func:`unsetenv`
+ functions are now required to build Python.
+ (Contributed by Victor Stinner in :issue:`39395`.)
+
Deprecated
==========
diff --git a/Lib/os.py b/Lib/os.py
index ca418ed..7ae1026 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -654,17 +654,15 @@ def get_exec_path(env=None):
return path_list.split(pathsep)
-# Change environ to automatically call putenv(), unsetenv if they exist.
+# Change environ to automatically call putenv() and unsetenv()
from _collections_abc import MutableMapping
class _Environ(MutableMapping):
- def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, putenv, unsetenv):
+ def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
self.encodekey = encodekey
self.decodekey = decodekey
self.encodevalue = encodevalue
self.decodevalue = decodevalue
- self.putenv = putenv
- self.unsetenv = unsetenv
self._data = data
def __getitem__(self, key):
@@ -678,12 +676,12 @@ class _Environ(MutableMapping):
def __setitem__(self, key, value):
key = self.encodekey(key)
value = self.encodevalue(value)
- self.putenv(key, value)
+ putenv(key, value)
self._data[key] = value
def __delitem__(self, key):
encodedkey = self.encodekey(key)
- self.unsetenv(encodedkey)
+ unsetenv(encodedkey)
try:
del self._data[encodedkey]
except KeyError:
@@ -712,22 +710,6 @@ class _Environ(MutableMapping):
self[key] = value
return self[key]
-try:
- _putenv = putenv
-except NameError:
- _putenv = lambda key, value: None
-else:
- if "putenv" not in __all__:
- __all__.append("putenv")
-
-try:
- _unsetenv = unsetenv
-except NameError:
- _unsetenv = lambda key: _putenv(key, "")
-else:
- if "unsetenv" not in __all__:
- __all__.append("unsetenv")
-
def _createenviron():
if name == 'nt':
# Where Env Var Names Must Be UPPERCASE
@@ -755,8 +737,7 @@ def _createenviron():
data = environ
return _Environ(data,
encodekey, decode,
- encode, decode,
- _putenv, _unsetenv)
+ encode, decode)
# unicode environ
environ = _createenviron()
@@ -781,8 +762,7 @@ if supports_bytes_environ:
# bytes environ
environb = _Environ(environ._data,
_check_bytes, bytes,
- _check_bytes, bytes,
- _putenv, _unsetenv)
+ _check_bytes, bytes)
del _check_bytes
def getenvb(key, default=None):
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index dbdc00c..9e3a169 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -953,8 +953,6 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
value_str = value.decode(sys.getfilesystemencoding(), 'surrogateescape')
self.assertEqual(os.environ['bytes'], value_str)
- @unittest.skipUnless(hasattr(os, 'putenv'), "Test needs os.putenv()")
- @unittest.skipUnless(hasattr(os, 'unsetenv'), "Test needs os.unsetenv()")
def test_putenv_unsetenv(self):
name = "PYTHONTESTVAR"
value = "testvalue"
@@ -975,8 +973,6 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
# On OS X < 10.6, unsetenv() doesn't return a value (bpo-13415).
@support.requires_mac_ver(10, 6)
- @unittest.skipUnless(hasattr(os, 'putenv'), "Test needs os.putenv()")
- @unittest.skipUnless(hasattr(os, 'unsetenv'), "Test needs os.unsetenv()")
def test_putenv_unsetenv_error(self):
# Empty variable name is invalid.
# "=" and null character are not allowed in a variable name.
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 4df882b..fad26d8 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -969,7 +969,6 @@ class PosixTester(unittest.TestCase):
self.assertEqual(type(k), item_type)
self.assertEqual(type(v), item_type)
- @unittest.skipUnless(hasattr(os, "putenv"), "requires os.putenv()")
def test_putenv(self):
with self.assertRaises(ValueError):
os.putenv('FRUIT\0VEGETABLE', 'cabbage')
diff --git a/Misc/NEWS.d/next/Build/2020-01-23-03-05-13.bpo-39395.RoArIZ.rst b/Misc/NEWS.d/next/Build/2020-01-23-03-05-13.bpo-39395.RoArIZ.rst
new file mode 100644
index 0000000..aa2146a
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2020-01-23-03-05-13.bpo-39395.RoArIZ.rst
@@ -0,0 +1,2 @@
+On non-Windows platforms, the :c:func:`setenv` and :c:func:`unsetenv` functions
+are now required to build Python.
diff --git a/Misc/NEWS.d/next/Library/2020-01-23-03-05-41.bpo-39395.4dda42.rst b/Misc/NEWS.d/next/Library/2020-01-23-03-05-41.bpo-39395.4dda42.rst
new file mode 100644
index 0000000..cf71370
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-01-23-03-05-41.bpo-39395.4dda42.rst
@@ -0,0 +1,2 @@
+The :func:`os.putenv` and :func:`os.unsetenv` functions are now always
+available.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 0f5995e..48dd7a7 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -6082,7 +6082,7 @@ exit:
#endif /* defined(MS_WINDOWS) */
-#if ((defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS))
+#if !defined(MS_WINDOWS)
PyDoc_STRVAR(os_putenv__doc__,
"putenv($module, name, value, /)\n"
@@ -6123,7 +6123,7 @@ exit:
return return_value;
}
-#endif /* ((defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS)) */
+#endif /* !defined(MS_WINDOWS) */
#if defined(MS_WINDOWS)
@@ -6161,7 +6161,7 @@ exit:
#endif /* defined(MS_WINDOWS) */
-#if (defined(HAVE_UNSETENV) && !defined(MS_WINDOWS))
+#if !defined(MS_WINDOWS)
PyDoc_STRVAR(os_unsetenv__doc__,
"unsetenv($module, name, /)\n"
@@ -6193,7 +6193,7 @@ exit:
return return_value;
}
-#endif /* (defined(HAVE_UNSETENV) && !defined(MS_WINDOWS)) */
+#endif /* !defined(MS_WINDOWS) */
PyDoc_STRVAR(os_strerror__doc__,
"strerror($module, code, /)\n"
@@ -8809,4 +8809,4 @@ exit:
#ifndef OS__REMOVE_DLL_DIRECTORY_METHODDEF
#define OS__REMOVE_DLL_DIRECTORY_METHODDEF
#endif /* !defined(OS__REMOVE_DLL_DIRECTORY_METHODDEF) */
-/*[clinic end generated code: output=0348cbdff48691e3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5d99f90cead7c0e1 input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 3a8e6aa..b71eddf 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -819,22 +819,8 @@ dir_fd_converter(PyObject *o, void *p)
}
}
-/* Windows _wputenv() and setenv() copy the arguments and so don't require
- the caller to manage the variable memory. Only Unix putenv() requires
- putenv_dict. */
-#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS) && !defined(HAVE_SETENV)
-# define PY_PUTENV_DICT
-#endif
-
typedef struct {
PyObject *billion;
-#ifdef PY_PUTENV_DICT
- /* putenv() requires that the caller manages the environment variable
- memory. Use a Python dictionary for that: name => env, where env is a
- string like "name=value". On Windows, dict keys and values are Unicode
- strings. On Unix, they are bytes strings. */
- PyObject *putenv_dict;
-#endif
PyObject *DirEntryType;
PyObject *ScandirIteratorType;
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
@@ -2118,9 +2104,6 @@ static int
_posix_clear(PyObject *module)
{
Py_CLEAR(_posixstate(module)->billion);
-#ifdef PY_PUTENV_DICT
- Py_CLEAR(_posixstate(module)->putenv_dict);
-#endif
Py_CLEAR(_posixstate(module)->DirEntryType);
Py_CLEAR(_posixstate(module)->ScandirIteratorType);
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
@@ -2145,9 +2128,6 @@ static int
_posix_traverse(PyObject *module, visitproc visit, void *arg)
{
Py_VISIT(_posixstate(module)->billion);
-#ifdef PY_PUTENV_DICT
- Py_VISIT(_posixstate(module)->putenv_dict);
-#endif
Py_VISIT(_posixstate(module)->DirEntryType);
Py_VISIT(_posixstate(module)->ScandirIteratorType);
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
@@ -10065,23 +10045,6 @@ os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset,
#endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */
-#ifdef PY_PUTENV_DICT
-static void
-posix_putenv_dict_setitem(PyObject *name, PyObject *value)
-{
- /* Install the first arg and newstr in putenv_dict;
- * this will cause previous value to be collected. This has to
- * happen after the real putenv() call because the old value
- * was still accessible until then. */
- if (PyDict_SetItem(_posixstate_global->putenv_dict, name, value))
- /* really not much we can do; just leak */
- PyErr_Clear();
- else
- Py_DECREF(value);
-}
-#endif /* PY_PUTENV_DICT */
-
-
#ifdef MS_WINDOWS
static PyObject*
win32_putenv(PyObject *name, PyObject *value)
@@ -10157,8 +10120,7 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
{
return win32_putenv(name, value);
}
-/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */
-#elif (defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS)
+#else
/*[clinic input]
os.putenv
@@ -10181,27 +10143,12 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
return NULL;
}
-#ifdef HAVE_SETENV
if (setenv(name_string, value_string, 1)) {
return posix_error();
}
-#else
- PyObject *bytes = PyBytes_FromFormat("%s=%s", name_string, value_string);
- if (bytes == NULL) {
- return NULL;
- }
-
- char *env = PyBytes_AS_STRING(bytes);
- if (putenv(env)) {
- Py_DECREF(bytes);
- return posix_error();
- }
-
- posix_putenv_dict_setitem(name, bytes);
-#endif
Py_RETURN_NONE;
}
-#endif /* defined(HAVE_SETENV) || defined(HAVE_PUTENV) */
+#endif /* !defined(MS_WINDOWS) */
#ifdef MS_WINDOWS
@@ -10219,8 +10166,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
{
return win32_putenv(name, NULL);
}
-/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */
-#elif defined(HAVE_UNSETENV) && !defined(MS_WINDOWS)
+#else
/*[clinic input]
os.unsetenv
name: FSConverter
@@ -10242,24 +10188,9 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
}
#endif
-#ifdef PY_PUTENV_DICT
- /* Remove the key from putenv_dict;
- * this will cause it to be collected. This has to
- * happen after the real unsetenv() call because the
- * old value was still accessible until then.
- */
- if (PyDict_DelItem(_posixstate(module)->putenv_dict, name)) {
- /* really not much we can do; just leak */
- if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
- return NULL;
- }
- PyErr_Clear();
- }
-#endif
-
Py_RETURN_NONE;
}
-#endif /* HAVE_UNSETENV */
+#endif /* !MS_WINDOWS */
/*[clinic input]
@@ -14553,12 +14484,6 @@ INITFUNC(void)
Py_INCREF(PyExc_OSError);
PyModule_AddObject(m, "error", PyExc_OSError);
-#ifdef PY_PUTENV_DICT
- /* Save putenv() parameters as values here, so we can collect them when they
- * get re-set with another call for the same key. */
- _posixstate(m)->putenv_dict = PyDict_New();
-#endif
-
#if defined(HAVE_WAITID) && !defined(__APPLE__)
waitid_result_desc.name = MODNAME ".waitid_result";
PyObject *WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc);
diff --git a/configure b/configure
index e966836..85120e4 100755
--- a/configure
+++ b/configure
@@ -11548,9 +11548,9 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
memrchr mbrtowc mkdirat mkfifo \
madvise mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
- pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \
+ pthread_condattr_setclock pthread_init pthread_kill pwrite pwritev pwritev2 \
readlink readlinkat readv realpath renameat \
- sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \
+ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
@@ -11558,7 +11558,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy strsignal symlinkat sync \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
- truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
+ truncate uname unlinkat utimensat utimes waitid waitpid wait3 wait4 \
wcscoll wcsftime wcsxfrm wmemcmp writev _getpty rtpSpawn
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
diff --git a/configure.ac b/configure.ac
index 36c165b..ab8e1b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3598,9 +3598,9 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
memrchr mbrtowc mkdirat mkfifo \
madvise mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
- pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \
+ pthread_condattr_setclock pthread_init pthread_kill pwrite pwritev pwritev2 \
readlink readlinkat readv realpath renameat \
- sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \
+ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
@@ -3608,7 +3608,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy strsignal symlinkat sync \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
- truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
+ truncate uname unlinkat utimensat utimes waitid waitpid wait3 wait4 \
wcscoll wcsftime wcsxfrm wmemcmp writev _getpty rtpSpawn)
# Force lchmod off for Linux. Linux disallows changing the mode of symbolic
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 1918fab..b560213 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -802,9 +802,6 @@
/* Define to 1 if you have the <pty.h> header file. */
#undef HAVE_PTY_H
-/* Define to 1 if you have the `putenv' function. */
-#undef HAVE_PUTENV
-
/* Define to 1 if you have the `pwrite' function. */
#undef HAVE_PWRITE
@@ -895,9 +892,6 @@
/* Define to 1 if you have the `setegid' function. */
#undef HAVE_SETEGID
-/* Define to 1 if you have the `setenv' function. */
-#undef HAVE_SETENV
-
/* Define to 1 if you have the `seteuid' function. */
#undef HAVE_SETEUID
@@ -1266,9 +1260,6 @@
/* Define to 1 if you have the `unlinkat' function. */
#undef HAVE_UNLINKAT
-/* Define to 1 if you have the `unsetenv' function. */
-#undef HAVE_UNSETENV
-
/* Define if you have a useable wchar_t type defined in wchar.h; useable means
wchar_t must be an unsigned type with at least 16 bits. (see
Include/unicodeobject.h). */