summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/contextlib.rst40
-rw-r--r--Lib/contextlib.py23
-rw-r--r--Lib/test/test_contextlib.py10
-rw-r--r--Misc/NEWS.d/next/Library/2017-11-22-17-21-01.bpo-10049.ttsBqb.rst3
4 files changed, 57 insertions, 19 deletions
diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst
index 1979369..48ca0da 100644
--- a/Doc/library/contextlib.rst
+++ b/Doc/library/contextlib.rst
@@ -137,6 +137,28 @@ Functions and classes provided:
``page.close()`` will be called when the :keyword:`with` block is exited.
+.. _simplifying-support-for-single-optional-context-managers:
+
+.. function:: nullcontext(enter_result=None)
+
+ Return a context manager that returns enter_result from ``__enter__``, but
+ otherwise does nothing. It is intended to be used as a stand-in for an
+ optional context manager, for example::
+
+ def process_file(file_or_path):
+ if isinstance(file_or_path, str):
+ # If string, open file
+ cm = open(file_or_path)
+ else:
+ # Caller is responsible for closing file
+ cm = nullcontext(file_or_path)
+
+ with cm as file:
+ # Perform processing on the file
+
+ .. versionadded:: 3.7
+
+
.. function:: suppress(*exceptions)
Return a context manager that suppresses any of the specified exceptions
@@ -433,24 +455,6 @@ statements to manage arbitrary resources that don't natively support the
context management protocol.
-Simplifying support for single optional context managers
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-In the specific case of a single optional context manager, :class:`ExitStack`
-instances can be used as a "do nothing" context manager, allowing a context
-manager to easily be omitted without affecting the overall structure of
-the source code::
-
- def debug_trace(details):
- if __debug__:
- return TraceContext(details)
- # Don't do anything special with the context in release mode
- return ExitStack()
-
- with debug_trace():
- # Suite is traced in debug mode, but runs normally otherwise
-
-
Catching exceptions from ``__enter__`` methods
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 962ceda..c1f8a84 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -5,7 +5,7 @@ import _collections_abc
from collections import deque
from functools import wraps
-__all__ = ["asynccontextmanager", "contextmanager", "closing",
+__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
"AbstractContextManager", "ContextDecorator", "ExitStack",
"redirect_stdout", "redirect_stderr", "suppress"]
@@ -469,3 +469,24 @@ class ExitStack(AbstractContextManager):
exc_details[1].__context__ = fixed_ctx
raise
return received_exc and suppressed_exc
+
+
+class nullcontext(AbstractContextManager):
+ """Context manager that does no additional processing.
+
+ Used as a stand-in for a normal context manager, when a particular
+ block of code is only sometimes used with a normal context manager:
+
+ cm = optional_cm if condition else nullcontext()
+ with cm:
+ # Perform operation, using optional_cm if condition is True
+ """
+
+ def __init__(self, enter_result=None):
+ self.enter_result = enter_result
+
+ def __enter__(self):
+ return self.enter_result
+
+ def __exit__(self, *excinfo):
+ pass
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index 64b6578..1a5e6ed 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -252,6 +252,16 @@ class ClosingTestCase(unittest.TestCase):
1 / 0
self.assertEqual(state, [1])
+
+class NullcontextTestCase(unittest.TestCase):
+ def test_nullcontext(self):
+ class C:
+ pass
+ c = C()
+ with nullcontext(c) as c_in:
+ self.assertIs(c_in, c)
+
+
class FileContextTestCase(unittest.TestCase):
def testWithOpen(self):
diff --git a/Misc/NEWS.d/next/Library/2017-11-22-17-21-01.bpo-10049.ttsBqb.rst b/Misc/NEWS.d/next/Library/2017-11-22-17-21-01.bpo-10049.ttsBqb.rst
new file mode 100644
index 0000000..b6153c2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-22-17-21-01.bpo-10049.ttsBqb.rst
@@ -0,0 +1,3 @@
+Added *nullcontext* no-op context manager to contextlib. This provides a
+simpler and faster alternative to ExitStack() when handling optional context
+managers.