mirror of
https://github.com/ceph/ceph
synced 2024-12-23 20:03:56 +00:00
44 lines
1.3 KiB
Python
44 lines
1.3 KiB
Python
import contextlib
|
|
import sys
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
@contextlib.contextmanager
|
|
def nested(*managers):
|
|
"""
|
|
Like contextlib.nested but takes callables returning context
|
|
managers, to avoid the major reason why contextlib.nested was
|
|
deprecated.
|
|
|
|
This version also logs any exceptions early, much like run_tasks,
|
|
to ease debugging. TODO combine nested and run_tasks.
|
|
"""
|
|
exits = []
|
|
vars = []
|
|
exc = (None, None, None)
|
|
try:
|
|
for mgr_fn in managers:
|
|
mgr = mgr_fn()
|
|
exit = mgr.__exit__
|
|
enter = mgr.__enter__
|
|
vars.append(enter())
|
|
exits.append(exit)
|
|
yield vars
|
|
except Exception:
|
|
log.exception('Saw exception from nested tasks')
|
|
exc = sys.exc_info()
|
|
finally:
|
|
while exits:
|
|
exit = exits.pop()
|
|
try:
|
|
if exit(*exc):
|
|
exc = (None, None, None)
|
|
except Exception:
|
|
exc = sys.exc_info()
|
|
if exc != (None, None, None):
|
|
# Don't rely on sys.exc_info() still containing
|
|
# the right information. Another exception may
|
|
# have been raised and caught by an exit method
|
|
raise exc[0], exc[1], exc[2]
|