From 178721a906547c9fc8b7fb0570d4047762167d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sat, 14 Dec 2019 18:32:31 +0100 Subject: [PATCH 1/8] Replace the else clause with a finally clause The else clause should instead be a finally clause to also handle the case when there is a non-local goto statement (break, continue, return) in suite (cf. https://stackoverflow.com/questions/59322585/what-is-the-exact-try-statement-equivalent-of-the-with-statement-in-python). --- Doc/reference/compound_stmts.rst | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 988eec6d254e10..2d98aa9b6caa8a 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -811,23 +811,26 @@ 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__ + value = type(manager).__aenter__(manager) + target = await value + exception = False - VAR = await aenter try: - BLOCK + suite except: - if not await aexit(mgr, *sys.exc_info()): + exception = True + if not await aexit(manager, *sys.exc_info()): raise - else: - await aexit(mgr, None, None, None) + finally: + if not exception: + await aexit(manager, None, None, None) See also :meth:`__aenter__` and :meth:`__aexit__` for details. From 0fd6b3e3b99177926f36663932fd5dbb36f3d374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sat, 14 Dec 2019 18:54:59 +0100 Subject: [PATCH 2/8] Add the try statement equivalent code of a with statement --- Doc/reference/compound_stmts.rst | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 2d98aa9b6caa8a..82ccf1757cb6c8 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -430,13 +430,36 @@ 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) + value = type(manager).__enter__(manager) + exit = type(manager).__exit__ + target = value + exception = False + + try: + suite + except: + exception = True + if not exit(manager, *sys.exc_info()): + raise + finally: + if not exception: + 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 -is equivalent to :: +is semantically equivalent to:: with A() as a: with B() as b: From 28f27a4fb773a78e0ca42eed48b71063b303b71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sat, 14 Dec 2019 18:59:31 +0100 Subject: [PATCH 3/8] Fix wrong trial order of __exit__ and __enter__ in the with statement --- Doc/reference/compound_stmts.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 82ccf1757cb6c8..c7afda4aee60e1 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -399,10 +399,10 @@ 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:`__exit__` is loaded for later use. - #. The context manager's :meth:`__enter__` method is invoked. +#. The context manager's :meth:`__exit__` is loaded for later use. + #. If a target was included in the :keyword:`with` statement, the return value from :meth:`__enter__` is assigned to it. From 41b99c1bd205f25f6b7f606b2378769d0a5f6514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sat, 14 Dec 2019 21:44:54 +0100 Subject: [PATCH 4/8] Add review suggestions --- Doc/reference/compound_stmts.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index c7afda4aee60e1..0cb578f67db4ad 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -398,11 +398,13 @@ 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__` method is invoked. + +#. 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. + #. If a target was included in the :keyword:`with` statement, the return value from :meth:`__enter__` is assigned to it. @@ -438,9 +440,10 @@ The following code:: is semantically equivalent to:: manager = (expression) - value = type(manager).__enter__(manager) + enter = type(manager).__enter__ exit = type(manager).__exit__ - target = value + value = enter(manager) + target = value # only if `as target` is present in the with statement exception = False try: @@ -841,8 +844,9 @@ is semantically equivalent to:: manager = (expression) aexit = type(manager).__aexit__ - value = type(manager).__aenter__(manager) - target = await value + aenter = type(manager).__aenter__ + value = await aenter(manager) + target = value # only if `as target` is present in the with statement exception = False try: From d39efb8c6dc88387dea56bf16165b24b3f6273b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sun, 15 Dec 2019 11:43:41 +0100 Subject: [PATCH 5/8] Move the target assignment in the try clause --- Doc/reference/compound_stmts.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 0cb578f67db4ad..74a0a8f74ed309 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -443,10 +443,10 @@ is semantically equivalent to:: enter = type(manager).__enter__ exit = type(manager).__exit__ value = enter(manager) - target = value # only if `as target` is present in the with statement exception = False try: + target = value # only if `as target` is present in the with statement suite except: exception = True @@ -846,10 +846,10 @@ is semantically equivalent to:: aexit = type(manager).__aexit__ aenter = type(manager).__aenter__ value = await aenter(manager) - target = value # only if `as target` is present in the with statement exception = False try: + target = value # only if `as target` is present in the with statement suite except: exception = True From be1aa1802d57d1b18ac14c5038918b9bd7bd8e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Sun, 15 Dec 2019 14:32:26 +0100 Subject: [PATCH 6/8] Rename a variable --- Doc/reference/compound_stmts.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 74a0a8f74ed309..dda86b73802704 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -443,17 +443,17 @@ is semantically equivalent to:: enter = type(manager).__enter__ exit = type(manager).__exit__ value = enter(manager) - exception = False + hit_except = False try: target = value # only if `as target` is present in the with statement suite except: - exception = True + hit_except = True if not exit(manager, *sys.exc_info()): raise finally: - if not exception: + if not hit_except: exit(manager, None, None, None) With more than one item, the context managers are processed as if multiple @@ -846,17 +846,17 @@ is semantically equivalent to:: aexit = type(manager).__aexit__ aenter = type(manager).__aenter__ value = await aenter(manager) - exception = False + hit_except = False try: target = value # only if `as target` is present in the with statement suite except: - exception = True + hit_except = True if not await aexit(manager, *sys.exc_info()): raise finally: - if not exception: + if not hit_except: await aexit(manager, None, None, None) See also :meth:`__aenter__` and :meth:`__aexit__` for details. From f7b273d472e361df3686272bc25dd7603a328d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Tue, 17 Dec 2019 00:04:30 +0100 Subject: [PATCH 7/8] Remove unnecessary comments --- Doc/reference/compound_stmts.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index dda86b73802704..874f8914d4a006 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -398,7 +398,7 @@ 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. @@ -446,7 +446,7 @@ is semantically equivalent to:: hit_except = False try: - target = value # only if `as target` is present in the with statement + target = value suite except: hit_except = True @@ -849,7 +849,7 @@ is semantically equivalent to:: hit_except = False try: - target = value # only if `as target` is present in the with statement + target = value suite except: hit_except = True From 1cbc19008e7deb106ee1205e4363b58d302ccc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Ogam?= Date: Wed, 18 Dec 2019 10:28:09 +0100 Subject: [PATCH 8/8] Use uppercase placeholders --- Doc/reference/compound_stmts.rst | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 874f8914d4a006..564d6cc42136da 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -434,20 +434,20 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo The following code:: - with expression as target: - suite + with EXPRESSION as TARGET: + SUITE is semantically equivalent to:: - manager = (expression) + manager = (EXPRESSION) enter = type(manager).__enter__ exit = type(manager).__exit__ value = enter(manager) hit_except = False try: - target = value - suite + TARGET = value + SUITE except: hit_except = True if not exit(manager, *sys.exc_info()): @@ -460,13 +460,13 @@ 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 semantically equivalent to:: with A() as a: with B() as b: - suite + SUITE .. versionchanged:: 3.1 Support for multiple context expressions. @@ -798,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. @@ -837,20 +838,20 @@ able to suspend execution in its *enter* and *exit* methods. The following code:: - async with expression as target: - suite + async with EXPRESSION as TARGET: + SUITE is semantically equivalent to:: - manager = (expression) + manager = (EXPRESSION) aexit = type(manager).__aexit__ aenter = type(manager).__aenter__ value = await aenter(manager) hit_except = False try: - target = value - suite + TARGET = value + SUITE except: hit_except = True if not await aexit(manager, *sys.exc_info()):