Repository: python/cpython
Pull request: gh-94393: Remove unneeded module state from _json


<!-- gh-issue-number: gh-94393 -->
* Issue: gh-94393
<!-- /gh-issue-number -->


Problem statement:
Remove unneeded module state from `_json` module
The `_json` module got multi-phase initialisation and heap types in GH-17835. However, there is no need for it to have module state. We can remove approx. 50 lines of code, and get rid of the unneeded state allocation.

Hints from issue discussion:

Commit message: gh-94393: Remove unneeded module state from _json

Patch to review:
diff --git a/Modules/_json.c b/Modules/_json.c
index 9464b9f498ede5..f283d55b41eff9 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -14,19 +14,6 @@
 #include "structmember.h"         // PyMemberDef
 #include "pycore_accu.h"
 
-typedef struct {
-    PyObject *PyScannerType;
-    PyObject *PyEncoderType;
-} _jsonmodulestate;
-
-static inline _jsonmodulestate*
-get_json_state(PyObject *module)
-{
-    void *state = PyModule_GetState(module);
-    assert(state != NULL);
-    return (_jsonmodulestate *)state;
-}
-
 
 typedef struct _PyScannerObject {
     PyObject_HEAD
@@ -1815,70 +1802,41 @@ PyDoc_STRVAR(module_doc,
 static int
 _json_exec(PyObject *module)
 {
-    _jsonmodulestate *state = get_json_state(module);
-
-    state->PyScannerType = PyType_FromSpec(&PyScannerType_spec);
-    if (state->PyScannerType == NULL) {
+    PyObject *PyScannerType = PyType_FromSpec(&PyScannerType_spec);
+    if (PyScannerType == NULL) {
         return -1;
     }
-    Py_INCREF(state->PyScannerType);
-    if (PyModule_AddObject(module, "make_scanner", state->PyScannerType) < 0) {
-        Py_DECREF(state->PyScannerType);
+    int rc = PyModule_AddObjectRef(module, "make_scanner", PyScannerType);
+    Py_DECREF(PyScannerType);
+    if (rc < 0) {
         return -1;
     }
 
-    state->PyEncoderType = PyType_FromSpec(&PyEncoderType_spec);
-    if (state->PyEncoderType == NULL) {
+    PyObject *PyEncoderType = PyType_FromSpec(&PyEncoderType_spec);
+    if (PyEncoderType == NULL) {
         return -1;
     }
-    Py_INCREF(state->PyEncoderType);
-    if (PyModule_AddObject(module, "make_encoder", state->PyEncoderType) < 0) {
-        Py_DECREF(state->PyEncoderType);
+    rc = PyModule_AddObjectRef(module, "make_encoder", PyEncoderType);
+    Py_DECREF(PyEncoderType);
+    if (rc < 0) {
         return -1;
     }
 
     return 0;
 }
 
-static int
-_jsonmodule_traverse(PyObject *module, visitproc visit, void *arg)
-{
-    _jsonmodulestate *state = get_json_state(module);
-    Py_VISIT(state->PyScannerType);
-    Py_VISIT(state->PyEncoderType);
-    return 0;
-}
-
-static int
-_jsonmodule_clear(PyObject *module)
-{
-    _jsonmodulestate *state = get_json_state(module);
-    Py_CLEAR(state->PyScannerType);
-    Py_CLEAR(state->PyEncoderType);
-    return 0;
-}
-
-static void
-_jsonmodule_free(void *module)
-{
-    _jsonmodule_clear((PyObject *)module);
-}
-
 static PyModuleDef_Slot _json_slots[] = {
     {Py_mod_exec, _json_exec},
     {0, NULL}
 };
 
 static struct PyModuleDef jsonmodule = {
-        PyModuleDef_HEAD_INIT,
-        "_json",
-        module_doc,
-        sizeof(_jsonmodulestate),
-        speedups_methods,
-        _json_slots,
-        _jsonmodule_traverse,
-        _jsonmodule_clear,
-        _jsonmodule_free,
+    .m_base = PyModuleDef_HEAD_INIT,
+    .m_name = "_json",
+    .m_doc = module_doc,
+    .m_size = 0,
+    .m_methods = speedups_methods,
+    .m_slots = _json_slots,
 };
 
 PyMODINIT_FUNC


Code review comments:
diff_hunk: @@ -1815,70 +1802,41 @@ PyDoc_STRVAR(module_doc,
 static int
 _json_exec(PyObject *module)
 {
-    _jsonmodulestate *state = get_json_state(module);
-
-    state->PyScannerType = PyType_FromSpec(&PyScannerType_spec);
-    if (state->PyScannerType == NULL) {
+    PyObject *PyScannerType = PyType_FromSpec(&PyScannerType_spec);
+    if (PyScannerType == NULL) {
         return -1;
     }
-    Py_INCREF(state->PyScannerType);
-    if (PyModule_AddObject(module, "make_scanner", state->PyScannerType) < 0) {
-        Py_DECREF(state->PyScannerType);
+    int rc = PyModule_AddObjectRef(module, "make_scanner", PyScannerType);
+    Py_DECREF(PyScannerType);
+    if (rc < 0) {
         return -1;
     }
 
-    state->PyEncoderType = PyType_FromSpec(&PyEncoderType_spec);
-    if (state->PyEncoderType == NULL) {
+    PyObject *PyEncoderType = PyType_FromSpec(&PyEncoderType_spec);
+    if (PyEncoderType == NULL) {
         return -1;
     }
-    Py_INCREF(state->PyEncoderType);
-    if (PyModule_AddObject(module, "make_encoder", state->PyEncoderType) < 0) {
-        Py_DECREF(state->PyEncoderType);
+    rc = PyModule_AddObjectRef(module, "make_encoder", PyEncoderType);
+    Py_DECREF(PyEncoderType);
+    if (rc < 0) {
         return -1;
     }
 
     return 0;
 }
 
-static int
-_jsonmodule_traverse(PyObject *module, visitproc visit, void *arg)
-{
-    _jsonmodulestate *state = get_json_state(module);
-    Py_VISIT(state->PyScannerType);
-    Py_VISIT(state->PyEncoderType);
-    return 0;
-}
-
-static int
-_jsonmodule_clear(PyObject *module)
-{
-    _jsonmodulestate *state = get_json_state(module);
-    Py_CLEAR(state->PyScannerType);
-    Py_CLEAR(state->PyEncoderType);
-    return 0;
-}
-
-static void
-_jsonmodule_free(void *module)
-{
-    _jsonmodule_clear((PyObject *)module);
-}
-
 static PyModuleDef_Slot _json_slots[] = {
     {Py_mod_exec, _json_exec},
     {0, NULL}
 };
 
 static struct PyModuleDef jsonmodule = {
-        PyModuleDef_HEAD_INIT,
-        "_json",
-        module_doc,
-        sizeof(_jsonmodulestate),
-        speedups_methods,
-        _json_slots,
-        _jsonmodule_traverse,
-        _jsonmodule_clear,
-        _jsonmodule_free,
+    .m_base = PyModuleDef_HEAD_INIT,
+    .m_name = "_json",
+    .m_doc = module_doc,
+    .m_size = 0,
path: Modules/_json.c
text: @user1:
The initializer can be left out if it's 0, just like the traverse/clear/free functions.

@author:
```suggestion
```