bpo-10049: Add a "no-op" (null) context manager to contextlib#4464
bpo-10049: Add a "no-op" (null) context manager to contextlib#4464ncoghlan merged 9 commits intopython:masterfrom
Conversation
Lib/contextlib.py
Outdated
| class nullcontext(AbstractContextManager): | ||
| """Context manager that does no additional processing. | ||
|
|
||
| Used as a standin for a normal context manager, when a particular block of code is only sometimes used with a normal context manager: |
There was a problem hiding this comment.
Please wrap long lines.
Typo: stand-in
Doc/library/contextlib.rst
Outdated
| return nullcontext(details) | ||
|
|
||
| with debug_trace(details) as d: | ||
| # Suite is traced in debug mode, but runs normally otherwise |
There was a problem hiding this comment.
Can you check if this code block is rendered correctly? Since comments are stripped out and do not become statements, this may be invalid code. If that is so (I’m not sure!), adding an ellipsis would fix it.
There was a problem hiding this comment.
It is rendered correctly. I am unsure about the example though. I used the example previously used for the recipe using ExitStack and could not think of a better one. I don't find it all too intuitive though.
There was a problem hiding this comment.
Maybe there was a better use case in the ticket?
There was a problem hiding this comment.
An example I encountered was having to close a file if I opened it in the function, but not if a file object was passed to the function. This could read:
def function(target):
""""Do something with target (file object or path as string."""
if isinstance(target, str): # or FileLike
cm = open(target)
else:
# Wrap the file in a no-op context manager, the caller will close it
cm = nullcontext(target)
with cm as file:
print('hello', file=file)There was a problem hiding this comment.
Thanks for the suggestion. Changed the docs.
|
|
||
|
|
||
| Simplifying support for single optional context managers | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
There was a problem hiding this comment.
I wonder if the section heading should be kept but the text changed to direct to nullcontext, so that people following links can see the new helper.
Also, if this is the only place that explained that ExitStack can work as a no-op, I think a line about that should be kept.
There was a problem hiding this comment.
Yes, it definitely should be kept.
There was a problem hiding this comment.
I agree we still need the hyperlink target, but given the clear example in the function's documentation, I think we can still delete the recipe section.
Doc/library/contextlib.rst
Outdated
| ``page.close()`` will be called when the :keyword:`with` block is exited. | ||
|
|
||
|
|
||
| .. function:: nullcontext(thing=None) |
There was a problem hiding this comment.
Minor: I’m nonplussed by the param name thing, I can’t think of a precedent in the stdlib.
There was a problem hiding this comment.
For this, I'd ask that we make the name explicit and call it enter_result.
Doc/library/contextlib.rst
Outdated
| ``page.close()`` will be called when the :keyword:`with` block is exited. | ||
|
|
||
|
|
||
| .. function:: nullcontext(thing=None) |
|
|
||
|
|
||
| Simplifying support for single optional context managers | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
There was a problem hiding this comment.
Yes, it definitely should be kept.
| @@ -0,0 +1 @@ | |||
| Added nullcontext no-op context manager to contextlib | |||
There was a problem hiding this comment.
Can you please make this a complete sentence?
There was a problem hiding this comment.
I think the main missing piece here is the explanation of the user benefit. Something like:
Added
nullcontextno-op context manager to contextlib. This provides a simpler and faster alternative to ExitStack() when handling optional context managers.
ncoghlan
left a comment
There was a problem hiding this comment.
Thanks! The general structure here looks good to me, but I'd prefer we used the more descriptive parameter and attribute name enter_result.
There's also a small docs tweak to ensure links to the old recipe section are automatically directed to the new context manager
|
|
||
|
|
||
| Simplifying support for single optional context managers | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
There was a problem hiding this comment.
I agree we still need the hyperlink target, but given the clear example in the function's documentation, I think we can still delete the recipe section.
Doc/library/contextlib.rst
Outdated
| ``page.close()`` will be called when the :keyword:`with` block is exited. | ||
|
|
||
|
|
||
| .. function:: nullcontext(thing=None) |
There was a problem hiding this comment.
For this, I'd ask that we make the name explicit and call it enter_result.
Doc/library/contextlib.rst
Outdated
|
|
||
| .. function:: nullcontext(thing=None) | ||
|
|
||
| Return a context manager that just returns *thing*. It is intended to be used |
There was a problem hiding this comment.
Adjust the first sentence to be:
Return a context manager that returns enter_result from
__enter__, but otherwise does nothing.
| @@ -137,6 +137,23 @@ Functions and classes provided: | |||
| ``page.close()`` will be called when the :keyword:`with` block is exited. | |||
|
|
|||
There was a problem hiding this comment.
Declare an explicit hyperlink anchor here with a blank line before the function definition:
.. _simplifying-support-for-single-optional-context-managers:
.. function:: nullcontext(enter_result=None)
Lib/contextlib.py
Outdated
| # Perform operation, using optional_cm if condition is True | ||
| """ | ||
|
|
||
| def __init__(self, thing=None): |
There was a problem hiding this comment.
As per the docs comment, replace thing with enter_result for both the parameter and attribute name.
| @@ -0,0 +1 @@ | |||
| Added nullcontext no-op context manager to contextlib | |||
There was a problem hiding this comment.
I think the main missing piece here is the explanation of the user benefit. Something like:
Added
nullcontextno-op context manager to contextlib. This provides a simpler and faster alternative to ExitStack() when handling optional context managers.
| with cm as file: | ||
| # Perform processing on the file | ||
|
|
||
|
|
There was a problem hiding this comment.
This needs a version added marker:
.. versionadded: 3.7
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
|
I have made the requested changes; please review again. |
Doc/library/contextlib.rst
Outdated
| as a stand-in for an optional context manager, for example:: | ||
| .. function:: nullcontext(enter_result=None) | ||
|
|
||
| Return a context manager that returns enter_result from ``__enter__``, but |
There was a problem hiding this comment.
rst blocks are indented with three spaces
ncoghlan
left a comment
There was a problem hiding this comment.
Thanks! Once the docs directive is fixed, I think this will be ready to merge.
Doc/library/contextlib.rst
Outdated
| with cm as file: | ||
| # Perform processing on the file | ||
|
|
||
| .. versionadded: 3.7 |
There was a problem hiding this comment.
Sorry, my suggested syntax here wasn't quite right (and that's what the CI build is complaining about). The directive needs a second colon:
.. versionadded:: 3.7
|
Thanks for the patch! |
bpo-10049: Add a "no-op" (null) context manager to contextlib
Removed section in docs using ExitStack() for no-op context manager
https://bugs.python.org/issue10049