+++ /dev/null
-"""Utilities for with-statement contexts. See PEP 343."""\r
-\r
-import sys\r
-from functools import wraps\r
-from warnings import warn\r
-\r
-__all__ = ["contextmanager", "nested", "closing"]\r
-\r
-class GeneratorContextManager(object):\r
- """Helper for @contextmanager decorator."""\r
-\r
- def __init__(self, gen):\r
- self.gen = gen\r
-\r
- def __enter__(self):\r
- try:\r
- return self.gen.next()\r
- except StopIteration:\r
- raise RuntimeError("generator didn't yield")\r
-\r
- def __exit__(self, type, value, traceback):\r
- if type is None:\r
- try:\r
- self.gen.next()\r
- except StopIteration:\r
- return\r
- else:\r
- raise RuntimeError("generator didn't stop")\r
- else:\r
- if value is None:\r
- # Need to force instantiation so we can reliably\r
- # tell if we get the same exception back\r
- value = type()\r
- try:\r
- self.gen.throw(type, value, traceback)\r
- raise RuntimeError("generator didn't stop after throw()")\r
- except StopIteration, exc:\r
- # Suppress the exception *unless* it's the same exception that\r
- # was passed to throw(). This prevents a StopIteration\r
- # raised inside the "with" statement from being suppressed\r
- return exc is not value\r
- except:\r
- # only re-raise if it's *not* the exception that was\r
- # passed to throw(), because __exit__() must not raise\r
- # an exception unless __exit__() itself failed. But throw()\r
- # has to raise the exception to signal propagation, so this\r
- # fixes the impedance mismatch between the throw() protocol\r
- # and the __exit__() protocol.\r
- #\r
- if sys.exc_info()[1] is not value:\r
- raise\r
-\r
-\r
-def contextmanager(func):\r
- """@contextmanager decorator.\r
-\r
- Typical usage:\r
-\r
- @contextmanager\r
- def some_generator(<arguments>):\r
- <setup>\r
- try:\r
- yield <value>\r
- finally:\r
- <cleanup>\r
-\r
- This makes this:\r
-\r
- with some_generator(<arguments>) as <variable>:\r
- <body>\r
-\r
- equivalent to this:\r
-\r
- <setup>\r
- try:\r
- <variable> = <value>\r
- <body>\r
- finally:\r
- <cleanup>\r
-\r
- """\r
- @wraps(func)\r
- def helper(*args, **kwds):\r
- return GeneratorContextManager(func(*args, **kwds))\r
- return helper\r
-\r
-\r
-@contextmanager\r
-def nested(*managers):\r
- """Combine multiple context managers into a single nested context manager.\r
-\r
- This function has been deprecated in favour of the multiple manager form\r
- of the with statement.\r
-\r
- The one advantage of this function over the multiple manager form of the\r
- with statement is that argument unpacking allows it to be\r
- used with a variable number of context managers as follows:\r
-\r
- with nested(*managers):\r
- do_something()\r
-\r
- """\r
- warn("With-statements now directly support multiple context managers",\r
- DeprecationWarning, 3)\r
- exits = []\r
- vars = []\r
- exc = (None, None, None)\r
- try:\r
- for mgr in managers:\r
- exit = mgr.__exit__\r
- enter = mgr.__enter__\r
- vars.append(enter())\r
- exits.append(exit)\r
- yield vars\r
- except:\r
- exc = sys.exc_info()\r
- finally:\r
- while exits:\r
- exit = exits.pop()\r
- try:\r
- if exit(*exc):\r
- exc = (None, None, None)\r
- except:\r
- exc = sys.exc_info()\r
- if exc != (None, None, None):\r
- # Don't rely on sys.exc_info() still containing\r
- # the right information. Another exception may\r
- # have been raised and caught by an exit method\r
- raise exc[0], exc[1], exc[2]\r
-\r
-\r
-class closing(object):\r
- """Context to automatically close something at the end of a block.\r
-\r
- Code like this:\r
-\r
- with closing(<module>.open(<arguments>)) as f:\r
- <block>\r
-\r
- is equivalent to this:\r
-\r
- f = <module>.open(<arguments>)\r
- try:\r
- <block>\r
- finally:\r
- f.close()\r
-\r
- """\r
- def __init__(self, thing):\r
- self.thing = thing\r
- def __enter__(self):\r
- return self.thing\r
- def __exit__(self, *exc_info):\r
- self.thing.close()\r