Mercurial > cpython-lru_cache-weakref
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 |
| 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 |
