Add external package with pyqver2 tool
This commit is contained in:
		
							
								
								
									
										33
									
								
								lib/spack/external/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/spack/external/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 | 
			
		||||
# Produced at the Lawrence Livermore National Laboratory.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of Spack.
 | 
			
		||||
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
 | 
			
		||||
# LLNL-CODE-647188
 | 
			
		||||
#
 | 
			
		||||
# For details, see https://scalability-llnl.github.io/spack
 | 
			
		||||
# Please also see the LICENSE file for our notice and the LGPL.
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License (as published by
 | 
			
		||||
# the Free Software Foundation) version 2.1 dated February 1999.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful, but
 | 
			
		||||
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
 | 
			
		||||
# conditions of the GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
##############################################################################
 | 
			
		||||
"""
 | 
			
		||||
This module contains external, potentially separately licensed,
 | 
			
		||||
packages that are included in spack.
 | 
			
		||||
 | 
			
		||||
So far:
 | 
			
		||||
    argparse:    We include our own version to be Python 2.6 compatible.
 | 
			
		||||
    pyqver2:     External script to query required python version of python source code.
 | 
			
		||||
                 Used for ensuring 2.6 compatibility.
 | 
			
		||||
"""
 | 
			
		||||
							
								
								
									
										392
									
								
								lib/spack/external/pyqver2.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										392
									
								
								lib/spack/external/pyqver2.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,392 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
#
 | 
			
		||||
# pyqver2.py
 | 
			
		||||
# by Greg Hewgill
 | 
			
		||||
# https://github.com/ghewgill/pyqver
 | 
			
		||||
#
 | 
			
		||||
# This software is provided 'as-is', without any express or implied
 | 
			
		||||
# warranty.  In no event will the author be held liable for any damages
 | 
			
		||||
# arising from the use of this software.
 | 
			
		||||
#
 | 
			
		||||
# Permission is granted to anyone to use this software for any purpose,
 | 
			
		||||
# including commercial applications, and to alter it and redistribute it
 | 
			
		||||
# freely, subject to the following restrictions:
 | 
			
		||||
#
 | 
			
		||||
# 1. The origin of this software must not be misrepresented; you must not
 | 
			
		||||
#    claim that you wrote the original software. If you use this software
 | 
			
		||||
#    in a product, an acknowledgment in the product documentation would be
 | 
			
		||||
#    appreciated but is not required.
 | 
			
		||||
# 2. Altered source versions must be plainly marked as such, and must not be
 | 
			
		||||
#    misrepresented as being the original software.
 | 
			
		||||
# 3. This notice may not be removed or altered from any source distribution.
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2009-2013 Greg Hewgill http://hewgill.com
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
import compiler
 | 
			
		||||
import platform
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
StandardModules = {
 | 
			
		||||
    "__future__":       (2, 1),
 | 
			
		||||
    "abc":              (2, 6),
 | 
			
		||||
    "argparse":         (2, 7),
 | 
			
		||||
    "ast":              (2, 6),
 | 
			
		||||
    "atexit":           (2, 0),
 | 
			
		||||
    "bz2":              (2, 3),
 | 
			
		||||
    "cgitb":            (2, 2),
 | 
			
		||||
    "collections":      (2, 4),
 | 
			
		||||
    "contextlib":       (2, 5),
 | 
			
		||||
    "cookielib":        (2, 4),
 | 
			
		||||
    "cProfile":         (2, 5),
 | 
			
		||||
    "csv":              (2, 3),
 | 
			
		||||
    "ctypes":           (2, 5),
 | 
			
		||||
    "datetime":         (2, 3),
 | 
			
		||||
    "decimal":          (2, 4),
 | 
			
		||||
    "difflib":          (2, 1),
 | 
			
		||||
    "DocXMLRPCServer":  (2, 3),
 | 
			
		||||
    "dummy_thread":     (2, 3),
 | 
			
		||||
    "dummy_threading":  (2, 3),
 | 
			
		||||
    "email":            (2, 2),
 | 
			
		||||
    "fractions":        (2, 6),
 | 
			
		||||
    "functools":        (2, 5),
 | 
			
		||||
    "future_builtins":  (2, 6),
 | 
			
		||||
    "hashlib":          (2, 5),
 | 
			
		||||
    "heapq":            (2, 3),
 | 
			
		||||
    "hmac":             (2, 2),
 | 
			
		||||
    "hotshot":          (2, 2),
 | 
			
		||||
    "HTMLParser":       (2, 2),
 | 
			
		||||
    "importlib":        (2, 7),
 | 
			
		||||
    "inspect":          (2, 1),
 | 
			
		||||
    "io":               (2, 6),
 | 
			
		||||
    "itertools":        (2, 3),
 | 
			
		||||
    "json":             (2, 6),
 | 
			
		||||
    "logging":          (2, 3),
 | 
			
		||||
    "modulefinder":     (2, 3),
 | 
			
		||||
    "msilib":           (2, 5),
 | 
			
		||||
    "multiprocessing":  (2, 6),
 | 
			
		||||
    "netrc":            (1, 5, 2),
 | 
			
		||||
    "numbers":          (2, 6),
 | 
			
		||||
    "optparse":         (2, 3),
 | 
			
		||||
    "ossaudiodev":      (2, 3),
 | 
			
		||||
    "pickletools":      (2, 3),
 | 
			
		||||
    "pkgutil":          (2, 3),
 | 
			
		||||
    "platform":         (2, 3),
 | 
			
		||||
    "pydoc":            (2, 1),
 | 
			
		||||
    "runpy":            (2, 5),
 | 
			
		||||
    "sets":             (2, 3),
 | 
			
		||||
    "shlex":            (1, 5, 2),
 | 
			
		||||
    "SimpleXMLRPCServer": (2, 2),
 | 
			
		||||
    "spwd":             (2, 5),
 | 
			
		||||
    "sqlite3":          (2, 5),
 | 
			
		||||
    "ssl":              (2, 6),
 | 
			
		||||
    "stringprep":       (2, 3),
 | 
			
		||||
    "subprocess":       (2, 4),
 | 
			
		||||
    "sysconfig":        (2, 7),
 | 
			
		||||
    "tarfile":          (2, 3),
 | 
			
		||||
    "textwrap":         (2, 3),
 | 
			
		||||
    "timeit":           (2, 3),
 | 
			
		||||
    "unittest":         (2, 1),
 | 
			
		||||
    "uuid":             (2, 5),
 | 
			
		||||
    "warnings":         (2, 1),
 | 
			
		||||
    "weakref":          (2, 1),
 | 
			
		||||
    "winsound":         (1, 5, 2),
 | 
			
		||||
    "wsgiref":          (2, 5),
 | 
			
		||||
    "xml.dom":          (2, 0),
 | 
			
		||||
    "xml.dom.minidom":  (2, 0),
 | 
			
		||||
    "xml.dom.pulldom":  (2, 0),
 | 
			
		||||
    "xml.etree.ElementTree": (2, 5),
 | 
			
		||||
    "xml.parsers.expat":(2, 0),
 | 
			
		||||
    "xml.sax":          (2, 0),
 | 
			
		||||
    "xml.sax.handler":  (2, 0),
 | 
			
		||||
    "xml.sax.saxutils": (2, 0),
 | 
			
		||||
    "xml.sax.xmlreader":(2, 0),
 | 
			
		||||
    "xmlrpclib":        (2, 2),
 | 
			
		||||
    "zipfile":          (1, 6),
 | 
			
		||||
    "zipimport":        (2, 3),
 | 
			
		||||
    "_ast":             (2, 5),
 | 
			
		||||
    "_winreg":          (2, 0),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Functions = {
 | 
			
		||||
    "all":                      (2, 5),
 | 
			
		||||
    "any":                      (2, 5),
 | 
			
		||||
    "collections.Counter":      (2, 7),
 | 
			
		||||
    "collections.defaultdict":  (2, 5),
 | 
			
		||||
    "collections.OrderedDict":  (2, 7),
 | 
			
		||||
    "enumerate":                (2, 3),
 | 
			
		||||
    "frozenset":                (2, 4),
 | 
			
		||||
    "itertools.compress":       (2, 7),
 | 
			
		||||
    "math.erf":                 (2, 7),
 | 
			
		||||
    "math.erfc":                (2, 7),
 | 
			
		||||
    "math.expm1":               (2, 7),
 | 
			
		||||
    "math.gamma":               (2, 7),
 | 
			
		||||
    "math.lgamma":              (2, 7),
 | 
			
		||||
    "memoryview":               (2, 7),
 | 
			
		||||
    "next":                     (2, 6),
 | 
			
		||||
    "os.getresgid":             (2, 7),
 | 
			
		||||
    "os.getresuid":             (2, 7),
 | 
			
		||||
    "os.initgroups":            (2, 7),
 | 
			
		||||
    "os.setresgid":             (2, 7),
 | 
			
		||||
    "os.setresuid":             (2, 7),
 | 
			
		||||
    "reversed":                 (2, 4),
 | 
			
		||||
    "set":                      (2, 4),
 | 
			
		||||
    "subprocess.check_call":    (2, 5),
 | 
			
		||||
    "subprocess.check_output":  (2, 7),
 | 
			
		||||
    "sum":                      (2, 3),
 | 
			
		||||
    "symtable.is_declared_global": (2, 7),
 | 
			
		||||
    "weakref.WeakSet":          (2, 7),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Identifiers = {
 | 
			
		||||
    "False":        (2, 2),
 | 
			
		||||
    "True":         (2, 2),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def uniq(a):
 | 
			
		||||
    if len(a) == 0:
 | 
			
		||||
        return []
 | 
			
		||||
    else:
 | 
			
		||||
        return [a[0]] + uniq([x for x in a if x != a[0]])
 | 
			
		||||
 | 
			
		||||
class NodeChecker(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.vers = dict()
 | 
			
		||||
        self.vers[(2,0)] = []
 | 
			
		||||
    def add(self, node, ver, msg):
 | 
			
		||||
        if ver not in self.vers:
 | 
			
		||||
            self.vers[ver] = []
 | 
			
		||||
        self.vers[ver].append((node.lineno, msg))
 | 
			
		||||
    def default(self, node):
 | 
			
		||||
        for child in node.getChildNodes():
 | 
			
		||||
            self.visit(child)
 | 
			
		||||
    def visitCallFunc(self, node):
 | 
			
		||||
        def rollup(n):
 | 
			
		||||
            if isinstance(n, compiler.ast.Name):
 | 
			
		||||
                return n.name
 | 
			
		||||
            elif isinstance(n, compiler.ast.Getattr):
 | 
			
		||||
                r = rollup(n.expr)
 | 
			
		||||
                if r:
 | 
			
		||||
                    return r + "." + n.attrname
 | 
			
		||||
        name = rollup(node.node)
 | 
			
		||||
        if name:
 | 
			
		||||
            v = Functions.get(name)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self.add(node, v, name)
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitClass(self, node):
 | 
			
		||||
        if node.bases:
 | 
			
		||||
            self.add(node, (2,2), "new-style class")
 | 
			
		||||
        if node.decorators:
 | 
			
		||||
            self.add(node, (2,6), "class decorator")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitDictComp(self, node):
 | 
			
		||||
        self.add(node, (2,7), "dictionary comprehension")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitFloorDiv(self, node):
 | 
			
		||||
        self.add(node, (2,2), "// operator")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitFrom(self, node):
 | 
			
		||||
        v = StandardModules.get(node.modname)
 | 
			
		||||
        if v is not None:
 | 
			
		||||
            self.add(node, v, node.modname)
 | 
			
		||||
        for n in node.names:
 | 
			
		||||
            name = node.modname + "." + n[0]
 | 
			
		||||
            v = Functions.get(name)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self.add(node, v, name)
 | 
			
		||||
    def visitFunction(self, node):
 | 
			
		||||
        if node.decorators:
 | 
			
		||||
            self.add(node, (2,4), "function decorator")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitGenExpr(self, node):
 | 
			
		||||
        self.add(node, (2,4), "generator expression")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitGetattr(self, node):
 | 
			
		||||
        if (isinstance(node.expr, compiler.ast.Const)
 | 
			
		||||
            and isinstance(node.expr.value, str)
 | 
			
		||||
            and node.attrname == "format"):
 | 
			
		||||
            self.add(node, (2,6), "string literal .format()")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitIfExp(self, node):
 | 
			
		||||
        self.add(node, (2,5), "inline if expression")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitImport(self, node):
 | 
			
		||||
        for n in node.names:
 | 
			
		||||
            v = StandardModules.get(n[0])
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self.add(node, v, n[0])
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitName(self, node):
 | 
			
		||||
        v = Identifiers.get(node.name)
 | 
			
		||||
        if v is not None:
 | 
			
		||||
            self.add(node, v, node.name)
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitSet(self, node):
 | 
			
		||||
        self.add(node, (2,7), "set literal")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitSetComp(self, node):
 | 
			
		||||
        self.add(node, (2,7), "set comprehension")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitTryFinally(self, node):
 | 
			
		||||
        # try/finally with a suite generates a Stmt node as the body,
 | 
			
		||||
        # but try/except/finally generates a TryExcept as the body
 | 
			
		||||
        if isinstance(node.body, compiler.ast.TryExcept):
 | 
			
		||||
            self.add(node, (2,5), "try/except/finally")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitWith(self, node):
 | 
			
		||||
        if isinstance(node.body, compiler.ast.With):
 | 
			
		||||
            self.add(node, (2,7), "with statement with multiple contexts")
 | 
			
		||||
        else:
 | 
			
		||||
            self.add(node, (2,5), "with statement")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
    def visitYield(self, node):
 | 
			
		||||
        self.add(node, (2,2), "yield expression")
 | 
			
		||||
        self.default(node)
 | 
			
		||||
 | 
			
		||||
def get_versions(source):
 | 
			
		||||
    """Return information about the Python versions required for specific features.
 | 
			
		||||
 | 
			
		||||
    The return value is a dictionary with keys as a version number as a tuple
 | 
			
		||||
    (for example Python 2.6 is (2,6)) and the value are a list of features that
 | 
			
		||||
    require the indicated Python version.
 | 
			
		||||
    """
 | 
			
		||||
    tree = compiler.parse(source)
 | 
			
		||||
    checker = compiler.walk(tree, NodeChecker())
 | 
			
		||||
    return checker.vers
 | 
			
		||||
 | 
			
		||||
def v27(source):
 | 
			
		||||
    if sys.version_info >= (2, 7):
 | 
			
		||||
        return qver(source)
 | 
			
		||||
    else:
 | 
			
		||||
        print >>sys.stderr, "Not all features tested, run --test with Python 2.7"
 | 
			
		||||
        return (2, 7)
 | 
			
		||||
 | 
			
		||||
def qver(source):
 | 
			
		||||
    """Return the minimum Python version required to run a particular bit of code.
 | 
			
		||||
 | 
			
		||||
    >>> qver('print "hello world"')
 | 
			
		||||
    (2, 0)
 | 
			
		||||
    >>> qver('class test(object): pass')
 | 
			
		||||
    (2, 2)
 | 
			
		||||
    >>> qver('yield 1')
 | 
			
		||||
    (2, 2)
 | 
			
		||||
    >>> qver('a // b')
 | 
			
		||||
    (2, 2)
 | 
			
		||||
    >>> qver('True')
 | 
			
		||||
    (2, 2)
 | 
			
		||||
    >>> qver('enumerate(a)')
 | 
			
		||||
    (2, 3)
 | 
			
		||||
    >>> qver('total = sum')
 | 
			
		||||
    (2, 0)
 | 
			
		||||
    >>> qver('sum(a)')
 | 
			
		||||
    (2, 3)
 | 
			
		||||
    >>> qver('(x*x for x in range(5))')
 | 
			
		||||
    (2, 4)
 | 
			
		||||
    >>> qver('class C:\\n @classmethod\\n def m(): pass')
 | 
			
		||||
    (2, 4)
 | 
			
		||||
    >>> qver('y if x else z')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('import hashlib')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('from hashlib import md5')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('import xml.etree.ElementTree')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('try:\\n try: pass;\\n except: pass;\\nfinally: pass')
 | 
			
		||||
    (2, 0)
 | 
			
		||||
    >>> qver('try: pass;\\nexcept: pass;\\nfinally: pass')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('from __future__ import with_statement\\nwith x: pass')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('collections.defaultdict(list)')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('from collections import defaultdict')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> qver('"{0}".format(0)')
 | 
			
		||||
    (2, 6)
 | 
			
		||||
    >>> qver('memoryview(x)')
 | 
			
		||||
    (2, 7)
 | 
			
		||||
    >>> v27('{1, 2, 3}')
 | 
			
		||||
    (2, 7)
 | 
			
		||||
    >>> v27('{x for x in s}')
 | 
			
		||||
    (2, 7)
 | 
			
		||||
    >>> v27('{x: y for x in s}')
 | 
			
		||||
    (2, 7)
 | 
			
		||||
    >>> qver('from __future__ import with_statement\\nwith x:\\n with y: pass')
 | 
			
		||||
    (2, 5)
 | 
			
		||||
    >>> v27('from __future__ import with_statement\\nwith x, y: pass')
 | 
			
		||||
    (2, 7)
 | 
			
		||||
    >>> qver('@decorator\\ndef f(): pass')
 | 
			
		||||
    (2, 4)
 | 
			
		||||
    >>> qver('@decorator\\nclass test:\\n pass')
 | 
			
		||||
    (2, 6)
 | 
			
		||||
 | 
			
		||||
    #>>> qver('0o0')
 | 
			
		||||
    #(2, 6)
 | 
			
		||||
    #>>> qver('@foo\\nclass C: pass')
 | 
			
		||||
    #(2, 6)
 | 
			
		||||
    """
 | 
			
		||||
    return max(get_versions(source).keys())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
 | 
			
		||||
    Verbose = False
 | 
			
		||||
    MinVersion = (2, 3)
 | 
			
		||||
    Lint = False
 | 
			
		||||
 | 
			
		||||
    files = []
 | 
			
		||||
    i = 1
 | 
			
		||||
    while i < len(sys.argv):
 | 
			
		||||
        a = sys.argv[i]
 | 
			
		||||
        if a == "--test":
 | 
			
		||||
            import doctest
 | 
			
		||||
            doctest.testmod()
 | 
			
		||||
            sys.exit(0)
 | 
			
		||||
        if a == "-v" or a == "--verbose":
 | 
			
		||||
            Verbose = True
 | 
			
		||||
        elif a == "-l" or a == "--lint":
 | 
			
		||||
            Lint = True
 | 
			
		||||
        elif a == "-m" or a == "--min-version":
 | 
			
		||||
            i += 1
 | 
			
		||||
            MinVersion = tuple(map(int, sys.argv[i].split(".")))
 | 
			
		||||
        else:
 | 
			
		||||
            files.append(a)
 | 
			
		||||
        i += 1
 | 
			
		||||
 | 
			
		||||
    if not files:
 | 
			
		||||
        print >>sys.stderr, """Usage: %s [options] source ...
 | 
			
		||||
 | 
			
		||||
        Report minimum Python version required to run given source files.
 | 
			
		||||
 | 
			
		||||
        -m x.y or --min-version x.y (default 2.3)
 | 
			
		||||
            report version triggers at or above version x.y in verbose mode
 | 
			
		||||
        -v or --verbose
 | 
			
		||||
            print more detailed report of version triggers for each version
 | 
			
		||||
    """ % sys.argv[0]
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
    for fn in files:
 | 
			
		||||
        try:
 | 
			
		||||
            f = open(fn)
 | 
			
		||||
            source = f.read()
 | 
			
		||||
            f.close()
 | 
			
		||||
            ver = get_versions(source)
 | 
			
		||||
            if Verbose:
 | 
			
		||||
                print fn
 | 
			
		||||
                for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True):
 | 
			
		||||
                    reasons = [x for x in uniq(ver[v]) if x]
 | 
			
		||||
                    if reasons:
 | 
			
		||||
                        # each reason is (lineno, message)
 | 
			
		||||
                        print "\t%s\t%s" % (".".join(map(str, v)), ", ".join([x[1] for x in reasons]))
 | 
			
		||||
            elif Lint:
 | 
			
		||||
                for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True):
 | 
			
		||||
                    reasons = [x for x in uniq(ver[v]) if x]
 | 
			
		||||
                    for r in reasons:
 | 
			
		||||
                        # each reason is (lineno, message)
 | 
			
		||||
                        print "%s:%s: %s %s" % (fn, r[0], ".".join(map(str, v)), r[1])
 | 
			
		||||
            else:
 | 
			
		||||
                print "%s\t%s" % (".".join(map(str, max(ver.keys()))), fn)
 | 
			
		||||
        except SyntaxError, x:
 | 
			
		||||
            print "%s: syntax error compiling with Python %s: %s" % (fn, platform.python_version(), x)
 | 
			
		||||
		Reference in New Issue
	
	Block a user