diff options
Diffstat (limited to 'Lib/contextlib.py')
| -rw-r--r-- | Lib/contextlib.py | 81 | 
1 files changed, 52 insertions, 29 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 144d6bb..a564943 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -48,7 +48,7 @@ class _GeneratorContextManager(ContextDecorator):          try:              return next(self.gen)          except StopIteration: -            raise RuntimeError("generator didn't yield") +            raise RuntimeError("generator didn't yield") from None      def __exit__(self, type, value, traceback):          if type is None: @@ -117,6 +117,9 @@ def contextmanager(func):      return helper +# Unfortunately, this was originally published as a class, so +# backwards compatibility prevents the use of the wrapper function +# approach used for the other classes  class closing(object):      """Context to automatically close something at the end of a block. @@ -141,55 +144,75 @@ class closing(object):      def __exit__(self, *exc_info):          self.thing.close() -class redirect_stdout: +class _RedirectStdout: +    """Helper for redirect_stdout.""" + +    def __init__(self, new_target): +        self._new_target = new_target +        self._old_target = self._sentinel = object() + +    def __enter__(self): +        if self._old_target is not self._sentinel: +            raise RuntimeError("Cannot reenter {!r}".format(self)) +        self._old_target = sys.stdout +        sys.stdout = self._new_target +        return self._new_target + +    def __exit__(self, exctype, excinst, exctb): +        restore_stdout = self._old_target +        self._old_target = self._sentinel +        sys.stdout = restore_stdout + +# Use a wrapper function since we don't care about supporting inheritance +# and a function gives much cleaner output in help() +def redirect_stdout(target):      """Context manager for temporarily redirecting stdout to another file          # How to send help() to stderr -          with redirect_stdout(sys.stderr):              help(dir)          # How to write help() to a file -          with open('help.txt', 'w') as f:              with redirect_stdout(f):                  help(pow) - -        # How to capture disassembly to a string - -        import dis -        import io - -        f = io.StringIO() -        with redirect_stdout(f): -            dis.dis('x**2 - y**2') -        s = f.getvalue() -      """ +    return _RedirectStdout(target) -    def __init__(self, new_target): -        self.new_target = new_target + +class _SuppressExceptions: +    """Helper for suppress.""" +    def __init__(self, *exceptions): +        self._exceptions = exceptions      def __enter__(self): -        self.old_target = sys.stdout -        sys.stdout = self.new_target -        return self.new_target +        pass      def __exit__(self, exctype, excinst, exctb): -        sys.stdout = self.old_target - -@contextmanager +        # Unlike isinstance and issubclass, exception handling only +        # looks at the concrete type heirarchy (ignoring the instance +        # and subclass checking hooks). However, all exceptions are +        # also required to be concrete subclasses of BaseException, so +        # if there's a discrepancy in behaviour, we currently consider it +        # the fault of the strange way the exception has been defined rather +        # than the fact that issubclass can be customised while the +        # exception checks can't. +        # See http://bugs.python.org/issue12029 for more details +        return exctype is not None and issubclass(exctype, self._exceptions) + +# Use a wrapper function since we don't care about supporting inheritance +# and a function gives much cleaner output in help()  def suppress(*exceptions):      """Context manager to suppress specified exceptions -         with suppress(OSError): -             os.remove(somefile) +    After the exception is suppressed, execution proceeds with the next +    statement following the with statement. +         with suppress(FileNotFoundError): +             os.remove(somefile) +         # Execution still resumes here if the file was already removed      """ -    try: -        yield -    except exceptions: -        pass +    return _SuppressExceptions(*exceptions)  # Inspired by discussions on http://bugs.python.org/issue13585  class ExitStack(object):  | 
