From 7d34c968fd35264c467adfd99ac276bc51250ec2 Mon Sep 17 00:00:00 2001 From: igorcoding Date: Tue, 18 Dec 2018 23:34:28 +0300 Subject: [PATCH] Added get() method for TarantoolTuple --- asynctnt/__init__.py | 2 +- asynctnt/iproto/tupleobj/tupleobj.c | 142 ++++++++++++++++++---------- tests/test_response.py | 18 ++++ 3 files changed, 110 insertions(+), 52 deletions(-) diff --git a/asynctnt/__init__.py b/asynctnt/__init__.py index 8aef895..cc28dfa 100644 --- a/asynctnt/__init__.py +++ b/asynctnt/__init__.py @@ -3,4 +3,4 @@ Iterator, Response, TarantoolTuple, PushIterator ) -__version__ = '1.0b1' +__version__ = '1.0b2' diff --git a/asynctnt/iproto/tupleobj/tupleobj.c b/asynctnt/iproto/tupleobj/tupleobj.c index 4375a47..988c834 100644 --- a/asynctnt/iproto/tupleobj/tupleobj.c +++ b/asynctnt/iproto/tupleobj/tupleobj.c @@ -258,6 +258,52 @@ ttuple_item(AtntTupleObject *o, Py_ssize_t i) } +static int +ttuple_item_by_name(AtntTupleObject *o, PyObject *item, PyObject **result) +{ + if (o->fields == NULL) { + goto noitem; + } + + PyObject *mapped; + Py_ssize_t i; + PyObject *value; + + mapped = PyObject_GetItem(o->fields->_mapping, item); + if (mapped == NULL) { + goto noitem; + } + + if (!PyIndex_Check(mapped)) { + Py_DECREF(mapped); + goto noitem; + } + + i = PyNumber_AsSsize_t(mapped, PyExc_IndexError); + Py_DECREF(mapped); + + if (i < 0) { + if (PyErr_Occurred()) { + PyErr_Clear(); + } + goto noitem; + } + + value = ttuple_item(o, i); + if (result == NULL) { + PyErr_Clear(); + goto noitem; + } + + *result = value; + return 0; + +noitem: + PyErr_SetObject(PyExc_KeyError, item); + return -1; +} + + static PyObject * ttuple_subscript(AtntTupleObject* o, PyObject* item) { @@ -287,58 +333,29 @@ ttuple_subscript(AtntTupleObject* o, PyObject* item) if (slicelength <= 0) { return PyTuple_New(0); } - else { - result = PyTuple_New(slicelength); - if (!result) return NULL; - - src = o->ob_item; - dest = ((PyTupleObject *)result)->ob_item; - for (cur = start, i = 0; i < slicelength; cur += step, i++) { - it = src[cur]; - Py_INCREF(it); - dest[i] = it; - } - - return result; - } - } - else if (o->fields != NULL) { - PyObject *mapped; - mapped = PyObject_GetItem(o->fields->_mapping, item); - if (mapped != NULL) { - Py_ssize_t i; - PyObject *result; - - if (!PyIndex_Check(mapped)) { - Py_DECREF(mapped); - goto noitem; - } - i = PyNumber_AsSsize_t(mapped, PyExc_IndexError); - Py_DECREF(mapped); + result = PyTuple_New(slicelength); + if (!result) return NULL; - if (i < 0) { - if (PyErr_Occurred()) { - PyErr_Clear(); - } - goto noitem; - } - - result = ttuple_item(o, i); - if (result == NULL) { - PyErr_Clear(); - goto noitem; - } - return result; - } - else { - goto noitem; + src = o->ob_item; + dest = ((PyTupleObject *)result)->ob_item; + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + it = src[cur]; + Py_INCREF(it); + dest[i] = it; } + + return result; } + else { + /* map by name */ + PyObject *result = NULL; + if (ttuple_item_by_name(o, item, &result) < 0) { + return NULL; + } -noitem: - _PyErr_SetKeyError(item); - return NULL; + return result; + } } @@ -511,6 +528,28 @@ ttuple_contains(AtntTupleObject *o, PyObject *arg) } +static PyObject * +ttuple_get(AtntTupleObject* o, PyObject* args) +{ + PyObject *key; + PyObject *defval = Py_None; + PyObject *val = NULL; + int res; + + if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &defval)) + return NULL; + + res = ttuple_item_by_name(o, key, &val); + if (res < 0) { + PyErr_Clear(); + Py_INCREF(defval); + val = defval; + } + + return val; +} + + static PySequenceMethods ttuple_as_sequence = { (lenfunc)ttuple_length, /* sq_length */ 0, /* sq_concat */ @@ -531,10 +570,11 @@ static PyMappingMethods ttuple_as_mapping = { static PyMethodDef ttuple_methods[] = { - {"values", (PyCFunction)ttuple_values, METH_NOARGS}, - {"keys", (PyCFunction)ttuple_keys, METH_NOARGS}, - {"items", (PyCFunction)ttuple_items, METH_NOARGS}, - {NULL, NULL} /* sentinel */ + {"values", (PyCFunction) ttuple_values, METH_NOARGS}, + {"keys", (PyCFunction) ttuple_keys, METH_NOARGS}, + {"items", (PyCFunction) ttuple_items, METH_NOARGS}, + {"get", (PyCFunction) ttuple_get, METH_VARARGS}, + {NULL, NULL} /* sentinel */ }; diff --git a/tests/test_response.py b/tests/test_response.py index 2036d32..2138120 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -129,6 +129,24 @@ async def test__response_tuple_contains(self): self.assertTrue('f5' in res) self.assertFalse('f6' in res) + async def test__response_tuple_key_error(self): + data = [0, 'hello', 5, 6, 'help', 'common', 'yo'] + res = await self.conn.insert(self.TESTER_SPACE_ID, data) + res = res[0] + + with self.assertRaises(KeyError): + _ = res['f100'] + + async def test__response_tuple_get(self): + data = [0, 'hello', 5, 6, 'help', 'common', 'yo'] + res = await self.conn.insert(self.TESTER_SPACE_ID, data) + res = res[0] + + self.assertEqual(res.get('f1'), 0) + self.assertEqual(res.get('f2'), 'hello') + self.assertEqual(res.get('f100'), None) + self.assertEqual(res.get('f100', 'zz'), 'zz') + async def test__response_with_no_space_format(self): res = await self.conn.insert('no_schema_space', [0, 'one'])