github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/third_party/stdlib/contextlib.py (about)

     1  """Utilities for with-statement contexts.  See PEP 343."""
     2  
     3  import sys
     4  # from functools import wraps
     5  import functools
     6  wraps = functools.wraps
     7  # from warnings import warn
     8  import warnings
     9  warn = warnings.warn
    10  
    11  
    12  __all__ = ["contextmanager", "nested", "closing"]
    13  
    14  class GeneratorContextManager(object):
    15      """Helper for @contextmanager decorator."""
    16  
    17      def __init__(self, gen):
    18          self.gen = gen
    19  
    20      def __enter__(self):
    21          try:
    22              return self.gen.next()
    23          except StopIteration:
    24              raise RuntimeError("generator didn't yield")
    25  
    26      def __exit__(self, t, value, tb):
    27          if t is None:
    28              try:
    29                  self.gen.next()
    30              except StopIteration:
    31                  return
    32              else:
    33                  raise RuntimeError("generator didn't stop")
    34          else:
    35              if value is None:
    36                  # Need to force instantiation so we can reliably
    37                  # tell if we get the same exception back
    38                  value = t()
    39              try:
    40                  # self.gen.throw(t, value, traceback)
    41                  # raise RuntimeError("generator didn't stop after throw()")
    42                  raise t(value)
    43              except StopIteration, exc:
    44                  # Suppress the exception *unless* it's the same exception that
    45                  # was passed to throw().  This prevents a StopIteration
    46                  # raised inside the "with" statement from being suppressed
    47                  return exc is not value
    48              except:
    49                  # only re-raise if it's *not* the exception that was
    50                  # passed to throw(), because __exit__() must not raise
    51                  # an exception unless __exit__() itself failed.  But throw()
    52                  # has to raise the exception to signal propagation, so this
    53                  # fixes the impedance mismatch between the throw() protocol
    54                  # and the __exit__() protocol.
    55                  #
    56                  if sys.exc_info()[1] is not value:
    57                      raise
    58  
    59  
    60  def contextmanager(func):
    61      """@contextmanager decorator.
    62  
    63      Typical usage:
    64  
    65          @contextmanager
    66          def some_generator(<arguments>):
    67              <setup>
    68              try:
    69                  yield <value>
    70              finally:
    71                  <cleanup>
    72  
    73      This makes this:
    74  
    75          with some_generator(<arguments>) as <variable>:
    76              <body>
    77  
    78      equivalent to this:
    79  
    80          <setup>
    81          try:
    82              <variable> = <value>
    83              <body>
    84          finally:
    85              <cleanup>
    86  
    87      """
    88      @wraps(func)
    89      def helper(*args, **kwds):
    90          return GeneratorContextManager(func(*args, **kwds))
    91      return helper
    92  
    93  
    94  @contextmanager
    95  def nested(*managers):
    96      """Combine multiple context managers into a single nested context manager.
    97  
    98     This function has been deprecated in favour of the multiple manager form
    99     of the with statement.
   100  
   101     The one advantage of this function over the multiple manager form of the
   102     with statement is that argument unpacking allows it to be
   103     used with a variable number of context managers as follows:
   104  
   105        with nested(*managers):
   106            do_something()
   107  
   108      """
   109      warn("With-statements now directly support multiple context managers",
   110           DeprecationWarning, 3)
   111      exits = []
   112      vars = []
   113      exc = (None, None, None)
   114      try:
   115          for mgr in managers:
   116              exit = mgr.__exit__
   117              enter = mgr.__enter__
   118              vars.append(enter())
   119              exits.append(exit)
   120          yield vars
   121      except:
   122          exc = sys.exc_info()
   123      finally:
   124          while exits:
   125              exit = exits.pop()
   126              try:
   127                  if exit(*exc):
   128                      exc = (None, None, None)
   129              except:
   130                  exc = sys.exc_info()
   131          if exc != (None, None, None):
   132              # Don't rely on sys.exc_info() still containing
   133              # the right information. Another exception may
   134              # have been raised and caught by an exit method
   135              raise exc[0], exc[1], exc[2]
   136  
   137  
   138  class closing(object):
   139      """Context to automatically close something at the end of a block.
   140  
   141      Code like this:
   142  
   143          with closing(<module>.open(<arguments>)) as f:
   144              <block>
   145  
   146      is equivalent to this:
   147  
   148          f = <module>.open(<arguments>)
   149          try:
   150              <block>
   151          finally:
   152              f.close()
   153  
   154      """
   155      def __init__(self, thing):
   156          self.thing = thing
   157      def __enter__(self):
   158          return self.thing
   159      def __exit__(self, *exc_info):
   160          self.thing.close()