Package: pymysql-utils
The pymysql_utils moduleThe pymysql_utils package makes interaction with MySQL from
Python more pythonic than its underlying packagemysqlclient(formerly MySQL-python), or the alternative underlying packagepymysql. Either mysqlclient, or pymysql may be chosen as the
foundation of pymysql_utils.Convenience methods for common MySQL operations, such as
managing tables, insertion, updates, and querying are also
available. Query results are iterators withnext()andnextall()methodsTested on:OSMySQLPythonmacosmysql 8.03.7macosmysql 8.02.7ubuntu 16.04 Xenialmysql 5.73.6ubuntu 16.04 Xenialmysql 5.72.7Quickstartfrompymysql_utils.pymysql_utilsimportMySQLDB# Create a database instance. For one approach to# dealing with password-protected databases, see# the Tips Section below.db=MySQLDB(user='myName',db='myDb')mySchema={'col1':'INT','col2':'varchar(255)',}db.createTable('myTable',mySchema)# Fill the table:colNames=['col1','col2']colValues=[(10,'row1'),(20,'row2'),(30,'row3'),]db.bulkInsert('myTable',colNames,colValues)# Result objects are iterators:forresultindb.query('SELECT col2 FROM myTable ORDER BY col1'):print(result)# row1# row2# row3A Bit More DetailThe database connection is encapsulated in an instance ofMySQLDB. This instance can maintain multiple queries
simulataneously. Each query result is aniteratorobject
from which result tuples can be retrieved one by one,
usingnext(), or all at once usingnextall(). Here is
an example of multiple queries interleaved. Assume the
above tablemyTableis populated in the database.query_str1='''SELECT col2FROM myTableORDER BY col1'''query_str2='''SELECT col2FROM myTableWHERE col1 = 20OR col1 = 30ORDER BY col1'''results1=db.query(query_str1)results2=db.query(query_str2)# Result objects know their total result count:results1.result_count()# --> 3results2.result_count()# --> 2# The db object can retrieve the result count# by the query string:db.result_count(query_str1)# --> 3results1.next()# --> 'row1'results2.next()# --> 'row2'results1.next()# --> 'row2'results2.next()# --> 'row3'results1.next()# --> 'row3'results2.next()# --> raises StopIterationresults2.result_count()# --> raises ValueError: query exhausted.Tips:Many methods return a two-tuple that includes a list of warnings, and a
list of errors.Check thein-code documentationfor all available methods.A number of frequent SQL operations can conveniently be accomplised
via dedicated methods:close,createTable,dropTable,insert,bulkInsert,truncateTable, andupdate.These, or other operations can also be accomplished by usingexecute()to submit arbitrary SQLA useful idiom for queries known to return a single result,
such as a count:db.query('...').next()The underlyingmysqlclientpackage does not expose the MySQL 5.7+login-pathoption. So theMySQLDB()call needs to include the
password if one is required. One way to avoid putting passwords into
your code is to place the password into a file in a well protected
directory, such as~/.ssh/mysql. Then read the password from there.Installation# Possibly in a virtual environment:pipinstallpymysql_utils
pythonsetup.pyinstall# Testing requires a bit of prep in the local MySQL:# a database 'unittest' must be created, and a user# 'unittest' without password must have permissions:### CREATE DATABASE unittest;# CREATE USER unittest@localhost;# GRANT SELECT, INSERT, UPDATE, DELETE,#       CREATE, DROP, ALTER#    ON `unittest`.* TO 'unittest'@'localhost';# The unittests give these instructions as well.# python setup.py testSelecting Python-only or C-PythonBy default pymysql_utils usesmysqlclient, and therefore a C-based
API to MySQL servers. Occasionally it may be desirable to use a
Python only solution. You may force pymysql_utils to use thepymysqllibrary instead ofmysqlclient.One reason for forcing Python only is a known incompatibility between
openssl 1.1.1[a,b,c] and mysqlclient (as of Jul 29, 2017).To have pymysql_utils use the Python-only pymysql library, do this:Copypymysql_utils/pymysql_utils_SAMPLE.cnftopymysql_utils/pymysql_utils.cnfInside this new config file, changeFORCE_PYTHON_NATIVE=FalsetoFORCE_PYTHON_NATIVE=True