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 index 00000000000000..bcb3307d37bc2f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-10-27-13-28-52.bpo-42064.UK4jgV.rst @@ -0,0 +1,2 @@ +Convert :mod:`sqlite3` to multi-phase initialisation (PEP 489). Patches by +Erlend E. Aasland. diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index e41ac0fc1ab733..e18a18b436666f 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -393,12 +393,75 @@ static int add_integer_constants(PyObject *module) { return ret; } -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 { \ @@ -416,26 +479,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) || @@ -444,6 +502,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); @@ -497,11 +556,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); }