[3.10] bpo-45083: Include the exception class qualname when formatting an exception (GH-28119) (GH-28134)

Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
(cherry picked from commit b4b6342848ec0459182a992151099252434cc619)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>

* Use a private version of _PyType_GetQualName

Co-authored-by: Ɓukasz Langa <lukasz@langa.pl>
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index f00e3eb..8d9f640 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -13,7 +13,8 @@
 #include "pycore_ast.h"           // PyAST_mod2obj
 #include "pycore_compile.h"       // _PyAST_Compile()
 #include "pycore_interp.h"        // PyInterpreterState.importlib
-#include "pycore_object.h"        // _PyDebug_PrintTotalRefs()
+#include "pycore_object.h"        // _PyDebug_PrintTotalRefs(),
+                                  // _PyType_GetQualName()
 #include "pycore_parser.h"        // _PyParser_ASTFromString()
 #include "pycore_pyerrors.h"      // _PyErr_Fetch, _Py_Offer_Suggestions
 #include "pycore_pylifecycle.h"   // _Py_UnhandledKeyboardInterrupt
@@ -961,36 +962,37 @@ print_exception(PyObject *f, PyObject *value)
         /* Don't do anything else */
     }
     else {
-        PyObject* moduleName;
-        const char *className;
+        PyObject* modulename;
+
         _Py_IDENTIFIER(__module__);
         assert(PyExceptionClass_Check(type));
-        className = PyExceptionClass_Name(type);
-        if (className != NULL) {
-            const char *dot = strrchr(className, '.');
-            if (dot != NULL)
-                className = dot+1;
-        }
 
-        moduleName = _PyObject_GetAttrId(type, &PyId___module__);
-        if (moduleName == NULL || !PyUnicode_Check(moduleName))
+        modulename = _PyObject_GetAttrId(type, &PyId___module__);
+        if (modulename == NULL || !PyUnicode_Check(modulename))
         {
-            Py_XDECREF(moduleName);
+            Py_XDECREF(modulename);
+            PyErr_Clear();
             err = PyFile_WriteString("<unknown>", f);
         }
         else {
-            if (!_PyUnicode_EqualToASCIIId(moduleName, &PyId_builtins))
+            if (!_PyUnicode_EqualToASCIIId(modulename, &PyId_builtins))
             {
-                err = PyFile_WriteObject(moduleName, f, Py_PRINT_RAW);
+                err = PyFile_WriteObject(modulename, f, Py_PRINT_RAW);
                 err += PyFile_WriteString(".", f);
             }
-            Py_DECREF(moduleName);
+            Py_DECREF(modulename);
         }
         if (err == 0) {
-            if (className == NULL)
-                      err = PyFile_WriteString("<unknown>", f);
-            else
-                      err = PyFile_WriteString(className, f);
+            PyObject* qualname = _PyType_GetQualName((PyTypeObject *)type);
+            if (qualname == NULL || !PyUnicode_Check(qualname)) {
+                Py_XDECREF(qualname);
+                PyErr_Clear();
+                err = PyFile_WriteString("<unknown>", f);
+            }
+            else {
+                err = PyFile_WriteObject(qualname, f, Py_PRINT_RAW);
+                Py_DECREF(qualname);
+            }
         }
     }
     if (err == 0 && (value != Py_None)) {