summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/os.rst48
-rw-r--r--Lib/ctypes/__init__.py2
-rw-r--r--Lib/ctypes/util.py4
-rwxr-xr-xLib/platform.py2
-rw-r--r--Lib/test/test__locale.py2
-rw-r--r--Lib/test/test_locale.py2
-rw-r--r--Lib/test/test_sysconfig.py5
-rw-r--r--Lib/uuid.py2
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/posixmodule.c162
10 files changed, 191 insertions, 42 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 59b1d10..9556be6 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -570,15 +570,31 @@ process and user.
single: gethostname() (in module socket)
single: gethostbyaddr() (in module socket)
- Return a 5-tuple containing information identifying the current operating
- system. The tuple contains 5 strings: ``(sysname, nodename, release, version,
- machine)``. Some systems truncate the nodename to 8 characters or to the
+ Returns information identifying the current operating system.
+ The return value is an object with five attributes:
+
+ * :attr:`sysname` - operating system name
+ * :attr:`nodename` - name of machine on network (implementation-defined)
+ * :attr:`release` - operating system release
+ * :attr:`version` - operating system version
+ * :attr:`machine` - hardware identifier
+
+ For backwards compatibility, this object is also iterable, behaving
+ like a five-tuple containing :attr:`sysname`, :attr:`nodename`,
+ :attr:`release`, :attr:`version`, and :attr:`machine`
+ in that order.
+
+ Some systems truncate :attr:`nodename` to 8 characters or to the
leading component; a better way to get the hostname is
:func:`socket.gethostname` or even
``socket.gethostbyaddr(socket.gethostname())``.
Availability: recent flavors of Unix.
+ .. versionchanged:: 3.3
+ Return type changed from a tuple to a tuple-like object
+ with named attributes.
+
.. function:: unsetenv(key)
@@ -2801,15 +2817,31 @@ written in Python, such as a mail server's external command delivery program.
.. function:: times()
- Return a 5-tuple of floating point numbers indicating accumulated (processor
- or other) times, in seconds. The items are: user time, system time,
- children's user time, children's system time, and elapsed real time since a
- fixed point in the past, in that order. See the Unix manual page
+ Returns the current global process times.
+ The return value is an object with five attributes:
+
+ * :attr:`user` - user time
+ * :attr:`system` - system time
+ * :attr:`children_user` - user time of all child processes
+ * :attr:`children_system` - system time of all child processes
+ * :attr:`elapsed` - elapsed real time since a fixed point in the past
+
+ For backwards compatibility, this object also behaves like a five-tuple
+ containing :attr:`user`, :attr:`system`, :attr:`children_user`,
+ :attr:`children_system`, and :attr:`elapsed` in that order.
+
+ See the Unix manual page
:manpage:`times(2)` or the corresponding Windows Platform API documentation.
- On Windows, only the first two items are filled, the others are zero.
+ On Windows, only :attr:`user` and :attr:`system` are known; the other
+ attributes are zero.
+ On OS/2, only :attr:`elapsed` is known; the other attributes are zero.
Availability: Unix, Windows.
+ .. versionchanged:: 3.3
+ Return type changed from a tuple to a tuple-like object
+ with named attributes.
+
.. function:: wait()
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index 111209a..f0bd66a 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -26,7 +26,7 @@ if _os.name == "posix" and _sys.platform == "darwin":
# libraries. OS X 10.3 is Darwin 7, so we check for
# that.
- if int(_os.uname()[2].split('.')[0]) < 8:
+ if int(_os.uname().release.split('.')[0]) < 8:
DEFAULT_MODE = RTLD_GLOBAL
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 61eb094..5555b2e 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -171,9 +171,9 @@ elif os.name == "posix":
def _findSoname_ldconfig(name):
import struct
if struct.calcsize('l') == 4:
- machine = os.uname()[4] + '-32'
+ machine = os.uname().machine + '-32'
else:
- machine = os.uname()[4] + '-64'
+ machine = os.uname().machine + '-64'
mach_map = {
'x86_64-64': 'libc6,x86-64',
'ppc64-64': 'libc6,64bit',
diff --git a/Lib/platform.py b/Lib/platform.py
index 4554659..b7dbcca 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -700,7 +700,7 @@ def _mac_ver_xml():
pl = plistlib.readPlist(fn)
release = pl['ProductVersion']
versioninfo=('', '', '')
- machine = os.uname()[4]
+ machine = os.uname().machine
if machine in ('ppc', 'Power Macintosh'):
# for compatibility with the gestalt based code
machine = 'PowerPC'
diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py
index f7f1abd..dab1565 100644
--- a/Lib/test/test__locale.py
+++ b/Lib/test/test__locale.py
@@ -12,7 +12,7 @@ from platform import uname
from test.support import run_unittest
if uname()[0] == "Darwin":
- maj, min, mic = [int(part) for part in uname()[2].split(".")]
+ maj, min, mic = [int(part) for part in uname().release.split(".")]
if (maj, min, mic) < (8, 0, 0):
raise unittest.SkipTest("locale support broken for OS X < 10.4")
diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py
index 7fdb6da..51a7bca 100644
--- a/Lib/test/test_locale.py
+++ b/Lib/test/test_locale.py
@@ -11,7 +11,7 @@ def get_enUS_locale():
if sys.platform == 'darwin':
import os
tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US")
- if int(os.uname()[2].split('.')[0]) < 10:
+ if int(os.uname().release.split('.')[0]) < 10:
# The locale test work fine on OSX 10.6, I (ronaldoussoren)
# haven't had time yet to verify if tests work on OSX 10.5
# (10.4 is known to be bad)
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
index 3cb63ed..aa5d582 100644
--- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py
@@ -14,7 +14,6 @@ from sysconfig import (get_paths, get_platform, get_config_vars,
_get_default_scheme, _expand_vars,
get_scheme_names, get_config_var, _main)
-
class TestSysConfig(unittest.TestCase):
def setUp(self):
@@ -26,7 +25,7 @@ class TestSysConfig(unittest.TestCase):
self._uname = os.uname()
else:
self.uname = None
- self._uname = None
+ self._set_uname(('',)*5)
os.uname = self._get_uname
# saving the environment
self.name = os.name
@@ -70,7 +69,7 @@ class TestSysConfig(unittest.TestCase):
super(TestSysConfig, self).tearDown()
def _set_uname(self, uname):
- self._uname = uname
+ self._uname = os.uname_result(uname)
def _get_uname(self):
return self._uname
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 5684ad7..0df0743 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -440,7 +440,7 @@ try:
import sys
if sys.platform == 'darwin':
import os
- if int(os.uname()[2].split('.')[0]) >= 9:
+ if int(os.uname().release.split('.')[0]) >= 9:
_uuid_generate_random = _uuid_generate_time = None
# On Windows prior to 2000, UuidCreate gives a UUID containing the
diff --git a/Misc/NEWS b/Misc/NEWS
index 6f3b85d..d4edb95 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -55,6 +55,10 @@ Core and Builtins
Library
-------
+- Issue #15118: Change return value of os.uname() and os.times() from
+ plain tuples to immutable iterable objects with named attributes
+ (structseq objects).
+
- Speed up _decimal by another 10-15% by caching the thread local context
that was last accessed. In the pi benchmark (64-bit platform, prec=9),
_decimal is now only 1.5x slower than float.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 6da030a..6cd8d88 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -4299,28 +4299,76 @@ exit:
}
-#ifdef HAVE_UNAME
PyDoc_STRVAR(posix_uname__doc__,
-"uname() -> (sysname, nodename, release, version, machine)\n\n\
-Return a tuple identifying the current operating system.");
+"uname() -> uname_result\n\n\
+Return an object identifying the current operating system.\n\
+The object behaves like a named tuple with the following fields:\n\
+ (sysname, nodename, release, version, machine)");
+
+static PyStructSequence_Field uname_result_fields[] = {
+ {"sysname", "operating system name"},
+ {"nodename", "name of machine on network (implementation-defined)"},
+ {"release", "operating system release"},
+ {"version", "operating system version"},
+ {"machine", "hardware identifier"},
+ {NULL}
+};
+
+PyDoc_STRVAR(uname_result__doc__,
+"uname_result: Result from os.uname().\n\n\
+This object may be accessed either as a tuple of\n\
+ (sysname, nodename, release, version, machine),\n\
+or via the attributes sysname, nodename, release, version, and machine.\n\
+\n\
+See os.uname for more information.");
+
+static PyStructSequence_Desc uname_result_desc = {
+ "uname_result", /* name */
+ uname_result__doc__, /* doc */
+ uname_result_fields,
+ 5
+};
+static PyTypeObject UnameResultType;
+
+
+#ifdef HAVE_UNAME
static PyObject *
posix_uname(PyObject *self, PyObject *noargs)
{
struct utsname u;
int res;
+ PyObject *value;
Py_BEGIN_ALLOW_THREADS
res = uname(&u);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error();
- return Py_BuildValue("(sssss)",
- u.sysname,
- u.nodename,
- u.release,
- u.version,
- u.machine);
+
+ value = PyStructSequence_New(&UnameResultType);
+ if (value == NULL)
+ return NULL;
+
+#define SET(i, field) \
+ { \
+ PyObject *o = PyUnicode_DecodeASCII(field, strlen(field), NULL); \
+ if (!o) { \
+ Py_DECREF(value); \
+ return NULL; \
+ } \
+ PyStructSequence_SET_ITEM(value, i, o); \
+ } \
+
+ SET(0, u.sysname);
+ SET(1, u.nodename);
+ SET(2, u.release);
+ SET(3, u.version);
+ SET(4, u.machine);
+
+#undef SET
+
+ return value;
}
#endif /* HAVE_UNAME */
@@ -7366,6 +7414,75 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
+static PyStructSequence_Field times_result_fields[] = {
+ {"user", "user time"},
+ {"system", "system time"},
+ {"children_user", "user time of children"},
+ {"children_system", "system time of children"},
+ {"elapsed", "elapsed time since an arbitrary point in the past"},
+ {NULL}
+};
+
+PyDoc_STRVAR(times_result__doc__,
+"times_result: Result from os.times().\n\n\
+This object may be accessed either as a tuple of\n\
+ (user, system, children_user, children_system, elapsed),\n\
+or via the attributes user, system, children_user, children_system,\n\
+and elapsed.\n\
+\n\
+See os.times for more information.");
+
+static PyStructSequence_Desc times_result_desc = {
+ "times_result", /* name */
+ times_result__doc__, /* doc */
+ times_result_fields,
+ 5
+};
+
+static PyTypeObject TimesResultType;
+
+
+#if defined(HAVE_TIMES) || defined(MS_WINDOWS)
+
+static PyObject *
+build_times_result(double user, double system,
+ double children_user, double children_system,
+ double elapsed)
+{
+ PyObject *value = PyStructSequence_New(&TimesResultType);
+ if (value == NULL)
+ return NULL;
+
+#define SET(i, field) \
+ { \
+ PyObject *o = PyFloat_FromDouble(field); \
+ if (!o) { \
+ Py_DECREF(value); \
+ return NULL; \
+ } \
+ PyStructSequence_SET_ITEM(value, i, o); \
+ } \
+
+ SET(0, user);
+ SET(1, system);
+ SET(2, children_user);
+ SET(3, children_system);
+ SET(4, elapsed);
+
+#undef SET
+
+ return value;
+}
+
+PyDoc_STRVAR(posix_times__doc__,
+"times() -> times_result\n\n\
+Return an object containing floating point numbers indicating process\n\
+times. The object behaves like a named tuple with these fields:\n\
+ (utime, stime, cutime, cstime, elapsed_time)");
+
+#endif
+
+
#ifdef HAVE_TIMES
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
static long
@@ -7384,7 +7501,7 @@ static PyObject *
posix_times(PyObject *self, PyObject *noargs)
{
/* Currently Only Uptime is Provided -- Others Later */
- return Py_BuildValue("ddddd",
+ return build_times_result(
(double)0 /* t.tms_utime / HZ */,
(double)0 /* t.tms_stime / HZ */,
(double)0 /* t.tms_cutime / HZ */,
@@ -7403,7 +7520,7 @@ posix_times(PyObject *self, PyObject *noargs)
c = times(&t);
if (c == (clock_t) -1)
return posix_error();
- return Py_BuildValue("ddddd",
+ return build_times_result(
(double)t.tms_utime / ticks_per_second,
(double)t.tms_stime / ticks_per_second,
(double)t.tms_cutime / ticks_per_second,
@@ -7411,11 +7528,7 @@ posix_times(PyObject *self, PyObject *noargs)
(double)c / ticks_per_second);
}
#endif /* not OS2 */
-#endif /* HAVE_TIMES */
-
-
-#ifdef MS_WINDOWS
-#define HAVE_TIMES /* so the method table will pick it up */
+#elif defined(MS_WINDOWS)
static PyObject *
posix_times(PyObject *self, PyObject *noargs)
{
@@ -7428,8 +7541,7 @@ posix_times(PyObject *self, PyObject *noargs)
1e7 is one second in such units; 1e-7 the inverse.
429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
*/
- return Py_BuildValue(
- "ddddd",
+ return build_times_result(
(double)(user.dwHighDateTime*429.4967296 +
user.dwLowDateTime*1e-7),
(double)(kernel.dwHighDateTime*429.4967296 +
@@ -7438,12 +7550,6 @@ posix_times(PyObject *self, PyObject *noargs)
(double)0,
(double)0);
}
-#endif /* MS_WINDOWS */
-
-#ifdef HAVE_TIMES
-PyDoc_STRVAR(posix_times__doc__,
-"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n\
-Return a tuple of floating point numbers indicating process times.");
#endif
@@ -11965,6 +12071,14 @@ INITFUNC(void)
PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
#endif
+ times_result_desc.name = MODNAME ".times_result";
+ PyStructSequence_InitType(&TimesResultType, &times_result_desc);
+ PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType);
+
+ uname_result_desc.name = MODNAME ".uname_result";
+ PyStructSequence_InitType(&UnameResultType, &uname_result_desc);
+ PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType);
+
#ifdef __APPLE__
/*
* Step 2 of weak-linking support on Mac OS X.