fork download
  1. import contextlib
  2. import unittest
  3.  
  4. class SafeContextMixin:
  5. def __init__(self, *args, **kwargs):
  6. with contextlib.ExitStack() as es:
  7. init = self._safe_init(*args, **kwargs)
  8. ret = None
  9. while True:
  10. try:
  11. ret = es.enter_context(init.send(ret))
  12. except StopIteration:
  13. break
  14. self.__exit_stack = es.pop_all()
  15. def __enter__(self):
  16. return self
  17. def __exit__(self, et, ev, eb):
  18. self.close()
  19. def close(self):
  20. self.__exit_stack.close()
  21.  
  22. # test
  23.  
  24. @contextlib.contextmanager
  25. def good():
  26. print("good init")
  27. try:
  28. yield 42
  29. finally:
  30. print("good close")
  31.  
  32. @contextlib.contextmanager
  33. def bad():
  34. print("bad init")
  35. raise Exception("bad")
  36.  
  37. class Foo(SafeContextMixin):
  38. def _safe_init(self, m1, m2):
  39. self.f1 = yield m1()
  40. self.f2 = yield m2()
  41.  
  42. def test(m1, m2):
  43. print("---")
  44. try:
  45. print("Before with")
  46. with Foo(m1, m2) as f:
  47. print("Inside with")
  48. print("After with")
  49. except Exception as e:
  50. print("Caugth :", e)
  51.  
  52. test(good, good)
  53. test(good, bad)
  54. test(bad, bad)
  55.  
Success #stdin #stdout 0.03s 29808KB
stdin
Standard input is empty
stdout
---
Before with
good init
good init
Inside with
good close
good close
After with
---
Before with
good init
bad init
good close
Caugth : bad
---
Before with
bad init
Caugth : bad