summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLele Gaifax <lele@metapensiero.it>2016-01-28 09:04:40 +0100
committerLele Gaifax <lele@metapensiero.it>2016-01-28 09:04:40 +0100
commitf84ef1f83cc64a5ea3a910b8d1bdf00b05e9ceab (patch)
tree88ea72eea39fd076dc730a304a9ec9823dfb6aa3
parent086ad9ce6413e73f93506523d4eb8e23710443dc (diff)
downloadsqlalchemy-f84ef1f83cc64a5ea3a910b8d1bdf00b05e9ceab.tar.gz
- properly handle negative indexes in RowProxy.__getitem__()pr/231
-rw-r--r--lib/sqlalchemy/cextension/resultproxy.c4
-rw-r--r--lib/sqlalchemy/engine/result.py9
-rw-r--r--test/engine/test_execute.py19
3 files changed, 31 insertions, 1 deletions
diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c
index a87fe7b56..331fae2b2 100644
--- a/lib/sqlalchemy/cextension/resultproxy.c
+++ b/lib/sqlalchemy/cextension/resultproxy.c
@@ -263,6 +263,8 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
#if PY_MAJOR_VERSION < 3
if (PyInt_CheckExact(key)) {
index = PyInt_AS_LONG(key);
+ if (index < 0)
+ index += BaseRowProxy_length(self);
} else
#endif
@@ -271,6 +273,8 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
if ((index == -1) && PyErr_Occurred())
/* -1 can be either the actual value, or an error flag. */
return NULL;
+ if (index < 0)
+ index += BaseRowProxy_length(self);
} else if (PySlice_Check(key)) {
values = PyObject_GetItem(self->row, key);
if (values == NULL)
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 39f4fc50c..9208686e1 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -215,10 +215,17 @@ class ResultMetaData(object):
self._keymap = {}
if not _baserowproxy_usecext:
- # keymap indexes by integer index...
+ # keymap indexes by integer index: this is only used
+ # in the pure Python BaseRowProxy.__getitem__
+ # implementation to avoid an expensive
+ # isinstance(key, util.int_types) in the most common
+ # case path
self._keymap.update([
(elem[0], (elem[3], elem[4], elem[0]))
for elem in raw
+ ] + [
+ (elem[0] - num_ctx_cols, (elem[3], elem[4], elem[0]))
+ for elem in raw
])
# processors in key order for certain per-row
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index 5ea5d3515..aadd170f3 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -951,6 +951,25 @@ class ResultProxyTest(fixtures.TestBase):
{'key': (None, None, 0), 0: (None, None, 0)})
assert isinstance(row, collections.Sequence)
+ def test_rowproxy_getitem(self):
+ metadata = MetaData()
+ metadata.bind = 'sqlite://'
+ values = Table('users', metadata,
+ Column('key', String(10), primary_key=True),
+ Column('value', String(10)))
+ values.create()
+
+ values.insert().execute(key='One', value='Uno')
+ row = values.select().execute().fetchone()
+
+ assert row['key'] == 'One'
+ assert row['value'] == 'Uno'
+ assert row[0] == 'One'
+ assert row[1] == 'Uno'
+ assert row[-2] == 'One'
+ assert row[-1] == 'Uno'
+ assert row[1:0:-1] == ('Uno',)
+
@testing.requires.cextensions
def test_row_c_sequence_check(self):
import csv