Skip to content

Commit 39b390c

Browse files
committed
Fix Record.items() to support duplicate keys. See #28 for details.
1 parent 7aac14e commit 39b390c

File tree

2 files changed

+13
-12
lines changed

2 files changed

+13
-12
lines changed

asyncpg/protocol/record/recordobj.c

+12-12
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ record_iter(PyObject *seq)
688688
typedef struct {
689689
PyObject_HEAD
690690
Py_ssize_t it_index;
691-
PyObject *it_map_iter;
691+
PyObject *it_key_iter;
692692
ApgRecordObject *it_seq; /* Set to NULL when iterator is exhausted */
693693
} ApgRecordItemsObject;
694694

@@ -697,7 +697,7 @@ static void
697697
record_items_dealloc(ApgRecordItemsObject *it)
698698
{
699699
PyObject_GC_UnTrack(it);
700-
Py_CLEAR(it->it_map_iter);
700+
Py_CLEAR(it->it_key_iter);
701701
Py_CLEAR(it->it_seq);
702702
PyObject_GC_Del(it);
703703
}
@@ -706,7 +706,7 @@ record_items_dealloc(ApgRecordItemsObject *it)
706706
static int
707707
record_items_traverse(ApgRecordItemsObject *it, visitproc visit, void *arg)
708708
{
709-
Py_VISIT(it->it_map_iter);
709+
Py_VISIT(it->it_key_iter);
710710
Py_VISIT(it->it_seq);
711711
return 0;
712712
}
@@ -726,11 +726,11 @@ record_items_next(ApgRecordItemsObject *it)
726726
return NULL;
727727
}
728728
assert(ApgRecord_CheckExact(seq));
729-
assert(it->it_map_iter != NULL);
729+
assert(it->it_key_iter != NULL);
730730

731-
key = PyIter_Next(it->it_map_iter);
731+
key = PyIter_Next(it->it_key_iter);
732732
if (key == NULL) {
733-
/* likely it_map_iter had less items than seq has values */
733+
/* likely it_key_iter had less items than seq has values */
734734
goto exhausted;
735735
}
736736

@@ -740,7 +740,7 @@ record_items_next(ApgRecordItemsObject *it)
740740
Py_INCREF(val);
741741
}
742742
else {
743-
/* it_map_iter had more items than seq has values */
743+
/* it_key_iter had more items than seq has values */
744744
Py_DECREF(key);
745745
goto exhausted;
746746
}
@@ -757,7 +757,7 @@ record_items_next(ApgRecordItemsObject *it)
757757
return tup;
758758

759759
exhausted:
760-
Py_CLEAR(it->it_map_iter);
760+
Py_CLEAR(it->it_key_iter);
761761
Py_CLEAR(it->it_seq);
762762
return NULL;
763763
}
@@ -823,23 +823,23 @@ static PyObject *
823823
record_new_items_iter(PyObject *seq)
824824
{
825825
ApgRecordItemsObject *it;
826-
PyObject *map_iter;
826+
PyObject *key_iter;
827827

828828
if (!ApgRecord_CheckExact(seq)) {
829829
PyErr_BadInternalCall();
830830
return NULL;
831831
}
832832

833-
map_iter = PyObject_GetIter(((ApgRecordObject*)seq)->desc->mapping);
834-
if (map_iter == NULL) {
833+
key_iter = PyObject_GetIter(((ApgRecordObject*)seq)->desc->keys);
834+
if (key_iter == NULL) {
835835
return NULL;
836836
}
837837

838838
it = PyObject_GC_New(ApgRecordItemsObject, &ApgRecordItems_Type);
839839
if (it == NULL)
840840
return NULL;
841841

842-
it->it_map_iter = map_iter;
842+
it->it_key_iter = key_iter;
843843
it->it_index = 0;
844844
Py_INCREF(seq);
845845
it->it_seq = (ApgRecordObject *)seq;

tests/test_record.py

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ async def test_record_duplicate_colnames(self):
298298
self.assertEqual(r['a'], 2)
299299
self.assertEqual(r[0], 1)
300300
self.assertEqual(repr(r), '<Record a=1 a=2>')
301+
self.assertEqual(list(r.items()), [('a', 1), ('a', 2)])
301302

302303
async def test_record_isinstance(self):
303304
"""Test that Record works with isinstance."""

0 commit comments

Comments
 (0)