bpo-31843: sqlite3.connect() now accepts PathLike objects as database name (#4299)

This commit is contained in:
Anders Lorentsen 2017-11-07 01:47:43 +01:00 committed by Victor Stinner
parent edb13ae48c
commit a22a127458
5 changed files with 32 additions and 7 deletions

View file

@ -172,9 +172,13 @@ Module functions and constants
.. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri]) .. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])
Opens a connection to the SQLite database file *database*. You can use Opens a connection to the SQLite database file *database*. By default returns a
``":memory:"`` to open a database connection to a database that resides in RAM :class:`Connection` object, unless a custom *factory* is given.
instead of on disk.
*database* is a :term:`path-like object` giving the pathname (absolute or
relative to the current working directory) of the database file to be opened.
You can use ``":memory:"`` to open a database connection to a database that
resides in RAM instead of on disk.
When a database is accessed by multiple connections, and one of the processes When a database is accessed by multiple connections, and one of the processes
modifies the database, the SQLite database is locked until that transaction is modifies the database, the SQLite database is locked until that transaction is
@ -223,6 +227,9 @@ Module functions and constants
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Added the *uri* parameter. Added the *uri* parameter.
.. versionchanged:: 3.7
*database* can now also be a :term:`path-like object`, not only a string.
.. function:: register_converter(typename, callable) .. function:: register_converter(typename, callable)

View file

@ -160,6 +160,17 @@ class ConnectionTests(unittest.TestCase):
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
self.cx.in_transaction = True self.cx.in_transaction = True
def CheckOpenWithPathLikeObject(self):
""" Checks that we can succesfully connect to a database using an object that
is PathLike, i.e. has __fspath__(). """
self.addCleanup(unlink, TESTFN)
class Path:
def __fspath__(self):
return TESTFN
path = Path()
with sqlite.connect(path) as cx:
cx.execute('create table test(id integer)')
def CheckOpenUri(self): def CheckOpenUri(self):
if sqlite.sqlite_version_info < (3, 7, 7): if sqlite.sqlite_version_info < (3, 7, 7):
with self.assertRaises(sqlite.NotSupportedError): with self.assertRaises(sqlite.NotSupportedError):

View file

@ -0,0 +1,2 @@
*database* argument of sqlite3.connect() now accepts a
:term:`path-like object`, instead of just a string.

View file

@ -76,6 +76,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
}; };
char* database; char* database;
PyObject* database_obj;
int detect_types = 0; int detect_types = 0;
PyObject* isolation_level = NULL; PyObject* isolation_level = NULL;
PyObject* factory = NULL; PyObject* factory = NULL;
@ -85,14 +86,16 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
double timeout = 5.0; double timeout = 5.0;
int rc; int rc;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOip", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|diOiOip", kwlist,
&database, &timeout, &detect_types, PyUnicode_FSConverter, &database_obj, &timeout, &detect_types,
&isolation_level, &check_same_thread, &isolation_level, &check_same_thread,
&factory, &cached_statements, &uri)) &factory, &cached_statements, &uri))
{ {
return -1; return -1;
} }
database = PyBytes_AsString(database_obj);
self->initialized = 1; self->initialized = 1;
self->begin_statement = NULL; self->begin_statement = NULL;
@ -124,6 +127,8 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
#endif #endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
Py_DECREF(database_obj);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
_pysqlite_seterror(self->db, NULL); _pysqlite_seterror(self->db, NULL);
return -1; return -1;

View file

@ -55,7 +55,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
"check_same_thread", "factory", "cached_statements", "uri", "check_same_thread", "factory", "cached_statements", "uri",
NULL NULL
}; };
char* database; PyObject* database;
int detect_types = 0; int detect_types = 0;
PyObject* isolation_level; PyObject* isolation_level;
PyObject* factory = NULL; PyObject* factory = NULL;
@ -66,7 +66,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
PyObject* result; PyObject* result;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOip", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|diOiOip", kwlist,
&database, &timeout, &detect_types, &database, &timeout, &detect_types,
&isolation_level, &check_same_thread, &isolation_level, &check_same_thread,
&factory, &cached_statements, &uri)) &factory, &cached_statements, &uri))