import sys | |
from collections import deque | |
class nested(object): | |
def __init__(self, *contexts): | |
self.contexts = contexts | |
self.entered = None | |
def __context__(self): | |
return self | |
def __enter__(self): | |
if self.entered is not None: | |
raise RuntimeError("Context is not reentrant") | |
self.entered = deque() | |
vars = [] | |
try: | |
for context in self.contexts: | |
mgr = context.__context__() | |
vars.append(mgr.__enter__()) | |
self.entered.appendleft(mgr) | |
except: | |
self.__exit__(*sys.exc_info()) | |
raise | |
return vars | |
def __exit__(self, *exc_info): | |
# Behave like nested with statements | |
# first in, last out | |
# New exceptions override old ones | |
ex = exc_info | |
for mgr in self.entered: | |
try: | |
mgr.__exit__(*ex) | |
except: | |
ex = sys.exc_info() | |
self.entered = None | |
if ex is not exc_info: | |
raise ex[0], ex[1], ex[2] |