import contextlib
import unittest

class SafeContextMixin:
	def __init__(self, *args, **kwargs):
		with contextlib.ExitStack() as es:
			init = self._safe_init(*args, **kwargs)
			ret = None
			while True:
				try:
					ret = es.enter_context(init.send(ret))
				except StopIteration:
					break
			self.__exit_stack = es.pop_all()
	def __enter__(self):
		return self
	def __exit__(self, et, ev, eb):
		self.close()
	def close(self):
		self.__exit_stack.close()
				
# test

@contextlib.contextmanager
def good():
	print("good init")
	try:
		yield 42
	finally:
		print("good close")

@contextlib.contextmanager
def bad():
	print("bad init")
	raise Exception("bad")

class Foo(SafeContextMixin):
	def _safe_init(self, m1, m2):
		self.f1 = yield m1()
		self.f2 = yield m2()

def test(m1, m2):
	print("---")
	try:
		print("Before with")
		with Foo(m1, m2) as f:
			print("Inside with")
		print("After with")
	except Exception as e:
		print("Caugth :", e)

test(good, good)
test(good, bad)
test(bad, bad)
