This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Look up __enter__ before __exit__ in the with statement documentation
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: brett.cannon, docs@python, gvanrossum, maggyero, mark.dickinson, miss-islington, ncoghlan
Priority: normal Keywords: easy, patch

Created on 2019-12-13 15:19 by maggyero, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 17608 merged maggyero, 2019-12-14 18:07
PR 17749 merged miss-islington, 2019-12-30 05:25
Messages (10)
msg358333 - (view) Author: Géry (maggyero) * Date: 2019-12-13 15:19
>>> class A: pass
    ... 
    >>> with A(): pass
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: __enter__

I expected `AttributeError: __exit__`, since PEP 343 states (https://www.python.org/dev/peps/pep-0343/#specification-the-with-statement):

> The details of the above translation are intended to prescribe the exact semantics. If either of the relevant methods are not found as expected, the interpreter will raise AttributeError, in the order that they are tried (__exit__, __enter__).

and the language documentation states (https://docs.python.org/3/reference/compound_stmts.html#the-with-statement):

> The execution of the with statement with one “item” proceeds as follows:
> 1. The context expression (the expression given in the with_item) is evaluated to obtain a context manager.
> 2. The context manager’s __exit__() is loaded for later use.
> 3. The context manager’s __enter__() method is invoked.
msg358334 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2019-12-13 15:29
See issue 27100, which led to a deliberate change in behaviour to look up __enter__ before __exit__. It looks like the documentation (not the PEP text, which shouldn't be considered normative; just the reference manual) needs to be adjusted to match the new behaviour.
msg358335 - (view) Author: Géry (maggyero) * Date: 2019-12-13 15:47
Thanks @mark.dickinson for the link. Can I open a documentation PR for this?
msg358346 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2019-12-13 17:49
@Gery please do open a documentation PR! :)
msg358399 - (view) Author: Géry (maggyero) * Date: 2019-12-14 18:08
Done @brett.cannon, would you like to review it? https://github.com/python/cpython/pull/17608
msg358416 - (view) Author: Géry (maggyero) * Date: 2019-12-15 11:27
@gvanrossum

By the way, is there any particular reason why the ``try`` statement implementation equivalent to the ``with`` statement given in PEP 343 puts the finally clause in an outer ``try`` statement instead of in the inner ``try`` statement? (cf. https://www.python.org/dev/peps/pep-0343/#specification-the-with-statement)

In other words, couldn't we simplify this:

```
mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)
```

into that?

```
mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    VAR = value  # Only if "as VAR" is present
    BLOCK
except:
    # The exceptional case is handled here
    exc = False
    if not exit(mgr, *sys.exc_info()):
        raise
    # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)
```
msg358419 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2019-12-15 12:23
It's a matter of historical timing: PEP 343 was written before try/except/finally was allowed, when try/finally and try/except were still distinct statements.

However, PEP 341 was *also* accepted and implemented for Python 2.5, allowing for the modern try/except/finally form: https://docs.python.org/dev/whatsnew/2.5.html#pep-341-unified-try-except-finally
msg358432 - (view) Author: Géry (maggyero) * Date: 2019-12-15 13:35
Thanks @ncoghlan, it perfectly answered my question on Stack Overflow: https://stackoverflow.com/questions/59322585/what-is-the-exact-try-statement-equivalent-of-the-with-statement-in-python
msg359020 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2019-12-30 05:24
New changeset 226e6e7d4326cf91ef37e13528eb1f62de1bb832 by Nick Coghlan (Géry Ogam) in branch 'master':
bpo-39037: Fix lookup order of magic methods in with statement documentation (GH-17608)
https://github.com/python/cpython/commit/226e6e7d4326cf91ef37e13528eb1f62de1bb832
msg359021 - (view) Author: miss-islington (miss-islington) Date: 2019-12-30 05:31
New changeset cbfafa3e3625dae96ce392c88c793f8af55167bf by Miss Islington (bot) in branch '3.8':
bpo-39037: Fix lookup order of magic methods in with statement documentation (GH-17608)
https://github.com/python/cpython/commit/cbfafa3e3625dae96ce392c88c793f8af55167bf
History
Date User Action Args
2022-04-11 14:59:24adminsetgithub: 83218
2020-01-14 12:19:39maggyerosettitle: Fix the trial order of the __exit__ and __enter__ methods in the with statement documentation -> Look up __enter__ before __exit__ in the with statement documentation
2019-12-30 11:07:49maggyerosetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-12-30 05:31:22miss-islingtonsetnosy: + miss-islington
messages: + msg359021
2019-12-30 05:25:48miss-islingtonsetpull_requests: + pull_request17187
2019-12-30 05:24:57ncoghlansetmessages: + msg359020
2019-12-15 13:35:54maggyerosetmessages: + msg358432
2019-12-15 12:23:33ncoghlansetmessages: + msg358419
2019-12-15 11:27:26maggyerosetmessages: + msg358416
2019-12-14 18:16:00maggyerosettitle: Wrong trial order of __exit__ and __enter__ in the with statement -> Fix the trial order of the __exit__ and __enter__ methods in the with statement documentation
2019-12-14 18:08:35maggyerosetmessages: + msg358399
2019-12-14 18:07:01maggyerosetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request17078
2019-12-13 17:49:39brett.cannonsetnosy: + brett.cannon
messages: + msg358346
2019-12-13 17:08:51serhiy.storchakasetnosy: + docs@python
assignee: docs@python
components: + Documentation, - Interpreter Core
keywords: + easy
stage: needs patch
2019-12-13 15:47:33maggyerosetmessages: + msg358335
2019-12-13 15:29:04mark.dickinsonsetnosy: + mark.dickinson
messages: + msg358334
2019-12-13 15:19:37maggyerocreate