ColumnClause pretends to be iterable and then isn't
Updating to SQLAlchemy 0.8, I'm getting regressions because ColumnClause.__iter__
now exists (defined in ColumnOperators
in 1e29a74bd62c6c872819388e430901c35f84f07c) only to raise an exception. This sucker-punches code that checks for iterableness either by hasattr(o, '__iter__')
or isinstance(o, collections.Iterable)
... such as this VALUES
compiler that supports tuples/lists/iterables on PostgreSQL, representing them as ARRAY
s:
@compiles(values)
def compile_values(element, compiler, asfrom=False, **kw):
v = u"VALUES %s" % ", ".join(
u"(%s)" % u", ".join(
u'ARRAY[%s](%s)' % ','.join(
(u"'%s'" % subel.replace(u"'", u"''").replace(u"%", u"%%"))
if isinstance(subel, unicode)
else str(subel) if isinstance(subel, int)
else compiler.process(subel)
for subel in elem
) if hasattr(elem, '__iter__')
and elem.__iter__.__func__ is not blocking_iter_func
else (u"'%s'" % elem.replace(u"'", u"''").replace(u"%", u"%%"))
if isinstance(elem, unicode)
else u'NULL' if elem is None
else compiler.process(elem) if isinstance(elem, ColumnElement)
else repr(elem)
for elem in tup)
for tup in element.list
)
if asfrom:
v = "(%s)" % v
return v
I get what the method is there for, but it satisfies the conventional ways of checking for iterableness, while it's actually there to assert ''non-''iterableness. That's not very neat.
I'm provisionally working around this as a special case:
from sqlalchemy.sql.operators import ColumnOperators
blocking_iter_func = ColumnOperators.__iter__.__func__
... if hasattr(elem, '__iter__') and elem.__iter__.__func__ is not blocking_iter_func
(and the wind carries a soft murmur of kittens screaming in the distance...)
Comments (5)
-
repo owner -
Account Deleted Hopefully nothing, for a while. :) (Our codebase is not a library, does not need to run on Python 3 until either (a) we want it to, or (b) libraries we want to use no longer support 2.7.x, neither of which seems imminent.)
We're not only detecting lists/tuples/sets, it's also generators, and our own types with
__iter__
defined. So justisinstance(o, (list, tuple, set))
orisinstance(o, collections.Sequence)
wouldn't hack it. In these (fairly common) cases we're looking for anything iterable that isn't a string. Presumably we'll just end up saying that verbatim, i.e.isinstance(o, collections.Iterable) and not isinstance(o, basestring)
, which isn't much neater, but at least explicit. -
repo owner - marked as critical
there's not much option here except to take that whole thing out, and wait for the stackoverflow issues when people call list() on their custom columns...
-
repo owner - changed status to resolved
-
repo owner - removed milestone
Removing milestone: 0.8.xx (automated comment)
- Log in to comment
what are you going to do about strings in Python 3? they have
__iter__()
also. I'm not sure if checking for__iter__
/Iterable
and nothing else to detect lists/tuples/sets is really feasible due to that.