1### 2# Copyright (c) 2005-2009, Jeremiah Fincher 3# Copyright (c) 2009-2010, James McCoy 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, 10# this list of conditions, and the following disclaimer. 11# * Redistributions in binary form must reproduce the above copyright notice, 12# this list of conditions, and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# * Neither the name of the author of this software nor the name of 15# contributors to this software may be used to endorse or promote products 16# derived from this software without specific prior written consent. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28# POSSIBILITY OF SUCH DAMAGE. 29### 30 31import sys 32import types 33import fnmatch 34import threading 35 36def universalImport(*names): 37 """Attempt to import the given modules, in order, returning the first 38 successfully imported module. ImportError will be raised, as usual, if 39 no imports succeed. To emulate ``from ModuleA import ModuleB'', pass the 40 string 'ModuleA.ModuleB'""" 41 f = sys._getframe(1) 42 for name in names: 43 try: 44 # __import__ didn't gain keyword arguments until 2.5 45 ret = __import__(name, f.f_globals) 46 except ImportError: 47 continue 48 else: 49 if '.' in name: 50 parts = name.split('.')[1:] 51 while parts: 52 ret = getattr(ret, parts[0]) 53 del parts[0] 54 return ret 55 raise ImportError(','.join(names)) 56 57def changeFunctionName(f, name, doc=None): 58 if doc is None: 59 doc = f.__doc__ 60 if hasattr(f, '__closure__'): 61 closure = f.__closure__ 62 else: 63 # Pypy 64 closure = f.func_closure 65 newf = types.FunctionType(f.__code__, f.__globals__, name, 66 f.__defaults__, closure) 67 newf.__doc__ = doc 68 return newf 69 70class Object(object): 71 def __ne__(self, other): 72 return not self == other 73 74class MetaSynchronized(type): 75 METHODS = '__synchronized__' 76 LOCK = '_MetaSynchronized_rlock' 77 def __new__(cls, name, bases, dict): 78 sync = set() 79 for base in bases: 80 if hasattr(base, MetaSynchronized.METHODS): 81 sync.update(getattr(base, MetaSynchronized.METHODS)) 82 if MetaSynchronized.METHODS in dict: 83 sync.update(dict[MetaSynchronized.METHODS]) 84 if sync: 85 def synchronized(f): 86 def g(self, *args, **kwargs): 87 lock = getattr(self, MetaSynchronized.LOCK) 88 lock.acquire() 89 try: 90 f(self, *args, **kwargs) 91 finally: 92 lock.release() 93 return changeFunctionName(g, f.__name__, f.__doc__) 94 for attr in sync: 95 if attr in dict: 96 dict[attr] = synchronized(dict[attr]) 97 original__init__ = dict.get('__init__') 98 def __init__(self, *args, **kwargs): 99 if not hasattr(self, MetaSynchronized.LOCK): 100 setattr(self, MetaSynchronized.LOCK, threading.RLock()) 101 if original__init__: 102 original__init__(self, *args, **kwargs) 103 else: 104 # newclass is defined below. 105 super(newclass, self).__init__(*args, **kwargs) 106 dict['__init__'] = __init__ 107 newclass = super(MetaSynchronized, cls).__new__(cls, name, bases, dict) 108 return newclass 109Synchronized = MetaSynchronized('Synchronized', (), {}) 110 111def glob2re(g): 112 pattern = fnmatch.translate(g) 113 if pattern.startswith('(?s:') and pattern.endswith(')\\Z'): 114 # Python >= 3.6 115 return pattern[4:-3] + '\\Z' 116 elif pattern.endswith('\\Z(?ms)'): 117 # Python >= 2.6 and < 3.6 118 # 119 # Translate glob to regular expression, trimming the "match EOL" 120 # portion of the regular expression. 121 # Some Python versions use \Z(?ms) per 122 # https://bugs.python.org/issue6665 123 return pattern[:-7] 124 else: 125 assert False, 'Python < 2.6, or unknown behavior of fnmatch.translate.' 126 127 128_debug_software_name = 'Limnoria' 129_debug_software_version = None 130# From http://code.activestate.com/recipes/52215-get-more-information-from-tracebacks/ 131def collect_extra_debug_data(): 132 """ 133 Print the usual traceback information, followed by a listing of all the 134 local variables in each frame. 135 """ 136 data = '' 137 try: 138 tb = sys.exc_info()[2] 139 stack = [] 140 141 while tb: 142 stack.append(tb.tb_frame) 143 tb = tb.tb_next 144 finally: 145 del tb 146 147 if _debug_software_version: 148 data += '%s version: %s\n\n' % \ 149 (_debug_software_name, _debug_software_version) 150 else: 151 data += '(Cannot get %s version.)\n\n' % _debug_software_name 152 153 data += 'Locals by frame, innermost last:\n' 154 for frame in stack: 155 data += '\n\n' 156 data += ('Frame %s in %s at line %s\n' % (frame.f_code.co_name, 157 frame.f_code.co_filename, 158 frame.f_lineno)) 159 frame_locals = frame.f_locals 160 for inspected in ('self', 'cls'): 161 if inspected in frame_locals: 162 try: 163 attribute_names = dir(frame_locals[inspected]) 164 except Exception: # For Python 2 and Pypy 165 try: 166 attribute_names = list( 167 frame_locals[inspected].__dict__) 168 except Exception: 169 attribute_names = [] 170 for attr_name in attribute_names: 171 try: 172 v = getattr(frame_locals[inspected], attr_name) 173 except Exception: 174 v = '<ERROR WHILE GETTING VALUE>' 175 frame_locals['%s.%s' % (inspected, attr_name)] = v 176 for key, value in frame_locals.items(): 177 if key == '__builtins__': 178 # This is flooding 179 continue 180 data += ('\t%20s = ' % key) 181 #We have to be careful not to cause a new error in our error 182 #printer! Calling str() on an unknown object could cause an 183 #error we don't want. 184 try: 185 data += repr(value) + '\n' 186 except Exception: 187 data += '<ERROR WHILE PRINTING VALUE>\n' 188 data += '\n' 189 data += '+-----------------------+\n' 190 data += '| End of locals display |\n' 191 data += '+-----------------------+\n' 192 data += '\n' 193 return data 194 195# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=78: 196