override with a column expression (e.g. by using ``'x' in col``)
would cause an endless loop in the case of an ARRAY type, as Python
defers this to ``__getitem__`` access which never raises for this
type. Overall, all use of ``__contains__`` now raises
NotImplementedError.
fixes #3642
(cherry picked from commit
e0a580b3d055a600afae61840058a5a30ef5fe74)
:version: 1.0.12
:released:
+ .. change::
+ :tags: bug, sql
+ :tickets: 3642
+
+ Fixed issue where inadvertent use of the Python ``__contains__``
+ override with a column expression (e.g. by using ``'x' in col``)
+ would cause an endless loop in the case of an ARRAY type, as Python
+ defers this to ``__getitem__`` access which never raises for this
+ type. Overall, all use of ``__contains__`` now raises
+ NotImplementedError.
+
.. change::
:tags: bug, engine, mysql
:tickets: 2696
"getitem": (_unsupported_impl,),
"lshift": (_unsupported_impl,),
"rshift": (_unsupported_impl,),
+ "contains": (_unsupported_impl,),
}
from operator import (
and_, or_, inv, add, mul, sub, mod, truediv, lt, le, ne, gt, ge, eq, neg,
- getitem, lshift, rshift
+ getitem, lshift, rshift, contains
)
if util.py2k:
"""
return self.operate(neg)
+ def __contains__(self, other):
+ return self.operate(contains, other)
+
def __getitem__(self, index):
"""Implement the [] operator.
class ArrayTest(fixtures.TablesTest, AssertsExecutionResults):
-
__only_on__ = 'postgresql'
__backend__ = True
__unsupported_on__ = 'postgresql+pg8000', 'postgresql+zxjdbc'
eq_(len(results), 1)
eq_(results[0][0], 5)
+ def test_contains_override_raises(self):
+ col = Column('x', postgresql.ARRAY(Integer))
+
+ assert_raises_message(
+ NotImplementedError,
+ "Operator 'contains' is not supported on this expression",
+ lambda: 'foo' in col
+ )
+
def test_array_subtype_resultprocessor(self):
arrtable = self.tables.arrtable
arrtable.insert().execute(intarr=[4, 5, 6],
from sqlalchemy.sql.elements import _literal_as_text
from sqlalchemy.schema import Column, Table, MetaData
from sqlalchemy.types import TypeEngine, TypeDecorator, UserDefinedType, \
- Boolean, NullType, MatchType
+ Boolean, NullType, MatchType, DateTime
from sqlalchemy.dialects import mysql, firebird, postgresql, oracle, \
sqlite, mssql
from sqlalchemy import util
def test_concat(self):
self._do_operate_test(operators.concat_op)
+ def test_contains_override_raises(self):
+ for col in [
+ Column('x', String),
+ Column('x', Integer),
+ Column('x', DateTime)
+ ]:
+ assert_raises_message(
+ NotImplementedError,
+ "Operator 'contains' is not supported on this expression",
+ lambda: 'foo' in col
+ )
+
class CustomUnaryOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL):
__dialect__ = 'default'