1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# coding: utf-8
# Inspired by discussions on http://bugs.python.org/issue13585
"""Context manager for dynamic management of a stack of exit callbacks
For example:
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list throw an exception
"""
=
"""Preserve the context stack by transferring it to a new instance"""
=
=
=
return
"""Helper to correctly register callbacks to __exit__ methods"""
return
=
"""Registers a callback with the standard __exit__ method signature
Can suppress exceptions the same way __exit__ methods can.
Also accepts any object with an __exit__ method (registering the
method instead of the object itself)
"""
# We use an unbound method rather than a bound method to follow
# the standard lookup behaviour for special methods
=
=
# Not a context manager, so assume its a callable
return # Allow use as a decorator
"""Registers an arbitrary callback and arguments.
Cannot suppress exceptions.
"""
# We changed the signature, so using @wraps is not appropriate, but
# setting __wrapped__ may still help with introspection
=
return # Allow use as a decorator
"""Enters the supplied context manager
If successful, also pushes its __exit__ method as a callback and
returns the result of the __enter__ method.
"""
# We look up the special methods on the type to match the with
# statement
=
=
=
return
"""Immediately unwind the context stack"""
return
return
# This looks complicated, but it is really just
# setting up a chain of try-expect statements to ensure
# that outer callbacks still get invoked even if an
# inner one throws an exception
# Callbacks are removed from the list in FIFO order
# but the recursion means they're invoked in LIFO order
=
# Innermost callback is invoked directly
return
# More callbacks left, so descend another level in the stack
=
=
# Check if this cb suppressed the inner exception
# Check if inner cb suppressed the original exception
=
= or
return
# Kick off the recursive chain
return