11"""Utilities for with-statement contexts. See PEP 343."""
2-
2+ import abc
33import sys
44from collections import deque
55from functools import wraps
66
7- __all__ = ["contextmanager" , "closing" , "ContextDecorator" , "ExitStack" ,
8- "redirect_stdout" , "redirect_stderr" , "suppress" ]
7+ __all__ = ["contextmanager" , "closing" , "AbstractContextManager" ,
8+ "ContextDecorator" , "ExitStack" , "redirect_stdout" ,
9+ "redirect_stderr" , "suppress" ]
10+
11+
12+ class AbstractContextManager (abc .ABC ):
13+
14+ """An abstract base class for context managers."""
15+
16+ def __enter__ (self ):
17+ """Return `self` upon entering the runtime context."""
18+ return self
19+
20+ @abc .abstractmethod
21+ def __exit__ (self , exc_type , exc_value , traceback ):
22+ """Raise any exception triggered within the runtime context."""
23+ return None
24+
25+ @classmethod
26+ def __subclasshook__ (cls , C ):
27+ if cls is AbstractContextManager :
28+ if (any ("__enter__" in B .__dict__ for B in C .__mro__ ) and
29+ any ("__exit__" in B .__dict__ for B in C .__mro__ )):
30+ return True
31+ return NotImplemented
932
1033
1134class ContextDecorator (object ):
@@ -31,7 +54,7 @@ def inner(*args, **kwds):
3154 return inner
3255
3356
34- class _GeneratorContextManager (ContextDecorator ):
57+ class _GeneratorContextManager (ContextDecorator , AbstractContextManager ):
3558 """Helper for @contextmanager decorator."""
3659
3760 def __init__ (self , func , args , kwds ):
@@ -134,7 +157,7 @@ def helper(*args, **kwds):
134157 return helper
135158
136159
137- class closing (object ):
160+ class closing (AbstractContextManager ):
138161 """Context to automatically close something at the end of a block.
139162
140163 Code like this:
@@ -159,7 +182,7 @@ def __exit__(self, *exc_info):
159182 self .thing .close ()
160183
161184
162- class _RedirectStream :
185+ class _RedirectStream ( AbstractContextManager ) :
163186
164187 _stream = None
165188
@@ -199,7 +222,7 @@ class redirect_stderr(_RedirectStream):
199222 _stream = "stderr"
200223
201224
202- class suppress :
225+ class suppress ( AbstractContextManager ) :
203226 """Context manager to suppress specified exceptions
204227
205228 After the exception is suppressed, execution proceeds with the next
@@ -230,7 +253,7 @@ def __exit__(self, exctype, excinst, exctb):
230253
231254
232255# Inspired by discussions on http://bugs.python.org/issue13585
233- class ExitStack (object ):
256+ class ExitStack (AbstractContextManager ):
234257 """Context manager for dynamic management of a stack of exit callbacks
235258
236259 For example:
@@ -309,9 +332,6 @@ def close(self):
309332 """Immediately unwind the context stack"""
310333 self .__exit__ (None , None , None )
311334
312- def __enter__ (self ):
313- return self
314-
315335 def __exit__ (self , * exc_details ):
316336 received_exc = exc_details [0 ] is not None
317337
0 commit comments