]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-42064: Adapt `sqlite3` to multi-phase init (PEP 489) (GH-29234)
authorErlend Egeberg Aasland <erlend.aasland@innova.no>
Tue, 2 Nov 2021 15:35:51 +0000 (16:35 +0100)
committerGitHub <noreply@github.com>
Tue, 2 Nov 2021 15:35:51 +0000 (16:35 +0100)
Misc/NEWS.d/next/Library/2021-10-27-13-28-52.bpo-42064.UK4jgV.rst [new file with mode: 0644]
Modules/_sqlite/module.c

diff --git a/Misc/NEWS.d/next/Library/2021-10-27-13-28-52.bpo-42064.UK4jgV.rst b/Misc/NEWS.d/next/Library/2021-10-27-13-28-52.bpo-42064.UK4jgV.rst
new file mode 100644 (file)
index 0000000..bcb3307
--- /dev/null
@@ -0,0 +1,2 @@
+Convert :mod:`sqlite3` to multi-phase initialisation (PEP 489). Patches by
+Erlend E. Aasland.
index 8666af171c8cb5e201498bd731c413f1391f2f1b..65229623b84d66a14e1f3929f2c0bb1b5f82e18b 100644 (file)
@@ -415,12 +415,75 @@ add_integer_constants(PyObject *module) {
     return 0;
 }
 
-struct PyModuleDef _sqlite3module = {
-    .m_base = PyModuleDef_HEAD_INIT,
-    .m_name = "_sqlite3",
-    .m_size = sizeof(pysqlite_state),
-    .m_methods = module_methods,
-};
+static int
+module_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    pysqlite_state *state = pysqlite_get_state(module);
+
+    // Exceptions
+    Py_VISIT(state->DataError);
+    Py_VISIT(state->DatabaseError);
+    Py_VISIT(state->Error);
+    Py_VISIT(state->IntegrityError);
+    Py_VISIT(state->InterfaceError);
+    Py_VISIT(state->InternalError);
+    Py_VISIT(state->NotSupportedError);
+    Py_VISIT(state->OperationalError);
+    Py_VISIT(state->ProgrammingError);
+    Py_VISIT(state->Warning);
+
+    // Types
+    Py_VISIT(state->ConnectionType);
+    Py_VISIT(state->CursorType);
+    Py_VISIT(state->PrepareProtocolType);
+    Py_VISIT(state->RowType);
+    Py_VISIT(state->StatementType);
+
+    // Misc
+    Py_VISIT(state->converters);
+    Py_VISIT(state->lru_cache);
+    Py_VISIT(state->psyco_adapters);
+
+    return 0;
+}
+
+static int
+module_clear(PyObject *module)
+{
+    pysqlite_state *state = pysqlite_get_state(module);
+
+    // Exceptions
+    Py_CLEAR(state->DataError);
+    Py_CLEAR(state->DatabaseError);
+    Py_CLEAR(state->Error);
+    Py_CLEAR(state->IntegrityError);
+    Py_CLEAR(state->InterfaceError);
+    Py_CLEAR(state->InternalError);
+    Py_CLEAR(state->NotSupportedError);
+    Py_CLEAR(state->OperationalError);
+    Py_CLEAR(state->ProgrammingError);
+    Py_CLEAR(state->Warning);
+
+    // Types
+    Py_CLEAR(state->ConnectionType);
+    Py_CLEAR(state->CursorType);
+    Py_CLEAR(state->PrepareProtocolType);
+    Py_CLEAR(state->RowType);
+    Py_CLEAR(state->StatementType);
+
+    // Misc
+    Py_CLEAR(state->converters);
+    Py_CLEAR(state->lru_cache);
+    Py_CLEAR(state->psyco_adapters);
+
+    return 0;
+}
+
+static void
+module_free(void *module)
+{
+    module_clear((PyObject *)module);
+}
 
 #define ADD_TYPE(module, type)                 \
 do {                                           \
@@ -438,26 +501,21 @@ do {                                                                   \
     ADD_TYPE(module, (PyTypeObject *)state->exc);                      \
 } while (0)
 
-PyMODINIT_FUNC PyInit__sqlite3(void)
+static int
+module_exec(PyObject *module)
 {
-    PyObject *module;
-
     if (sqlite3_libversion_number() < 3007015) {
         PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.7.15 or higher required");
-        return NULL;
+        return -1;
     }
 
     int rc = sqlite3_initialize();
     if (rc != SQLITE_OK) {
         PyErr_SetString(PyExc_ImportError, sqlite3_errstr(rc));
-        return NULL;
+        return -1;
     }
 
-    module = PyModule_Create(&_sqlite3module);
-    pysqlite_state *state = pysqlite_get_state(module);
-
-    if (!module ||
-        (pysqlite_row_setup_types(module) < 0) ||
+    if ((pysqlite_row_setup_types(module) < 0) ||
         (pysqlite_cursor_setup_types(module) < 0) ||
         (pysqlite_connection_setup_types(module) < 0) ||
         (pysqlite_statement_setup_types(module) < 0) ||
@@ -466,6 +524,7 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
         goto error;
     }
 
+    pysqlite_state *state = pysqlite_get_state(module);
     ADD_TYPE(module, state->ConnectionType);
     ADD_TYPE(module, state->CursorType);
     ADD_TYPE(module, state->PrepareProtocolType);
@@ -519,11 +578,31 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
         goto error;
     }
 
-    return module;
+    return 0;
 
 error:
     sqlite3_shutdown();
-    PyErr_SetString(PyExc_ImportError, MODULE_NAME ": init failed");
-    Py_XDECREF(module);
-    return NULL;
+    return -1;
+}
+
+static struct PyModuleDef_Slot module_slots[] = {
+    {Py_mod_exec, module_exec},
+    {0, NULL},
+};
+
+struct PyModuleDef _sqlite3module = {
+    .m_base = PyModuleDef_HEAD_INIT,
+    .m_name = "_sqlite3",
+    .m_size = sizeof(pysqlite_state),
+    .m_methods = module_methods,
+    .m_slots = module_slots,
+    .m_traverse = module_traverse,
+    .m_clear = module_clear,
+    .m_free = module_free,
+};
+
+PyMODINIT_FUNC
+PyInit__sqlite3(void)
+{
+    return PyModuleDef_Init(&_sqlite3module);
 }