Package translate :: Package misc :: Module contextlib
[hide private]
[frames] | no frames]

Source Code for Module translate.misc.contextlib

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # Copyright 2002-2006 Zuza Software Foundation 
  5  #  
  6  # This file is part of translate. 
  7  # The file was copied from the Python 2.5 source. 
  8  # 
  9  # translate is free software; you can redistribute it and/or modify 
 10  # it under the terms of the GNU General Public License as published by 
 11  # the Free Software Foundation; either version 2 of the License, or 
 12  # (at your option) any later version. 
 13  #  
 14  # translate is distributed in the hope that it will be useful, 
 15  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 16  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 17  # GNU General Public License for more details. 
 18  # 
 19  # You should have received a copy of the GNU General Public License 
 20  # along with translate; if not, write to the Free Software 
 21  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 22  # 
 23   
 24  # NB! IMPORTANT SEMANTIC DIFFERENCE WITH THE OFFICIAL contextlib. 
 25  # In Python 2.5+, if an exception is thrown in a 'with' statement 
 26  # which uses a generator-based context manager (that is, a 
 27  # context manager created by decorating a generator with 
 28  # @contextmanager), the exception will be propagated to the  
 29  # generator via the .throw method of the generator. 
 30  # 
 31  # This does not exist in Python 2.4. Thus, we just naively finish 
 32  # off the context manager. This also means that generator-based 
 33  # context managers can't deal with exceptions, so be warned. 
 34   
 35  """Utilities for with-statement contexts.  See PEP 343.""" 
 36   
 37  import sys 
 38   
 39  __all__ = ["contextmanager", "nested", "closing"] 
40 41 -class GeneratorContextManager(object):
42 """Helper for @contextmanager decorator.""" 43
44 - def __init__(self, gen):
45 self.gen = gen
46
47 - def __enter__(self):
48 try: 49 return self.gen.next() 50 except StopIteration: 51 raise RuntimeError("generator didn't yield")
52
53 - def __exit__(self, type, value, tb):
54 if type is None: 55 try: 56 self.gen.next() 57 except StopIteration: 58 return 59 else: 60 raise RuntimeError("generator didn't stop") 61 else: 62 if value is None: 63 # Need to force instantiation so we can reliably 64 # tell if we get the same exception back 65 value = type() 66 try: 67 try: 68 self.gen.next() 69 except StopIteration: 70 import traceback 71 traceback.print_exception(type, value, tb) 72 raise value 73 except StopIteration, exc: 74 # Suppress the exception *unless* it's the same exception that 75 # was passed to throw(). This prevents a StopIteration 76 # raised inside the "with" statement from being suppressed 77 return exc is not value
78
79 -def contextmanager(func):
80 """@contextmanager decorator. 81 82 Typical usage: 83 84 @contextmanager 85 def some_generator(<arguments>): 86 <setup> 87 try: 88 yield <value> 89 finally: 90 <cleanup> 91 92 This makes this: 93 94 with some_generator(<arguments>) as <variable>: 95 <body> 96 97 equivalent to this: 98 99 <setup> 100 try: 101 <variable> = <value> 102 <body> 103 finally: 104 <cleanup> 105 106 """ 107 def helper(*args, **kwds): 108 return GeneratorContextManager(func(*args, **kwds))
109 try: 110 helper.__name__ = func.__name__ 111 helper.__doc__ = func.__doc__ 112 helper.__dict__ = func.__dict__ 113 except: 114 pass 115 return helper 116
117 118 @contextmanager 119 -def nested(*managers):
120 """Support multiple context managers in a single with-statement. 121 122 Code like this: 123 124 with nested(A, B, C) as (X, Y, Z): 125 <body> 126 127 is equivalent to this: 128 129 with A as X: 130 with B as Y: 131 with C as Z: 132 <body> 133 134 """ 135 exits = [] 136 vars = [] 137 exc = (None, None, None) 138 # Lambdas are an easy way to create unique objects. We don't want 139 # this to be None, since our answer might actually be None 140 undefined = lambda: 42 141 result = undefined 142 143 try: 144 for mgr in managers: 145 exit = mgr.__exit__ 146 enter = mgr.__enter__ 147 vars.append(enter()) 148 exits.append(exit) 149 result = vars 150 except: 151 exc = sys.exc_info() 152 153 # If nothing has gone wrong, then result contains our return value 154 # and thus it is not equal to 'undefined'. Thus, yield the value. 155 if result != undefined: 156 yield result 157 158 while exits: 159 exit = exits.pop() 160 try: 161 if exit(*exc): 162 exc = (None, None, None) 163 except: 164 exc = sys.exc_info() 165 if exc != (None, None, None): 166 # Don't rely on sys.exc_info() still containing 167 # the right information. Another exception may 168 # have been raised and caught by an exit method 169 raise exc[0], exc[1], exc[2]
170
171 -class closing(object):
172 """Context to automatically close something at the end of a block. 173 174 Code like this: 175 176 with closing(<module>.open(<arguments>)) as f: 177 <block> 178 179 is equivalent to this: 180 181 f = <module>.open(<arguments>) 182 try: 183 <block> 184 finally: 185 f.close() 186 187 """
188 - def __init__(self, thing):
189 self.thing = thing
190 - def __enter__(self):
191 return self.thing
192 - def __exit__(self, *exc_info):
193 self.thing.close()
194