]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- BinaryExpression now keeps track of "left" and "right" as passed in,
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Dec 2012 17:37:52 +0000 (12:37 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Dec 2012 17:37:52 +0000 (12:37 -0500)
so that they can be compared in ``__nonzero__`` prior to their
self_group() step.  [ticket:2621]

doc/build/changelog/changelog_08.rst
lib/sqlalchemy/sql/expression.py
test/sql/test_operators.py
test/sql/test_selectable.py

index 38aba26d87cb985e79590d8333053f52d3344f53..a27e076f8111492218976802e6e8afae62df1dad 100644 (file)
@@ -6,6 +6,27 @@
 .. changelog::
     :version: 0.8.0b2
 
+    .. change::
+        :tags: sql, bug
+        :tickets: 2621
+
+      Made an adjustment to the "boolean", (i.e. ``__nonzero__``)
+      evaluation of binary expressions, i.e. ``x1 == x2``, such
+      that the "auto-grouping" applied by :class:`.BinaryExpression`
+      in some cases won't get in the way of this comparison.
+      Previously, an expression like::
+
+        expr1 = mycolumn > 2
+        bool(expr1 == expr1)
+
+      Would evaulate as ``False``, even though this is an identity
+      comparison, because ``mycolumn > 2`` would be "grouped" before
+      being placed into the :class:`.BinaryExpression`, thus changing
+      its identity.   :class:`.BinaryExpression` now keeps track
+      of the "original" objects passed in.
+      Additionally the ``__nonzero__`` method now only returns if
+      the operator is ``==`` or ``!=`` - all others raise ``TypeError``.
+
     .. change::
         :tags: firebird, bug
         :tickets: 2622
index 3dc8dfea495b4a8d1e608524c75e913f924dadf9..aa912a0f6d2f5dde880f4ec548478f7d74928fcc 100644 (file)
@@ -3723,6 +3723,7 @@ class BinaryExpression(ColumnElement):
         # refer to BinaryExpression directly and pass strings
         if isinstance(operator, basestring):
             operator = operators.custom_op(operator)
+        self._orig = (left, right)
         self.left = _literal_as_text(left).self_group(against=operator)
         self.right = _literal_as_text(right).self_group(against=operator)
         self.operator = operator
@@ -3735,9 +3736,9 @@ class BinaryExpression(ColumnElement):
             self.modifiers = modifiers
 
     def __nonzero__(self):
-        try:
-            return self.operator(hash(self.left), hash(self.right))
-        except:
+        if self.operator in (operator.eq, operator.ne):
+            return self.operator(hash(self._orig[0]), hash(self._orig[1]))
+        else:
             raise TypeError("Boolean value of this clause is not defined")
 
     @property
index 9da9d94c320dfbeec8a7bfdbba70fdcf9c8a496c..45f4978ed128beb4d260f75786d6c9462c2d4e8b 100644 (file)
@@ -833,6 +833,58 @@ class ComparisonOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL):
     def test_comparison_operators_ge(self):
         self._test_comparison_op(operator.ge, '>=', '<=')
 
+class NonZeroTest(fixtures.TestBase):
+    def _raises(self, expr):
+        assert_raises_message(
+            TypeError,
+            "Boolean value of this clause is not defined",
+            bool, expr
+        )
+
+    def _assert_true(self, expr):
+        is_(bool(expr), True)
+
+    def _assert_false(self, expr):
+        is_(bool(expr), False)
+
+    def test_column_identity_eq(self):
+        c1 = column('c1')
+        self._assert_true(c1 == c1)
+
+    def test_column_identity_gt(self):
+        c1 = column('c1')
+        self._raises(c1 > c1)
+
+    def test_column_compare_eq(self):
+        c1, c2 = column('c1'), column('c2')
+        self._assert_false(c1 == c2)
+
+    def test_column_compare_gt(self):
+        c1, c2 = column('c1'), column('c2')
+        self._raises(c1 > c2)
+
+    def test_binary_identity_eq(self):
+        c1 = column('c1')
+        expr = c1 > 5
+        self._assert_true(expr == expr)
+
+    def test_labeled_binary_identity_eq(self):
+        c1 = column('c1')
+        expr = (c1 > 5).label(None)
+        self._assert_true(expr == expr)
+
+    def test_annotated_binary_identity_eq(self):
+        c1 = column('c1')
+        expr1 = (c1 > 5)
+        expr2 = expr1._annotate({"foo": "bar"})
+        self._assert_true(expr1 == expr2)
+
+    def test_labeled_binary_compare_gt(self):
+        c1 = column('c1')
+        expr1 = (c1 > 5).label(None)
+        expr2 = (c1 > 5).label(None)
+        self._assert_false(expr1 == expr2)
+
 class NegationTest(fixtures.TestBase, testing.AssertsCompiledSQL):
     __dialect__ = 'default'
 
index 65dc654702735857eaa9b7872340dbca1f7fb4f2..a60916b44a80bf937ed377d537df7d2b2481d7e8 100644 (file)
@@ -1287,7 +1287,9 @@ class AnnotationsTest(fixtures.TestBase):
             t.c.x,
             a,
             s,
-            s2
+            s2,
+            t.c.x > 1,
+            (t.c.x > 1).label(None)
         ]:
             annot = obj._annotate({})
             eq_(set([obj]), set([annot]))