summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-11-09 11:40:23 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-11-09 11:40:23 -0500
commita41c50ad63f688cce99fdb9920c4f7c24ef0c866 (patch)
treed811319676606ce89642bf316499e101c785b974
parent30bc42403754110df1fdec3037c7700cc4f26b70 (diff)
downloadsqlalchemy-a41c50ad63f688cce99fdb9920c4f7c24ef0c866.tar.gz
- Implemented sequence check capability for the C
version of RowProxy, as well as 2.7 style "collections.Sequence" registration for RowProxy. [ticket:1871]
-rw-r--r--CHANGES6
-rw-r--r--lib/sqlalchemy/cextension/resultproxy.c8
-rw-r--r--lib/sqlalchemy/engine/base.py8
-rw-r--r--lib/sqlalchemy/test/requires.py15
-rw-r--r--test/aaa_profiling/test_resultset.py4
-rw-r--r--test/engine/test_execute.py31
6 files changed, 68 insertions, 4 deletions
diff --git a/CHANGES b/CHANGES
index 65715de54..1b4f7cd34 100644
--- a/CHANGES
+++ b/CHANGES
@@ -19,6 +19,12 @@ CHANGES
is an outer join, thus allowing primary rows without
a referenced child row to be correctly returned
in results. [ticket:1954]
+
+- engine
+ - Implemented sequence check capability for the C
+ version of RowProxy, as well as 2.7 style
+ "collections.Sequence" registration for RowProxy.
+ [ticket:1871]
- mysql
- Fixed error handling for Jython + zxjdbc, such that
diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c
index 7404b9ed2..73e127345 100644
--- a/lib/sqlalchemy/cextension/resultproxy.c
+++ b/lib/sqlalchemy/cextension/resultproxy.c
@@ -327,6 +327,12 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
}
static PyObject *
+BaseRowProxy_getitem(PyObject *self, Py_ssize_t i)
+{
+ return BaseRowProxy_subscript((BaseRowProxy*)self, PyInt_FromSsize_t(i));
+}
+
+static PyObject *
BaseRowProxy_getattro(BaseRowProxy *self, PyObject *name)
{
PyObject *tmp;
@@ -506,7 +512,7 @@ static PySequenceMethods BaseRowProxy_as_sequence = {
(lenfunc)BaseRowProxy_length, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
- 0, /* sq_item */
+ (ssizeargfunc)BaseRowProxy_getitem, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index ef402ceea..10b2b6782 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -2090,6 +2090,14 @@ class RowProxy(BaseRowProxy):
def itervalues(self):
return iter(self)
+try:
+ # Register RowProxy with Sequence,
+ # so sequence protocol is implemented
+ import collections
+ collections.Sequence.register(RowProxy)
+except ImportError:
+ pass
+
class ResultMetaData(object):
"""Handle cursor.description, applying additional info from an execution
diff --git a/lib/sqlalchemy/test/requires.py b/lib/sqlalchemy/test/requires.py
index 14c548f12..5b68a18e1 100644
--- a/lib/sqlalchemy/test/requires.py
+++ b/lib/sqlalchemy/test/requires.py
@@ -252,6 +252,12 @@ def sane_rowcount(fn):
skip_if(lambda: not testing.db.dialect.supports_sane_rowcount)
)
+def cextensions(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(lambda: not _has_cextensions(), "C extensions not installed")
+ )
+
def dbapi_lastrowid(fn):
return _chain_decorators_on(
fn,
@@ -279,7 +285,14 @@ def python2(fn):
"Python version 2.xx is required."
)
)
-
+
+def _has_cextensions():
+ try:
+ from sqlalchemy import cresultproxy, cprocessors
+ return True
+ except ImportError:
+ return False
+
def _has_sqlite():
from sqlalchemy import create_engine
try:
diff --git a/test/aaa_profiling/test_resultset.py b/test/aaa_profiling/test_resultset.py
index d71b8dab8..bd9d3ae50 100644
--- a/test/aaa_profiling/test_resultset.py
+++ b/test/aaa_profiling/test_resultset.py
@@ -30,13 +30,13 @@ class ResultSetTest(TestBase, AssertsExecutionResults):
metadata.drop_all()
@profiling.function_call_count(14416, versions={'2.4': 13214,
- '2.6+cextension': 409})
+ '2.6+cextension': 409, '2.7+cextension':438})
def test_string(self):
[tuple(row) for row in t.select().execute().fetchall()]
# sqlite3 returns native unicode. so shouldn't be an increase here.
@profiling.function_call_count(14396, versions={'2.4': 13214,
- '2.6+cextension': 409})
+ '2.6+cextension': 409, '2.7+cextension':409})
def test_unicode(self):
[tuple(row) for row in t2.select().execute().fetchall()]
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index ee5953c74..bbec402b2 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -289,6 +289,37 @@ class ResultProxyTest(TestBase):
assert_raises(AssertionError, t.delete().execute)
finally:
engine.dialect.execution_ctx_cls = execution_ctx_cls
+
+ def test_rowproxy_is_sequence(self):
+ import collections
+ from sqlalchemy.engine import RowProxy
+
+ row = RowProxy(object(), ['value'], [None], {'key'
+ : (None, 0), 0: (None, 0)})
+ assert isinstance(row, collections.Sequence)
+
+ @testing.requires.cextensions
+ def test_row_c_sequence_check(self):
+ import csv
+ import collections
+ from StringIO import StringIO
+
+ metadata = MetaData()
+ metadata.bind = 'sqlite://'
+ users = Table('users', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('name', String(40)),
+ )
+ users.create()
+
+ users.insert().execute(name='Test')
+ row = users.select().execute().fetchone()
+
+ s = StringIO()
+ writer = csv.writer(s)
+ # csv performs PySequenceCheck call
+ writer.writerow(row)
+ assert s.getvalue().strip() == '1,Test'
class ProxyConnectionTest(TestBase):