Limitations
EasyMySQL 0.1.9.x is a thin, deliberately small wrapper. This page lists the behaviours that surprise people, each with the workaround that applies while you are on this release line.
1. Python 3.10 and newer
The library checks argument types with collections.Iterable. That alias was
deprecated in Python 3.3 and removed in Python 3.10, so on newer interpreters
the check itself raises
AttributeError: module 'collections' has no attribute 'Iterable'.
What that means in practice:
| Call | Python ≤ 3.9 | Python ≥ 3.10 |
|---|---|---|
insert(table, data) | Works | Works — no type check on this path |
select(table, "id = 1") | Works | Works — the check short-circuits on strings |
select(table, {'id': 1}) | Works | AttributeError |
delete(table, "id = 1") | Works | Works |
delete(table, {'id': 1}) | Works | AttributeError |
update(...) — any form | Works | AttributeError |
query(), execute() | Works | Works |
update() is the worst case: it runs the check against its data
argument before it ever inspects the condition, so no calling convention avoids it.
Workarounds
- Pin your interpreter to Python 3.9 or older.
-
Or, on 3.10+, use string conditions everywhere and replace
update()withexecute(). - Or restore the alias before importing the library — a shim, not a fix, but it makes the dictionary paths work again:
import collections, collections.abc
if not hasattr(collections, 'Iterable'):
collections.Iterable = collections.abc.Iterable
from easymysql.mysql import mysql # import *after* the shim
2. No escaping or parameter binding
Every SQL statement is built by string concatenation. Values are passed through
str() and wrapped in single quotes — nothing is escaped and PyMySQL's
placeholders are never used.
Two consequences:
- Apostrophes break statements.
db.insert('users', {'name': "O'Brien"})generatesVALUES ('O'Brien'), a syntax error. - Any untrusted value is a SQL injection vector. A form field containing
' OR '1'='1reaching a table name, a value, or a string condition changes the meaning of the query.
Never pass unvalidated user input to any EasyMySQL method. Where you must handle user-supplied values, validate or escape them yourself before the call — or use PyMySQL directly, which supports real parameter binding.
3. Errors are printed, not raised
execute() and query() wrap the statement in a bare
try/except that prints Exeception occured:{e} to stdout and
swallows the exception. Since every other method routes through execute(), no
database error ever propagates as a Python exception.
Practical effects:
try/exceptaround an EasyMySQL call never fires for SQL errors.-
After a failed statement the cursor still holds the previous statement's state, so
count(),getLastId()and the return value ofinsert()can report stale numbers. query()returnsNoneon failure, versus[]on an empty result.- Failures are invisible in logs unless you are capturing stdout.
If a write must be confirmed, re-read the row rather than trusting the call to have raised.
4. Every value is sent as a quoted string
Values become '<str(value)>'. MySQL coerces numeric literals back into
numeric columns, so ordinary data round-trips fine, but:
Noneis written as the string'None', notNULL.True/Falsebecome'True'/'False', not1/0.datetimeobjects rely on theirstr()form matching what MySQL accepts.
For real NULLs, use execute() with a
literal NULL. For booleans, pass 0 and 1 yourself.
5. Dictionary conditions only support equality and AND
A dict condition always becomes key='value' joined with AND. There
is no way to express OR, <, >,
LIKE, IN or IS NULL through a dictionary — use a
string condition for those.
6. No connection options beyond the four credentials
The constructor takes only hostname, username, password and database. There is no parameter
for port, socket, charset, SSL, connection timeout or autocommit; the underlying PyMySQL
connection uses defaults for all of them, including port 3306 and no TLS. A
non-standard setup needs PyMySQL directly.
7. Single shared cursor, not thread-safe
One cursor is created at connect time and reused for every statement. Two threads sharing a
mysql instance will interleave on that cursor and read each other's results —
give each thread its own instance.
8. Broken methods
truncate() and resetCache() call execute() on the
connection object instead of the instance and raise AttributeError on every
call. See Raw SQL & Utilities for replacements.
version() returns the hard-coded string "0.1.9.2" even in the
0.1.9.3 release. Use pip show easymysql instead.