[Python-checkins] bpo-46417: Factorize _PyExc_InitTypes() code (GH-30804)

vstinner webhook-mailer at python.org
Sat Jan 22 15:49:12 EST 2022


https://github.com/python/cpython/commit/f1bcdeaca6e912a2bec1fbcff76cc49e7f761d38
commit: f1bcdeaca6e912a2bec1fbcff76cc49e7f761d38
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022-01-22T21:48:56+01:00
summary:

bpo-46417: Factorize _PyExc_InitTypes() code (GH-30804)

Add 'static_exceptions' list to factorize code between
_PyExc_InitTypes() and _PyBuiltins_AddExceptions().

_PyExc_InitTypes() does nothing if it's not the main interpreter.

Sort exceptions in Lib/test/exception_hierarchy.txt.

files:
M Include/internal/pycore_exceptions.h
M Include/internal/pycore_pylifecycle.h
M Lib/test/exception_hierarchy.txt
M Objects/exceptions.c
M Python/pylifecycle.c

diff --git a/Include/internal/pycore_exceptions.h b/Include/internal/pycore_exceptions.h
index 1651966dad936..4a9df70913199 100644
--- a/Include/internal/pycore_exceptions.h
+++ b/Include/internal/pycore_exceptions.h
@@ -13,7 +13,7 @@ extern "C" {
 
 extern PyStatus _PyExc_InitState(PyInterpreterState *);
 extern PyStatus _PyExc_InitGlobalObjects(PyInterpreterState *);
-extern PyStatus _PyExc_InitTypes(PyInterpreterState *);
+extern int _PyExc_InitTypes(PyInterpreterState *);
 extern void _PyExc_Fini(PyInterpreterState *);
 
 
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index dfa8fd6bd0d28..35e560b42ee0a 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -59,7 +59,7 @@ extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options);
 extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config);
 extern int _PySys_UpdateConfig(PyThreadState *tstate);
 extern void _PySys_Fini(PyInterpreterState *interp);
-extern PyStatus _PyBuiltins_AddExceptions(PyObject * bltinmod);
+extern int _PyBuiltins_AddExceptions(PyObject * bltinmod);
 extern PyStatus _Py_HashRandomization_Init(const PyConfig *);
 
 extern PyStatus _PyImportZip_Init(PyThreadState *tstate);
diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt
index 5c0bfda373794..1eca123be0fec 100644
--- a/Lib/test/exception_hierarchy.txt
+++ b/Lib/test/exception_hierarchy.txt
@@ -1,12 +1,9 @@
 BaseException
- ├── SystemExit
- ├── KeyboardInterrupt
- ├── GeneratorExit
  ├── BaseExceptionGroup
+ ├── GeneratorExit
+ ├── KeyboardInterrupt
+ ├── SystemExit
  └── Exception
-      ├── ExceptionGroup [BaseExceptionGroup]
-      ├── StopIteration
-      ├── StopAsyncIteration
       ├── ArithmeticError
       │    ├── FloatingPointError
       │    ├── OverflowError
@@ -15,6 +12,7 @@ BaseException
       ├── AttributeError
       ├── BufferError
       ├── EOFError
+      ├── ExceptionGroup [BaseExceptionGroup]
       ├── ImportError
       │    └── ModuleNotFoundError
       ├── LookupError
@@ -43,6 +41,8 @@ BaseException
       ├── RuntimeError
       │    ├── NotImplementedError
       │    └── RecursionError
+      ├── StopAsyncIteration
+      ├── StopIteration
       ├── SyntaxError
       │    └── IndentationError
       │         └── TabError
@@ -54,14 +54,14 @@ BaseException
       │         ├── UnicodeEncodeError
       │         └── UnicodeTranslateError
       └── Warning
+           ├── BytesWarning
            ├── DeprecationWarning
+           ├── EncodingWarning
+           ├── FutureWarning
+           ├── ImportWarning
            ├── PendingDeprecationWarning
+           ├── ResourceWarning
            ├── RuntimeWarning
            ├── SyntaxWarning
-           ├── UserWarning
-           ├── FutureWarning
-           ├── ImportWarning
            ├── UnicodeWarning
-           ├── BytesWarning
-           ├── EncodingWarning
-           └── ResourceWarning
+           └── UserWarning
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 22a47131aa12c..f8f727c673c02 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -3421,92 +3421,121 @@ SimpleExtendsException(PyExc_Warning, ResourceWarning,
 #endif
 #endif /* MS_WINDOWS */
 
-PyStatus
+struct static_exception {
+    PyTypeObject *exc;
+    const char *name;
+};
+
+static struct static_exception static_exceptions[] = {
+#define ITEM(NAME) {&_PyExc_##NAME, #NAME}
+    // Level 1
+    ITEM(BaseException),
+
+    // Level 2: BaseException subclasses
+    ITEM(BaseExceptionGroup),
+    ITEM(Exception),
+    ITEM(GeneratorExit),
+    ITEM(KeyboardInterrupt),
+    ITEM(SystemExit),
+
+    // Level 3: Exception(BaseException) subclasses
+    ITEM(ArithmeticError),
+    ITEM(AssertionError),
+    ITEM(AttributeError),
+    ITEM(BufferError),
+    ITEM(EOFError),
+    //ITEM(ExceptionGroup),
+    ITEM(ImportError),
+    ITEM(LookupError),
+    ITEM(MemoryError),
+    ITEM(NameError),
+    ITEM(OSError),
+    ITEM(ReferenceError),
+    ITEM(RuntimeError),
+    ITEM(StopAsyncIteration),
+    ITEM(StopIteration),
+    ITEM(SyntaxError),
+    ITEM(SystemError),
+    ITEM(TypeError),
+    ITEM(ValueError),
+    ITEM(Warning),
+
+    // Level 4: ArithmeticError(Exception) subclasses
+    ITEM(FloatingPointError),
+    ITEM(OverflowError),
+    ITEM(ZeroDivisionError),
+
+    // Level 4: Warning(Exception) subclasses
+    ITEM(BytesWarning),
+    ITEM(DeprecationWarning),
+    ITEM(EncodingWarning),
+    ITEM(FutureWarning),
+    ITEM(ImportWarning),
+    ITEM(PendingDeprecationWarning),
+    ITEM(ResourceWarning),
+    ITEM(RuntimeWarning),
+    ITEM(SyntaxWarning),
+    ITEM(UnicodeWarning),
+    ITEM(UserWarning),
+
+    // Level 4: OSError(Exception) subclasses
+    ITEM(BlockingIOError),
+    ITEM(ChildProcessError),
+    ITEM(ConnectionError),
+    ITEM(FileExistsError),
+    ITEM(FileNotFoundError),
+    ITEM(InterruptedError),
+    ITEM(IsADirectoryError),
+    ITEM(NotADirectoryError),
+    ITEM(PermissionError),
+    ITEM(ProcessLookupError),
+    ITEM(TimeoutError),
+
+    // Level 4: Other subclasses
+    ITEM(IndentationError), // base: SyntaxError(Exception)
+    ITEM(IndexError),  // base: LookupError(Exception)
+    ITEM(KeyError),  // base: LookupError(Exception)
+    ITEM(ModuleNotFoundError), // base: ImportError(Exception)
+    ITEM(NotImplementedError),  // base: RuntimeError(Exception)
+    ITEM(RecursionError),  // base: RuntimeError(Exception)
+    ITEM(UnboundLocalError), // base: NameError(Exception)
+    ITEM(UnicodeError),  // base: ValueError(Exception)
+
+    // Level 5: ConnectionError(OSError) subclasses
+    ITEM(BrokenPipeError),
+    ITEM(ConnectionAbortedError),
+    ITEM(ConnectionRefusedError),
+    ITEM(ConnectionResetError),
+
+    // Level 5: IndentationError(SyntaxError) subclasses
+    ITEM(TabError),  // base: IndentationError
+
+    // Level 5: UnicodeError(ValueError) subclasses
+    ITEM(UnicodeDecodeError),
+    ITEM(UnicodeEncodeError),
+    ITEM(UnicodeTranslateError),
+#undef ITEM
+};
+
+
+int
 _PyExc_InitTypes(PyInterpreterState *interp)
 {
-#define PRE_INIT(TYPE) \
-    if (!(_PyExc_ ## TYPE.tp_flags & Py_TPFLAGS_READY)) { \
-        if (PyType_Ready(&_PyExc_ ## TYPE) < 0) { \
-            return _PyStatus_ERR("exceptions bootstrapping error."); \
-        } \
-        Py_INCREF(PyExc_ ## TYPE); \
+    if (!_Py_IsMainInterpreter(interp)) {
+        return 0;
     }
 
-    PRE_INIT(BaseException);
-    PRE_INIT(BaseExceptionGroup);
-    PRE_INIT(Exception);
-    PRE_INIT(TypeError);
-    PRE_INIT(StopAsyncIteration);
-    PRE_INIT(StopIteration);
-    PRE_INIT(GeneratorExit);
-    PRE_INIT(SystemExit);
-    PRE_INIT(KeyboardInterrupt);
-    PRE_INIT(ImportError);
-    PRE_INIT(ModuleNotFoundError);
-    PRE_INIT(OSError);
-    PRE_INIT(EOFError);
-    PRE_INIT(RuntimeError);
-    PRE_INIT(RecursionError);
-    PRE_INIT(NotImplementedError);
-    PRE_INIT(NameError);
-    PRE_INIT(UnboundLocalError);
-    PRE_INIT(AttributeError);
-    PRE_INIT(SyntaxError);
-    PRE_INIT(IndentationError);
-    PRE_INIT(TabError);
-    PRE_INIT(LookupError);
-    PRE_INIT(IndexError);
-    PRE_INIT(KeyError);
-    PRE_INIT(ValueError);
-    PRE_INIT(UnicodeError);
-    PRE_INIT(UnicodeEncodeError);
-    PRE_INIT(UnicodeDecodeError);
-    PRE_INIT(UnicodeTranslateError);
-    PRE_INIT(AssertionError);
-    PRE_INIT(ArithmeticError);
-    PRE_INIT(FloatingPointError);
-    PRE_INIT(OverflowError);
-    PRE_INIT(ZeroDivisionError);
-    PRE_INIT(SystemError);
-    PRE_INIT(ReferenceError);
-    PRE_INIT(MemoryError);
-    PRE_INIT(BufferError);
-    PRE_INIT(Warning);
-    PRE_INIT(UserWarning);
-    PRE_INIT(EncodingWarning);
-    PRE_INIT(DeprecationWarning);
-    PRE_INIT(PendingDeprecationWarning);
-    PRE_INIT(SyntaxWarning);
-    PRE_INIT(RuntimeWarning);
-    PRE_INIT(FutureWarning);
-    PRE_INIT(ImportWarning);
-    PRE_INIT(UnicodeWarning);
-    PRE_INIT(BytesWarning);
-    PRE_INIT(ResourceWarning);
-
-    /* OSError subclasses */
-    PRE_INIT(ConnectionError);
-
-    PRE_INIT(BlockingIOError);
-    PRE_INIT(BrokenPipeError);
-    PRE_INIT(ChildProcessError);
-    PRE_INIT(ConnectionAbortedError);
-    PRE_INIT(ConnectionRefusedError);
-    PRE_INIT(ConnectionResetError);
-    PRE_INIT(FileExistsError);
-    PRE_INIT(FileNotFoundError);
-    PRE_INIT(IsADirectoryError);
-    PRE_INIT(NotADirectoryError);
-    PRE_INIT(InterruptedError);
-    PRE_INIT(PermissionError);
-    PRE_INIT(ProcessLookupError);
-    PRE_INIT(TimeoutError);
+    for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
+        PyTypeObject *exc = static_exceptions[i].exc;
 
-    return _PyStatus_OK();
-
-#undef PRE_INIT
+        if (PyType_Ready(exc) < 0) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
+
 PyStatus
 _PyExc_InitGlobalObjects(PyInterpreterState *interp)
 {
@@ -3569,12 +3598,28 @@ _PyExc_InitState(PyInterpreterState *interp)
 
 
 /* Add exception types to the builtins module */
-PyStatus
+int
 _PyBuiltins_AddExceptions(PyObject *bltinmod)
 {
-#define POST_INIT(TYPE) \
-    if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) { \
-        return _PyStatus_ERR("Module dictionary insertion problem."); \
+    PyObject *mod_dict = PyModule_GetDict(bltinmod);
+    if (mod_dict == NULL) {
+        return -1;
+    }
+
+    for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
+        struct static_exception item = static_exceptions[i];
+
+        if (PyDict_SetItemString(mod_dict, item.name, (PyObject*)item.exc)) {
+            return -1;
+        }
+    }
+
+    PyObject *PyExc_ExceptionGroup = create_exception_group_class();
+    if (!PyExc_ExceptionGroup) {
+        return -1;
+    }
+    if (PyDict_SetItemString(mod_dict, "ExceptionGroup", PyExc_ExceptionGroup)) {
+        return -1;
     }
 
 #define INIT_ALIAS(NAME, TYPE) \
@@ -3582,103 +3627,20 @@ _PyBuiltins_AddExceptions(PyObject *bltinmod)
         Py_INCREF(PyExc_ ## TYPE); \
         Py_XDECREF(PyExc_ ## NAME); \
         PyExc_ ## NAME = PyExc_ ## TYPE; \
-        if (PyDict_SetItemString(bdict, # NAME, PyExc_ ## NAME)) { \
-            return _PyStatus_ERR("Module dictionary insertion problem."); \
+        if (PyDict_SetItemString(mod_dict, # NAME, PyExc_ ## NAME)) { \
+            return -1; \
         } \
     } while (0)
 
-    PyObject *bdict;
-
-    bdict = PyModule_GetDict(bltinmod);
-    if (bdict == NULL) {
-        return _PyStatus_ERR("exceptions bootstrapping error.");
-    }
-
-    PyObject *PyExc_ExceptionGroup = create_exception_group_class();
-    if (!PyExc_ExceptionGroup) {
-        return _PyStatus_ERR("exceptions bootstrapping error.");
-    }
-
-    POST_INIT(BaseException);
-    POST_INIT(Exception);
-    POST_INIT(BaseExceptionGroup);
-    POST_INIT(ExceptionGroup);
-    POST_INIT(TypeError);
-    POST_INIT(StopAsyncIteration);
-    POST_INIT(StopIteration);
-    POST_INIT(GeneratorExit);
-    POST_INIT(SystemExit);
-    POST_INIT(KeyboardInterrupt);
-    POST_INIT(ImportError);
-    POST_INIT(ModuleNotFoundError);
-    POST_INIT(OSError);
     INIT_ALIAS(EnvironmentError, OSError);
     INIT_ALIAS(IOError, OSError);
 #ifdef MS_WINDOWS
     INIT_ALIAS(WindowsError, OSError);
 #endif
-    POST_INIT(EOFError);
-    POST_INIT(RuntimeError);
-    POST_INIT(RecursionError);
-    POST_INIT(NotImplementedError);
-    POST_INIT(NameError);
-    POST_INIT(UnboundLocalError);
-    POST_INIT(AttributeError);
-    POST_INIT(SyntaxError);
-    POST_INIT(IndentationError);
-    POST_INIT(TabError);
-    POST_INIT(LookupError);
-    POST_INIT(IndexError);
-    POST_INIT(KeyError);
-    POST_INIT(ValueError);
-    POST_INIT(UnicodeError);
-    POST_INIT(UnicodeEncodeError);
-    POST_INIT(UnicodeDecodeError);
-    POST_INIT(UnicodeTranslateError);
-    POST_INIT(AssertionError);
-    POST_INIT(ArithmeticError);
-    POST_INIT(FloatingPointError);
-    POST_INIT(OverflowError);
-    POST_INIT(ZeroDivisionError);
-    POST_INIT(SystemError);
-    POST_INIT(ReferenceError);
-    POST_INIT(MemoryError);
-    POST_INIT(BufferError);
-    POST_INIT(Warning);
-    POST_INIT(UserWarning);
-    POST_INIT(EncodingWarning);
-    POST_INIT(DeprecationWarning);
-    POST_INIT(PendingDeprecationWarning);
-    POST_INIT(SyntaxWarning);
-    POST_INIT(RuntimeWarning);
-    POST_INIT(FutureWarning);
-    POST_INIT(ImportWarning);
-    POST_INIT(UnicodeWarning);
-    POST_INIT(BytesWarning);
-    POST_INIT(ResourceWarning);
-
-    /* OSError subclasses */
-    POST_INIT(ConnectionError);
-
-    POST_INIT(BlockingIOError);
-    POST_INIT(BrokenPipeError);
-    POST_INIT(ChildProcessError);
-    POST_INIT(ConnectionAbortedError);
-    POST_INIT(ConnectionRefusedError);
-    POST_INIT(ConnectionResetError);
-    POST_INIT(FileExistsError);
-    POST_INIT(FileNotFoundError);
-    POST_INIT(IsADirectoryError);
-    POST_INIT(NotADirectoryError);
-    POST_INIT(InterruptedError);
-    POST_INIT(PermissionError);
-    POST_INIT(ProcessLookupError);
-    POST_INIT(TimeoutError);
-
-    return _PyStatus_OK();
 
-#undef POST_INIT
 #undef INIT_ALIAS
+
+    return 0;
 }
 
 void
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index a53f532e9e202..aca3b1a5fd1a4 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -740,9 +740,8 @@ pycore_init_types(PyInterpreterState *interp)
         return status;
     }
 
-    status = _PyExc_InitTypes(interp);
-    if (_PyStatus_EXCEPTION(status)) {
-        return status;
+    if (_PyExc_InitTypes(interp) < 0) {
+        return _PyStatus_ERR("failed to initialize an exception type");
     }
 
     status = _PyExc_InitGlobalObjects(interp);
@@ -790,9 +789,8 @@ pycore_init_builtins(PyThreadState *tstate)
     Py_INCREF(builtins_dict);
     interp->builtins = builtins_dict;
 
-    PyStatus status = _PyBuiltins_AddExceptions(bimod);
-    if (_PyStatus_EXCEPTION(status)) {
-        return status;
+    if (_PyBuiltins_AddExceptions(bimod) < 0) {
+        return _PyStatus_ERR("failed to add exceptions to builtins");
     }
 
     interp->builtins_copy = PyDict_Copy(interp->builtins);



More information about the Python-checkins mailing list