Fixed regression caused by an internal code change in response to recent
Mypy releases that caused the very unusual case of a list of ORM-mapped
attribute expressions passed to :meth:`.ColumnOperators.in_` to no longer
be accepted.
in this commit we had to revisit
d8dd28c42e where mypy typing
didn't accept ColumnOperartors. the type here is the _HasClauseElement[_T]
protocol which means we need to use a duck type for a runtime check.
Fixes: #12019
Change-Id: Ib378e9cb8defb49d5ac4d726ec93d6bdc581b6a9
--- /dev/null
+.. change::
+ :tags: orm, bug
+ :tickets: 12019
+
+ Fixed regression caused by an internal code change in response to recent
+ Mypy releases that caused the very unusual case of a list of ORM-mapped
+ attribute expressions passed to :meth:`.ColumnOperators.in_` to no longer
+ be accepted.
def _literal_coercion(self, element, *, expr, operator, **kw):
if util.is_non_string_iterable(element):
non_literal_expressions: Dict[
- Optional[ColumnElement[Any]],
- ColumnElement[Any],
+ Optional[_ColumnExpressionArgument[Any]],
+ _ColumnExpressionArgument[Any],
] = {}
element = list(element)
for o in element:
if not _is_literal(o):
if not isinstance(
o, util.preloaded.sql_elements.ColumnElement
- ):
+ ) and not hasattr(o, "__clause_element__"):
self._raise_for_expected(element, **kw)
else:
assert_raises(NotImplementedError, Address.user.in_, [User(id=5)])
+ def test_in_instrumented_attribute(self):
+ """test #12019"""
+ User = self.classes.User
+
+ self._test(
+ User.id.in_([User.id, User.name]),
+ "users.id IN (users.id, users.name)",
+ )
+
def test_neg(self):
User = self.classes.User
return op
+class ColExpressionDuckTypeOnly:
+ def __init__(self, expr):
+ self.expr = expr
+
+ def __clause_element__(self):
+ return self.expr
+
+
class DefaultColumnComparatorTest(
testing.AssertsCompiledSQL, fixtures.TestBase
):
"mytable.myid IN (mytable.myid)",
)
+ def test_in_14_5(self):
+ """test #12019"""
+ self.assert_compile(
+ self.table1.c.myid.in_(
+ [ColExpressionDuckTypeOnly(self.table1.c.myid)]
+ ),
+ "mytable.myid IN (mytable.myid)",
+ )
+
def test_in_15(self):
self.assert_compile(
self.table1.c.myid.in_(["a", self.table1.c.myid]),