diff -r 754fcc099834 Lib/test/test_structseq.py --- a/Lib/test/test_structseq.py Mon May 26 00:14:14 2014 -0700 +++ b/Lib/test/test_structseq.py Mon May 26 15:28:41 2014 +0530 @@ -81,6 +81,10 @@ self.assertEqual(len(t), t.n_sequence_fields) self.assertEqual(t.n_unnamed_fields, 0) self.assertEqual(t.n_fields, time._STRUCT_TM_ITEMS) + # Issue 1820: Match namedtuple API + _fields = ('tm_year', 'tm_mon', 'tm_mday', 'tm_hour', 'tm_min', + 'tm_sec', 'tm_wday', 'tm_yday', 'tm_isdst') + self.assertEqual(t._fields, _fields) def test_constructor(self): t = time.struct_time diff -r 754fcc099834 Objects/structseq.c --- a/Objects/structseq.c Mon May 26 00:14:14 2014 -0700 +++ b/Objects/structseq.c Mon May 26 15:28:41 2014 +0530 @@ -7,6 +7,7 @@ static char visible_length_key[] = "n_sequence_fields"; static char real_length_key[] = "n_fields"; static char unnamed_fields_key[] = "n_unnamed_fields"; +static char _fields_key[] = "_fields"; /* Fields with this name have only a field index, not a field name. They are only allowed for indices < n_visible_fields. */ @@ -14,6 +15,7 @@ _Py_IDENTIFIER(n_sequence_fields); _Py_IDENTIFIER(n_fields); _Py_IDENTIFIER(n_unnamed_fields); +_Py_IDENTIFIER(_fields); #define VISIBLE_SIZE(op) Py_SIZE(op) #define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \ @@ -326,7 +328,7 @@ PyObject *dict; PyMemberDef* members; int n_members, n_unnamed_members, i, k; - PyObject *v; + PyObject *v, *_fields; #ifdef Py_TRACE_REFS /* if the type object was chained, unchain it first @@ -347,6 +349,13 @@ type->tp_name = desc->name; type->tp_doc = desc->doc; + /* _fields only has the visible named keys*/ + _fields = PyTuple_New(desc->n_in_sequence - n_unnamed_members); + if (_fields == NULL) { + PyErr_NoMemory(); + return -1; + } + members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); if (members == NULL) { PyErr_NoMemory(); @@ -357,6 +366,12 @@ if (desc->fields[i].name == PyStructSequence_UnnamedField) continue; members[k].name = desc->fields[i].name; + if (i < desc->n_in_sequence) { + PyObject *field_name; + field_name = PyUnicode_FromString(members[k].name); + Py_INCREF(field_name); + PyTuple_SET_ITEM(_fields, k, field_name); + } members[k].type = T_OBJECT; members[k].offset = offsetof(PyStructSequence, ob_item) + i * sizeof(PyObject*); @@ -388,6 +403,11 @@ SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence); SET_DICT_FROM_INT(real_length_key, n_members); SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members); + if (PyDict_SetItemString(dict, _fields_key, _fields) < 0) { + Py_DECREF(_fields); + return -1; + } + Py_DECREF(_fields); return 0; } @@ -417,7 +437,8 @@ { if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL || _PyUnicode_FromId(&PyId_n_fields) == NULL - || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL) + || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL + || _PyUnicode_FromId(&PyId__fields) == NULL) return -1; return 0;