- marked as minor
repair result type for is_, is_not_
I've been working on some system which type-checks variables and ran across this behaviour where sometimes the type
attribute of a BinaryExpression
would be NullType()
. This is confusion because I can't build something which checks for NULL via a boolean operation.
For example: table.c.col.isnot(None) == True
would work, though the type
s are incompatible, so I can't check beforehand. I hope this makes sense?
From the code I can't deduce if this is intentional or not, though there is special casing going on in sqlalchemy.sql.default_comparator._boolean_compare
.
The most current versions of 1.1 and 1.0 are both affected.
A script to illustrate the behaviour is attached.
Even if this behaviour is intentional, I'd be happy to have an explanation as to why this is.
Comments (7)
-
reporter -
repo owner this is a bug as the result type is missing on line 54 of lib/sqlalchemy/sql/default_comparator.py.
-
repo owner - changed milestone to 1.2
- changed component to sql
- changed title to repair result type for is_, is_not_
- marked as major
-
repo owner that is, the majority are repaired by:
diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py index 827492f..68459c1 100644 --- a/lib/sqlalchemy/sql/default_comparator.py +++ b/lib/sqlalchemy/sql/default_comparator.py @@ -50,11 +50,13 @@ def _boolean_compare(expr, op, obj, negate=None, reverse=False, if op in (operators.eq, operators.is_): return BinaryExpression(expr, _const_expr(obj), operators.is_, - negate=operators.isnot) + negate=operators.isnot, + type_=result_type) elif op in (operators.ne, operators.isnot): return BinaryExpression(expr, _const_expr(obj), operators.isnot, - negate=operators.is_) + negate=operators.is_, + type_=result_type) else: raise exc.ArgumentError( "Only '=', '!=', 'is_()', 'isnot()', "
for the custom_op thing, honoring is_comparison is something new.
-
repo owner the custom op issue is:
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 215c09e..f244e99 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -2471,7 +2471,9 @@ class NullType(TypeEngine): class Comparator(TypeEngine.Comparator): def _adapt_expression(self, op, other_comparator): - if isinstance(other_comparator, NullType.Comparator) or \ + if operators.is_comparison(op): + return op, BOOLEANTYPE + elif isinstance(other_comparator, NullType.Comparator) or \ not operators.is_commutative(op): return op, self.expr.type else:
however that has the potential to impact other situations as well; it probably impacts them correctly but any behavioral change has to be considered for backwards-compatible impact if we wanted this in 1.1.x.
-
repo owner -
repo owner - changed status to resolved
Enforce boolean result type for all eq_, is_, isnot, comparison
Repaired issue where the type of an expression that used :meth:
.ColumnOperators.is_
or similar would not be a "boolean" type, instead the type would be "nulltype", as well as when using custom comparison operators against an untyped expression. This typing can impact how the expression behaves in larger contexts as well as in result-row-handling.Change-Id: Ib810ff686de500d8db26ae35a51005fab29603b6 Fixes:
#3873→ <<cset 433d2ee9f14a>>
- Log in to comment