diff options
author | Pablo Galindo <Pablogsal@gmail.com> | 2021-03-04 00:03:44 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-04 00:03:44 (GMT) |
commit | 0632b1012d4dfa81ffef0d686a4710f6134f77a8 (patch) | |
tree | b1387749144a2ba1582fbb9023fdc4ddbdb6c3aa | |
parent | 9c7927400cd8f1d283bf7915b6b33fea81b8655d (diff) | |
download | cpython-0632b1012d4dfa81ffef0d686a4710f6134f77a8.zip cpython-0632b1012d4dfa81ffef0d686a4710f6134f77a8.tar.gz cpython-0632b1012d4dfa81ffef0d686a4710f6134f77a8.tar.bz2 |
bpo-42128: Add __match_args__ to structseq-based classes (GH-24732)
-rw-r--r-- | Lib/test/test_structseq.py | 12 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-03-03-19-04-23.bpo-42128.VouZjn.rst | 2 | ||||
-rw-r--r-- | Objects/structseq.c | 34 |
3 files changed, 48 insertions, 0 deletions
diff --git a/Lib/test/test_structseq.py b/Lib/test/test_structseq.py index 36630a1..a9fe193 100644 --- a/Lib/test/test_structseq.py +++ b/Lib/test/test_structseq.py @@ -122,5 +122,17 @@ class StructSeqTest(unittest.TestCase): self.assertEqual(list(t[start:stop:step]), L[start:stop:step]) + def test_match_args(self): + expected_args = ('tm_year', 'tm_mon', 'tm_mday', 'tm_hour', 'tm_min', + 'tm_sec', 'tm_wday', 'tm_yday', 'tm_isdst') + self.assertEqual(time.struct_time.__match_args__, expected_args) + + def test_match_args_with_unnamed_fields(self): + expected_args = ('st_mode', 'st_ino', 'st_dev', 'st_nlink', 'st_uid', + 'st_gid', 'st_size') + self.assertEqual(os.stat_result.n_unnamed_fields, 3) + self.assertEqual(os.stat_result.__match_args__, expected_args) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-03-03-19-04-23.bpo-42128.VouZjn.rst b/Misc/NEWS.d/next/Core and Builtins/2021-03-03-19-04-23.bpo-42128.VouZjn.rst new file mode 100644 index 0000000..7c4733a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-03-03-19-04-23.bpo-42128.VouZjn.rst @@ -0,0 +1,2 @@ +Add ``__match_args__`` to :c:type:`structsequence` based classes. Patch by +Pablo Galindo. diff --git a/Objects/structseq.c b/Objects/structseq.c index 4222afa..8a92bdb 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -15,6 +15,7 @@ static const char visible_length_key[] = "n_sequence_fields"; static const char real_length_key[] = "n_fields"; static const char unnamed_fields_key[] = "n_unnamed_fields"; +static const char match_args_key[] = "__match_args__"; /* Fields with this name have only a field index, not a field name. They are only allowed for indices < n_visible_fields. */ @@ -399,7 +400,40 @@ initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict, SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence); SET_DICT_FROM_SIZE(real_length_key, n_members); SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members); + + // Prepare and set __match_args__ + Py_ssize_t i, k; + PyObject* keys = PyTuple_New(desc->n_in_sequence); + if (keys == NULL) { + return -1; + } + + for (i = k = 0; i < desc->n_in_sequence; ++i) { + if (desc->fields[i].name == PyStructSequence_UnnamedField) { + continue; + } + PyObject* new_member = PyUnicode_FromString(desc->fields[i].name); + if (new_member == NULL) { + goto error; + } + PyTuple_SET_ITEM(keys, k, new_member); + k++; + } + + if (_PyTuple_Resize(&keys, k) == -1) { + goto error; + } + + if (PyDict_SetItemString(dict, match_args_key, keys) < 0) { + goto error; + } + + Py_DECREF(keys); return 0; + +error: + Py_DECREF(keys); + return -1; } static void |