]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed 0.9 regression where the new sortable support for :class:`.RowProxy`
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 29 Jan 2014 04:43:14 +0000 (23:43 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 29 Jan 2014 04:43:14 +0000 (23:43 -0500)
would lead to ``TypeError`` when compared to non-tuple types as it attempted
to apply tuple() to the "other" object unconditionally.  The
full range of Python comparison operators have now been implemented on
:class:`.RowProxy`, using an approach that guarantees a comparison
system that is equivalent to that of a tuple, and the "other" object
is only coerced if it's an instance of RowProxy. [ticket:2924]

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/engine/result.py
test/sql/test_query.py

index d0cf14f6e18f62ad1e46b7a23e176a4935ae99c5..b6bc07847ef5076917c461da29039f210c05a726 100644 (file)
 .. changelog::
     :version: 0.9.2
 
+    .. change::
+        :tags: bug, sql
+        :tickets: 2924, 2848
+
+        Fixed 0.9 regression where the new sortable support for :class:`.RowProxy`
+        would lead to ``TypeError`` when compared to non-tuple types as it attempted
+        to apply tuple() to the "other" object unconditionally.  The
+        full range of Python comparison operators have now been implemented on
+        :class:`.RowProxy`, using an approach that guarantees a comparison
+        system that is equivalent to that of a tuple, and the "other" object
+        is only coerced if it's an instance of RowProxy.
+
     .. change::
         :tags: bug, orm
         :tickets: 2918
index f9e0ca0d293fdb77ab2b46cca51f1496470a8414..6c98dae18631e69122aeaf41edcf042dd7fe723f 100644 (file)
@@ -12,6 +12,7 @@ and :class:`.RowProxy."""
 from .. import exc, util
 from ..sql import expression, sqltypes
 import collections
+import operator
 
 # This reconstructor is necessary so that pickles with the C extension or
 # without use the same Binary format.
@@ -125,14 +126,28 @@ class RowProxy(BaseRowProxy):
 
     __hash__ = None
 
+    def _op(self, other, op):
+        return op(tuple(self), tuple(other)) \
+            if isinstance(other, RowProxy) \
+            else op(tuple(self), other)
+
     def __lt__(self, other):
-        return tuple(self) < tuple(other)
+        return self._op(other, operator.lt)
+
+    def __le__(self, other):
+        return self._op(other, operator.le)
+
+    def __ge__(self, other):
+        return self._op(other, operator.ge)
+
+    def __gt__(self, other):
+        return self._op(other, operator.gt)
 
     def __eq__(self, other):
-        return other is self or tuple(other) == tuple(self)
+        return self._op(other, operator.eq)
 
     def __ne__(self, other):
-        return not self.__eq__(other)
+        return self._op(other, operator.ne)
 
     def __repr__(self):
         return repr(tuple(self))
index 40c63b1793fa6e46b9dcb71e6b8492b50a23e1a2..8cbd01c6615f0f9b48ee237841a3da06b2332b8c 100644 (file)
@@ -304,7 +304,7 @@ class QueryTest(fixtures.TestBase):
 
 
     def test_row_comparison(self):
-        users.insert().execute(user_id = 7, user_name = 'jack')
+        users.insert().execute(user_id = 7, user_name='jack')
         rp = users.select().execute().first()
 
         self.assert_(rp == rp)
@@ -317,6 +317,30 @@ class QueryTest(fixtures.TestBase):
         self.assert_(not (rp != equal))
         self.assert_(not (equal != equal))
 
+        def endless():
+            while True:
+                yield 1
+        self.assert_(rp != endless())
+        self.assert_(endless() != rp)
+
+        # test that everything compares the same
+        # as it would against a tuple
+        import operator
+        for compare in [False, 8, endless(), 'xyz', (7, 'jack')]:
+            for op in [
+                operator.eq, operator.ne, operator.gt,
+                operator.lt, operator.ge, operator.le
+            ]:
+                eq_(
+                    op(equal, compare),
+                    op(rp, compare)
+                )
+                eq_(
+                    op(compare, equal),
+                    op(compare, rp)
+                )
+
+
     @testing.provide_metadata
     def test_column_label_overlap_fallback(self):
         content = Table('content', self.metadata,