summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/minimum_python_versions.yaml30
-rw-r--r--lib/spack/external/__init__.py8
-rwxr-xr-xlib/spack/external/pyqver2.py344
-rwxr-xr-xlib/spack/external/pyqver3.py248
-rw-r--r--lib/spack/llnl/util/cpu/microarchitecture.py2
-rw-r--r--lib/spack/llnl/util/cpu/schema.py2
-rw-r--r--lib/spack/llnl/util/lang.py8
-rw-r--r--lib/spack/spack/mirror.py2
-rw-r--r--lib/spack/spack/repo.py2
-rw-r--r--lib/spack/spack/test/python_version.py159
-rw-r--r--lib/spack/spack/test/schema.py2
-rw-r--r--lib/spack/spack/util/imp/importlib_importer.py2
-rw-r--r--lib/spack/spack/variant.py2
13 files changed, 42 insertions, 769 deletions
diff --git a/.github/workflows/minimum_python_versions.yaml b/.github/workflows/minimum_python_versions.yaml
new file mode 100644
index 0000000000..f0a5736849
--- /dev/null
+++ b/.github/workflows/minimum_python_versions.yaml
@@ -0,0 +1,30 @@
+name: Minimum Python Versions
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+ pull_request:
+ branches:
+ - master
+ - develop
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Setup Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 2.7
+ - name: Install Python Packages
+ run: |
+ pip install --upgrade pip
+ pip install --upgrade vermin
+ - name: Minimum Version (Spack's Core)
+ run: vermin --backport argparse -t=2.6- -t=3.5- -v lib/spack/spack/ lib/spack/llnl/ bin/
+ - name: Minimum Version (Repositories)
+ run: vermin --backport argparse -t=2.6- -t=3.5- -v var/spack/repos
diff --git a/lib/spack/external/__init__.py b/lib/spack/external/__init__.py
index 1001ff5fff..3550a4235f 100644
--- a/lib/spack/external/__init__.py
+++ b/lib/spack/external/__init__.py
@@ -82,14 +82,6 @@ py
ini-parsing, io, code, and log facilities.
* Version: 1.4.34 (last version supporting Python 2.6)
-pyqver
-------
-
-* Homepage: https://github.com/ghewgill/pyqver
-* Usage: External script to query required python version of
- python source code. Used for ensuring 2.6 compatibility.
-* Version: Unversioned
-
pytest
------
diff --git a/lib/spack/external/pyqver2.py b/lib/spack/external/pyqver2.py
deleted file mode 100755
index 07b191425b..0000000000
--- a/lib/spack/external/pyqver2.py
+++ /dev/null
@@ -1,344 +0,0 @@
-#!/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),
-# skip argparse now that it's in lib/spack/external
-# "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),
- "functools.total_ordering": (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.Const):
- return type(n.value).__name__
- elif isinstance(n, compiler.ast.Getattr):
- r = rollup(n.expr)
- if r:
- return r + "." + n.attrname
- name = rollup(node.node)
- if name:
- # Special handling for empty format strings, which aren't
- # allowed in Python 2.6
- if name in ('unicode.format', 'str.format'):
- n = node.node
- if isinstance(n, compiler.ast.Getattr):
- n = n.expr
- if isinstance(n, compiler.ast.Const):
- if '{}' in n.value:
- self.add(node, (2,7), name + ' with {} format string')
-
- 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, filename=None):
- """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())
diff --git a/lib/spack/external/pyqver3.py b/lib/spack/external/pyqver3.py
deleted file mode 100755
index b63576a064..0000000000
--- a/lib/spack/external/pyqver3.py
+++ /dev/null
@@ -1,248 +0,0 @@
-#!/usr/bin/env python3
-#
-# pyqver3.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 ast
-import platform
-import sys
-
-StandardModules = {
-# skip argparse now that it's in lib/spack/external
-# "argparse": (3, 2),
- "faulthandler": (3, 3),
- "importlib": (3, 1),
- "ipaddress": (3, 3),
- "lzma": (3, 3),
- "tkinter.ttk": (3, 1),
- "unittest.mock": (3, 3),
- "venv": (3, 3),
-}
-
-Functions = {
- "bytearray.maketrans": (3, 1),
- "bytes.maketrans": (3, 1),
- "bz2.open": (3, 3),
- "collections.Counter": (3, 1),
- "collections.OrderedDict": (3, 1),
- "crypt.mksalt": (3, 3),
- "email.generator.BytesGenerator": (3, 2),
- "email.message_from_binary_file": (3, 2),
- "email.message_from_bytes": (3, 2),
- "functools.lru_cache": (3, 2),
- "gzip.compress": (3, 2),
- "gzip.decompress": (3, 2),
- "inspect.getclosurevars": (3, 3),
- "inspect.getgeneratorlocals": (3, 3),
- "inspect.getgeneratorstate": (3, 2),
- "itertools.combinations_with_replacement": (3, 1),
- "itertools.compress": (3, 1),
- "logging.config.dictConfig": (3, 2),
- "logging.NullHandler": (3, 1),
- "math.erf": (3, 2),
- "math.erfc": (3, 2),
- "math.expm1": (3, 2),
- "math.gamma": (3, 2),
- "math.isfinite": (3, 2),
- "math.lgamma": (3, 2),
- "math.log2": (3, 3),
- "os.environb": (3, 2),
- "os.fsdecode": (3, 2),
- "os.fsencode": (3, 2),
- "os.fwalk": (3, 3),
- "os.getenvb": (3, 2),
- "os.get_exec_path": (3, 2),
- "os.getgrouplist": (3, 3),
- "os.getpriority": (3, 3),
- "os.getresgid": (3, 2),
- "os.getresuid": (3, 2),
- "os.get_terminal_size": (3, 3),
- "os.getxattr": (3, 3),
- "os.initgroups": (3, 2),
- "os.listxattr": (3, 3),
- "os.lockf": (3, 3),
- "os.pipe2": (3, 3),
- "os.posix_fadvise": (3, 3),
- "os.posix_fallocate": (3, 3),
- "os.pread": (3, 3),
- "os.pwrite": (3, 3),
- "os.readv": (3, 3),
- "os.removexattr": (3, 3),
- "os.replace": (3, 3),
- "os.sched_get_priority_max": (3, 3),
- "os.sched_get_priority_min": (3, 3),
- "os.sched_getaffinity": (3, 3),
- "os.sched_getparam": (3, 3),
- "os.sched_getscheduler": (3, 3),
- "os.sched_rr_get_interval": (3, 3),
- "os.sched_setaffinity": (3, 3),
- "os.sched_setparam": (3, 3),
- "os.sched_setscheduler": (3, 3),
- "os.sched_yield": (3, 3),
- "os.sendfile": (3, 3),
- "os.setpriority": (3, 3),
- "os.setresgid": (3, 2),
- "os.setresuid": (3, 2),
- "os.setxattr": (3, 3),
- "os.sync": (3, 3),
- "os.truncate": (3, 3),
- "os.waitid": (3, 3),
- "os.writev": (3, 3),
- "shutil.chown": (3, 3),
- "shutil.disk_usage": (3, 3),
- "shutil.get_archive_formats": (3, 3),
- "shutil.get_terminal_size": (3, 3),
- "shutil.get_unpack_formats": (3, 3),
- "shutil.make_archive": (3, 3),
- "shutil.register_archive_format": (3, 3),
- "shutil.register_unpack_format": (3, 3),
- "shutil.unpack_archive": (3, 3),
- "shutil.unregister_archive_format": (3, 3),
- "shutil.unregister_unpack_format": (3, 3),
- "shutil.which": (3, 3),
- "signal.pthread_kill": (3, 3),
- "signal.pthread_sigmask": (3, 3),
- "signal.sigpending": (3, 3),
- "signal.sigtimedwait": (3, 3),
- "signal.sigwait": (3, 3),
- "signal.sigwaitinfo": (3, 3),
- "socket.CMSG_LEN": (3, 3),
- "socket.CMSG_SPACE": (3, 3),
- "socket.fromshare": (3, 3),
- "socket.if_indextoname": (3, 3),
- "socket.if_nameindex": (3, 3),
- "socket.if_nametoindex": (3, 3),
- "socket.sethostname": (3, 3),
- "ssl.match_hostname": (3, 2),
- "ssl.RAND_bytes": (3, 3),
- "ssl.RAND_pseudo_bytes": (3, 3),
- "ssl.SSLContext": (3, 2),
- "ssl.SSLEOFError": (3, 3),
- "ssl.SSLSyscallError": (3, 3),
- "ssl.SSLWantReadError": (3, 3),
- "ssl.SSLWantWriteError": (3, 3),
- "ssl.SSLZeroReturnError": (3, 3),
- "stat.filemode": (3, 3),
- "textwrap.indent": (3, 3),
- "threading.get_ident": (3, 3),
- "time.clock_getres": (3, 3),
- "time.clock_gettime": (3, 3),
- "time.clock_settime": (3, 3),
- "time.get_clock_info": (3, 3),
- "time.monotonic": (3, 3),
- "time.perf_counter": (3, 3),
- "time.process_time": (3, 3),
- "types.new_class": (3, 3),
- "types.prepare_class": (3, 3),
-}
-
-def uniq(a):
- if len(a) == 0:
- return []
- else:
- return [a[0]] + uniq([x for x in a if x != a[0]])
-
-class NodeChecker(ast.NodeVisitor):
- def __init__(self):
- self.vers = dict()
- self.vers[(3,0)] = []
- def add(self, node, ver, msg):
- if ver not in self.vers:
- self.vers[ver] = []
- self.vers[ver].append((node.lineno, msg))
- def visit_Call(self, node):
- def rollup(n):
- if isinstance(n, ast.Name):
- return n.id
- elif isinstance(n, ast.Attribute):
- r = rollup(n.value)
- if r:
- return r + "." + n.attr
- name = rollup(node.func)
- if name:
- v = Functions.get(name)
- if v is not None:
- self.add(node, v, name)
- self.generic_visit(node)
- def visit_Import(self, node):
- for n in node.names:
- v = StandardModules.get(n.name)
- if v is not None:
- self.add(node, v, n.name)
- self.generic_visit(node)
- def visit_ImportFrom(self, node):
- v = StandardModules.get(node.module)
- if v is not None:
- self.add(node, v, node.module)
- for n in node.names:
- name = node.module + "." + n.name
- v = Functions.get(name)
- if v is not None:
- self.add(node, v, name)
- def visit_Raise(self, node):
- if isinstance(node.cause, ast.Name) and node.cause.id == "None":
- self.add(node, (3,3), "raise ... from None")
- def visit_YieldFrom(self, node):
- self.add(node, (3,3), "yield from")
-
-def get_versions(source, filename=None):
- """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 3.1 is (3,1)) and the value are a list of features that
- require the indicated Python version.
- """
- tree = ast.parse(source, filename=filename)
- checker = NodeChecker()
- checker.visit(tree)
- return checker.vers
-
-def v33(source):
- if sys.version_info >= (3, 3):
- return qver(source)
- else:
- print("Not all features tested, run --test with Python 3.3", file=sys.stderr)
- return (3, 3)
-
-def qver(source):
- """Return the minimum Python version required to run a particular bit of code.
-
- >>> qver('print("hello world")')
- (3, 0)
- >>> qver("import importlib")
- (3, 1)
- >>> qver("from importlib import x")
- (3, 1)
- >>> qver("import tkinter.ttk")
- (3, 1)
- >>> qver("from collections import Counter")
- (3, 1)
- >>> qver("collections.OrderedDict()")
- (3, 1)
- >>> qver("import functools\\n@functools.lru_cache()\\ndef f(x): x*x")
- (3, 2)
- >>> v33("yield from x")
- (3, 3)
- >>> v33("raise x from None")
- (3, 3)
- """
- return max(get_versions(source).keys())
diff --git a/lib/spack/llnl/util/cpu/microarchitecture.py b/lib/spack/llnl/util/cpu/microarchitecture.py
index 3d1590376a..759bff5058 100644
--- a/lib/spack/llnl/util/cpu/microarchitecture.py
+++ b/lib/spack/llnl/util/cpu/microarchitecture.py
@@ -8,7 +8,7 @@ import re
import warnings
try:
- from collections.abc import Sequence
+ from collections.abc import Sequence # novm
except ImportError:
from collections import Sequence
diff --git a/lib/spack/llnl/util/cpu/schema.py b/lib/spack/llnl/util/cpu/schema.py
index cc15cb64ba..14cdf4e00f 100644
--- a/lib/spack/llnl/util/cpu/schema.py
+++ b/lib/spack/llnl/util/cpu/schema.py
@@ -6,7 +6,7 @@ import json
import os.path
try:
- from collections.abc import MutableMapping
+ from collections.abc import MutableMapping # novm
except ImportError:
from collections import MutableMapping
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 11820a7f58..bdb551dcad 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -612,12 +612,14 @@ def load_module_from_file(module_name, module_path):
"""
if sys.version_info[0] == 3 and sys.version_info[1] >= 5:
import importlib.util
- spec = importlib.util.spec_from_file_location(module_name, module_path)
- module = importlib.util.module_from_spec(spec)
+ spec = importlib.util.spec_from_file_location( # novm
+ module_name, module_path)
+ module = importlib.util.module_from_spec(spec) # novm
spec.loader.exec_module(module)
elif sys.version_info[0] == 3 and sys.version_info[1] < 5:
import importlib.machinery
- loader = importlib.machinery.SourceFileLoader(module_name, module_path)
+ loader = importlib.machinery.SourceFileLoader( # novm
+ module_name, module_path)
module = loader.load_module()
elif sys.version_info[0] == 2:
import imp
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index ceb53801ce..650b7bd409 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -24,7 +24,7 @@ import ruamel.yaml.error as yaml_error
from ordereddict_backport import OrderedDict
try:
- from collections.abc import Mapping
+ from collections.abc import Mapping # novm
except ImportError:
from collections import Mapping
diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py
index 3ea196dd4d..8b124a4a18 100644
--- a/lib/spack/spack/repo.py
+++ b/lib/spack/spack/repo.py
@@ -20,7 +20,7 @@ import traceback
from six import string_types, add_metaclass
try:
- from collections.abc import Mapping
+ from collections.abc import Mapping # novm
except ImportError:
from collections import Mapping
diff --git a/lib/spack/spack/test/python_version.py b/lib/spack/spack/test/python_version.py
deleted file mode 100644
index 6875aa4655..0000000000
--- a/lib/spack/spack/test/python_version.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
-# Spack Project Developers. See the top-level COPYRIGHT file for details.
-#
-# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-"""Check that Spack complies with minimum supported python versions.
-
-We ensure that all Spack files work with Python2 >= 2.6 and Python3 >= 3.0.
-
-We'd like to drop 2.6 support at some point, but there are still many HPC
-systems that ship with RHEL6/CentOS 6, which have Python 2.6 as the
-default version. Once those go away, we can likely drop 2.6 and increase
-the minimum supported Python 3 version, as well.
-"""
-from __future__ import print_function
-
-import os
-import sys
-import re
-
-import pytest
-
-import llnl.util.tty as tty
-
-import spack.paths
-from spack.paths import lib_path as spack_lib_path
-
-
-#
-# This test uses pyqver, by Greg Hewgill, which is a dual-source module.
-# That means we need to do different checks depending on whether we're
-# running Python 2 or Python 3.
-#
-if sys.version_info[0] < 3:
- import pyqver2 as pyqver
- spack_min_supported = (2, 6)
-
- # Exclude Python 3 versions of dual-source modules when using Python 2
- exclude_paths = [
- # Jinja 2 has some 'async def' functions that are not treated correctly
- # by pyqver.py
- os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
- os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
- os.path.join(spack_lib_path, 'external', 'yaml', 'lib3'),
- os.path.join(spack_lib_path, 'external', 'pyqver3.py'),
- # Uses importlib
- os.path.join(spack_lib_path, 'spack', 'test', 'schema.py')
- ]
-
-else:
- import pyqver3 as pyqver
- spack_min_supported = (3, 0)
-
- # Exclude Python 2 versions of dual-source modules when using Python 3
- exclude_paths = [
- # Jinja 2 has some 'async def' functions that are not treated correctly
- # by pyqver.py
- os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
- os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
- os.path.join(spack_lib_path, 'external', 'yaml', 'lib'),
- os.path.join(spack_lib_path, 'external', 'pyqver2.py'),
- # Uses importlib
- os.path.join(spack_lib_path, 'spack', 'test', 'schema.py')
- ]
-
-
-def pyfiles(search_paths, exclude=()):
- """Generator that yields all the python files in the search paths.
-
- Args:
- search_paths (list of str): list of paths to search for python files
- exclude (list of str): file paths to exclude from search
-
- Yields:
- python files in the search path.
- """
- # first file is the spack script.
- yield spack.paths.spack_script
-
- # Iterate through the whole spack source tree.
- for path in search_paths:
- for root, dirnames, filenames in os.walk(path):
- for filename in filenames:
- realpath = os.path.realpath(os.path.join(root, filename))
- if any(realpath.startswith(p) for p in exclude):
- continue
-
- if re.match(r'^[^.#].*\.py$', filename):
- yield os.path.join(root, filename)
-
-
-def check_python_versions(files):
- """Check that a set of Python files works with supported Ptyhon versions"""
- # This is a dict dict mapping:
- # version -> filename -> reasons
- #
- # Reasons are tuples of (lineno, string), where the string is the
- # cause for a version incompatibility.
- all_issues = {}
-
- # Parse files and run pyqver on each file.
- for path in files:
- with open(path) as pyfile:
- full_text = pyfile.read()
- versions = pyqver.get_versions(full_text, path)
-
- for ver, reasons in versions.items():
- if ver <= spack_min_supported:
- continue
-
- # Record issues. Mark exceptions with '# nopyqver' comment
- for lineno, cause in reasons:
- lines = full_text.split('\n')
- if not re.search(r'#\s*nopyqver\s*$', lines[lineno - 1]):
- all_issues.setdefault(ver, {})[path] = reasons
-
- # Print a message if there are are issues
- if all_issues:
- tty.msg("Spack must remain compatible with Python version %d.%d"
- % spack_min_supported)
-
- # Print out a table showing which files/linenos require which
- # python version, and a string describing why.
- for v in sorted(all_issues.keys(), reverse=True):
- messages = []
- for path in sorted(all_issues[v].keys()):
- short_path = path
- if path.startswith(spack.paths.prefix):
- short_path = path[len(spack.paths.prefix):]
-
- reasons = [r for r in set(all_issues[v][path]) if r]
- for lineno, cause in reasons:
- file_line = "%s:%s" % (short_path.lstrip('/'), lineno)
- messages.append((file_line, cause))
-
- print()
- tty.msg("These files require version %d.%d:" % v)
- maxlen = max(len(f) for f, prob in messages)
- fmt = "%%-%ds%%s" % (maxlen + 3)
- print(fmt % ('File', 'Reason'))
- print(fmt % ('-' * (maxlen), '-' * 20))
- for msg in messages:
- print(fmt % msg)
-
- # Fail this test if there were issues.
- assert not all_issues
-
-
-@pytest.mark.maybeslow
-def test_core_module_compatibility():
- """Test that all core spack modules work with supported Python versions."""
- check_python_versions(
- pyfiles([spack_lib_path], exclude=exclude_paths))
-
-
-@pytest.mark.maybeslow
-def test_package_module_compatibility():
- """Test that all spack packages work with supported Python versions."""
- check_python_versions(pyfiles([spack.paths.packages_path]))
diff --git a/lib/spack/spack/test/schema.py b/lib/spack/spack/test/schema.py
index 9149b77b37..c86964000d 100644
--- a/lib/spack/spack/test/schema.py
+++ b/lib/spack/spack/test/schema.py
@@ -107,7 +107,7 @@ def test_module_suffixes(module_suffixes_schema):
'repos'
])
def test_schema_validation(meta_schema, config_name):
- import importlib
+ import importlib # novm
module_name = 'spack.schema.{0}'.format(config_name)
module = importlib.import_module(module_name)
schema = getattr(module, 'schema')
diff --git a/lib/spack/spack/util/imp/importlib_importer.py b/lib/spack/spack/util/imp/importlib_importer.py
index 33c50cb601..fb4ad58aa6 100644
--- a/lib/spack/spack/util/imp/importlib_importer.py
+++ b/lib/spack/spack/util/imp/importlib_importer.py
@@ -7,7 +7,7 @@
``importlib`` is only fully implemented in Python 3.
"""
-from importlib.machinery import SourceFileLoader
+from importlib.machinery import SourceFileLoader # novm
class PrependFileLoader(SourceFileLoader):
diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py
index bdee9d3552..250843f115 100644
--- a/lib/spack/spack/variant.py
+++ b/lib/spack/spack/variant.py
@@ -21,7 +21,7 @@ import spack.directives
import spack.error as error
try:
- from collections.abc import Sequence
+ from collections.abc import Sequence # novm
except ImportError:
from collections import Sequence