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) |