diff --git a/src/MySQLdb/connections.py b/src/MySQLdb/connections.py index 98847a65..af0d28c3 100644 --- a/src/MySQLdb/connections.py +++ b/src/MySQLdb/connections.py @@ -5,6 +5,7 @@ override Connection.default_cursor with a non-standard Cursor class. """ +import os import re from . import _mysql, cursors @@ -214,6 +215,23 @@ class object, used to create cursors (keyword only) # PEP-249 requires autocommit to be initially off autocommit = kwargs2.pop("autocommit", False) + # Accept path-like objects for C API string options (e.g. pathlib.Path). + # See https://github.com/PyMySQL/mysqlclient/issues/319 + for key in ( + "read_default_file", + "read_default_group", + "unix_socket", + "ssl_key", + "ssl_cert", + "ssl_ca", + "ssl_capath", + "ssl_cipher", + "init_command", + "local_infile_dir", + ): + if key in kwargs2 and kwargs2[key] is not None: + kwargs2[key] = os.fspath(kwargs2[key]) + self._set_attributes(*args, **kwargs2) super().__init__(*args, **kwargs2) diff --git a/tests/test_connection_pathlike.py b/tests/test_connection_pathlike.py new file mode 100644 index 00000000..f1cb0ac0 --- /dev/null +++ b/tests/test_connection_pathlike.py @@ -0,0 +1,25 @@ +"""Path-like connection options (#319).""" +import os +from pathlib import Path +from unittest import mock + +import MySQLdb + + +def test_read_default_file_path_converted_via_fspath(): + path = Path("/tmp/does-not-need-to-exist.cnf") + captured = {} + + def fake_c_init(self, *args, **kwargs): + captured.update(kwargs) + raise RuntimeError("stop after c init kwargs captured") + + with mock.patch.object(MySQLdb._mysql.connection, "__init__", fake_c_init): + with mock.patch.object(MySQLdb.connections.Connection, "_set_attributes"): + try: + MySQLdb.connections.Connection(read_default_file=path) + except RuntimeError as exc: + assert str(exc) == "stop after c init kwargs captured" + + assert captured["read_default_file"] == os.fspath(path) + assert isinstance(captured["read_default_file"], str)