pymysql unicode expects unicode or non-unicode for statement/binds at the same time

Issue #3337 resolved
Mike Bayer repo owner created an issue

we can set supports_unicode_statements and supports_unicode_binds to True or False and PyMySQL tests pass from 0.4 to 0.6.6. However, if statements is True and binds is False as it is right now, then the "executemany" tests fail, b.c. pymysql is generally using string interpolation to produce the string. Stack is as follows:

#!

$ python -m pytest test/dialect/test_suite.py --dburi "mysql+pymysql://scott:tiger@localhost/test?charset=utf8" -k UnicodeVarcharTest 
===================================================================== test session starts ======================================================================
platform darwin -- Python 2.7.5 -- py-1.4.26 -- pytest-2.6.4 -- /Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
plugins: cov, xdist
collected 143 items 

test/dialect/test_suite.py <- lib/sqlalchemy/testing/suite/test_types.py::UnicodeVarcharTest_mysql_pymysql::test_empty_strings_varchar PASSED
test/dialect/test_suite.py <- lib/sqlalchemy/testing/suite/test_types.py::UnicodeVarcharTest_mysql_pymysql::test_literal PASSED
test/dialect/test_suite.py <- lib/sqlalchemy/testing/suite/test_types.py::UnicodeVarcharTest_mysql_pymysql::test_round_trip PASSED
test/dialect/test_suite.py <- lib/sqlalchemy/testing/suite/test_types.py::UnicodeVarcharTest_mysql_pymysql::test_round_trip_executemany FAILED

=========================================================================== FAILURES ===========================================================================
_________________________________________________ UnicodeVarcharTest_mysql_pymysql.test_round_trip_executemany _________________________________________________
Traceback (most recent call last):
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/testing/suite/test_types.py", line 89, in test_round_trip_executemany
    for i in range(3)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1978, in execute
    return connection.execute(statement, *multiparams, **params)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 914, in execute
    return meth(self, multiparams, params)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
    compiled_sql, distilled_params
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1146, in _execute_context
    context)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1335, in _handle_dbapi_exception
    util.reraise(*exc_info)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1116, in _execute_context
    context)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/dialects/mysql/mysqldb.py", line 95, in do_executemany
    rowcount = cursor.executemany(statement, parameters)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymysql/cursors.py", line 148, in executemany
    self._get_db().encoding)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymysql/cursors.py", line 162, in _do_execute_many
    v = values % escape(next(args), conn)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 64: ordinal not in range(128)
=================================================================== short test summary info ====================================================================
FAIL test/dialect/test_suite.py::UnicodeVarcharTest_mysql_pymysql::()::test_round_trip_executemany
======================================================== 139 tests deselected by '-kUnicodeVarcharTest' ========================================================
====================================================== 1 failed, 3 passed, 139 deselected in 0.27 seconds ======================================================
classics-MacBook-Pro:sqlalchemy classic$ 

the fix works all the way back for pymysql 0.4 which was five years ago so this is good for 0.9.

Comments (2)

  1. Mike Bayer reporter
    • Fixed unicode support for PyMySQL when using an "executemany" operation with unicode parameters. SQLAlchemy now passes both the statement as well as the bound parameters as unicode objects, as PyMySQL generally uses string interpolation internally to produce the final statement, and in the case of executemany does the "encode" step only on the final statement. fixes #3337

    (cherry picked from commit dcf5408f7d315b4d9ddec5d0d696eb364d763099)

    Conflicts: lib/sqlalchemy/dialects/mysql/pymysql.py

    → <<cset 41ca5c8c6769>>

  2. Mike Bayer reporter
    • Fixed unicode support for PyMySQL when using an "executemany" operation with unicode parameters. SQLAlchemy now passes both the statement as well as the bound parameters as unicode objects, as PyMySQL generally uses string interpolation internally to produce the final statement, and in the case of executemany does the "encode" step only on the final statement. fixes #3337

    → <<cset db853306c404>>

  3. Log in to comment