Close issue #6210: Implement PEP 409
diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt
index f9e4d3b..b64c650 100644
--- a/Doc/ACKS.txt
+++ b/Doc/ACKS.txt
@@ -62,6 +62,7 @@
    * Stefan Franke
    * Jim Fulton
    * Peter Funk
+   * Ethan Furman
    * Lele Gaifax
    * Matthew Gallagher
    * Gabriel Genellina
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index c7252ed..fd7aee7 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -421,17 +421,24 @@
 
 .. c:function:: PyObject* PyException_GetCause(PyObject *ex)
 
-   Return the cause (another exception instance set by ``raise ... from ...``)
-   associated with the exception as a new reference, as accessible from Python
-   through :attr:`__cause__`.  If there is no cause associated, this returns
-   *NULL*.
+   Return the cause (either an exception instance, or :const:`None`,
+   set by ``raise ... from ...``) associated with the exception as a new
+   reference, as accessible from Python through :attr:`__cause__`.
+
+   If there is no cause associated, this returns *NULL* (from Python
+   ``__cause__ is Ellipsis``).  If the cause is :const:`None`, the default
+   exception display routines stop showing the context chain.
 
 
 .. c:function:: void PyException_SetCause(PyObject *ex, PyObject *ctx)
 
    Set the cause associated with the exception to *ctx*.  Use *NULL* to clear
-   it.  There is no type check to make sure that *ctx* is an exception instance.
-   This steals a reference to *ctx*.
+   it.  There is no type check to make sure that *ctx* is either an exception
+   instance or :const:`None`.  This steals a reference to *ctx*.
+
+   If the cause is set to :const:`None` the default exception display
+   routines will not display this exception's context, and will not follow the
+   chain any further.
 
 
 .. _unicodeexceptions:
diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
index 3f1a30d..7e3a0c3 100644
--- a/Doc/library/exceptions.rst
+++ b/Doc/library/exceptions.rst
@@ -34,6 +34,24 @@
 defining exceptions is available in the Python Tutorial under
 :ref:`tut-userexceptions`.
 
+When raising (or re-raising) an exception in an :keyword:`except` clause
+:attr:`__context__` is automatically set to the last exception caught; if the
+new exception is not handled the traceback that is eventually displayed will
+include the originating exception(s) and the final exception.
+
+This implicit exception chain can be made explicit by using :keyword:`from`
+with :keyword:`raise`.  The single argument to :keyword:`from` must be an
+exception or :const:`None`, and it will bet set as :attr:`__cause__` on the
+raised exception.  If :attr:`__cause__` is an exception it will be displayed
+instead of :attr:`__context__`; if :attr:`__cause__` is None,
+:attr:`__context__` will not be displayed by the default exception handling
+code.  (Note:  the default value for :attr:`__context__` is :const:`None`,
+while the default value for :attr:`__cause__` is :const:`Ellipsis`.)
+
+In either case, the default exception handling code will not display
+any of the remaining links in the :attr:`__context__` chain if
+:attr:`__cause__` has been set.
+
 
 Base classes
 ------------
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index be06595..1526a0a 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -2985,10 +2985,11 @@
 The Ellipsis Object
 -------------------
 
-This object is commonly used by slicing (see :ref:`slicings`).  It supports no
-special operations.  There is exactly one ellipsis object, named
-:const:`Ellipsis` (a built-in name).  ``type(Ellipsis)()`` produces the
-:const:`Ellipsis` singleton.
+This object is commonly used by slicing (see :ref:`slicings`), but may also
+be used in other situations where a sentinel value other than :const:`None`
+is needed.  It supports no special operations.  There is exactly one ellipsis
+object, named :const:`Ellipsis` (a built-in name).  ``type(Ellipsis)()``
+produces the :const:`Ellipsis` singleton.
 
 It is written as ``Ellipsis`` or ``...``.
 
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index 560331f..9023dfa 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -254,6 +254,9 @@
 PEP 380: Syntax for Delegating to a Subgenerator
 ================================================
 
+:pep:`380` - Syntax for Delegating to a Subgenerator
+ PEP written by Greg Ewing.
+
 PEP 380 adds the ``yield from`` expression, allowing a generator to delegate
 part of its operations to another generator. This allows a section of code
 containing 'yield' to be factored out and placed in another generator.
@@ -267,6 +270,67 @@
 Nick Coghlan)
 
 
+PEP 409: Suppressing exception context
+======================================
+
+:pep:`409` - Suppressing exception context
+ PEP written by Ethan Furman, implemented by Ethan Furman and Nick Coghlan.
+
+PEP 409 introduces new syntax that allows the display of the chained
+exception context to be disabled. This allows cleaner error messages in
+applications that convert between exception types::
+
+    >>> class D:
+    ...     def __init__(self, extra):
+    ...         self._extra_attributes = extra
+    ...     def __getattr__(self, attr):
+    ...         try:
+    ...             return self._extra_attributes[attr]
+    ...         except KeyError:
+    ...             raise AttributeError(attr) from None
+    ...
+    >>> D({}).x
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in <module>
+      File "<stdin>", line 8, in __getattr__
+    AttributeError: x
+
+Without the ``from None`` suffix to suppress the cause, the original
+exception would be displayed by default::
+
+    >>> class C:
+    ...     def __init__(self, extra):
+    ...         self._extra_attributes = extra
+    ...     def __getattr__(self, attr):
+    ...         try:
+    ...             return self._extra_attributes[attr]
+    ...         except KeyError:
+    ...             raise AttributeError(attr)
+    ...
+    >>> C({}).x
+    Traceback (most recent call last):
+      File "<stdin>", line 6, in __getattr__
+    KeyError: 'x'
+
+    During handling of the above exception, another exception occurred:
+
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in <module>
+      File "<stdin>", line 8, in __getattr__
+    AttributeError: x
+
+No debugging capability is lost, as the original exception context remains
+available if needed (for example, if an intervening library has incorrectly
+suppressed valuable underlying details)::
+
+    >>> try:
+    ...     D({}).x
+    ... except AttributeError as exc:
+    ...     print(repr(exc.__context__))
+    ...
+    KeyError('x',)
+
+
 PEP 3155: Qualified name for classes and functions
 ==================================================