Title: contextlib.ExitStack.__enter__ has trivial but undocumented behavior
Type: Stage: patch review
Components: Documentation Versions: Python 3.11
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, martin.panter, r.david.murray, walker.hale.iv
Priority: normal Keywords: easy

Created on 2016-10-24 02:36 by walker.hale.iv, last changed 2021-06-18 22:34 by iritkatriel.

File name Uploaded Description Edit
issue28516.diff walker.hale.iv, 2016-10-24 18:25 review
Messages (6)
msg279296 - (view) Author: Walker Hale IV (walker.hale.iv) * Date: 2016-10-24 02:36
contextlib.ExitStack implies but does not explicitly state that its __enter__ method trivially returns self.

This means that if a user invokes pop_all and then uses the resulting ExitStack instance in a with statement, the user will be relying on undocumented behavior. Avoiding undocumented behavior forces the user to instead use a tedious try/finally construct, partially defeating the elegance of context managers.

I propose that:

1. The ExitStack.__enter__ method be briefly mentioned as doing nothing besides returning self.

2. The example in pop_all documentation be expanded to show a following with statement that uses the new ExitStack instance.

The discussion in section is not sufficient to make this trivial point clear.
msg279311 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-10-24 15:02
Hmm.  I guess we just assume it is obvious, given that the with statement examples name the variable 'stack', and the pop_all docs mention that no callbacks are called until it is closed "or at the end of a with statement".  So, technically, using the result of a pop_all in a with statement is documented.  I could be made clearer though if someone wants to propose a doc patch.  I'm not sure it is worth expanding the example, though.
msg279326 - (view) Author: Walker Hale IV (walker.hale.iv) * Date: 2016-10-24 18:36
This one-line patch should clarify the point.
msg279463 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-10-25 22:48
I agree it is good to explicitly document the __enter__() result, rather than relying on assumptions and example code. The patch looks good to me.

I don’t understand the problem with pop_all() though. Is there still a problem if we apply your patch?
msg279467 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-10-26 00:15
Actually, the __enter__ method is looked up on the class, so saying "the __enter__ method of the instance" could be a bit confusing.  Also, many context managers return self, so 'trivially' isn't really necessary as a modifier.

What if we added a sentence to the first paragraph that said "ExitStack instances return themselves when used in a with statement."  Since that is immediately followed by an example of doing that, it seems like the best place to put it.
msg279486 - (view) Author: Walker Hale IV (walker.hale.iv) * Date: 2016-10-26 03:13
Clarifying the documentation regarding the __enter__ method eliminates the need for further discussion on this point regarding pop_all(), which was really just the motivating use case.

That leaves the question of the most readable documentation change that accomplishes the result — some point between verbose and terse that minimizes the time required to comprehend the material.

My problem with the language "ExitStack instances return themselves when used in a with statement" is that it only specifies the return value of the __enter__ method but leaves open the question of whether the __enter__ method is doing anything else, particularly in the case of an ExitStack that is already loaded with context managers. How does a reader know that the __enter__ method of a loaded ExitStack doesn't call the __enter__ method of the the context managers inside? The documentation elsewhere provides strong evidence against this, but nothing that makes the point explicit. The reader is left with an exercise in deduction.

How about replacing my previous wording with: "The __enter__ method has no behavior besides returning the ExitStack instance?"

(I feel a little dirty using that language, since it might tie the hands of future developers. The truly correct wording would be "The __enter__ method is idempotent and behaves as if the only thing it does is return the ExitStack instance." That more verbose description gives future developers the freedom to do weird JIT optimizations and caching as needed, but who has the patience for such legally exhaustive specification?)

Placing the wording where I did — at the end of the class discussion and prior to the new methods — prevents this point from obscuring the main purpose of ExitStack while still leaving a place for such messy but important details. (Amazing the thought that goes into documenting a two-line method.)
Date User Action Args
2021-06-18 22:34:41iritkatrielsetkeywords: + easy, - patch
versions: + Python 3.11, - Python 3.5, Python 3.6, Python 3.7
2016-10-26 03:13:38walker.hale.ivsetmessages: + msg279486
2016-10-26 00:15:31r.david.murraysetmessages: + msg279467
2016-10-25 22:48:56martin.pantersetversions: - Python 3.3, Python 3.4
nosy: + martin.panter

messages: + msg279463

stage: patch review
2016-10-24 18:36:57walker.hale.ivsetmessages: + msg279326
2016-10-24 18:25:24walker.hale.ivsetfiles: + issue28516.diff

nosy: + docs@python
assignee: docs@python
components: + Documentation
keywords: + patch
2016-10-24 15:02:56r.david.murraysetnosy: + r.david.murray
messages: + msg279311
2016-10-24 02:36:51walker.hale.ivcreate