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 42 -class GeneratorContextManager(object):
43 """Helper for @contextmanager decorator.""" 44
45 - def __init__(self, gen):
46 self.gen = gen
47
48 - def __enter__(self):
49 try: 50 return self.gen.next() 51 except StopIteration: 52 raise RuntimeError("generator didn't yield")
53
54 - def __exit__(self, type, value, tb):
55 if type is None: 56 try: 57 self.gen.next() 58 except StopIteration: 59 return 60 else: 61 raise RuntimeError("generator didn't stop") 62 else: 63 if value is None: 64 # Need to force instantiation so we can reliably 65 # tell if we get the same exception back 66 value = type() 67 try: 68 try: 69 self.gen.next() 70 except StopIteration: 71 import traceback 72 traceback.print_exception(type, value, tb) 73 raise value 74 except StopIteration, exc: 75 # Suppress the exception *unless* it's the same exception that 76 # was passed to throw(). This prevents a StopIteration 77 # raised inside the "with" statement from being suppressed 78 return exc is not value
79
80 81 -def contextmanager(func):
82 """@contextmanager decorator. 83 84 Typical usage: 85 86 @contextmanager 87 def some_generator(<arguments>): 88 <setup> 89 try: 90 yield <value> 91 finally: 92 <cleanup> 93 94 This makes this: 95 96 with some_generator(<arguments>) as <variable>: 97 <body> 98 99 equivalent to this: 100 101 <setup> 102 try: 103 <variable> = <value> 104 <body> 105 finally: 106 <cleanup> 107 108 """ 109 110 def helper(*args, **kwds): 111 return GeneratorContextManager(func(*args, **kwds))
112 try: 113 helper.__name__ = func.__name__ 114 helper.__doc__ = func.__doc__ 115 helper.__dict__ = func.__dict__ 116 except: 117 pass 118 return helper 119
120 121 @contextmanager 122 -def nested(*managers):
123 """Support multiple context managers in a single with-statement. 124 125 Code like this: 126 127 with nested(A, B, C) as (X, Y, Z): 128 <body> 129 130 is equivalent to this: 131 132 with A as X: 133 with B as Y: 134 with C as Z: 135 <body> 136 137 """ 138 exits = [] 139 vars = [] 140 exc = (None, None, None) 141 # Lambdas are an easy way to create unique objects. We don't want 142 # this to be None, since our answer might actually be None 143 undefined = lambda: 42 144 result = undefined 145 146 try: 147 for mgr in managers: 148 exit = mgr.__exit__ 149 enter = mgr.__enter__ 150 vars.append(enter()) 151 exits.append(exit) 152 result = vars 153 except: 154 exc = sys.exc_info() 155 156 # If nothing has gone wrong, then result contains our return value 157 # and thus it is not equal to 'undefined'. Thus, yield the value. 158 if result != undefined: 159 yield result 160 161 while exits: 162 exit = exits.pop() 163 try: 164 if exit(*exc): 165 exc = (None, None, None) 166 except: 167 exc = sys.exc_info() 168 if exc != (None, None, None): 169 # Don't rely on sys.exc_info() still containing 170 # the right information. Another exception may 171 # have been raised and caught by an exit method 172 raise exc[0], exc[1], exc[2]
173
174 175 -class closing(object):
176 """Context to automatically close something at the end of a block. 177 178 Code like this: 179 180 with closing(<module>.open(<arguments>)) as f: 181 <block> 182 183 is equivalent to this: 184 185 f = <module>.open(<arguments>) 186 try: 187 <block> 188 finally: 189 f.close() 190 191 """ 192
193 - def __init__(self, thing):
194 self.thing = thing
195
196 - def __enter__(self):
197 return self.thing
198
199 - def __exit__(self, *exc_info):
200 self.thing.close()
201