Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 605a62d

Browse files
committed
Issue #15118: Change return value of os.uname() and os.times() from
plain tuples to immutable iterable objects with named attributes (structseq objects).
1 parent f62445a commit 605a62d

10 files changed

Lines changed: 191 additions & 42 deletions

File tree

Doc/library/os.rst

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -570,15 +570,31 @@ process and user.
570570
single: gethostname() (in module socket)
571571
single: gethostbyaddr() (in module socket)
572572

573-
Return a 5-tuple containing information identifying the current operating
574-
system. The tuple contains 5 strings: ``(sysname, nodename, release, version,
575-
machine)``. Some systems truncate the nodename to 8 characters or to the
573+
Returns information identifying the current operating system.
574+
The return value is an object with five attributes:
575+
576+
* :attr:`sysname` - operating system name
577+
* :attr:`nodename` - name of machine on network (implementation-defined)
578+
* :attr:`release` - operating system release
579+
* :attr:`version` - operating system version
580+
* :attr:`machine` - hardware identifier
581+
582+
For backwards compatibility, this object is also iterable, behaving
583+
like a five-tuple containing :attr:`sysname`, :attr:`nodename`,
584+
:attr:`release`, :attr:`version`, and :attr:`machine`
585+
in that order.
586+
587+
Some systems truncate :attr:`nodename` to 8 characters or to the
576588
leading component; a better way to get the hostname is
577589
:func:`socket.gethostname` or even
578590
``socket.gethostbyaddr(socket.gethostname())``.
579591

580592
Availability: recent flavors of Unix.
581593

594+
.. versionchanged:: 3.3
595+
Return type changed from a tuple to a tuple-like object
596+
with named attributes.
597+
582598

583599
.. function:: unsetenv(key)
584600

@@ -2801,15 +2817,31 @@ written in Python, such as a mail server's external command delivery program.
28012817

28022818
.. function:: times()
28032819

2804-
Return a 5-tuple of floating point numbers indicating accumulated (processor
2805-
or other) times, in seconds. The items are: user time, system time,
2806-
children's user time, children's system time, and elapsed real time since a
2807-
fixed point in the past, in that order. See the Unix manual page
2820+
Returns the current global process times.
2821+
The return value is an object with five attributes:
2822+
2823+
* :attr:`user` - user time
2824+
* :attr:`system` - system time
2825+
* :attr:`children_user` - user time of all child processes
2826+
* :attr:`children_system` - system time of all child processes
2827+
* :attr:`elapsed` - elapsed real time since a fixed point in the past
2828+
2829+
For backwards compatibility, this object also behaves like a five-tuple
2830+
containing :attr:`user`, :attr:`system`, :attr:`children_user`,
2831+
:attr:`children_system`, and :attr:`elapsed` in that order.
2832+
2833+
See the Unix manual page
28082834
:manpage:`times(2)` or the corresponding Windows Platform API documentation.
2809-
On Windows, only the first two items are filled, the others are zero.
2835+
On Windows, only :attr:`user` and :attr:`system` are known; the other
2836+
attributes are zero.
2837+
On OS/2, only :attr:`elapsed` is known; the other attributes are zero.
28102838

28112839
Availability: Unix, Windows.
28122840

2841+
.. versionchanged:: 3.3
2842+
Return type changed from a tuple to a tuple-like object
2843+
with named attributes.
2844+
28132845

28142846
.. function:: wait()
28152847

Lib/ctypes/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# libraries. OS X 10.3 is Darwin 7, so we check for
2727
# that.
2828

29-
if int(_os.uname()[2].split('.')[0]) < 8:
29+
if int(_os.uname().release.split('.')[0]) < 8:
3030
DEFAULT_MODE = RTLD_GLOBAL
3131

3232
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \

Lib/ctypes/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ def find_library(name):
171171
def _findSoname_ldconfig(name):
172172
import struct
173173
if struct.calcsize('l') == 4:
174-
machine = os.uname()[4] + '-32'
174+
machine = os.uname().machine + '-32'
175175
else:
176-
machine = os.uname()[4] + '-64'
176+
machine = os.uname().machine + '-64'
177177
mach_map = {
178178
'x86_64-64': 'libc6,x86-64',
179179
'ppc64-64': 'libc6,64bit',

Lib/platform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ def _mac_ver_xml():
700700
pl = plistlib.readPlist(fn)
701701
release = pl['ProductVersion']
702702
versioninfo=('', '', '')
703-
machine = os.uname()[4]
703+
machine = os.uname().machine
704704
if machine in ('ppc', 'Power Macintosh'):
705705
# for compatibility with the gestalt based code
706706
machine = 'PowerPC'

Lib/test/test__locale.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from test.support import run_unittest
1313

1414
if uname()[0] == "Darwin":
15-
maj, min, mic = [int(part) for part in uname()[2].split(".")]
15+
maj, min, mic = [int(part) for part in uname().release.split(".")]
1616
if (maj, min, mic) < (8, 0, 0):
1717
raise unittest.SkipTest("locale support broken for OS X < 10.4")
1818

Lib/test/test_locale.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def get_enUS_locale():
1111
if sys.platform == 'darwin':
1212
import os
1313
tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US")
14-
if int(os.uname()[2].split('.')[0]) < 10:
14+
if int(os.uname().release.split('.')[0]) < 10:
1515
# The locale test work fine on OSX 10.6, I (ronaldoussoren)
1616
# haven't had time yet to verify if tests work on OSX 10.5
1717
# (10.4 is known to be bad)

Lib/test/test_sysconfig.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
_get_default_scheme, _expand_vars,
1515
get_scheme_names, get_config_var, _main)
1616

17-
1817
class TestSysConfig(unittest.TestCase):
1918

2019
def setUp(self):
@@ -26,7 +25,7 @@ def setUp(self):
2625
self._uname = os.uname()
2726
else:
2827
self.uname = None
29-
self._uname = None
28+
self._set_uname(('',)*5)
3029
os.uname = self._get_uname
3130
# saving the environment
3231
self.name = os.name
@@ -70,7 +69,7 @@ def tearDown(self):
7069
super(TestSysConfig, self).tearDown()
7170

7271
def _set_uname(self, uname):
73-
self._uname = uname
72+
self._uname = os.uname_result(uname)
7473

7574
def _get_uname(self):
7675
return self._uname

Lib/uuid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def _netbios_getnode():
440440
import sys
441441
if sys.platform == 'darwin':
442442
import os
443-
if int(os.uname()[2].split('.')[0]) >= 9:
443+
if int(os.uname().release.split('.')[0]) >= 9:
444444
_uuid_generate_random = _uuid_generate_time = None
445445

446446
# On Windows prior to 2000, UuidCreate gives a UUID containing the

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ Core and Builtins
5555
Library
5656
-------
5757

58+
- Issue #15118: Change return value of os.uname() and os.times() from
59+
plain tuples to immutable iterable objects with named attributes
60+
(structseq objects).
61+
5862
- Speed up _decimal by another 10-15% by caching the thread local context
5963
that was last accessed. In the pi benchmark (64-bit platform, prec=9),
6064
_decimal is now only 1.5x slower than float.

Modules/posixmodule.c

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,28 +4299,76 @@ posix_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
42994299
}
43004300

43014301

4302-
#ifdef HAVE_UNAME
43034302
PyDoc_STRVAR(posix_uname__doc__,
4304-
"uname() -> (sysname, nodename, release, version, machine)\n\n\
4305-
Return a tuple identifying the current operating system.");
4303+
"uname() -> uname_result\n\n\
4304+
Return an object identifying the current operating system.\n\
4305+
The object behaves like a named tuple with the following fields:\n\
4306+
(sysname, nodename, release, version, machine)");
4307+
4308+
static PyStructSequence_Field uname_result_fields[] = {
4309+
{"sysname", "operating system name"},
4310+
{"nodename", "name of machine on network (implementation-defined)"},
4311+
{"release", "operating system release"},
4312+
{"version", "operating system version"},
4313+
{"machine", "hardware identifier"},
4314+
{NULL}
4315+
};
4316+
4317+
PyDoc_STRVAR(uname_result__doc__,
4318+
"uname_result: Result from os.uname().\n\n\
4319+
This object may be accessed either as a tuple of\n\
4320+
(sysname, nodename, release, version, machine),\n\
4321+
or via the attributes sysname, nodename, release, version, and machine.\n\
4322+
\n\
4323+
See os.uname for more information.");
4324+
4325+
static PyStructSequence_Desc uname_result_desc = {
4326+
"uname_result", /* name */
4327+
uname_result__doc__, /* doc */
4328+
uname_result_fields,
4329+
5
4330+
};
43064331

4332+
static PyTypeObject UnameResultType;
4333+
4334+
4335+
#ifdef HAVE_UNAME
43074336
static PyObject *
43084337
posix_uname(PyObject *self, PyObject *noargs)
43094338
{
43104339
struct utsname u;
43114340
int res;
4341+
PyObject *value;
43124342

43134343
Py_BEGIN_ALLOW_THREADS
43144344
res = uname(&u);
43154345
Py_END_ALLOW_THREADS
43164346
if (res < 0)
43174347
return posix_error();
4318-
return Py_BuildValue("(sssss)",
4319-
u.sysname,
4320-
u.nodename,
4321-
u.release,
4322-
u.version,
4323-
u.machine);
4348+
4349+
value = PyStructSequence_New(&UnameResultType);
4350+
if (value == NULL)
4351+
return NULL;
4352+
4353+
#define SET(i, field) \
4354+
{ \
4355+
PyObject *o = PyUnicode_DecodeASCII(field, strlen(field), NULL); \
4356+
if (!o) { \
4357+
Py_DECREF(value); \
4358+
return NULL; \
4359+
} \
4360+
PyStructSequence_SET_ITEM(value, i, o); \
4361+
} \
4362+
4363+
SET(0, u.sysname);
4364+
SET(1, u.nodename);
4365+
SET(2, u.release);
4366+
SET(3, u.version);
4367+
SET(4, u.machine);
4368+
4369+
#undef SET
4370+
4371+
return value;
43244372
}
43254373
#endif /* HAVE_UNAME */
43264374

@@ -7366,6 +7414,75 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
73667414
#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
73677415

73687416

7417+
static PyStructSequence_Field times_result_fields[] = {
7418+
{"user", "user time"},
7419+
{"system", "system time"},
7420+
{"children_user", "user time of children"},
7421+
{"children_system", "system time of children"},
7422+
{"elapsed", "elapsed time since an arbitrary point in the past"},
7423+
{NULL}
7424+
};
7425+
7426+
PyDoc_STRVAR(times_result__doc__,
7427+
"times_result: Result from os.times().\n\n\
7428+
This object may be accessed either as a tuple of\n\
7429+
(user, system, children_user, children_system, elapsed),\n\
7430+
or via the attributes user, system, children_user, children_system,\n\
7431+
and elapsed.\n\
7432+
\n\
7433+
See os.times for more information.");
7434+
7435+
static PyStructSequence_Desc times_result_desc = {
7436+
"times_result", /* name */
7437+
times_result__doc__, /* doc */
7438+
times_result_fields,
7439+
5
7440+
};
7441+
7442+
static PyTypeObject TimesResultType;
7443+
7444+
7445+
#if defined(HAVE_TIMES) || defined(MS_WINDOWS)
7446+
7447+
static PyObject *
7448+
build_times_result(double user, double system,
7449+
double children_user, double children_system,
7450+
double elapsed)
7451+
{
7452+
PyObject *value = PyStructSequence_New(&TimesResultType);
7453+
if (value == NULL)
7454+
return NULL;
7455+
7456+
#define SET(i, field) \
7457+
{ \
7458+
PyObject *o = PyFloat_FromDouble(field); \
7459+
if (!o) { \
7460+
Py_DECREF(value); \
7461+
return NULL; \
7462+
} \
7463+
PyStructSequence_SET_ITEM(value, i, o); \
7464+
} \
7465+
7466+
SET(0, user);
7467+
SET(1, system);
7468+
SET(2, children_user);
7469+
SET(3, children_system);
7470+
SET(4, elapsed);
7471+
7472+
#undef SET
7473+
7474+
return value;
7475+
}
7476+
7477+
PyDoc_STRVAR(posix_times__doc__,
7478+
"times() -> times_result\n\n\
7479+
Return an object containing floating point numbers indicating process\n\
7480+
times. The object behaves like a named tuple with these fields:\n\
7481+
(utime, stime, cutime, cstime, elapsed_time)");
7482+
7483+
#endif
7484+
7485+
73697486
#ifdef HAVE_TIMES
73707487
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
73717488
static long
@@ -7384,7 +7501,7 @@ static PyObject *
73847501
posix_times(PyObject *self, PyObject *noargs)
73857502
{
73867503
/* Currently Only Uptime is Provided -- Others Later */
7387-
return Py_BuildValue("ddddd",
7504+
return build_times_result(
73887505
(double)0 /* t.tms_utime / HZ */,
73897506
(double)0 /* t.tms_stime / HZ */,
73907507
(double)0 /* t.tms_cutime / HZ */,
@@ -7403,19 +7520,15 @@ posix_times(PyObject *self, PyObject *noargs)
74037520
c = times(&t);
74047521
if (c == (clock_t) -1)
74057522
return posix_error();
7406-
return Py_BuildValue("ddddd",
7523+
return build_times_result(
74077524
(double)t.tms_utime / ticks_per_second,
74087525
(double)t.tms_stime / ticks_per_second,
74097526
(double)t.tms_cutime / ticks_per_second,
74107527
(double)t.tms_cstime / ticks_per_second,
74117528
(double)c / ticks_per_second);
74127529
}
74137530
#endif /* not OS2 */
7414-
#endif /* HAVE_TIMES */
7415-
7416-
7417-
#ifdef MS_WINDOWS
7418-
#define HAVE_TIMES /* so the method table will pick it up */
7531+
#elif defined(MS_WINDOWS)
74197532
static PyObject *
74207533
posix_times(PyObject *self, PyObject *noargs)
74217534
{
@@ -7428,8 +7541,7 @@ posix_times(PyObject *self, PyObject *noargs)
74287541
1e7 is one second in such units; 1e-7 the inverse.
74297542
429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
74307543
*/
7431-
return Py_BuildValue(
7432-
"ddddd",
7544+
return build_times_result(
74337545
(double)(user.dwHighDateTime*429.4967296 +
74347546
user.dwLowDateTime*1e-7),
74357547
(double)(kernel.dwHighDateTime*429.4967296 +
@@ -7438,12 +7550,6 @@ posix_times(PyObject *self, PyObject *noargs)
74387550
(double)0,
74397551
(double)0);
74407552
}
7441-
#endif /* MS_WINDOWS */
7442-
7443-
#ifdef HAVE_TIMES
7444-
PyDoc_STRVAR(posix_times__doc__,
7445-
"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n\
7446-
Return a tuple of floating point numbers indicating process times.");
74477553
#endif
74487554

74497555

@@ -11965,6 +12071,14 @@ INITFUNC(void)
1196512071
PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
1196612072
#endif
1196712073

12074+
times_result_desc.name = MODNAME ".times_result";
12075+
PyStructSequence_InitType(&TimesResultType, &times_result_desc);
12076+
PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType);
12077+
12078+
uname_result_desc.name = MODNAME ".uname_result";
12079+
PyStructSequence_InitType(&UnameResultType, &uname_result_desc);
12080+
PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType);
12081+
1196812082
#ifdef __APPLE__
1196912083
/*
1197012084
* Step 2 of weak-linking support on Mac OS X.

0 commit comments

Comments
 (0)