[Python-checkins] bpo-39037: Fix lookup order of magic methods in with statement documentation (GH-17608)

Miss Islington (bot) webhook-mailer at python.org
Mon Dec 30 00:31:23 EST 2019


https://github.com/python/cpython/commit/cbfafa3e3625dae96ce392c88c793f8af55167bf
commit: cbfafa3e3625dae96ce392c88c793f8af55167bf
branch: 3.8
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2019-12-29T21:31:18-08:00
summary:

bpo-39037: Fix lookup order of magic methods in with statement documentation (GH-17608)


* __enter__ is now looked up before __exit__ to give a more intuitive error message
* add pseudo-code equivalent for the with statement
* fix pseudo-code for the async with statement to use a finally clause
* use SUITE rather than BLOCK for consistency with the language grammar

Patch by Géry Ogam.
(cherry picked from commit 226e6e7d4326cf91ef37e13528eb1f62de1bb832)

Co-authored-by: Géry Ogam <gery.ogam at gmail.com>

files:
M Doc/reference/compound_stmts.rst

diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst
index 988eec6d254e1..564d6cc42136d 100644
--- a/Doc/reference/compound_stmts.rst
+++ b/Doc/reference/compound_stmts.rst
@@ -399,6 +399,8 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo
 #. The context expression (the expression given in the :token:`with_item`) is
    evaluated to obtain a context manager.
 
+#. The context manager's :meth:`__enter__` is loaded for later use.
+
 #. The context manager's :meth:`__exit__` is loaded for later use.
 
 #. The context manager's :meth:`__enter__` method is invoked.
@@ -430,17 +432,41 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo
    value from :meth:`__exit__` is ignored, and execution proceeds at the normal
    location for the kind of exit that was taken.
 
+The following code::
+
+    with EXPRESSION as TARGET:
+        SUITE
+
+is semantically equivalent to::
+
+    manager = (EXPRESSION)
+    enter = type(manager).__enter__
+    exit = type(manager).__exit__
+    value = enter(manager)
+    hit_except = False
+
+    try:
+        TARGET = value
+        SUITE
+    except:
+        hit_except = True
+        if not exit(manager, *sys.exc_info()):
+            raise
+    finally:
+        if not hit_except:
+            exit(manager, None, None, None)
+
 With more than one item, the context managers are processed as if multiple
 :keyword:`with` statements were nested::
 
    with A() as a, B() as b:
-       suite
+       SUITE
 
-is equivalent to ::
+is semantically equivalent to::
 
    with A() as a:
        with B() as b:
-           suite
+           SUITE
 
 .. versionchanged:: 3.1
    Support for multiple context expressions.
@@ -772,24 +798,25 @@ iterators.
 The following code::
 
     async for TARGET in ITER:
-        BLOCK
+        SUITE
     else:
-        BLOCK2
+        SUITE2
 
 Is semantically equivalent to::
 
     iter = (ITER)
     iter = type(iter).__aiter__(iter)
     running = True
+
     while running:
         try:
             TARGET = await type(iter).__anext__(iter)
         except StopAsyncIteration:
             running = False
         else:
-            BLOCK
+            SUITE
     else:
-        BLOCK2
+        SUITE2
 
 See also :meth:`__aiter__` and :meth:`__anext__` for details.
 
@@ -811,23 +838,27 @@ able to suspend execution in its *enter* and *exit* methods.
 
 The following code::
 
-    async with EXPR as VAR:
-        BLOCK
+    async with EXPRESSION as TARGET:
+        SUITE
 
-Is semantically equivalent to::
+is semantically equivalent to::
 
-    mgr = (EXPR)
-    aexit = type(mgr).__aexit__
-    aenter = type(mgr).__aenter__(mgr)
+    manager = (EXPRESSION)
+    aexit = type(manager).__aexit__
+    aenter = type(manager).__aenter__
+    value = await aenter(manager)
+    hit_except = False
 
-    VAR = await aenter
     try:
-        BLOCK
+        TARGET = value
+        SUITE
     except:
-        if not await aexit(mgr, *sys.exc_info()):
+        hit_except = True
+        if not await aexit(manager, *sys.exc_info()):
             raise
-    else:
-        await aexit(mgr, None, None, None)
+    finally:
+        if not hit_except:
+            await aexit(manager, None, None, None)
 
 See also :meth:`__aenter__` and :meth:`__aexit__` for details.
 



More information about the Python-checkins mailing list