how to use mysql defaults file (my.cnf) with sqlalchemy?

Question:

I’d like to have sqlalchemy get the hostname, username, and password for the mysql database it’s connecting to.

The documentation says mysql schemas are specified as such:

mysql_db = create_engine('mysql://scott:tiger@localhost/foo')

Is it possible to instead source a mysql defaults file such as /etc/my.cnf and get the login details from there? I’d like to avoid embedding the username/password in my code.

Asked By: Christine

||

Answers:

Here is a result that was found on the sqlalchemy mailing list, posted by Tom H:

http://www.mail-archive.com/[email protected]/msg11241.html

from sqlalchemy.engine.url import URL

myDB = URL(drivername='mysql', host='localhost',
    database='my_database_name',
    query={ 'read_default_file' : '/path/to/.my.cnf' }
)
engine = create_engine(name_or_url=myDB)
# use the engine as usual, no password needed in your code file :)
Answered By: Mark Hildreth

If you want to use MySQLdb you could parse the ini file with ConfigParser:

sql_ini_fileparser = ConfigParser.RawConfigParser()
sql_ini_fileparser.read('example.cfg')
user = sql_ini_fileparser.get('client', 'user')
password = sql_ini_fileparser.get('client', 'password')
Answered By: Karel

This is an old question, but the accepted answer still forces you to include the hostname as a string. I was looking for a solution that reads the my.cnf file and gets the hostname from there as well.

The first thing I found was this page, and the suggestion to build the URL using the query={'read_default_file': 'my.cnf'} keyword. The following are all equivalent to his answer, and they all require you to pass in the hostname explicitly, but at least you can get passwords, ports, charset, and other things from the my.cnf file

engine = create_engine('mysql+pymysql://hostname', connect_args={'read_default_file': 'mu.cnf'})
engine = create_engine('mysql+pymysql://hostname?read_default_file=my.cnf')

After reading much of the source code, I believe there is no possible way to get a sqlalchemy engine without passing the hostname into create_engine somehow.

So somehow you have to get the hostname from somewhere else. The simplest options for this are to use an environment variable ie host=os.getenv('DATABASE_URI') or to parse a config file using the configparser library like karlo suggested. I prefer the config file because then you don’t have to inject usernames and passwords into environment variables – here’s roughly how pymysql parses the file in the source code for pymysql.connections.Connection

from configparser import Parser

read_default_group = 'client' # replace this if you're super special
read_default_file = '/etc/my.cnf' # replace this with the path you want to use

cfg = Parser()
cfg.read(defaults_file) 

def _config(key, arg=None):
    try:
        return cfg.get(read_default_group, key)
    except Exception:
        return arg

user = _config("user")
password = _config("password")
host = _config("host")
database = _config("database")
port = int(_config("port", 3306))
charset = _config("charset", "utf8mb4")
engine = create_engine(f'mysql+pymysql://{user}:{password}@{host}:{port}/{database}?charset={charset}')
Answered By: krethika

I know this is an old thread, but the solutions mentioned above would not work for me when attempting to do this as I was connecting via a socket in the cnf file.

Instead, I have done the following which works:

First off I parse the cnf file to get the username and password.

CnfFile = open('/directory/.MyCnfFile.cnf', 'r')
for Line in CnfFile:
    if Line.startswith("user"):
        User = Line.lstrip("user=")
        User = User.rstrip("n")
    if Line.startswith("password"):
        Password = Line.lstrip("password=")
        Password = Password.rstrip("n")

I then create the engine using the socket.

engine = create_engine("mysql+pymysql://"+User+":"+Password+"@localhost?unix_socket=/var/run/mysqld/mysqld-socket.sock")
Answered By: Doonwong
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.