X Tutup
Skip to content

bpo-10049: Add a "no-op" (null) context manager to contextlib#4464

Merged
ncoghlan merged 9 commits intopython:masterfrom
Jesse-Bakker:add-contextlib-nullcontext
Nov 23, 2017
Merged

bpo-10049: Add a "no-op" (null) context manager to contextlib#4464
ncoghlan merged 9 commits intopython:masterfrom
Jesse-Bakker:add-contextlib-nullcontext

Conversation

@Jesse-Bakker
Copy link
Contributor

@Jesse-Bakker Jesse-Bakker commented Nov 19, 2017

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

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap long lines.

Typo: stand-in

return nullcontext(details)

with debug_trace(details) as d:
# Suite is traced in debug mode, but runs normally otherwise
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there was a better use case in the ticket?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. Changed the docs.

@merwok merwok self-requested a review November 19, 2017 18:34


Simplifying support for single optional context managers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it definitely should be kept.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

``page.close()`` will be called when the :keyword:`with` block is exited.


.. function:: nullcontext(thing=None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I’m nonplussed by the param name thing, I can’t think of a precedent in the stdlib.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

obj is probably more common.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, I'd ask that we make the name explicit and call it enter_result.

``page.close()`` will be called when the :keyword:`with` block is exited.


.. function:: nullcontext(thing=None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

obj is probably more common.



Simplifying support for single optional context managers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it definitely should be kept.

@@ -0,0 +1 @@
Added nullcontext no-op context manager to contextlib
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please make this a complete sentence?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main missing piece here is the explanation of the user benefit. Something like:

Added nullcontext no-op context manager to contextlib. This provides a simpler and faster alternative to ExitStack() when handling optional context managers.

Copy link
Contributor

@ncoghlan ncoghlan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

``page.close()`` will be called when the :keyword:`with` block is exited.


.. function:: nullcontext(thing=None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, I'd ask that we make the name explicit and call it enter_result.


.. function:: nullcontext(thing=None)

Return a context manager that just returns *thing*. It is intended to be used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

# Perform operation, using optional_cm if condition is True
"""

def __init__(self, thing=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main missing piece here is the explanation of the user benefit. Something like:

Added nullcontext no-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


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a version added marker:

.. versionadded: 3.7

@bedevere-bot
Copy link

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. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@Jesse-Bakker
Copy link
Contributor Author

I have made the requested changes; please review again.

@bedevere-bot
Copy link

Thanks for making the requested changes!

@merwok, @ncoghlan: please review the changes made to this pull request.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rst blocks are indented with three spaces

Copy link
Contributor

@ncoghlan ncoghlan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Once the docs directive is fixed, I think this will be ready to merge.

with cm as file:
# Perform processing on the file

.. versionadded: 3.7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@ncoghlan ncoghlan merged commit 0784a2e into python:master Nov 23, 2017
@ncoghlan
Copy link
Contributor

Thanks for the patch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

X Tutup