-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Changing column order causes baked tuple_ query to raise TypeError #5393
Description
Describe the bug
If I create a "regular" tuple_ query, it works as expected, even if I switch columns around in tuple_.
However, switching column order causes the baked variant of the same tuple_ query to raise a sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite Date type only accepts Python date objects as input.. Seems to happen with Date and DateTime columns, but that may be because most of my other columns have interchangeable types.
May very well be user error. Would love to know what I'm doing wrong with the baked query.
Expected behavior
All queries return a count of 1.
To Reproduce
from sqlalchemy import Column, Date, Integer, create_engine, tuple_, bindparam
from sqlalchemy.ext.baked import bakery as bakery_maker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from datetime import date
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
first = Column(Integer)
second = Column(Date)
# Setup.
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
session = Session(bind=engine)
# Insert a row.
foo = Foo(first=1, second=date(2000, 1, 1))
session.add(foo)
def make_regular_query(columns, values):
return session.query(Foo).filter(tuple_(*columns).in_(values))
def make_baked_query(columns):
return bakery_maker()(lambda session: session.query(Foo)
.filter(tuple_(*columns).in_(bindparam('values', expanding=True))))
def run():
# (first, second) order.
cols = Foo.first, Foo.second
values = [(foo.first, foo.second)]
print('(first, second) regular query',
make_regular_query(cols, values).count())
print('(first, second) baked query',
make_baked_query(cols)(session).params(values=values).count())
# (second,) order.
cols = (Foo.second,)
values = [(foo.second,)]
print('(second,) regular query',
make_regular_query(cols, values).count())
print('(second,) baked query',
make_baked_query(cols)(session).params(values=values).count())
# (second, first) order.
cols = Foo.second, Foo.first
values = [(foo.second, foo.first)]
print('(second, first) regular query',
make_regular_query(cols, values).count())
print('(second, first) baked query',
make_baked_query(cols)(session).params(values=values).count())
# sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite Date type only accepts Python date objects as input.
run()Error
(first, second) regular query 1
(first, second) baked query 1
(second,) regular query 1
(second,) baked query 1
(second, first) regular query 1
Traceback (most recent call last):
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1211, in _execute_context
context = constructor(dialect, self, conn, *args)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 836, in _init_compiled
param.append(processors[key](compiled_params[key]))
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/dialects/sqlite/base.py", line 837, in process
"SQLite Date type only accepts Python "
TypeError: SQLite Date type only accepts Python date objects as input.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 73, in <module>
run()
File "test.py", line 69, in run
make_baked_query(cols)(session).params(values=values).count())
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/ext/baked.py", line 461, in count
return bq.for_session(self.session).params(self._params).scalar()
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/ext/baked.py", line 474, in scalar
ret = self.one()
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/ext/baked.py", line 505, in one
ret = self.one_or_none()
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/ext/baked.py", line 527, in one_or_none
ret = list(self)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/ext/baked.py", line 445, in __iter__
return q._execute_and_instances(context)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3506, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1020, in execute
return meth(self, multiparams, params)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 298, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_clauseelement
distilled_params,
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1214, in _execute_context
e, util.text_type(statement), parameters, None, None
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1518, in _handle_dbapi_exception
sqlalchemy_exception, with_traceback=exc_info[2], from_=e
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 178, in raise_
raise exception
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1211, in _execute_context
context = constructor(dialect, self, conn, *args)
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 836, in _init_compiled
param.append(processors[key](compiled_params[key]))
File "/home/user/.local/lib/python3.7/site-packages/sqlalchemy/dialects/sqlite/base.py", line 837, in process
"SQLite Date type only accepts Python "
sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite Date type only accepts Python date objects as input.
[SQL: SELECT count(*) AS count_1
FROM (SELECT foo.id AS foo_id, foo.first AS foo_first, foo.second AS foo_second
FROM foo
WHERE (foo.second, foo.first) IN ([EXPANDING_values])) AS anon_1]
[parameters: [{'values': [(datetime.date(2000, 1, 1), 1)]}]]
Additional context
If I (re)use a single bakery throughout (bakery = bakery_maker() in the setup), I get other unpredictable behavior from the baked queries (like no results if I switch column order), so I'm guessing running that each time I bake a query is the right way to go about it.
Versions.
- OS: Ubuntu 18.04
- Python: Python 3.7.4
- SQLAlchemy: 1.3.17
- Database: SQLite
Have a nice day!