how to use mysql defaults file (my.cnf) with sqlalchemy?
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 sourc开发者_高级运维e 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.
Here is a result that was found on the sqlalchemy mailing list, posted by Tom H:
http://www.mail-archive.com/sqlalchemy@googlegroups.com/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 :)
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')
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}')
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")
精彩评论