Issue #15118: Change return value of os.uname() and os.times() from
plain tuples to immutable iterable objects with named attributes (structseq objects).
This commit is contained in:
parent
f62445ad30
commit
605a62ddb1
|
@ -570,15 +570,31 @@ process and user.
|
||||||
single: gethostname() (in module socket)
|
single: gethostname() (in module socket)
|
||||||
single: gethostbyaddr() (in module socket)
|
single: gethostbyaddr() (in module socket)
|
||||||
|
|
||||||
Return a 5-tuple containing information identifying the current operating
|
Returns information identifying the current operating system.
|
||||||
system. The tuple contains 5 strings: ``(sysname, nodename, release, version,
|
The return value is an object with five attributes:
|
||||||
machine)``. Some systems truncate the nodename to 8 characters or to the
|
|
||||||
|
* :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
|
leading component; a better way to get the hostname is
|
||||||
:func:`socket.gethostname` or even
|
:func:`socket.gethostname` or even
|
||||||
``socket.gethostbyaddr(socket.gethostname())``.
|
``socket.gethostbyaddr(socket.gethostname())``.
|
||||||
|
|
||||||
Availability: recent flavors of Unix.
|
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)
|
.. function:: unsetenv(key)
|
||||||
|
|
||||||
|
@ -2801,15 +2817,31 @@ written in Python, such as a mail server's external command delivery program.
|
||||||
|
|
||||||
.. function:: times()
|
.. function:: times()
|
||||||
|
|
||||||
Return a 5-tuple of floating point numbers indicating accumulated (processor
|
Returns the current global process times.
|
||||||
or other) times, in seconds. The items are: user time, system time,
|
The return value is an object with five attributes:
|
||||||
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
|
* :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.
|
: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.
|
Availability: Unix, Windows.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
Return type changed from a tuple to a tuple-like object
|
||||||
|
with named attributes.
|
||||||
|
|
||||||
|
|
||||||
.. function:: wait()
|
.. function:: wait()
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ if _os.name == "posix" and _sys.platform == "darwin":
|
||||||
# libraries. OS X 10.3 is Darwin 7, so we check for
|
# libraries. OS X 10.3 is Darwin 7, so we check for
|
||||||
# that.
|
# that.
|
||||||
|
|
||||||
if int(_os.uname()[2].split('.')[0]) < 8:
|
if int(_os.uname().release.split('.')[0]) < 8:
|
||||||
DEFAULT_MODE = RTLD_GLOBAL
|
DEFAULT_MODE = RTLD_GLOBAL
|
||||||
|
|
||||||
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
||||||
|
|
|
@ -171,9 +171,9 @@ elif os.name == "posix":
|
||||||
def _findSoname_ldconfig(name):
|
def _findSoname_ldconfig(name):
|
||||||
import struct
|
import struct
|
||||||
if struct.calcsize('l') == 4:
|
if struct.calcsize('l') == 4:
|
||||||
machine = os.uname()[4] + '-32'
|
machine = os.uname().machine + '-32'
|
||||||
else:
|
else:
|
||||||
machine = os.uname()[4] + '-64'
|
machine = os.uname().machine + '-64'
|
||||||
mach_map = {
|
mach_map = {
|
||||||
'x86_64-64': 'libc6,x86-64',
|
'x86_64-64': 'libc6,x86-64',
|
||||||
'ppc64-64': 'libc6,64bit',
|
'ppc64-64': 'libc6,64bit',
|
||||||
|
|
|
@ -700,7 +700,7 @@ def _mac_ver_xml():
|
||||||
pl = plistlib.readPlist(fn)
|
pl = plistlib.readPlist(fn)
|
||||||
release = pl['ProductVersion']
|
release = pl['ProductVersion']
|
||||||
versioninfo=('', '', '')
|
versioninfo=('', '', '')
|
||||||
machine = os.uname()[4]
|
machine = os.uname().machine
|
||||||
if machine in ('ppc', 'Power Macintosh'):
|
if machine in ('ppc', 'Power Macintosh'):
|
||||||
# for compatibility with the gestalt based code
|
# for compatibility with the gestalt based code
|
||||||
machine = 'PowerPC'
|
machine = 'PowerPC'
|
||||||
|
|
|
@ -12,7 +12,7 @@ from platform import uname
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest
|
||||||
|
|
||||||
if uname()[0] == "Darwin":
|
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):
|
if (maj, min, mic) < (8, 0, 0):
|
||||||
raise unittest.SkipTest("locale support broken for OS X < 10.4")
|
raise unittest.SkipTest("locale support broken for OS X < 10.4")
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ def get_enUS_locale():
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
import os
|
import os
|
||||||
tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US")
|
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)
|
# 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
|
# haven't had time yet to verify if tests work on OSX 10.5
|
||||||
# (10.4 is known to be bad)
|
# (10.4 is known to be bad)
|
||||||
|
|
|
@ -14,7 +14,6 @@ from sysconfig import (get_paths, get_platform, get_config_vars,
|
||||||
_get_default_scheme, _expand_vars,
|
_get_default_scheme, _expand_vars,
|
||||||
get_scheme_names, get_config_var, _main)
|
get_scheme_names, get_config_var, _main)
|
||||||
|
|
||||||
|
|
||||||
class TestSysConfig(unittest.TestCase):
|
class TestSysConfig(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -26,7 +25,7 @@ class TestSysConfig(unittest.TestCase):
|
||||||
self._uname = os.uname()
|
self._uname = os.uname()
|
||||||
else:
|
else:
|
||||||
self.uname = None
|
self.uname = None
|
||||||
self._uname = None
|
self._set_uname(('',)*5)
|
||||||
os.uname = self._get_uname
|
os.uname = self._get_uname
|
||||||
# saving the environment
|
# saving the environment
|
||||||
self.name = os.name
|
self.name = os.name
|
||||||
|
@ -70,7 +69,7 @@ class TestSysConfig(unittest.TestCase):
|
||||||
super(TestSysConfig, self).tearDown()
|
super(TestSysConfig, self).tearDown()
|
||||||
|
|
||||||
def _set_uname(self, uname):
|
def _set_uname(self, uname):
|
||||||
self._uname = uname
|
self._uname = os.uname_result(uname)
|
||||||
|
|
||||||
def _get_uname(self):
|
def _get_uname(self):
|
||||||
return self._uname
|
return self._uname
|
||||||
|
|
|
@ -440,7 +440,7 @@ try:
|
||||||
import sys
|
import sys
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
import os
|
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
|
_uuid_generate_random = _uuid_generate_time = None
|
||||||
|
|
||||||
# On Windows prior to 2000, UuidCreate gives a UUID containing the
|
# On Windows prior to 2000, UuidCreate gives a UUID containing the
|
||||||
|
|
|
@ -55,6 +55,10 @@ Core and Builtins
|
||||||
Library
|
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
|
- 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),
|
that was last accessed. In the pi benchmark (64-bit platform, prec=9),
|
||||||
_decimal is now only 1.5x slower than float.
|
_decimal is now only 1.5x slower than float.
|
||||||
|
|
|
@ -4299,28 +4299,76 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_UNAME
|
|
||||||
PyDoc_STRVAR(posix_uname__doc__,
|
PyDoc_STRVAR(posix_uname__doc__,
|
||||||
"uname() -> (sysname, nodename, release, version, machine)\n\n\
|
"uname() -> uname_result\n\n\
|
||||||
Return a tuple identifying the current operating system.");
|
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 *
|
static PyObject *
|
||||||
posix_uname(PyObject *self, PyObject *noargs)
|
posix_uname(PyObject *self, PyObject *noargs)
|
||||||
{
|
{
|
||||||
struct utsname u;
|
struct utsname u;
|
||||||
int res;
|
int res;
|
||||||
|
PyObject *value;
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = uname(&u);
|
res = uname(&u);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return posix_error();
|
return posix_error();
|
||||||
return Py_BuildValue("(sssss)",
|
|
||||||
u.sysname,
|
value = PyStructSequence_New(&UnameResultType);
|
||||||
u.nodename,
|
if (value == NULL)
|
||||||
u.release,
|
return NULL;
|
||||||
u.version,
|
|
||||||
u.machine);
|
#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 */
|
#endif /* HAVE_UNAME */
|
||||||
|
|
||||||
|
@ -7366,6 +7414,75 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
|
#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
|
#ifdef HAVE_TIMES
|
||||||
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
|
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
|
||||||
static long
|
static long
|
||||||
|
@ -7384,7 +7501,7 @@ static PyObject *
|
||||||
posix_times(PyObject *self, PyObject *noargs)
|
posix_times(PyObject *self, PyObject *noargs)
|
||||||
{
|
{
|
||||||
/* Currently Only Uptime is Provided -- Others Later */
|
/* 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_utime / HZ */,
|
||||||
(double)0 /* t.tms_stime / HZ */,
|
(double)0 /* t.tms_stime / HZ */,
|
||||||
(double)0 /* t.tms_cutime / HZ */,
|
(double)0 /* t.tms_cutime / HZ */,
|
||||||
|
@ -7403,7 +7520,7 @@ posix_times(PyObject *self, PyObject *noargs)
|
||||||
c = times(&t);
|
c = times(&t);
|
||||||
if (c == (clock_t) -1)
|
if (c == (clock_t) -1)
|
||||||
return posix_error();
|
return posix_error();
|
||||||
return Py_BuildValue("ddddd",
|
return build_times_result(
|
||||||
(double)t.tms_utime / ticks_per_second,
|
(double)t.tms_utime / ticks_per_second,
|
||||||
(double)t.tms_stime / ticks_per_second,
|
(double)t.tms_stime / ticks_per_second,
|
||||||
(double)t.tms_cutime / 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);
|
(double)c / ticks_per_second);
|
||||||
}
|
}
|
||||||
#endif /* not OS2 */
|
#endif /* not OS2 */
|
||||||
#endif /* HAVE_TIMES */
|
#elif defined(MS_WINDOWS)
|
||||||
|
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
|
||||||
#define HAVE_TIMES /* so the method table will pick it up */
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
posix_times(PyObject *self, PyObject *noargs)
|
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.
|
1e7 is one second in such units; 1e-7 the inverse.
|
||||||
429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
|
429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
|
||||||
*/
|
*/
|
||||||
return Py_BuildValue(
|
return build_times_result(
|
||||||
"ddddd",
|
|
||||||
(double)(user.dwHighDateTime*429.4967296 +
|
(double)(user.dwHighDateTime*429.4967296 +
|
||||||
user.dwLowDateTime*1e-7),
|
user.dwLowDateTime*1e-7),
|
||||||
(double)(kernel.dwHighDateTime*429.4967296 +
|
(double)(kernel.dwHighDateTime*429.4967296 +
|
||||||
|
@ -7438,12 +7550,6 @@ posix_times(PyObject *self, PyObject *noargs)
|
||||||
(double)0,
|
(double)0,
|
||||||
(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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -11965,6 +12071,14 @@ INITFUNC(void)
|
||||||
PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
|
PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
times_result_desc.name = MODNAME ".times_result";
|
||||||
|
PyStructSequence_InitType(&TimesResultType, ×_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__
|
#ifdef __APPLE__
|
||||||
/*
|
/*
|
||||||
* Step 2 of weak-linking support on Mac OS X.
|
* Step 2 of weak-linking support on Mac OS X.
|
||||||
|
|
Loading…
Reference in New Issue