summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny McClanahan <1305167+cosmicexplorer@users.noreply.github.com>2022-01-21 15:32:52 -0500
committerGitHub <noreply@github.com>2022-01-21 12:32:52 -0800
commit0c2de252f1e33d293bb8832e2053d1b4a96eed16 (patch)
tree06875d74b79950a88716c7491d599dade0d8261b
parent796f5a3cbc0136742b24f0e77730a165653bd91f (diff)
downloadspack-0c2de252f1e33d293bb8832e2053d1b4a96eed16.tar.gz
spack-0c2de252f1e33d293bb8832e2053d1b4a96eed16.tar.bz2
spack-0c2de252f1e33d293bb8832e2053d1b4a96eed16.tar.xz
spack-0c2de252f1e33d293bb8832e2053d1b4a96eed16.zip
introduce `llnl.util.compat` to remove sys.version_info checks (#21720)
- also split typing.py into typing_extensions and add py2 shims
-rw-r--r--lib/spack/external/py2/typing.py140
-rw-r--r--lib/spack/external/py2/typing_extensions.py26
-rw-r--r--lib/spack/llnl/util/compat.py39
-rw-r--r--lib/spack/llnl/util/filesystem.py6
-rw-r--r--lib/spack/llnl/util/lang.py12
-rw-r--r--lib/spack/spack/ci_needs_workaround.py13
-rw-r--r--lib/spack/spack/ci_optimization.py33
-rw-r--r--lib/spack/spack/cmd/python.py2
-rw-r--r--lib/spack/spack/directives.py8
-rw-r--r--lib/spack/spack/filesystem_view.py7
-rw-r--r--lib/spack/spack/mirror.py6
-rw-r--r--lib/spack/spack/package.py2
-rw-r--r--lib/spack/spack/repo.py9
-rw-r--r--lib/spack/spack/s3_handler.py2
-rw-r--r--lib/spack/spack/schema/environment.py6
-rw-r--r--lib/spack/spack/solver/asp.py11
-rw-r--r--lib/spack/spack/spec.py8
-rw-r--r--lib/spack/spack/test/ci.py7
-rw-r--r--lib/spack/spack/test/cmd/versions.py2
-rw-r--r--lib/spack/spack/test/conftest.py7
-rw-r--r--lib/spack/spack/test/packages.py30
-rw-r--r--lib/spack/spack/test/spec_yaml.py8
-rw-r--r--lib/spack/spack/util/environment.py11
-rw-r--r--lib/spack/spack/util/mock_package.py1
-rw-r--r--lib/spack/spack/util/pattern.py6
-rw-r--r--lib/spack/spack/util/py2.py16
-rw-r--r--lib/spack/spack/util/s3.py8
-rw-r--r--lib/spack/spack/util/spack_json.py39
-rw-r--r--lib/spack/spack/util/spack_yaml.py11
-rw-r--r--lib/spack/spack/variant.py7
-rw-r--r--lib/spack/spack/verify.py10
-rw-r--r--pyproject.toml1
32 files changed, 248 insertions, 246 deletions
diff --git a/lib/spack/external/py2/typing.py b/lib/spack/external/py2/typing.py
index cc32de8844..7c36962d9f 100644
--- a/lib/spack/external/py2/typing.py
+++ b/lib/spack/external/py2/typing.py
@@ -6,79 +6,77 @@
This is a fake set of symbols to allow spack to import typing in python
versions where we do not support type checking (<3)
"""
-Annotated = None
-Any = None
-Callable = None
-ForwardRef = None
-Generic = None
-Literal = None
-Optional = None
-Tuple = None
-TypeVar = None
-Union = None
-AbstractSet = None
-ByteString = None
-Container = None
-Hashable = None
-ItemsView = None
-Iterable = None
-Iterator = None
-KeysView = None
-Mapping = None
-MappingView = None
-MutableMapping = None
-MutableSequence = None
-MutableSet = None
-Sequence = None
-Sized = None
-ValuesView = None
-Awaitable = None
-AsyncIterator = None
-AsyncIterable = None
-Coroutine = None
-Collection = None
-AsyncGenerator = None
-AsyncContextManager = None
-Reversible = None
-SupportsAbs = None
-SupportsBytes = None
-SupportsComplex = None
-SupportsFloat = None
-SupportsInt = None
-SupportsRound = None
-ChainMap = None
-Dict = None
-List = None
-OrderedDict = None
-Set = None
-FrozenSet = None
-NamedTuple = None
-Generator = None
-AnyStr = None
-cast = None
+from collections import defaultdict
+
+# (1) Unparameterized types.
+Annotated = object
+Any = object
+AnyStr = object
+ByteString = object
+Counter = object
+Final = object
+Hashable = object
+NoReturn = object
+Sized = object
+SupportsAbs = object
+SupportsBytes = object
+SupportsComplex = object
+SupportsFloat = object
+SupportsIndex = object
+SupportsInt = object
+SupportsRound = object
+
+# (2) Parameterized types.
+AbstractSet = defaultdict(lambda: object)
+AsyncContextManager = defaultdict(lambda: object)
+AsyncGenerator = defaultdict(lambda: object)
+AsyncIterable = defaultdict(lambda: object)
+AsyncIterator = defaultdict(lambda: object)
+Awaitable = defaultdict(lambda: object)
+Callable = defaultdict(lambda: object)
+ChainMap = defaultdict(lambda: object)
+ClassVar = defaultdict(lambda: object)
+Collection = defaultdict(lambda: object)
+Container = defaultdict(lambda: object)
+ContextManager = defaultdict(lambda: object)
+Coroutine = defaultdict(lambda: object)
+DefaultDict = defaultdict(lambda: object)
+Deque = defaultdict(lambda: object)
+Dict = defaultdict(lambda: object)
+ForwardRef = defaultdict(lambda: object)
+FrozenSet = defaultdict(lambda: object)
+Generator = defaultdict(lambda: object)
+Generic = defaultdict(lambda: object)
+ItemsView = defaultdict(lambda: object)
+Iterable = defaultdict(lambda: object)
+Iterator = defaultdict(lambda: object)
+KeysView = defaultdict(lambda: object)
+List = defaultdict(lambda: object)
+Literal = defaultdict(lambda: object)
+Mapping = defaultdict(lambda: object)
+MappingView = defaultdict(lambda: object)
+MutableMapping = defaultdict(lambda: object)
+MutableSequence = defaultdict(lambda: object)
+MutableSet = defaultdict(lambda: object)
+NamedTuple = defaultdict(lambda: object)
+Optional = defaultdict(lambda: object)
+OrderedDict = defaultdict(lambda: object)
+Reversible = defaultdict(lambda: object)
+Sequence = defaultdict(lambda: object)
+Set = defaultdict(lambda: object)
+Tuple = defaultdict(lambda: object)
+Type = defaultdict(lambda: object)
+TypedDict = defaultdict(lambda: object)
+Union = defaultdict(lambda: object)
+ValuesView = defaultdict(lambda: object)
+
+# (3) Type variable declarations.
+TypeVar = lambda *args, **kwargs: None
+
+# (4) Functions.
+cast = lambda _type, x: x
get_args = None
get_origin = None
get_type_hints = None
no_type_check = None
no_type_check_decorator = None
-NoReturn = None
-
-# these are the typing extension symbols
-ClassVar = None
-Final = None
-Protocol = None
-Type = None
-TypedDict = None
-ContextManager = None
-Counter = None
-Deque = None
-DefaultDict = None
-SupportsIndex = None
-final = None
-IntVar = None
-Literal = None
-NewType = None
-overload = None
-runtime_checkable = None
-Text = None
-TYPE_CHECKING = None
diff --git a/lib/spack/external/py2/typing_extensions.py b/lib/spack/external/py2/typing_extensions.py
new file mode 100644
index 0000000000..ca6bc10999
--- /dev/null
+++ b/lib/spack/external/py2/typing_extensions.py
@@ -0,0 +1,26 @@
+# Copyright 2013-2021 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)
+"""
+This is a fake set of symbols to allow spack to import typing in python
+versions where we do not support type checking (<3)
+"""
+from collections import defaultdict
+
+# (1) Unparameterized types.
+IntVar = object
+Literal = object
+NewType = object
+Text = object
+
+# (2) Parameterized types.
+Protocol = defaultdict(lambda: object)
+
+# (3) Macro for avoiding evaluation except during type checking.
+TYPE_CHECKING = False
+
+# (4) Decorators.
+final = lambda x: x
+overload = lambda x: x
+runtime_checkable = lambda x: x
diff --git a/lib/spack/llnl/util/compat.py b/lib/spack/llnl/util/compat.py
new file mode 100644
index 0000000000..ca914d0fb6
--- /dev/null
+++ b/lib/spack/llnl/util/compat.py
@@ -0,0 +1,39 @@
+# Copyright 2013-2022 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)
+# isort: off
+
+import sys
+
+if sys.version_info < (3,):
+ from itertools import ifilter as filter
+ from itertools import imap as map
+ from itertools import izip as zip
+ from itertools import izip_longest as zip_longest # novm
+ from urllib import urlencode as urlencode
+ from urllib import urlopen as urlopen
+else:
+ filter = filter
+ map = map
+ zip = zip
+ from itertools import zip_longest as zip_longest # novm # noqa: F401
+ from urllib.parse import urlencode as urlencode # novm # noqa: F401
+ from urllib.request import urlopen as urlopen # novm # noqa: F401
+
+if sys.version_info >= (3, 3):
+ from collections.abc import Hashable as Hashable # novm
+ from collections.abc import Iterable as Iterable # novm
+ from collections.abc import Mapping as Mapping # novm
+ from collections.abc import MutableMapping as MutableMapping # novm
+ from collections.abc import MutableSequence as MutableSequence # novm
+ from collections.abc import MutableSet as MutableSet # novm
+ from collections.abc import Sequence as Sequence # novm
+else:
+ from collections import Hashable as Hashable # noqa: F401
+ from collections import Iterable as Iterable # noqa: F401
+ from collections import Mapping as Mapping # noqa: F401
+ from collections import MutableMapping as MutableMapping # noqa: F401
+ from collections import MutableSequence as MutableSequence # noqa: F401
+ from collections import MutableSet as MutableSet # noqa: F401
+ from collections import Sequence as Sequence # noqa: F401
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index d44812e5ae..f9f2b3162f 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -21,15 +21,11 @@ from contextlib import contextmanager
import six
from llnl.util import tty
+from llnl.util.compat import Sequence
from llnl.util.lang import dedupe, memoized
from spack.util.executable import Executable
-if sys.version_info >= (3, 3):
- from collections.abc import Sequence # novm
-else:
- from collections import Sequence
-
__all__ = [
'FileFilter',
'FileList',
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 180cedac88..c806cab1d7 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -14,17 +14,7 @@ from datetime import datetime, timedelta
from six import string_types
-if sys.version_info < (3, 0):
- from itertools import izip_longest # novm
- zip_longest = izip_longest
-else:
- from itertools import zip_longest # novm
-
-if sys.version_info >= (3, 3):
- from collections.abc import Hashable, MutableMapping # novm
-else:
- from collections import Hashable, MutableMapping
-
+from llnl.util.compat import Hashable, MutableMapping, zip_longest
# Ignore emacs backups when listing modules
ignore_modules = [r'^\.#', '~$']
diff --git a/lib/spack/spack/ci_needs_workaround.py b/lib/spack/spack/ci_needs_workaround.py
index 6252baa323..ae4cf33cd3 100644
--- a/lib/spack/spack/ci_needs_workaround.py
+++ b/lib/spack/spack/ci_needs_workaround.py
@@ -3,18 +3,11 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import collections
-
-try:
- # dynamically import to keep vermin from complaining
- collections_abc = __import__('collections.abc')
-except ImportError:
- collections_abc = collections
-
+from llnl.util.compat import Mapping
get_job_name = lambda needs_entry: (
needs_entry.get('job') if (
- isinstance(needs_entry, collections_abc.Mapping) and
+ isinstance(needs_entry, Mapping) and
needs_entry.get('artifacts', True))
else
@@ -25,7 +18,7 @@ get_job_name = lambda needs_entry: (
def convert_job(job_entry):
- if not isinstance(job_entry, collections_abc.Mapping):
+ if not isinstance(job_entry, Mapping):
return job_entry
needs = job_entry.get('needs')
diff --git a/lib/spack/spack/ci_optimization.py b/lib/spack/spack/ci_optimization.py
index f32429a5fa..b63abb3446 100644
--- a/lib/spack/spack/ci_optimization.py
+++ b/lib/spack/spack/ci_optimization.py
@@ -3,28 +3,23 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import collections
-
-try:
- # dynamically import to keep vermin from complaining
- collections_abc = __import__('collections.abc')
-except ImportError:
- collections_abc = collections
-
import copy
import hashlib
+from collections import defaultdict
+
+from llnl.util.compat import Mapping, Sequence
import spack.util.spack_yaml as syaml
def sort_yaml_obj(obj):
- if isinstance(obj, collections_abc.Mapping):
+ if isinstance(obj, Mapping):
return syaml.syaml_dict(
(k, sort_yaml_obj(v))
for k, v in
sorted(obj.items(), key=(lambda item: str(item[0]))))
- if isinstance(obj, collections_abc.Sequence) and not isinstance(obj, str):
+ if isinstance(obj, Sequence) and not isinstance(obj, str):
return syaml.syaml_list(sort_yaml_obj(x) for x in obj)
return obj
@@ -44,8 +39,8 @@ def matches(obj, proto):
Precondition: proto must not have any reference cycles
"""
- if isinstance(obj, collections_abc.Mapping):
- if not isinstance(proto, collections_abc.Mapping):
+ if isinstance(obj, Mapping):
+ if not isinstance(proto, Mapping):
return False
return all(
@@ -53,10 +48,10 @@ def matches(obj, proto):
for key, val in proto.items()
)
- if (isinstance(obj, collections_abc.Sequence) and
+ if (isinstance(obj, Sequence) and
not isinstance(obj, str)):
- if not (isinstance(proto, collections_abc.Sequence) and
+ if not (isinstance(proto, Sequence) and
not isinstance(proto, str)):
return False
@@ -90,8 +85,8 @@ def subkeys(obj, proto):
Otherwise, obj is returned.
"""
- if not (isinstance(obj, collections_abc.Mapping) and
- isinstance(proto, collections_abc.Mapping)):
+ if not (isinstance(obj, Mapping) and
+ isinstance(proto, Mapping)):
return obj
new_obj = {}
@@ -104,7 +99,7 @@ def subkeys(obj, proto):
matches(proto[key], value)):
continue
- if isinstance(value, collections_abc.Mapping):
+ if isinstance(value, Mapping):
new_obj[key] = subkeys(value, proto[key])
continue
@@ -132,7 +127,7 @@ def add_extends(yaml, key):
has_key = ('extends' in yaml)
extends = yaml.get('extends')
- if has_key and not isinstance(extends, (str, collections_abc.Sequence)):
+ if has_key and not isinstance(extends, (str, Sequence)):
return
if extends is None:
@@ -283,7 +278,7 @@ def build_histogram(iterator, key):
The list is sorted in descending order by count, yielding the most
frequently occuring hashes first.
"""
- buckets = collections.defaultdict(int)
+ buckets = defaultdict(int)
values = {}
num_objects = 0
diff --git a/lib/spack/spack/cmd/python.py b/lib/spack/spack/cmd/python.py
index 5224e8bbc9..901574c12d 100644
--- a/lib/spack/spack/cmd/python.py
+++ b/lib/spack/spack/cmd/python.py
@@ -73,7 +73,7 @@ def ipython_interpreter(args):
support running a script or arguments
"""
try:
- import IPython
+ import IPython # type: ignore[import]
except ImportError:
tty.die("ipython is not installed, install and try again.")
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index 5de64ebf52..81f58f542d 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -30,13 +30,13 @@ The available directives are:
import functools
import os.path
import re
-import sys
from typing import List, Set # novm
import six
import llnl.util.lang
import llnl.util.tty.color
+from llnl.util.compat import Sequence
import spack.error
import spack.patch
@@ -48,12 +48,6 @@ from spack.fetch_strategy import from_kwargs
from spack.resource import Resource
from spack.version import Version, VersionChecksumError
-if sys.version_info >= (3, 3):
- from collections.abc import Sequence # novm
-else:
- from collections import Sequence
-
-
__all__ = ['DirectiveError', 'DirectiveMeta']
#: These are variant names used by Spack internally; packages can't use them
diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py
index d1ec998f94..a95f9f9f6d 100644
--- a/lib/spack/spack/filesystem_view.py
+++ b/lib/spack/spack/filesystem_view.py
@@ -11,6 +11,7 @@ import shutil
import sys
from llnl.util import tty
+from llnl.util.compat import filter, map, zip
from llnl.util.filesystem import mkdirp, remove_dead_links, remove_empty_directories
from llnl.util.lang import index_by, match_predicate
from llnl.util.link_tree import LinkTree, MergeConflictError
@@ -29,12 +30,6 @@ from spack.directory_layout import (
)
from spack.error import SpackError
-# compatability
-if sys.version_info < (3, 0):
- from itertools import ifilter as filter
- from itertools import imap as map
- from itertools import izip as zip
-
__all__ = ["FilesystemView", "YamlFilesystemView"]
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index 3b8a60992c..0085d920b8 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -21,12 +21,8 @@ import traceback
import ruamel.yaml.error as yaml_error
import six
-if sys.version_info >= (3, 5):
- from collections.abc import Mapping # novm
-else:
- from collections import Mapping
-
import llnl.util.tty as tty
+from llnl.util.compat import Mapping
from llnl.util.filesystem import mkdirp
import spack.config
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 6f7e7a71b5..5df80f1e03 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1293,7 +1293,7 @@ class PackageBase(six.with_metaclass(PackageMeta, PackageViewMixin, object)):
"""Get the prefix into which this package should be installed."""
return self.spec.prefix
- @property # type: ignore
+ @property # type: ignore[misc]
@memoized
def compiler(self):
"""Get the spack.compiler.Compiler object used to build this package"""
diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py
index 63d8dfafbc..42a7aab5b6 100644
--- a/lib/spack/spack/repo.py
+++ b/lib/spack/spack/repo.py
@@ -18,18 +18,13 @@ import traceback
import types
from typing import Dict # novm
-import six
-
-if sys.version_info >= (3, 5):
- from collections.abc import Mapping # novm
-else:
- from collections import Mapping
-
import ruamel.yaml as yaml
+import six
import llnl.util.filesystem as fs
import llnl.util.lang
import llnl.util.tty as tty
+from llnl.util.compat import Mapping
import spack.caches
import spack.config
diff --git a/lib/spack/spack/s3_handler.py b/lib/spack/spack/s3_handler.py
index 66fa73e07a..9f775abafb 100644
--- a/lib/spack/spack/s3_handler.py
+++ b/lib/spack/spack/s3_handler.py
@@ -63,7 +63,7 @@ def _s3_open(url):
class UrllibS3Handler(urllib_request.HTTPSHandler):
def s3_open(self, req):
orig_url = req.get_full_url()
- from botocore.exceptions import ClientError
+ from botocore.exceptions import ClientError # type: ignore[import]
try:
url, headers, stream = _s3_open(orig_url)
return urllib_response.addinfourl(stream, headers, url)
diff --git a/lib/spack/spack/schema/environment.py b/lib/spack/spack/schema/environment.py
index 90632c266c..3bb02d33d0 100644
--- a/lib/spack/spack/schema/environment.py
+++ b/lib/spack/spack/schema/environment.py
@@ -38,13 +38,9 @@ def parse(config_obj):
config_obj: a configuration dictionary conforming to the
schema definition for environment modifications
"""
- import sys
+ from llnl.util.compat import Sequence
import spack.util.environment as ev
- if sys.version_info >= (3, 5):
- from collections.abc import Sequence # novm
- else:
- from collections import Sequence # novm
env = ev.EnvironmentModifications()
for command, variable in config_obj.items():
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index d6c8fc8d3a..4f727cdf48 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -17,13 +17,15 @@ from six import string_types
import archspec.cpu
+from llnl.util.compat import Sequence
+
try:
- import clingo
+ import clingo # type: ignore[import]
# There may be a better way to detect this
clingo_cffi = hasattr(clingo.Symbol, '_rep')
except ImportError:
- clingo = None # type: ignore
+ clingo = None
clingo_cffi = False
import llnl.util.lang
@@ -49,11 +51,6 @@ import spack.util.timer
import spack.variant
import spack.version
-if sys.version_info >= (3, 3):
- from collections.abc import Sequence # novm
-else:
- from collections import Sequence
-
# these are from clingo.ast and bootstrapped later
ASTType = None
parse_files = None
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index aa9cd6a709..e97a3ca12d 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -81,7 +81,6 @@ import itertools
import operator
import os
import re
-import sys
import warnings
import ruamel.yaml as yaml
@@ -91,6 +90,7 @@ import llnl.util.filesystem as fs
import llnl.util.lang as lang
import llnl.util.tty as tty
import llnl.util.tty.color as clr
+from llnl.util.compat import Mapping
import spack.compiler
import spack.compilers
@@ -117,12 +117,6 @@ import spack.util.string
import spack.variant as vt
import spack.version as vn
-if sys.version_info >= (3, 3):
- from collections.abc import Mapping # novm
-else:
- from collections import Mapping
-
-
__all__ = [
'CompilerSpec',
'Spec',
diff --git a/lib/spack/spack/test/ci.py b/lib/spack/spack/test/ci.py
index e054ccf14f..7bff8f8447 100644
--- a/lib/spack/spack/test/ci.py
+++ b/lib/spack/spack/test/ci.py
@@ -3,7 +3,6 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import collections
import itertools as it
import json
import os
@@ -24,12 +23,6 @@ import spack.spec as spec
import spack.util.gpg
import spack.util.spack_yaml as syaml
-try:
- # dynamically import to keep vermin from complaining
- collections_abc = __import__('collections.abc')
-except ImportError:
- collections_abc = collections
-
@pytest.fixture
def tmp_scope():
diff --git a/lib/spack/spack/test/cmd/versions.py b/lib/spack/spack/test/cmd/versions.py
index 0482c654a7..d931a3fe9b 100644
--- a/lib/spack/spack/test/cmd/versions.py
+++ b/lib/spack/spack/test/cmd/versions.py
@@ -41,7 +41,7 @@ def test_remote_versions_only():
@pytest.mark.usefixtures('mock_packages')
def test_new_versions_only(monkeypatch):
"""Test a package for which new versions should be available."""
- from spack.pkg.builtin.mock.brillig import Brillig
+ from spack.pkg.builtin.mock.brillig import Brillig # type: ignore[import]
def mock_fetch_remote_versions(*args, **kwargs):
mock_remote_versions = {
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index c3bd724517..d805112e5f 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -15,6 +15,7 @@ import re
import shutil
import tempfile
import xml.etree.ElementTree
+from typing import Dict # novm
import py
import pytest
@@ -50,8 +51,8 @@ from spack.util.pattern import Bunch
#
# Return list of shas for latest two git commits in local spack repo
#
-@pytest.fixture
-def last_two_git_commits(scope='session'):
+@pytest.fixture(scope='session')
+def last_two_git_commits():
git = spack.util.executable.which('git', required=True)
spack_git_path = spack.paths.prefix
with working_dir(spack_git_path):
@@ -1488,7 +1489,7 @@ repo:
class MockBundle(object):
has_code = False
name = 'mock-bundle'
- versions = {} # type: ignore
+ versions = {} # type: Dict
@pytest.fixture
diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
index beec23f0be..7170a08aae 100644
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -55,13 +55,13 @@ class TestPackage(object):
# Below tests target direct imports of spack packages from the
# spack.pkg namespace
def test_import_package(self):
- import spack.pkg.builtin.mock.mpich # noqa
+ import spack.pkg.builtin.mock.mpich # type: ignore[import] # noqa
def test_import_package_as(self):
- import spack.pkg.builtin.mock.mpich as mp # noqa
- import spack.pkg.builtin.mock # noqa
- import spack.pkg.builtin.mock as m # noqa
- from spack.pkg.builtin import mock # noqa
+ import spack.pkg.builtin.mock # noqa
+ import spack.pkg.builtin.mock as m # noqa
+ import spack.pkg.builtin.mock.mpich as mp # noqa
+ from spack.pkg.builtin import mock # noqa
def test_inheritance_of_diretives(self):
p = spack.repo.get('simple-inheritance')
@@ -104,18 +104,18 @@ class TestPackage(object):
from spack.pkg.builtin.mock.mpich import Mpich # noqa
def test_import_module_from_package(self):
- from spack.pkg.builtin.mock import mpich # noqa
+ from spack.pkg.builtin.mock import mpich # noqa
def test_import_namespace_container_modules(self):
- import spack.pkg # noqa
- import spack.pkg as p # noqa
- from spack import pkg # noqa
- import spack.pkg.builtin # noqa
- import spack.pkg.builtin as b # noqa
- from spack.pkg import builtin # noqa
- import spack.pkg.builtin.mock # noqa
- import spack.pkg.builtin.mock as m # noqa
- from spack.pkg.builtin import mock # noqa
+ import spack.pkg # noqa
+ import spack.pkg as p # noqa
+ import spack.pkg.builtin # noqa
+ import spack.pkg.builtin as b # noqa
+ import spack.pkg.builtin.mock # noqa
+ import spack.pkg.builtin.mock as m # noqa
+ from spack import pkg # noqa
+ from spack.pkg import builtin # noqa
+ from spack.pkg.builtin import mock # noqa
@pytest.mark.regression('2737')
diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py
index ce27c24629..8aa14b9230 100644
--- a/lib/spack/spack/test/spec_yaml.py
+++ b/lib/spack/spack/test/spec_yaml.py
@@ -11,10 +11,11 @@ YAML format preserves DAG information in the spec.
import ast
import inspect
import os
-import sys
import pytest
+from llnl.util.compat import Iterable, Mapping
+
import spack.hash_types as ht
import spack.spec
import spack.util.spack_json as sjson
@@ -25,11 +26,6 @@ from spack.spec import Spec, save_dependency_specfiles
from spack.util.mock_package import MockPackageMultiRepo
from spack.util.spack_yaml import SpackYAMLError, syaml_dict
-if sys.version_info >= (3, 3):
- from collections.abc import Iterable, Mapping # novm
-else:
- from collections import Iterable, Mapping
-
def check_yaml_round_trip(spec):
yaml_text = spec.to_yaml()
diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py
index b6c3ac359b..9b143b0b6b 100644
--- a/lib/spack/spack/util/environment.py
+++ b/lib/spack/spack/util/environment.py
@@ -25,6 +25,7 @@ import spack.config
import spack.platforms
import spack.spec
import spack.util.executable as executable
+import spack.util.spack_json as sjson
system_paths = ['/', '/usr', '/usr/local']
suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64']
@@ -1027,13 +1028,7 @@ def environment_after_sourcing_files(*files, **kwargs):
# If we're in python2, convert to str objects instead of unicode
# like json gives us. We can't put unicode in os.environ anyway.
- if sys.version_info[0] < 3:
- environment = dict(
- (k.encode('utf-8'), v.encode('utf-8'))
- for k, v in environment.items()
- )
-
- return environment
+ return sjson.encode_json_dict(environment)
current_environment = kwargs.get('env', dict(os.environ))
for f in files:
@@ -1074,7 +1069,7 @@ def sanitize(environment, blacklist, whitelist):
return subset
# Don't modify input, make a copy instead
- environment = dict(environment)
+ environment = sjson.decode_json_dict(dict(environment))
# Retain (whitelist) has priority over prune (blacklist)
prune = set_intersection(set(environment), *blacklist)
diff --git a/lib/spack/spack/util/mock_package.py b/lib/spack/spack/util/mock_package.py
index c600933cc9..b5f942aedf 100644
--- a/lib/spack/spack/util/mock_package.py
+++ b/lib/spack/spack/util/mock_package.py
@@ -103,7 +103,6 @@ class MockPackageMultiRepo(object):
return False
def repo_for_pkg(self, name):
- import collections
Repo = collections.namedtuple('Repo', ['namespace'])
return Repo('mockrepo')
diff --git a/lib/spack/spack/util/pattern.py b/lib/spack/spack/util/pattern.py
index 1eb8b6a7a1..220e18b4a3 100644
--- a/lib/spack/spack/util/pattern.py
+++ b/lib/spack/spack/util/pattern.py
@@ -5,12 +5,8 @@
import functools
import inspect
-import sys
-if sys.version_info >= (3, 3):
- from collections.abc import MutableSequence # novm
-else:
- from collections import MutableSequence
+from llnl.util.compat import MutableSequence
class Delegate(object):
diff --git a/lib/spack/spack/util/py2.py b/lib/spack/spack/util/py2.py
new file mode 100644
index 0000000000..b92a6d66d9
--- /dev/null
+++ b/lib/spack/spack/util/py2.py
@@ -0,0 +1,16 @@
+# Copyright 2013-2022 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)
+
+import base64
+
+from six import PY3, binary_type, text_type
+
+
+def b32encode(digest):
+ # type: (binary_type) -> text_type
+ b32 = base64.b32encode(digest)
+ if PY3:
+ return b32.decode()
+ return b32
diff --git a/lib/spack/spack/util/s3.py b/lib/spack/spack/util/s3.py
index c8c885c5ab..b52a879e21 100644
--- a/lib/spack/spack/util/s3.py
+++ b/lib/spack/spack/util/s3.py
@@ -61,16 +61,16 @@ def create_s3_session(url, connection={}):
# NOTE(opadron): import boto and friends as late as possible. We don't
# want to require boto as a dependency unless the user actually wants to
# access S3 mirrors.
- from boto3 import Session
- from botocore.exceptions import ClientError
+ from boto3 import Session # type: ignore[import]
+ from botocore.exceptions import ClientError # type: ignore[import]
s3_connection, s3_client_args = get_mirror_s3_connection_info(connection)
session = Session(**s3_connection)
# if no access credentials provided above, then access anonymously
if not session.get_credentials():
- from botocore import UNSIGNED
- from botocore.client import Config
+ from botocore import UNSIGNED # type: ignore[import]
+ from botocore.client import Config # type: ignore[import]
s3_client_args["config"] = Config(signature_version=UNSIGNED)
diff --git a/lib/spack/spack/util/spack_json.py b/lib/spack/spack/util/spack_json.py
index 38bae8f387..7083b3c80a 100644
--- a/lib/spack/spack/util/spack_json.py
+++ b/lib/spack/spack/util/spack_json.py
@@ -5,13 +5,13 @@
"""Simple wrapper around JSON to guarantee consistent use of load/dump. """
import json
-import sys
+from typing import Any, Dict, Optional # novm
-from six import iteritems, string_types
+from six import PY3, iteritems, string_types
import spack.error
-__all__ = ['load', 'dump', 'SpackJSONError']
+__all__ = ['load', 'dump', 'SpackJSONError', 'encode_json_dict', 'decode_json_dict']
_json_dump_args = {
'indent': 2,
@@ -20,27 +20,45 @@ _json_dump_args = {
def load(stream):
+ # type: (Any) -> Dict
"""Spack JSON needs to be ordered to support specs."""
if isinstance(stream, string_types):
- load = json.loads
+ load = json.loads # type: ignore[assignment]
else:
- load = json.load
+ load = json.load # type: ignore[assignment]
return _strify(load(stream, object_hook=_strify), ignore_dicts=True)
+def encode_json_dict(data):
+ # type: (Dict) -> Dict
+ """Converts python 2 unicodes to str in JSON data."""
+ return _strify(data)
+
+
def dump(data, stream=None):
+ # type: (Dict, Optional[Any]) -> Optional[str]
"""Dump JSON with a reasonable amount of indentation and separation."""
+ data = _strify(data)
if stream is None:
- return json.dumps(data, **_json_dump_args)
- else:
- return json.dump(data, stream, **_json_dump_args)
+ return json.dumps(data, **_json_dump_args) # type: ignore[arg-type]
+ json.dump(data, stream, **_json_dump_args) # type: ignore[arg-type]
+ return None
+
+
+def decode_json_dict(data):
+ # type: (Dict) -> Dict
+ """Converts str to python 2 unicodes in JSON data."""
+ return _strify(data)
def _strify(data, ignore_dicts=False):
- """Converts python 2 unicodes to str in JSON data."""
+ # type: (Dict, bool) -> Dict
+ """Helper method for ``encode_json_dict()`` and ``decode_json_dict()``.
+
+ Converts python 2 unicodes to str in JSON data, or the other way around."""
# this is a no-op in python 3
- if sys.version_info[0] >= 3:
+ if PY3:
return data
# if this is a unicode string in python 2, return its string representation
@@ -66,4 +84,5 @@ class SpackJSONError(spack.error.SpackError):
"""Raised when there are issues with JSON parsing."""
def __init__(self, msg, json_error):
+ # type: (str, BaseException) -> None
super(SpackJSONError, self).__init__(msg, str(json_error))
diff --git a/lib/spack/spack/util/spack_yaml.py b/lib/spack/spack/util/spack_yaml.py
index d869b19dc7..227b9d7449 100644
--- a/lib/spack/spack/util/spack_yaml.py
+++ b/lib/spack/spack/util/spack_yaml.py
@@ -15,30 +15,23 @@
import collections
import ctypes
import re
-import sys
from typing import List # novm
import ruamel.yaml as yaml
from ruamel.yaml import RoundTripDumper, RoundTripLoader
from six import StringIO, string_types
+from llnl.util.compat import Mapping
from llnl.util.tty.color import cextra, clen, colorize
import spack.error
-if sys.version_info >= (3, 3):
- from collections.abc import Mapping # novm
-else:
- from collections import Mapping
-
-
# Only export load and dump
__all__ = ['load', 'dump', 'SpackYAMLError']
+
# Make new classes so we can add custom attributes.
# Also, use OrderedDict instead of just dict.
-
-
class syaml_dict(collections.OrderedDict):
def __repr__(self):
mappings = ('%r: %r' % (k, v) for k, v in self.items())
diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py
index 1be147ff6f..ccbc5db33e 100644
--- a/lib/spack/spack/variant.py
+++ b/lib/spack/spack/variant.py
@@ -11,17 +11,12 @@ import functools
import inspect
import itertools
import re
-import sys
from six import StringIO
-if sys.version_info >= (3, 5):
- from collections.abc import Sequence # novm
-else:
- from collections import Sequence
-
import llnl.util.lang as lang
import llnl.util.tty.color
+from llnl.util.compat import Sequence
import spack.directives
import spack.error as error
diff --git a/lib/spack/spack/verify.py b/lib/spack/spack/verify.py
index 382592fcdc..dca908f345 100644
--- a/lib/spack/spack/verify.py
+++ b/lib/spack/spack/verify.py
@@ -2,28 +2,22 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import base64
import hashlib
import os
-import sys
import llnl.util.tty as tty
import spack.filesystem_view
import spack.store
import spack.util.file_permissions as fp
+import spack.util.py2 as compat
import spack.util.spack_json as sjson
def compute_hash(path):
with open(path, 'rb') as f:
sha1 = hashlib.sha1(f.read()).digest()
- b32 = base64.b32encode(sha1)
-
- if sys.version_info[0] >= 3:
- b32 = b32.decode()
-
- return b32
+ return compat.b32encode(sha1)
def create_manifest_entry(path):
diff --git a/pyproject.toml b/pyproject.toml
index d09e589bed..4b6da081c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -10,6 +10,7 @@ sections = [
known_first_party = "spack"
known_archspec = "archspec"
known_llnl = "llnl"
+known_third_party = ["ruamel", "six"]
src_paths = "lib"
honor_noqa = true