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

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:

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:

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:

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.

Next step

See the changelog →