1import collections 2import inspect 3import io 4import sys 5 6py27 = sys.version_info >= (2, 7) 7py2k = sys.version_info.major < 3 8py3k = sys.version_info.major >= 3 9py35 = sys.version_info >= (3, 5) 10py36 = sys.version_info >= (3, 6) 11 12 13ArgSpec = collections.namedtuple( 14 "ArgSpec", ["args", "varargs", "keywords", "defaults"] 15) 16 17 18def inspect_getargspec(func): 19 """getargspec based on fully vendored getfullargspec from Python 3.3.""" 20 21 if inspect.ismethod(func): 22 func = func.__func__ 23 if not inspect.isfunction(func): 24 raise TypeError("{!r} is not a Python function".format(func)) 25 26 co = func.__code__ 27 if not inspect.iscode(co): 28 raise TypeError("{!r} is not a code object".format(co)) 29 30 nargs = co.co_argcount 31 names = co.co_varnames 32 nkwargs = co.co_kwonlyargcount if py3k else 0 33 args = list(names[:nargs]) 34 35 nargs += nkwargs 36 varargs = None 37 if co.co_flags & inspect.CO_VARARGS: 38 varargs = co.co_varnames[nargs] 39 nargs = nargs + 1 40 varkw = None 41 if co.co_flags & inspect.CO_VARKEYWORDS: 42 varkw = co.co_varnames[nargs] 43 44 return ArgSpec(args, varargs, varkw, func.__defaults__) 45 46 47if py3k: 48 from io import StringIO 49else: 50 # accepts strings 51 from StringIO import StringIO # noqa 52 53if py3k: 54 import builtins as compat_builtins 55 56 string_types = (str,) 57 binary_type = bytes 58 text_type = str 59 60 def callable(fn): # noqa 61 return hasattr(fn, "__call__") 62 63 def u(s): 64 return s 65 66 def ue(s): 67 return s 68 69 range = range # noqa 70else: 71 import __builtin__ as compat_builtins 72 73 string_types = (basestring,) # noqa 74 binary_type = str 75 text_type = unicode # noqa 76 callable = callable # noqa 77 78 def u(s): 79 return unicode(s, "utf-8") # noqa 80 81 def ue(s): 82 return unicode(s, "unicode_escape") # noqa 83 84 range = xrange # noqa 85 86if py3k: 87 import collections.abc as collections_abc 88else: 89 import collections as collections_abc # noqa 90 91if py35: 92 93 def _formatannotation(annotation, base_module=None): 94 """vendored from python 3.7 95 """ 96 97 if getattr(annotation, "__module__", None) == "typing": 98 return repr(annotation).replace("typing.", "") 99 if isinstance(annotation, type): 100 if annotation.__module__ in ("builtins", base_module): 101 return annotation.__qualname__ 102 return annotation.__module__ + "." + annotation.__qualname__ 103 return repr(annotation) 104 105 def inspect_formatargspec( 106 args, 107 varargs=None, 108 varkw=None, 109 defaults=None, 110 kwonlyargs=(), 111 kwonlydefaults={}, 112 annotations={}, 113 formatarg=str, 114 formatvarargs=lambda name: "*" + name, 115 formatvarkw=lambda name: "**" + name, 116 formatvalue=lambda value: "=" + repr(value), 117 formatreturns=lambda text: " -> " + text, 118 formatannotation=_formatannotation, 119 ): 120 """Copy formatargspec from python 3.7 standard library. 121 122 Python 3 has deprecated formatargspec and requested that Signature 123 be used instead, however this requires a full reimplementation 124 of formatargspec() in terms of creating Parameter objects and such. 125 Instead of introducing all the object-creation overhead and having 126 to reinvent from scratch, just copy their compatibility routine. 127 128 """ 129 130 def formatargandannotation(arg): 131 result = formatarg(arg) 132 if arg in annotations: 133 result += ": " + formatannotation(annotations[arg]) 134 return result 135 136 specs = [] 137 if defaults: 138 firstdefault = len(args) - len(defaults) 139 for i, arg in enumerate(args): 140 spec = formatargandannotation(arg) 141 if defaults and i >= firstdefault: 142 spec = spec + formatvalue(defaults[i - firstdefault]) 143 specs.append(spec) 144 if varargs is not None: 145 specs.append(formatvarargs(formatargandannotation(varargs))) 146 else: 147 if kwonlyargs: 148 specs.append("*") 149 if kwonlyargs: 150 for kwonlyarg in kwonlyargs: 151 spec = formatargandannotation(kwonlyarg) 152 if kwonlydefaults and kwonlyarg in kwonlydefaults: 153 spec += formatvalue(kwonlydefaults[kwonlyarg]) 154 specs.append(spec) 155 if varkw is not None: 156 specs.append(formatvarkw(formatargandannotation(varkw))) 157 result = "(" + ", ".join(specs) + ")" 158 if "return" in annotations: 159 result += formatreturns(formatannotation(annotations["return"])) 160 return result 161 162 163else: 164 from inspect import formatargspec as inspect_formatargspec # noqa 165 166 167if py3k: 168 from configparser import ConfigParser as SafeConfigParser 169 import configparser 170else: 171 from ConfigParser import SafeConfigParser # noqa 172 import ConfigParser as configparser # noqa 173 174if py2k: 175 from mako.util import parse_encoding 176 177if py35: 178 import importlib.util 179 import importlib.machinery 180 181 def load_module_py(module_id, path): 182 spec = importlib.util.spec_from_file_location(module_id, path) 183 module = importlib.util.module_from_spec(spec) 184 spec.loader.exec_module(module) 185 return module 186 187 def load_module_pyc(module_id, path): 188 spec = importlib.util.spec_from_file_location(module_id, path) 189 module = importlib.util.module_from_spec(spec) 190 spec.loader.exec_module(module) 191 return module 192 193 194elif py3k: 195 import importlib.machinery 196 197 def load_module_py(module_id, path): 198 module = importlib.machinery.SourceFileLoader( 199 module_id, path 200 ).load_module(module_id) 201 del sys.modules[module_id] 202 return module 203 204 def load_module_pyc(module_id, path): 205 module = importlib.machinery.SourcelessFileLoader( 206 module_id, path 207 ).load_module(module_id) 208 del sys.modules[module_id] 209 return module 210 211 212if py3k: 213 214 def get_bytecode_suffixes(): 215 try: 216 return importlib.machinery.BYTECODE_SUFFIXES 217 except AttributeError: 218 return importlib.machinery.DEBUG_BYTECODE_SUFFIXES 219 220 def get_current_bytecode_suffixes(): 221 if py35: 222 suffixes = importlib.machinery.BYTECODE_SUFFIXES 223 else: 224 if sys.flags.optimize: 225 suffixes = importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES 226 else: 227 suffixes = importlib.machinery.BYTECODE_SUFFIXES 228 229 return suffixes 230 231 def has_pep3147(): 232 233 if py35: 234 return True 235 else: 236 # TODO: not sure if we are supporting old versions of Python 237 # the import here emits a deprecation warning which the test 238 # suite only catches if imp wasn't imported alreadt 239 # http://www.python.org/dev/peps/pep-3147/#detecting-pep-3147-availability 240 import imp 241 242 return hasattr(imp, "get_tag") 243 244 245else: 246 import imp 247 248 def load_module_py(module_id, path): # noqa 249 with open(path, "rb") as fp: 250 mod = imp.load_source(module_id, path, fp) 251 if py2k: 252 source_encoding = parse_encoding(fp) 253 if source_encoding: 254 mod._alembic_source_encoding = source_encoding 255 del sys.modules[module_id] 256 return mod 257 258 def load_module_pyc(module_id, path): # noqa 259 with open(path, "rb") as fp: 260 mod = imp.load_compiled(module_id, path, fp) 261 # no source encoding here 262 del sys.modules[module_id] 263 return mod 264 265 def get_current_bytecode_suffixes(): 266 if sys.flags.optimize: 267 return [".pyo"] # e.g. .pyo 268 else: 269 return [".pyc"] # e.g. .pyc 270 271 def has_pep3147(): 272 return False 273 274 275try: 276 exec_ = getattr(compat_builtins, "exec") 277except AttributeError: 278 # Python 2 279 def exec_(func_text, globals_, lcl): 280 exec("exec func_text in globals_, lcl") 281 282 283################################################ 284# cross-compatible metaclass implementation 285# Copyright (c) 2010-2012 Benjamin Peterson 286 287 288def with_metaclass(meta, base=object): 289 """Create a base class with a metaclass.""" 290 return meta("%sBase" % meta.__name__, (base,), {}) 291 292 293################################################ 294 295if py3k: 296 297 def reraise(tp, value, tb=None, cause=None): 298 if cause is not None: 299 value.__cause__ = cause 300 if value.__traceback__ is not tb: 301 raise value.with_traceback(tb) 302 raise value 303 304 def raise_from_cause(exception, exc_info=None): 305 if exc_info is None: 306 exc_info = sys.exc_info() 307 exc_type, exc_value, exc_tb = exc_info 308 reraise(type(exception), exception, tb=exc_tb, cause=exc_value) 309 310 311else: 312 exec( 313 "def reraise(tp, value, tb=None, cause=None):\n" 314 " raise tp, value, tb\n" 315 ) 316 317 def raise_from_cause(exception, exc_info=None): 318 # not as nice as that of Py3K, but at least preserves 319 # the code line where the issue occurred 320 if exc_info is None: 321 exc_info = sys.exc_info() 322 exc_type, exc_value, exc_tb = exc_info 323 reraise(type(exception), exception, tb=exc_tb) 324 325 326# produce a wrapper that allows encoded text to stream 327# into a given buffer, but doesn't close it. 328# not sure of a more idiomatic approach to this. 329class EncodedIO(io.TextIOWrapper): 330 def close(self): 331 pass 332 333 334if py2k: 335 # in Py2K, the io.* package is awkward because it does not 336 # easily wrap the file type (e.g. sys.stdout) and I can't 337 # figure out at all how to wrap StringIO.StringIO 338 # and also might be user specified too. So create a full 339 # adapter. 340 341 class ActLikePy3kIO(object): 342 343 """Produce an object capable of wrapping either 344 sys.stdout (e.g. file) *or* StringIO.StringIO(). 345 346 """ 347 348 def _false(self): 349 return False 350 351 def _true(self): 352 return True 353 354 readable = seekable = _false 355 writable = _true 356 closed = False 357 358 def __init__(self, file_): 359 self.file_ = file_ 360 361 def write(self, text): 362 return self.file_.write(text) 363 364 def flush(self): 365 return self.file_.flush() 366 367 class EncodedIO(EncodedIO): 368 def __init__(self, file_, encoding): 369 super(EncodedIO, self).__init__( 370 ActLikePy3kIO(file_), encoding=encoding 371 ) 372