annotate Lib/contextlib.py @ 87690:66c1c9f32567 default tip

Add use_weakref option to functools.lru_cache The use_weakref option makes lru_cache create weak references to the function arguments when creating the cache key, which prevents them from staying in the memory forever even after all other references to them are gone. This is a proof of concept for http://bugs.python.org/issue19859
author Radomir Dopieralski <devel@sheep.art.pl>
date Tue, 03 Dec 2013 16:02:48 +0100
parents 87d49e2cdd34
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
1 """Utilities for with-statement contexts. See PEP 343."""
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
2
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
3 import sys
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
4 from collections import deque
46664
031dfe455585 Merged revisions 62425-62429,62434-62436,62441,62444,62446-62448,62450-62455,62463,62465-62466,62469,62474,62476-62478,62480,62485,62492,62497-62498,62500,62507,62513-62514,62516,62521,62531,62535,62545-62546,62548-62551,62553-62559,62569,62574,62577,62593,62595,62604-62606,62608,62616,62626-62627,62636,62638,62644-62645,62647-62648,62651-62653,62656,62661,62663,62680,62686-62687,62696,62699-62703,62711 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43756
diff changeset
5 from functools import wraps
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
6
86195
63a1ee94b3ed Issue #15805: Add contextlib.redirect_stdout()
Raymond Hettinger <python@rcn.com>
parents: 85912
diff changeset
7 __all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack",
86403
22247b7d17fa Close #19266: contextlib.ignore -> contextlib.suppress
Nick Coghlan <ncoghlan@gmail.com>
parents: 86209
diff changeset
8 "redirect_stdout", "suppress"]
62652
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
9
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
10
62652
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
11 class ContextDecorator(object):
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
12 "A base class or mixin that enables context managers to work as decorators."
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
13
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
14 def _recreate_cm(self):
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
15 """Return a recreated instance of self.
69851
9b76edfddc54 Remove trailing whitespace
Nick Coghlan <ncoghlan@gmail.com>
parents: 69849
diff changeset
16
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
17 Allows an otherwise one-shot context manager like
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
18 _GeneratorContextManager to support use as
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
19 a decorator via implicit recreation.
69851
9b76edfddc54 Remove trailing whitespace
Nick Coghlan <ncoghlan@gmail.com>
parents: 69849
diff changeset
20
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
21 This is a private interface just for _GeneratorContextManager.
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
22 See issue #11647 for details.
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
23 """
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
24 return self
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
25
62652
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
26 def __call__(self, func):
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
27 @wraps(func)
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
28 def inner(*args, **kwds):
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
29 with self._recreate_cm():
62652
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
30 return func(*args, **kwds)
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
31 return inner
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
32
30e1d8d08105 Issue 9110. Adding ContextDecorator to contextlib. This enables the creation of APIs that act as decorators as well as context managers. contextlib.contextmanager changed to use ContextDecorator.
Michael Foord <fuzzyman@voidspace.org.uk>
parents: 55020
diff changeset
33
67463
c03f64c71b05 Issue #10859: Make `contextlib.GeneratorContextManager` officially
Antoine Pitrou <solipsis@pitrou.net>
parents: 62652
diff changeset
34 class _GeneratorContextManager(ContextDecorator):
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
35 """Helper for @contextmanager decorator."""
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
36
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
37 def __init__(self, func, *args, **kwds):
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
38 self.gen = func(*args, **kwds)
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
39 self.func, self.args, self.kwds = func, args, kwds
86650
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
40 # Issue 19330: ensure context manager instances have good docstrings
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
41 doc = getattr(func, "__doc__", None)
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
42 if doc is None:
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
43 doc = type(self).__doc__
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
44 self.__doc__ = doc
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
45 # Unfortunately, this still doesn't provide good help output when
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
46 # inspecting the created context manager instances, since pydoc
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
47 # currently bypasses the instance docstring and shows the docstring
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
48 # for the class instead.
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
49 # See http://bugs.python.org/issue19404 for more details.
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
50
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
51 def _recreate_cm(self):
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
52 # _GCM instances are one-shot context managers, so the
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
53 # CM must be recreated each time a decorated function is
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
54 # called
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
55 return self.__class__(self.func, *self.args, **self.kwds)
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
56
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
57 def __enter__(self):
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
58 try:
41501
0c5019afc55b PEP 3114: rename .next() to .__next__() and add next() builtin.
Georg Brandl <georg@python.org>
parents: 40587
diff changeset
59 return next(self.gen)
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
60 except StopIteration:
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
61 raise RuntimeError("generator didn't yield") from None
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
62
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
63 def __exit__(self, type, value, traceback):
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
64 if type is None:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
65 try:
41501
0c5019afc55b PEP 3114: rename .next() to .__next__() and add next() builtin.
Georg Brandl <georg@python.org>
parents: 40587
diff changeset
66 next(self.gen)
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
67 except StopIteration:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
68 return
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
69 else:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
70 raise RuntimeError("generator didn't stop")
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
71 else:
43756
317ba53cd45c Merged revisions 58742-58816 via svnmerge from
Guido van Rossum <guido@python.org>
parents: 43189
diff changeset
72 if value is None:
317ba53cd45c Merged revisions 58742-58816 via svnmerge from
Guido van Rossum <guido@python.org>
parents: 43189
diff changeset
73 # Need to force instantiation so we can reliably
317ba53cd45c Merged revisions 58742-58816 via svnmerge from
Guido van Rossum <guido@python.org>
parents: 43189
diff changeset
74 # tell if we get the same exception back
317ba53cd45c Merged revisions 58742-58816 via svnmerge from
Guido van Rossum <guido@python.org>
parents: 43189
diff changeset
75 value = type()
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
76 try:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
77 self.gen.throw(type, value, traceback)
37879
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
78 raise RuntimeError("generator didn't stop after throw()")
40587
6b18a095c2e7 SF patch 1631942 by Collin Winter:
Guido van Rossum <guido@python.org>
parents: 38453
diff changeset
79 except StopIteration as exc:
37879
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
80 # Suppress the exception *unless* it's the same exception that
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
81 # was passed to throw(). This prevents a StopIteration
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
82 # raised inside the "with" statement from being suppressed
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
83 return exc is not value
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
84 except:
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
85 # only re-raise if it's *not* the exception that was
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
86 # passed to throw(), because __exit__() must not raise
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
87 # an exception unless __exit__() itself failed. But throw()
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
88 # has to raise the exception to signal propagation, so this
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
89 # fixes the impedance mismatch between the throw() protocol
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
90 # and the __exit__() protocol.
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
91 #
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
92 if sys.exc_info()[1] is not value:
f731859e9b3b Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
Thomas Wouters <thomas@python.org>
parents: 36926
diff changeset
93 raise
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
94
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
95
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
96 def contextmanager(func):
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
97 """@contextmanager decorator.
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
98
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
99 Typical usage:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
100
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
101 @contextmanager
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
102 def some_generator(<arguments>):
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
103 <setup>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
104 try:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
105 yield <value>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
106 finally:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
107 <cleanup>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
108
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
109 This makes this:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
110
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
111 with some_generator(<arguments>) as <variable>:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
112 <body>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
113
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
114 equivalent to this:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
115
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
116 <setup>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
117 try:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
118 <variable> = <value>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
119 <body>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
120 finally:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
121 <cleanup>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
122
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
123 """
46664
031dfe455585 Merged revisions 62425-62429,62434-62436,62441,62444,62446-62448,62450-62455,62463,62465-62466,62469,62474,62476-62478,62480,62485,62492,62497-62498,62500,62507,62513-62514,62516,62521,62531,62535,62545-62546,62548-62551,62553-62559,62569,62574,62577,62593,62595,62604-62606,62608,62616,62626-62627,62636,62638,62644-62645,62647-62648,62651-62653,62656,62661,62663,62680,62686-62687,62696,62699-62703,62711 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43756
diff changeset
124 @wraps(func)
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
125 def helper(*args, **kwds):
69849
e4ba097123f6 Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray.
Nick Coghlan <ncoghlan@gmail.com>
parents: 67463
diff changeset
126 return _GeneratorContextManager(func, *args, **kwds)
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
127 return helper
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
128
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
129
38453
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
130 class closing(object):
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
131 """Context to automatically close something at the end of a block.
36737
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
132
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
133 Code like this:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
134
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
135 with closing(<module>.open(<arguments>)) as f:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
136 <block>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
137
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
138 is equivalent to this:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
139
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
140 f = <module>.open(<arguments>)
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
141 try:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
142 <block>
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
143 finally:
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
144 f.close()
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
145
fa92fe15251a Updates to the with-statement:
Guido van Rossum <guido@python.org>
parents:
diff changeset
146 """
38453
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
147 def __init__(self, thing):
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
148 self.thing = thing
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
149 def __enter__(self):
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
150 return self.thing
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
151 def __exit__(self, *exc_info):
29ae5e0fc348 Much-needed merge (using svnmerge.py this time) of trunk changes into p3yk.
Thomas Wouters <thomas@python.org>
parents: 37879
diff changeset
152 self.thing.close()
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
153
86650
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
154 class redirect_stdout:
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
155 """Context manager for temporarily redirecting stdout to another file
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
156
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
157 # How to send help() to stderr
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
158 with redirect_stdout(sys.stderr):
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
159 help(dir)
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
160
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
161 # How to write help() to a file
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
162 with open('help.txt', 'w') as f:
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
163 with redirect_stdout(f):
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
164 help(pow)
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
165 """
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
166
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
167 def __init__(self, new_target):
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
168 self._new_target = new_target
86869
87d49e2cdd34 Close #19403: make contextlib.redirect_stdout reentrant
Nick Coghlan <ncoghlan@gmail.com>
parents: 86650
diff changeset
169 # We use a list of old targets to make this CM re-entrant
87d49e2cdd34 Close #19403: make contextlib.redirect_stdout reentrant
Nick Coghlan <ncoghlan@gmail.com>
parents: 86650
diff changeset
170 self._old_targets = []
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
171
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
172 def __enter__(self):
86869
87d49e2cdd34 Close #19403: make contextlib.redirect_stdout reentrant
Nick Coghlan <ncoghlan@gmail.com>
parents: 86650
diff changeset
173 self._old_targets.append(sys.stdout)
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
174 sys.stdout = self._new_target
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
175 return self._new_target
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
176
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
177 def __exit__(self, exctype, excinst, exctb):
86869
87d49e2cdd34 Close #19403: make contextlib.redirect_stdout reentrant
Nick Coghlan <ncoghlan@gmail.com>
parents: 86650
diff changeset
178 sys.stdout = self._old_targets.pop()
86195
63a1ee94b3ed Issue #15805: Add contextlib.redirect_stdout()
Raymond Hettinger <python@rcn.com>
parents: 85912
diff changeset
179
63a1ee94b3ed Issue #15805: Add contextlib.redirect_stdout()
Raymond Hettinger <python@rcn.com>
parents: 85912
diff changeset
180
86650
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
181 class suppress:
86403
22247b7d17fa Close #19266: contextlib.ignore -> contextlib.suppress
Nick Coghlan <ncoghlan@gmail.com>
parents: 86209
diff changeset
182 """Context manager to suppress specified exceptions
82598
406b47c64480 Issue #15806: Add contextlib.ignored().
Raymond Hettinger <python@rcn.com>
parents: 80929
diff changeset
183
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
184 After the exception is suppressed, execution proceeds with the next
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
185 statement following the with statement.
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
186
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
187 with suppress(FileNotFoundError):
82598
406b47c64480 Issue #15806: Add contextlib.ignored().
Raymond Hettinger <python@rcn.com>
parents: 80929
diff changeset
188 os.remove(somefile)
86470
124a7ba1e911 contextlib doc updates and refactoring
Nick Coghlan <ncoghlan@gmail.com>
parents: 86403
diff changeset
189 # Execution still resumes here if the file was already removed
82598
406b47c64480 Issue #15806: Add contextlib.ignored().
Raymond Hettinger <python@rcn.com>
parents: 80929
diff changeset
190 """
86650
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
191
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
192 def __init__(self, *exceptions):
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
193 self._exceptions = exceptions
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
194
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
195 def __enter__(self):
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
196 pass
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
197
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
198 def __exit__(self, exctype, excinst, exctb):
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
199 # Unlike isinstance and issubclass, CPython exception handling
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
200 # currently only looks at the concrete type hierarchy (ignoring
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
201 # the instance and subclass checking hooks). While Guido considers
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
202 # that a bug rather than a feature, it's a fairly hard one to fix
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
203 # due to various internal implementation details. suppress provides
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
204 # the simpler issubclass based semantics, rather than trying to
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
205 # exactly reproduce the limitations of the CPython interpreter.
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
206 #
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
207 # See http://bugs.python.org/issue12029 for more details
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
208 return exctype is not None and issubclass(exctype, self._exceptions)
09153a9a3bb9 Close #19330 by using public classes in contextlib
Nick Coghlan <ncoghlan@gmail.com>
parents: 86470
diff changeset
209
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
210
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
211 # Inspired by discussions on http://bugs.python.org/issue13585
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
212 class ExitStack(object):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
213 """Context manager for dynamic management of a stack of exit callbacks
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
214
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
215 For example:
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
216
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
217 with ExitStack() as stack:
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
218 files = [stack.enter_context(open(fname)) for fname in filenames]
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
219 # All opened files will automatically be closed at the end of
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
220 # the with statement, even if attempts to open files later
80929
15a391919deb Issue #16714: use 'raise' exceptions, don't 'throw'.
Andrew Svetlov <andrew.svetlov@gmail.com>
parents: 77282
diff changeset
221 # in the list raise an exception
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
222
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
223 """
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
224 def __init__(self):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
225 self._exit_callbacks = deque()
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
226
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
227 def pop_all(self):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
228 """Preserve the context stack by transferring it to a new instance"""
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
229 new_stack = type(self)()
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
230 new_stack._exit_callbacks = self._exit_callbacks
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
231 self._exit_callbacks = deque()
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
232 return new_stack
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
233
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
234 def _push_cm_exit(self, cm, cm_exit):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
235 """Helper to correctly register callbacks to __exit__ methods"""
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
236 def _exit_wrapper(*exc_details):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
237 return cm_exit(cm, *exc_details)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
238 _exit_wrapper.__self__ = cm
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
239 self.push(_exit_wrapper)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
240
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
241 def push(self, exit):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
242 """Registers a callback with the standard __exit__ method signature
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
243
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
244 Can suppress exceptions the same way __exit__ methods can.
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
245
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
246 Also accepts any object with an __exit__ method (registering a call
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
247 to the method instead of the object itself)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
248 """
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
249 # We use an unbound method rather than a bound method to follow
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
250 # the standard lookup behaviour for special methods
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
251 _cb_type = type(exit)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
252 try:
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
253 exit_method = _cb_type.__exit__
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
254 except AttributeError:
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
255 # Not a context manager, so assume its a callable
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
256 self._exit_callbacks.append(exit)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
257 else:
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
258 self._push_cm_exit(exit, exit_method)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
259 return exit # Allow use as a decorator
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
260
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
261 def callback(self, callback, *args, **kwds):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
262 """Registers an arbitrary callback and arguments.
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
263
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
264 Cannot suppress exceptions.
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
265 """
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
266 def _exit_wrapper(exc_type, exc, tb):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
267 callback(*args, **kwds)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
268 # We changed the signature, so using @wraps is not appropriate, but
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
269 # setting __wrapped__ may still help with introspection
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
270 _exit_wrapper.__wrapped__ = callback
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
271 self.push(_exit_wrapper)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
272 return callback # Allow use as a decorator
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
273
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
274 def enter_context(self, cm):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
275 """Enters the supplied context manager
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
276
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
277 If successful, also pushes its __exit__ method as a callback and
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
278 returns the result of the __enter__ method.
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
279 """
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
280 # We look up the special methods on the type to match the with statement
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
281 _cm_type = type(cm)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
282 _exit = _cm_type.__exit__
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
283 result = _cm_type.__enter__(cm)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
284 self._push_cm_exit(cm, _exit)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
285 return result
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
286
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
287 def close(self):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
288 """Immediately unwind the context stack"""
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
289 self.__exit__(None, None, None)
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
290
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
291 def __enter__(self):
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
292 return self
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
293
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
294 def __exit__(self, *exc_details):
85911
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
295 received_exc = exc_details[0] is not None
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
296
77282
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
297 # We manipulate the exception state so it behaves as though
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
298 # we were actually nesting multiple with statements
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
299 frame_exc = sys.exc_info()[1]
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
300 def _fix_exception_context(new_exc, old_exc):
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
301 while 1:
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
302 exc_context = new_exc.__context__
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
303 if exc_context in (None, frame_exc):
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
304 break
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
305 new_exc = exc_context
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
306 new_exc.__context__ = old_exc
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
307
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
308 # Callbacks are invoked in LIFO order to match the behaviour of
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
309 # nested context managers
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
310 suppressed_exc = False
85911
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
311 pending_raise = False
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
312 while self._exit_callbacks:
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
313 cb = self._exit_callbacks.pop()
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
314 try:
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
315 if cb(*exc_details):
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
316 suppressed_exc = True
85911
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
317 pending_raise = False
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
318 exc_details = (None, None, None)
77095
8ef66c73b1e1 Close #13585: add contextlib.ExitStack to replace the ill-fated contextlib.nested API
Nick Coghlan <ncoghlan@gmail.com>
parents: 71037
diff changeset
319 except:
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
320 new_exc_details = sys.exc_info()
77282
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
321 # simulate the stack of exceptions by setting the context
c108bc96aec6 Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Nick Coghlan <ncoghlan@gmail.com>
parents: 77260
diff changeset
322 _fix_exception_context(new_exc_details[1], exc_details[1])
85911
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
323 pending_raise = True
77260
c0c7618762e5 Close #14963: Use an iterative algorithm in contextlib.ExitStack.__exit__ (Patch by Alon Horev)
Nick Coghlan <ncoghlan@gmail.com>
parents: 77095
diff changeset
324 exc_details = new_exc_details
85911
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
325 if pending_raise:
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
326 try:
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
327 # bare "raise exc_details[1]" replaces our carefully
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
328 # set-up context
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
329 fixed_ctx = exc_details[1].__context__
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
330 raise exc_details[1]
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
331 except BaseException:
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
332 exc_details[1].__context__ = fixed_ctx
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
333 raise
423736775f6b Close #19092: ExitStack now reraises exceptions from __exit__
Nick Coghlan <ncoghlan@gmail.com>
parents: 80929
diff changeset
334 return received_exc and suppressed_exc