PEP 415: Implement suppression of __context__ display with an exception attribute

This replaces the original PEP 409 implementation. See #14133.
diff --git a/Python/ceval.c b/Python/ceval.c
index b9a006b..718bb32 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3572,23 +3572,26 @@
 
     if (cause) {
         PyObject *fixed_cause;
-        int result;
         if (PyExceptionClass_Check(cause)) {
             fixed_cause = PyObject_CallObject(cause, NULL);
             if (fixed_cause == NULL)
                 goto raise_error;
-            Py_CLEAR(cause);
-        } else {
-            /* Let "exc.__cause__ = cause" handle all further checks */
-            fixed_cause = cause;
-            cause = NULL; /* Steal the reference */
+            Py_DECREF(cause);
         }
-        /* We retain ownership of the reference to fixed_cause */
-        result = _PyException_SetCauseChecked(value, fixed_cause);
-        Py_DECREF(fixed_cause);
-        if (result < 0) {
+        else if (PyExceptionInstance_Check(cause)) {
+            fixed_cause = cause;
+        }
+        else if (cause == Py_None) {
+            Py_DECREF(cause);
+            fixed_cause = NULL;
+        }
+        else {
+            PyErr_SetString(PyExc_TypeError,
+                            "exception causes must derive from "
+                            "BaseException");
             goto raise_error;
         }
+        PyException_SetCause(value, fixed_cause);
     }
 
     PyErr_SetObject(type, value);
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index cd3cf5c..d9eb5e7 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -1761,11 +1761,7 @@
         else if (PyExceptionInstance_Check(value)) {
             cause = PyException_GetCause(value);
             context = PyException_GetContext(value);
-            if (cause && cause == Py_None) {
-                /* print neither cause nor context */
-                ;
-            }
-            else if (cause) {
+            if (cause) {
                 res = PySet_Contains(seen, cause);
                 if (res == -1)
                     PyErr_Clear();
@@ -1776,7 +1772,8 @@
                         cause_message, f);
                 }
             }
-            else if (context) {
+            else if (context &&
+                !((PyBaseExceptionObject *)value)->suppress_context) {
                 res = PySet_Contains(seen, context);
                 if (res == -1)
                     PyErr_Clear();