Mercurial > repos > sanbi-uwc > vcf_to_alignment
comparison pyqver2.py @ 2:a0c85f2d74a5 draft
planemo upload for repository https://github.com/sanbi-sa/tools-sanbi-uwc commit 9612f06b8c60520dc0a047ec072ced317c7796e4
| author | sanbi-uwc |
|---|---|
| date | Wed, 01 Feb 2017 08:45:12 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:4b9ddf64558d | 2:a0c85f2d74a5 |
|---|---|
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 import compiler | |
| 4 import platform | |
| 5 import sys | |
| 6 | |
| 7 StandardModules = { | |
| 8 "__future__": (2, 1), | |
| 9 "abc": (2, 6), | |
| 10 "argparse": (2, 7), | |
| 11 "ast": (2, 6), | |
| 12 "atexit": (2, 0), | |
| 13 "bz2": (2, 3), | |
| 14 "cgitb": (2, 2), | |
| 15 "collections": (2, 4), | |
| 16 "contextlib": (2, 5), | |
| 17 "cookielib": (2, 4), | |
| 18 "cProfile": (2, 5), | |
| 19 "csv": (2, 3), | |
| 20 "ctypes": (2, 5), | |
| 21 "datetime": (2, 3), | |
| 22 "decimal": (2, 4), | |
| 23 "difflib": (2, 1), | |
| 24 "DocXMLRPCServer": (2, 3), | |
| 25 "dummy_thread": (2, 3), | |
| 26 "dummy_threading": (2, 3), | |
| 27 "email": (2, 2), | |
| 28 "fractions": (2, 6), | |
| 29 "functools": (2, 5), | |
| 30 "future_builtins": (2, 6), | |
| 31 "hashlib": (2, 5), | |
| 32 "heapq": (2, 3), | |
| 33 "hmac": (2, 2), | |
| 34 "hotshot": (2, 2), | |
| 35 "HTMLParser": (2, 2), | |
| 36 "importlib": (2, 7), | |
| 37 "inspect": (2, 1), | |
| 38 "io": (2, 6), | |
| 39 "itertools": (2, 3), | |
| 40 "json": (2, 6), | |
| 41 "logging": (2, 3), | |
| 42 "modulefinder": (2, 3), | |
| 43 "msilib": (2, 5), | |
| 44 "multiprocessing": (2, 6), | |
| 45 "netrc": (1, 5, 2), | |
| 46 "numbers": (2, 6), | |
| 47 "optparse": (2, 3), | |
| 48 "ossaudiodev": (2, 3), | |
| 49 "pickletools": (2, 3), | |
| 50 "pkgutil": (2, 3), | |
| 51 "platform": (2, 3), | |
| 52 "pydoc": (2, 1), | |
| 53 "runpy": (2, 5), | |
| 54 "sets": (2, 3), | |
| 55 "shlex": (1, 5, 2), | |
| 56 "SimpleXMLRPCServer": (2, 2), | |
| 57 "spwd": (2, 5), | |
| 58 "sqlite3": (2, 5), | |
| 59 "ssl": (2, 6), | |
| 60 "stringprep": (2, 3), | |
| 61 "subprocess": (2, 4), | |
| 62 "sysconfig": (2, 7), | |
| 63 "tarfile": (2, 3), | |
| 64 "textwrap": (2, 3), | |
| 65 "timeit": (2, 3), | |
| 66 "unittest": (2, 1), | |
| 67 "uuid": (2, 5), | |
| 68 "warnings": (2, 1), | |
| 69 "weakref": (2, 1), | |
| 70 "winsound": (1, 5, 2), | |
| 71 "wsgiref": (2, 5), | |
| 72 "xml.dom": (2, 0), | |
| 73 "xml.dom.minidom": (2, 0), | |
| 74 "xml.dom.pulldom": (2, 0), | |
| 75 "xml.etree.ElementTree": (2, 5), | |
| 76 "xml.parsers.expat":(2, 0), | |
| 77 "xml.sax": (2, 0), | |
| 78 "xml.sax.handler": (2, 0), | |
| 79 "xml.sax.saxutils": (2, 0), | |
| 80 "xml.sax.xmlreader":(2, 0), | |
| 81 "xmlrpclib": (2, 2), | |
| 82 "zipfile": (1, 6), | |
| 83 "zipimport": (2, 3), | |
| 84 "_ast": (2, 5), | |
| 85 "_winreg": (2, 0), | |
| 86 } | |
| 87 | |
| 88 Functions = { | |
| 89 "all": (2, 5), | |
| 90 "any": (2, 5), | |
| 91 "collections.Counter": (2, 7), | |
| 92 "collections.defaultdict": (2, 5), | |
| 93 "collections.OrderedDict": (2, 7), | |
| 94 "enumerate": (2, 3), | |
| 95 "frozenset": (2, 4), | |
| 96 "itertools.compress": (2, 7), | |
| 97 "math.erf": (2, 7), | |
| 98 "math.erfc": (2, 7), | |
| 99 "math.expm1": (2, 7), | |
| 100 "math.gamma": (2, 7), | |
| 101 "math.lgamma": (2, 7), | |
| 102 "memoryview": (2, 7), | |
| 103 "next": (2, 6), | |
| 104 "os.getresgid": (2, 7), | |
| 105 "os.getresuid": (2, 7), | |
| 106 "os.initgroups": (2, 7), | |
| 107 "os.setresgid": (2, 7), | |
| 108 "os.setresuid": (2, 7), | |
| 109 "reversed": (2, 4), | |
| 110 "set": (2, 4), | |
| 111 "subprocess.check_call": (2, 5), | |
| 112 "subprocess.check_output": (2, 7), | |
| 113 "sum": (2, 3), | |
| 114 "symtable.is_declared_global": (2, 7), | |
| 115 "weakref.WeakSet": (2, 7), | |
| 116 } | |
| 117 | |
| 118 Identifiers = { | |
| 119 "False": (2, 2), | |
| 120 "True": (2, 2), | |
| 121 } | |
| 122 | |
| 123 def uniq(a): | |
| 124 if len(a) == 0: | |
| 125 return [] | |
| 126 else: | |
| 127 return [a[0]] + uniq([x for x in a if x != a[0]]) | |
| 128 | |
| 129 class NodeChecker(object): | |
| 130 def __init__(self): | |
| 131 self.vers = dict() | |
| 132 self.vers[(2,0)] = [] | |
| 133 def add(self, node, ver, msg): | |
| 134 if ver not in self.vers: | |
| 135 self.vers[ver] = [] | |
| 136 self.vers[ver].append((node.lineno, msg)) | |
| 137 def default(self, node): | |
| 138 for child in node.getChildNodes(): | |
| 139 self.visit(child) | |
| 140 def visitCallFunc(self, node): | |
| 141 def rollup(n): | |
| 142 if isinstance(n, compiler.ast.Name): | |
| 143 return n.name | |
| 144 elif isinstance(n, compiler.ast.Getattr): | |
| 145 r = rollup(n.expr) | |
| 146 if r: | |
| 147 return r + "." + n.attrname | |
| 148 name = rollup(node.node) | |
| 149 if name: | |
| 150 v = Functions.get(name) | |
| 151 if v is not None: | |
| 152 self.add(node, v, name) | |
| 153 self.default(node) | |
| 154 def visitClass(self, node): | |
| 155 if node.bases: | |
| 156 self.add(node, (2,2), "new-style class") | |
| 157 if node.decorators: | |
| 158 self.add(node, (2,6), "class decorator") | |
| 159 self.default(node) | |
| 160 def visitDictComp(self, node): | |
| 161 self.add(node, (2,7), "dictionary comprehension") | |
| 162 self.default(node) | |
| 163 def visitFloorDiv(self, node): | |
| 164 self.add(node, (2,2), "// operator") | |
| 165 self.default(node) | |
| 166 def visitFrom(self, node): | |
| 167 v = StandardModules.get(node.modname) | |
| 168 if v is not None: | |
| 169 self.add(node, v, node.modname) | |
| 170 for n in node.names: | |
| 171 name = node.modname + "." + n[0] | |
| 172 v = Functions.get(name) | |
| 173 if v is not None: | |
| 174 self.add(node, v, name) | |
| 175 def visitFunction(self, node): | |
| 176 if node.decorators: | |
| 177 self.add(node, (2,4), "function decorator") | |
| 178 self.default(node) | |
| 179 def visitGenExpr(self, node): | |
| 180 self.add(node, (2,4), "generator expression") | |
| 181 self.default(node) | |
| 182 def visitGetattr(self, node): | |
| 183 if (isinstance(node.expr, compiler.ast.Const) | |
| 184 and isinstance(node.expr.value, str) | |
| 185 and node.attrname == "format"): | |
| 186 self.add(node, (2,6), "string literal .format()") | |
| 187 self.default(node) | |
| 188 def visitIfExp(self, node): | |
| 189 self.add(node, (2,5), "inline if expression") | |
| 190 self.default(node) | |
| 191 def visitImport(self, node): | |
| 192 for n in node.names: | |
| 193 v = StandardModules.get(n[0]) | |
| 194 if v is not None: | |
| 195 self.add(node, v, n[0]) | |
| 196 self.default(node) | |
| 197 def visitName(self, node): | |
| 198 v = Identifiers.get(node.name) | |
| 199 if v is not None: | |
| 200 self.add(node, v, node.name) | |
| 201 self.default(node) | |
| 202 def visitSet(self, node): | |
| 203 self.add(node, (2,7), "set literal") | |
| 204 self.default(node) | |
| 205 def visitSetComp(self, node): | |
| 206 self.add(node, (2,7), "set comprehension") | |
| 207 self.default(node) | |
| 208 def visitTryFinally(self, node): | |
| 209 # try/finally with a suite generates a Stmt node as the body, | |
| 210 # but try/except/finally generates a TryExcept as the body | |
| 211 if isinstance(node.body, compiler.ast.TryExcept): | |
| 212 self.add(node, (2,5), "try/except/finally") | |
| 213 self.default(node) | |
| 214 def visitWith(self, node): | |
| 215 if isinstance(node.body, compiler.ast.With): | |
| 216 self.add(node, (2,7), "with statement with multiple contexts") | |
| 217 else: | |
| 218 self.add(node, (2,5), "with statement") | |
| 219 self.default(node) | |
| 220 def visitYield(self, node): | |
| 221 self.add(node, (2,2), "yield expression") | |
| 222 self.default(node) | |
| 223 | |
| 224 def get_versions(source): | |
| 225 """Return information about the Python versions required for specific features. | |
| 226 | |
| 227 The return value is a dictionary with keys as a version number as a tuple | |
| 228 (for example Python 2.6 is (2,6)) and the value are a list of features that | |
| 229 require the indicated Python version. | |
| 230 """ | |
| 231 tree = compiler.parse(source) | |
| 232 checker = compiler.walk(tree, NodeChecker()) | |
| 233 return checker.vers | |
| 234 | |
| 235 def v27(source): | |
| 236 if sys.version_info >= (2, 7): | |
| 237 return qver(source) | |
| 238 else: | |
| 239 print >>sys.stderr, "Not all features tested, run --test with Python 2.7" | |
| 240 return (2, 7) | |
| 241 | |
| 242 def qver(source): | |
| 243 """Return the minimum Python version required to run a particular bit of code. | |
| 244 | |
| 245 >>> qver('print "hello world"') | |
| 246 (2, 0) | |
| 247 >>> qver('class test(object): pass') | |
| 248 (2, 2) | |
| 249 >>> qver('yield 1') | |
| 250 (2, 2) | |
| 251 >>> qver('a // b') | |
| 252 (2, 2) | |
| 253 >>> qver('True') | |
| 254 (2, 2) | |
| 255 >>> qver('enumerate(a)') | |
| 256 (2, 3) | |
| 257 >>> qver('total = sum') | |
| 258 (2, 0) | |
| 259 >>> qver('sum(a)') | |
| 260 (2, 3) | |
| 261 >>> qver('(x*x for x in range(5))') | |
| 262 (2, 4) | |
| 263 >>> qver('class C:\\n @classmethod\\n def m(): pass') | |
| 264 (2, 4) | |
| 265 >>> qver('y if x else z') | |
| 266 (2, 5) | |
| 267 >>> qver('import hashlib') | |
| 268 (2, 5) | |
| 269 >>> qver('from hashlib import md5') | |
| 270 (2, 5) | |
| 271 >>> qver('import xml.etree.ElementTree') | |
| 272 (2, 5) | |
| 273 >>> qver('try:\\n try: pass;\\n except: pass;\\nfinally: pass') | |
| 274 (2, 0) | |
| 275 >>> qver('try: pass;\\nexcept: pass;\\nfinally: pass') | |
| 276 (2, 5) | |
| 277 >>> qver('from __future__ import with_statement\\nwith x: pass') | |
| 278 (2, 5) | |
| 279 >>> qver('collections.defaultdict(list)') | |
| 280 (2, 5) | |
| 281 >>> qver('from collections import defaultdict') | |
| 282 (2, 5) | |
| 283 >>> qver('"{0}".format(0)') | |
| 284 (2, 6) | |
| 285 >>> qver('memoryview(x)') | |
| 286 (2, 7) | |
| 287 >>> v27('{1, 2, 3}') | |
| 288 (2, 7) | |
| 289 >>> v27('{x for x in s}') | |
| 290 (2, 7) | |
| 291 >>> v27('{x: y for x in s}') | |
| 292 (2, 7) | |
| 293 >>> qver('from __future__ import with_statement\\nwith x:\\n with y: pass') | |
| 294 (2, 5) | |
| 295 >>> v27('from __future__ import with_statement\\nwith x, y: pass') | |
| 296 (2, 7) | |
| 297 >>> qver('@decorator\\ndef f(): pass') | |
| 298 (2, 4) | |
| 299 >>> qver('@decorator\\nclass test:\\n pass') | |
| 300 (2, 6) | |
| 301 | |
| 302 #>>> qver('0o0') | |
| 303 #(2, 6) | |
| 304 #>>> qver('@foo\\nclass C: pass') | |
| 305 #(2, 6) | |
| 306 """ | |
| 307 return max(get_versions(source).keys()) | |
| 308 | |
| 309 Verbose = False | |
| 310 MinVersion = (2, 3) | |
| 311 Lint = False | |
| 312 | |
| 313 files = [] | |
| 314 i = 1 | |
| 315 while i < len(sys.argv): | |
| 316 a = sys.argv[i] | |
| 317 if a == "--test": | |
| 318 import doctest | |
| 319 doctest.testmod() | |
| 320 sys.exit(0) | |
| 321 if a == "-v" or a == "--verbose": | |
| 322 Verbose = True | |
| 323 elif a == "-l" or a == "--lint": | |
| 324 Lint = True | |
| 325 elif a == "-m" or a == "--min-version": | |
| 326 i += 1 | |
| 327 MinVersion = tuple(map(int, sys.argv[i].split("."))) | |
| 328 else: | |
| 329 files.append(a) | |
| 330 i += 1 | |
| 331 | |
| 332 if not files: | |
| 333 print >>sys.stderr, """Usage: %s [options] source ... | |
| 334 | |
| 335 Report minimum Python version required to run given source files. | |
| 336 | |
| 337 -m x.y or --min-version x.y (default 2.3) | |
| 338 report version triggers at or above version x.y in verbose mode | |
| 339 -v or --verbose | |
| 340 print more detailed report of version triggers for each version | |
| 341 """ % sys.argv[0] | |
| 342 sys.exit(1) | |
| 343 | |
| 344 for fn in files: | |
| 345 try: | |
| 346 f = open(fn) | |
| 347 source = f.read() | |
| 348 f.close() | |
| 349 ver = get_versions(source) | |
| 350 if Verbose: | |
| 351 print fn | |
| 352 for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True): | |
| 353 reasons = [x for x in uniq(ver[v]) if x] | |
| 354 if reasons: | |
| 355 # each reason is (lineno, message) | |
| 356 print "\t%s\t%s" % (".".join(map(str, v)), ", ".join([x[1] for x in reasons])) | |
| 357 elif Lint: | |
| 358 for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True): | |
| 359 reasons = [x for x in uniq(ver[v]) if x] | |
| 360 for r in reasons: | |
| 361 # each reason is (lineno, message) | |
| 362 print "%s:%s: %s %s" % (fn, r[0], ".".join(map(str, v)), r[1]) | |
| 363 else: | |
| 364 print "%s\t%s" % (".".join(map(str, max(ver.keys()))), fn) | |
| 365 except SyntaxError, x: | |
| 366 print "%s: syntax error compiling with Python %s: %s" % (fn, platform.python_version(), x) |
