diff --git a/edgedb/protocol/codecs/base.pyx b/edgedb/protocol/codecs/base.pyx index 0fda61b5..8b3d4349 100644 --- a/edgedb/protocol/codecs/base.pyx +++ b/edgedb/protocol/codecs/base.pyx @@ -271,10 +271,20 @@ cdef class BaseNamedRecordCodec(BaseRecordCodec): for i in range(objlen): if is_dict: name = datatypes.record_desc_pointer_name(self.descriptor, i) - item = obj[name] + try: + item = obj[name] + except KeyError: + raise ValueError( + f"named tuple dict is missing '{name}' key", + ) from None elif is_namedtuple: name = datatypes.record_desc_pointer_name(self.descriptor, i) - item = getattr(obj, name) + try: + item = getattr(obj, name) + except AttributeError: + raise ValueError( + f"named tuple is missing '{name}' attribute", + ) from None else: item = obj[i] diff --git a/tests/test_namedtuples.py b/tests/test_namedtuples.py index fc59f5d3..04a74ddc 100644 --- a/tests/test_namedtuples.py +++ b/tests/test_namedtuples.py @@ -19,6 +19,7 @@ from collections import namedtuple, UserDict +import edgedb from edgedb import _testbase as tb @@ -36,3 +37,16 @@ async def test_namedtuple_01(self): ''', val) self.assertEqual(res, (10, 'y')) + + async def test_namedtuple_02(self): + NT1 = namedtuple('NT2', ['x', 'z']) + + with self.assertRaisesRegex(edgedb.InvalidArgumentError, 'is missing'): + self.client.query_single(''' + select >$0 + ''', dict(x=20, z='test')) + + with self.assertRaisesRegex(edgedb.InvalidArgumentError, 'is missing'): + self.client.query_single(''' + select >$0 + ''', NT1(x=20, z='test'))