Path: blob/master/venv/Lib/site-packages/pip/_vendor/contextlib2.py
811 views
"""contextlib2 - backports and enhancements to the contextlib module"""12import abc3import sys4import warnings5from collections import deque6from functools import wraps78__all__ = ["contextmanager", "closing", "nullcontext",9"AbstractContextManager",10"ContextDecorator", "ExitStack",11"redirect_stdout", "redirect_stderr", "suppress"]1213# Backwards compatibility14__all__ += ["ContextStack"]151617# Backport abc.ABC18if sys.version_info[:2] >= (3, 4):19_abc_ABC = abc.ABC20else:21_abc_ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})222324# Backport classic class MRO25def _classic_mro(C, result):26if C in result:27return28result.append(C)29for B in C.__bases__:30_classic_mro(B, result)31return result323334# Backport _collections_abc._check_methods35def _check_methods(C, *methods):36try:37mro = C.__mro__38except AttributeError:39mro = tuple(_classic_mro(C, []))4041for method in methods:42for B in mro:43if method in B.__dict__:44if B.__dict__[method] is None:45return NotImplemented46break47else:48return NotImplemented49return True505152class AbstractContextManager(_abc_ABC):53"""An abstract base class for context managers."""5455def __enter__(self):56"""Return `self` upon entering the runtime context."""57return self5859@abc.abstractmethod60def __exit__(self, exc_type, exc_value, traceback):61"""Raise any exception triggered within the runtime context."""62return None6364@classmethod65def __subclasshook__(cls, C):66"""Check whether subclass is considered a subclass of this ABC."""67if cls is AbstractContextManager:68return _check_methods(C, "__enter__", "__exit__")69return NotImplemented707172class ContextDecorator(object):73"""A base class or mixin that enables context managers to work as decorators."""7475def refresh_cm(self):76"""Returns the context manager used to actually wrap the call to the77decorated function.7879The default implementation just returns *self*.8081Overriding this method allows otherwise one-shot context managers82like _GeneratorContextManager to support use as decorators via83implicit recreation.8485DEPRECATED: refresh_cm was never added to the standard library's86ContextDecorator API87"""88warnings.warn("refresh_cm was never added to the standard library",89DeprecationWarning)90return self._recreate_cm()9192def _recreate_cm(self):93"""Return a recreated instance of self.9495Allows an otherwise one-shot context manager like96_GeneratorContextManager to support use as97a decorator via implicit recreation.9899This is a private interface just for _GeneratorContextManager.100See issue #11647 for details.101"""102return self103104def __call__(self, func):105@wraps(func)106def inner(*args, **kwds):107with self._recreate_cm():108return func(*args, **kwds)109return inner110111112class _GeneratorContextManager(ContextDecorator):113"""Helper for @contextmanager decorator."""114115def __init__(self, func, args, kwds):116self.gen = func(*args, **kwds)117self.func, self.args, self.kwds = func, args, kwds118# Issue 19330: ensure context manager instances have good docstrings119doc = getattr(func, "__doc__", None)120if doc is None:121doc = type(self).__doc__122self.__doc__ = doc123# Unfortunately, this still doesn't provide good help output when124# inspecting the created context manager instances, since pydoc125# currently bypasses the instance docstring and shows the docstring126# for the class instead.127# See http://bugs.python.org/issue19404 for more details.128129def _recreate_cm(self):130# _GCM instances are one-shot context managers, so the131# CM must be recreated each time a decorated function is132# called133return self.__class__(self.func, self.args, self.kwds)134135def __enter__(self):136try:137return next(self.gen)138except StopIteration:139raise RuntimeError("generator didn't yield")140141def __exit__(self, type, value, traceback):142if type is None:143try:144next(self.gen)145except StopIteration:146return147else:148raise RuntimeError("generator didn't stop")149else:150if value is None:151# Need to force instantiation so we can reliably152# tell if we get the same exception back153value = type()154try:155self.gen.throw(type, value, traceback)156raise RuntimeError("generator didn't stop after throw()")157except StopIteration as exc:158# Suppress StopIteration *unless* it's the same exception that159# was passed to throw(). This prevents a StopIteration160# raised inside the "with" statement from being suppressed.161return exc is not value162except RuntimeError as exc:163# Don't re-raise the passed in exception164if exc is value:165return False166# Likewise, avoid suppressing if a StopIteration exception167# was passed to throw() and later wrapped into a RuntimeError168# (see PEP 479).169if _HAVE_EXCEPTION_CHAINING and exc.__cause__ is value:170return False171raise172except:173# only re-raise if it's *not* the exception that was174# passed to throw(), because __exit__() must not raise175# an exception unless __exit__() itself failed. But throw()176# has to raise the exception to signal propagation, so this177# fixes the impedance mismatch between the throw() protocol178# and the __exit__() protocol.179#180if sys.exc_info()[1] is not value:181raise182183184def contextmanager(func):185"""@contextmanager decorator.186187Typical usage:188189@contextmanager190def some_generator(<arguments>):191<setup>192try:193yield <value>194finally:195<cleanup>196197This makes this:198199with some_generator(<arguments>) as <variable>:200<body>201202equivalent to this:203204<setup>205try:206<variable> = <value>207<body>208finally:209<cleanup>210211"""212@wraps(func)213def helper(*args, **kwds):214return _GeneratorContextManager(func, args, kwds)215return helper216217218class closing(object):219"""Context to automatically close something at the end of a block.220221Code like this:222223with closing(<module>.open(<arguments>)) as f:224<block>225226is equivalent to this:227228f = <module>.open(<arguments>)229try:230<block>231finally:232f.close()233234"""235def __init__(self, thing):236self.thing = thing237238def __enter__(self):239return self.thing240241def __exit__(self, *exc_info):242self.thing.close()243244245class _RedirectStream(object):246247_stream = None248249def __init__(self, new_target):250self._new_target = new_target251# We use a list of old targets to make this CM re-entrant252self._old_targets = []253254def __enter__(self):255self._old_targets.append(getattr(sys, self._stream))256setattr(sys, self._stream, self._new_target)257return self._new_target258259def __exit__(self, exctype, excinst, exctb):260setattr(sys, self._stream, self._old_targets.pop())261262263class redirect_stdout(_RedirectStream):264"""Context manager for temporarily redirecting stdout to another file.265266# How to send help() to stderr267with redirect_stdout(sys.stderr):268help(dir)269270# How to write help() to a file271with open('help.txt', 'w') as f:272with redirect_stdout(f):273help(pow)274"""275276_stream = "stdout"277278279class redirect_stderr(_RedirectStream):280"""Context manager for temporarily redirecting stderr to another file."""281282_stream = "stderr"283284285class suppress(object):286"""Context manager to suppress specified exceptions287288After the exception is suppressed, execution proceeds with the next289statement following the with statement.290291with suppress(FileNotFoundError):292os.remove(somefile)293# Execution still resumes here if the file was already removed294"""295296def __init__(self, *exceptions):297self._exceptions = exceptions298299def __enter__(self):300pass301302def __exit__(self, exctype, excinst, exctb):303# Unlike isinstance and issubclass, CPython exception handling304# currently only looks at the concrete type hierarchy (ignoring305# the instance and subclass checking hooks). While Guido considers306# that a bug rather than a feature, it's a fairly hard one to fix307# due to various internal implementation details. suppress provides308# the simpler issubclass based semantics, rather than trying to309# exactly reproduce the limitations of the CPython interpreter.310#311# See http://bugs.python.org/issue12029 for more details312return exctype is not None and issubclass(exctype, self._exceptions)313314315# Context manipulation is Python 3 only316_HAVE_EXCEPTION_CHAINING = sys.version_info[0] >= 3317if _HAVE_EXCEPTION_CHAINING:318def _make_context_fixer(frame_exc):319def _fix_exception_context(new_exc, old_exc):320# Context may not be correct, so find the end of the chain321while 1:322exc_context = new_exc.__context__323if exc_context is old_exc:324# Context is already set correctly (see issue 20317)325return326if exc_context is None or exc_context is frame_exc:327break328new_exc = exc_context329# Change the end of the chain to point to the exception330# we expect it to reference331new_exc.__context__ = old_exc332return _fix_exception_context333334def _reraise_with_existing_context(exc_details):335try:336# bare "raise exc_details[1]" replaces our carefully337# set-up context338fixed_ctx = exc_details[1].__context__339raise exc_details[1]340except BaseException:341exc_details[1].__context__ = fixed_ctx342raise343else:344# No exception context in Python 2345def _make_context_fixer(frame_exc):346return lambda new_exc, old_exc: None347348# Use 3 argument raise in Python 2,349# but use exec to avoid SyntaxError in Python 3350def _reraise_with_existing_context(exc_details):351exc_type, exc_value, exc_tb = exc_details352exec("raise exc_type, exc_value, exc_tb")353354# Handle old-style classes if they exist355try:356from types import InstanceType357except ImportError:358# Python 3 doesn't have old-style classes359_get_type = type360else:361# Need to handle old-style context managers on Python 2362def _get_type(obj):363obj_type = type(obj)364if obj_type is InstanceType:365return obj.__class__ # Old-style class366return obj_type # New-style class367368369# Inspired by discussions on http://bugs.python.org/issue13585370class ExitStack(object):371"""Context manager for dynamic management of a stack of exit callbacks372373For example:374375with ExitStack() as stack:376files = [stack.enter_context(open(fname)) for fname in filenames]377# All opened files will automatically be closed at the end of378# the with statement, even if attempts to open files later379# in the list raise an exception380381"""382def __init__(self):383self._exit_callbacks = deque()384385def pop_all(self):386"""Preserve the context stack by transferring it to a new instance"""387new_stack = type(self)()388new_stack._exit_callbacks = self._exit_callbacks389self._exit_callbacks = deque()390return new_stack391392def _push_cm_exit(self, cm, cm_exit):393"""Helper to correctly register callbacks to __exit__ methods"""394def _exit_wrapper(*exc_details):395return cm_exit(cm, *exc_details)396_exit_wrapper.__self__ = cm397self.push(_exit_wrapper)398399def push(self, exit):400"""Registers a callback with the standard __exit__ method signature401402Can suppress exceptions the same way __exit__ methods can.403404Also accepts any object with an __exit__ method (registering a call405to the method instead of the object itself)406"""407# We use an unbound method rather than a bound method to follow408# the standard lookup behaviour for special methods409_cb_type = _get_type(exit)410try:411exit_method = _cb_type.__exit__412except AttributeError:413# Not a context manager, so assume its a callable414self._exit_callbacks.append(exit)415else:416self._push_cm_exit(exit, exit_method)417return exit # Allow use as a decorator418419def callback(self, callback, *args, **kwds):420"""Registers an arbitrary callback and arguments.421422Cannot suppress exceptions.423"""424def _exit_wrapper(exc_type, exc, tb):425callback(*args, **kwds)426# We changed the signature, so using @wraps is not appropriate, but427# setting __wrapped__ may still help with introspection428_exit_wrapper.__wrapped__ = callback429self.push(_exit_wrapper)430return callback # Allow use as a decorator431432def enter_context(self, cm):433"""Enters the supplied context manager434435If successful, also pushes its __exit__ method as a callback and436returns the result of the __enter__ method.437"""438# We look up the special methods on the type to match the with statement439_cm_type = _get_type(cm)440_exit = _cm_type.__exit__441result = _cm_type.__enter__(cm)442self._push_cm_exit(cm, _exit)443return result444445def close(self):446"""Immediately unwind the context stack"""447self.__exit__(None, None, None)448449def __enter__(self):450return self451452def __exit__(self, *exc_details):453received_exc = exc_details[0] is not None454455# We manipulate the exception state so it behaves as though456# we were actually nesting multiple with statements457frame_exc = sys.exc_info()[1]458_fix_exception_context = _make_context_fixer(frame_exc)459460# Callbacks are invoked in LIFO order to match the behaviour of461# nested context managers462suppressed_exc = False463pending_raise = False464while self._exit_callbacks:465cb = self._exit_callbacks.pop()466try:467if cb(*exc_details):468suppressed_exc = True469pending_raise = False470exc_details = (None, None, None)471except:472new_exc_details = sys.exc_info()473# simulate the stack of exceptions by setting the context474_fix_exception_context(new_exc_details[1], exc_details[1])475pending_raise = True476exc_details = new_exc_details477if pending_raise:478_reraise_with_existing_context(exc_details)479return received_exc and suppressed_exc480481482# Preserve backwards compatibility483class ContextStack(ExitStack):484"""Backwards compatibility alias for ExitStack"""485486def __init__(self):487warnings.warn("ContextStack has been renamed to ExitStack",488DeprecationWarning)489super(ContextStack, self).__init__()490491def register_exit(self, callback):492return self.push(callback)493494def register(self, callback, *args, **kwds):495return self.callback(callback, *args, **kwds)496497def preserve(self):498return self.pop_all()499500501class nullcontext(AbstractContextManager):502"""Context manager that does no additional processing.503Used as a stand-in for a normal context manager, when a particular504block of code is only sometimes used with a normal context manager:505cm = optional_cm if condition else nullcontext()506with cm:507# Perform operation, using optional_cm if condition is True508"""509510def __init__(self, enter_result=None):511self.enter_result = enter_result512513def __enter__(self):514return self.enter_result515516def __exit__(self, *excinfo):517pass518519520