]> granicus.if.org Git - python/commitdiff
bpo-31843: sqlite3.connect() now accepts PathLike objects as database name (#4299)
authorAnders Lorentsen <Phaqui@gmail.com>
Tue, 7 Nov 2017 00:47:43 +0000 (01:47 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 7 Nov 2017 00:47:43 +0000 (16:47 -0800)
Doc/library/sqlite3.rst
Lib/sqlite3/test/dbapi.py
Misc/NEWS.d/next/Library/2017-11-07-00-37-50.bpo-31843.lM2gkR.rst [new file with mode: 0644]
Modules/_sqlite/connection.c
Modules/_sqlite/module.c

index ef0c0bf64cdadd76c2465da52ccb9b3689e9f0d5..c7b9af4037f801bd8c4b91988410d7a274116e94 100644 (file)
@@ -172,9 +172,13 @@ Module functions and constants
 
 .. 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
-   ``":memory:"`` to open a database connection to a database that resides in RAM
-   instead of on disk.
+   Opens a connection to the SQLite database file *database*. By default returns a
+   :class:`Connection` object, unless a custom *factory* is given.
+
+   *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
    modifies the database, the SQLite database is locked until that transaction is
@@ -223,6 +227,9 @@ Module functions and constants
    .. versionchanged:: 3.4
       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)
 
index 12c9fb460fd780fa8501de791e38fb53069c17c8..5332975e0a651f4b5e3185ed3ea802d101ed492e 100644 (file)
@@ -160,6 +160,17 @@ class ConnectionTests(unittest.TestCase):
         with self.assertRaises(AttributeError):
             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):
         if sqlite.sqlite_version_info < (3, 7, 7):
             with self.assertRaises(sqlite.NotSupportedError):
diff --git a/Misc/NEWS.d/next/Library/2017-11-07-00-37-50.bpo-31843.lM2gkR.rst b/Misc/NEWS.d/next/Library/2017-11-07-00-37-50.bpo-31843.lM2gkR.rst
new file mode 100644 (file)
index 0000000..c3142f0
--- /dev/null
@@ -0,0 +1,2 @@
+*database* argument of sqlite3.connect() now accepts a
+:term:`path-like object`, instead of just a string.
index 70e56aad520575aa219d62ecc7f0bb4749b662ea..57eee2d32df4654ccccb5fead05fed4abe7280e5 100644 (file)
@@ -76,6 +76,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
     };
 
     char* database;
+    PyObject* database_obj;
     int detect_types = 0;
     PyObject* isolation_level = NULL;
     PyObject* factory = NULL;
@@ -85,14 +86,16 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
     double timeout = 5.0;
     int rc;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOip", kwlist,
-                                     &database, &timeout, &detect_types,
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|diOiOip", kwlist,
+                                     PyUnicode_FSConverter, &database_obj, &timeout, &detect_types,
                                      &isolation_level, &check_same_thread,
                                      &factory, &cached_statements, &uri))
     {
         return -1;
     }
 
+    database = PyBytes_AsString(database_obj);
+
     self->initialized = 1;
 
     self->begin_statement = NULL;
@@ -124,6 +127,8 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
 #endif
     Py_END_ALLOW_THREADS
 
+    Py_DECREF(database_obj);
+
     if (rc != SQLITE_OK) {
         _pysqlite_seterror(self->db, NULL);
         return -1;
index ffb711830bc616bd1efdf038d0828d1b1761627b..9066c32db5547a67c41b170686e1d8f922404d78 100644 (file)
@@ -55,7 +55,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
         "check_same_thread", "factory", "cached_statements", "uri",
         NULL
     };
-    char* database;
+    PyObject* database;
     int detect_types = 0;
     PyObject* isolation_level;
     PyObject* factory = NULL;
@@ -66,7 +66,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
 
     PyObject* result;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOip", kwlist,
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|diOiOip", kwlist,
                                      &database, &timeout, &detect_types,
                                      &isolation_level, &check_same_thread,
                                      &factory, &cached_statements, &uri))