introduce llnl.util.compat to remove sys.version_info checks (#21720)

- also split typing.py into typing_extensions and add py2 shims
This commit is contained in:
Danny McClanahan 2022-01-21 15:32:52 -05:00 committed by GitHub
parent 796f5a3cbc
commit 0c2de252f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 248 additions and 246 deletions

View file

@ -6,79 +6,77 @@
This is a fake set of symbols to allow spack to import typing in python This is a fake set of symbols to allow spack to import typing in python
versions where we do not support type checking (<3) versions where we do not support type checking (<3)
""" """
Annotated = None from collections import defaultdict
Any = None
Callable = None # (1) Unparameterized types.
ForwardRef = None Annotated = object
Generic = None Any = object
Literal = None AnyStr = object
Optional = None ByteString = object
Tuple = None Counter = object
TypeVar = None Final = object
Union = None Hashable = object
AbstractSet = None NoReturn = object
ByteString = None Sized = object
Container = None SupportsAbs = object
Hashable = None SupportsBytes = object
ItemsView = None SupportsComplex = object
Iterable = None SupportsFloat = object
Iterator = None SupportsIndex = object
KeysView = None SupportsInt = object
Mapping = None SupportsRound = object
MappingView = None
MutableMapping = None # (2) Parameterized types.
MutableSequence = None AbstractSet = defaultdict(lambda: object)
MutableSet = None AsyncContextManager = defaultdict(lambda: object)
Sequence = None AsyncGenerator = defaultdict(lambda: object)
Sized = None AsyncIterable = defaultdict(lambda: object)
ValuesView = None AsyncIterator = defaultdict(lambda: object)
Awaitable = None Awaitable = defaultdict(lambda: object)
AsyncIterator = None Callable = defaultdict(lambda: object)
AsyncIterable = None ChainMap = defaultdict(lambda: object)
Coroutine = None ClassVar = defaultdict(lambda: object)
Collection = None Collection = defaultdict(lambda: object)
AsyncGenerator = None Container = defaultdict(lambda: object)
AsyncContextManager = None ContextManager = defaultdict(lambda: object)
Reversible = None Coroutine = defaultdict(lambda: object)
SupportsAbs = None DefaultDict = defaultdict(lambda: object)
SupportsBytes = None Deque = defaultdict(lambda: object)
SupportsComplex = None Dict = defaultdict(lambda: object)
SupportsFloat = None ForwardRef = defaultdict(lambda: object)
SupportsInt = None FrozenSet = defaultdict(lambda: object)
SupportsRound = None Generator = defaultdict(lambda: object)
ChainMap = None Generic = defaultdict(lambda: object)
Dict = None ItemsView = defaultdict(lambda: object)
List = None Iterable = defaultdict(lambda: object)
OrderedDict = None Iterator = defaultdict(lambda: object)
Set = None KeysView = defaultdict(lambda: object)
FrozenSet = None List = defaultdict(lambda: object)
NamedTuple = None Literal = defaultdict(lambda: object)
Generator = None Mapping = defaultdict(lambda: object)
AnyStr = None MappingView = defaultdict(lambda: object)
cast = None 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_args = None
get_origin = None get_origin = None
get_type_hints = None get_type_hints = None
no_type_check = None no_type_check = None
no_type_check_decorator = 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

View file

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

View file

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

View file

@ -21,15 +21,11 @@
import six import six
from llnl.util import tty from llnl.util import tty
from llnl.util.compat import Sequence
from llnl.util.lang import dedupe, memoized from llnl.util.lang import dedupe, memoized
from spack.util.executable import Executable from spack.util.executable import Executable
if sys.version_info >= (3, 3):
from collections.abc import Sequence # novm
else:
from collections import Sequence
__all__ = [ __all__ = [
'FileFilter', 'FileFilter',
'FileList', 'FileList',

View file

@ -14,17 +14,7 @@
from six import string_types from six import string_types
if sys.version_info < (3, 0): from llnl.util.compat import Hashable, MutableMapping, zip_longest
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
# Ignore emacs backups when listing modules # Ignore emacs backups when listing modules
ignore_modules = [r'^\.#', '~$'] ignore_modules = [r'^\.#', '~$']

View file

@ -3,18 +3,11 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import collections from llnl.util.compat import Mapping
try:
# dynamically import to keep vermin from complaining
collections_abc = __import__('collections.abc')
except ImportError:
collections_abc = collections
get_job_name = lambda needs_entry: ( get_job_name = lambda needs_entry: (
needs_entry.get('job') if ( needs_entry.get('job') if (
isinstance(needs_entry, collections_abc.Mapping) and isinstance(needs_entry, Mapping) and
needs_entry.get('artifacts', True)) needs_entry.get('artifacts', True))
else else
@ -25,7 +18,7 @@
def convert_job(job_entry): def convert_job(job_entry):
if not isinstance(job_entry, collections_abc.Mapping): if not isinstance(job_entry, Mapping):
return job_entry return job_entry
needs = job_entry.get('needs') needs = job_entry.get('needs')

View file

@ -3,28 +3,23 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # 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 copy
import hashlib import hashlib
from collections import defaultdict
from llnl.util.compat import Mapping, Sequence
import spack.util.spack_yaml as syaml import spack.util.spack_yaml as syaml
def sort_yaml_obj(obj): def sort_yaml_obj(obj):
if isinstance(obj, collections_abc.Mapping): if isinstance(obj, Mapping):
return syaml.syaml_dict( return syaml.syaml_dict(
(k, sort_yaml_obj(v)) (k, sort_yaml_obj(v))
for k, v in for k, v in
sorted(obj.items(), key=(lambda item: str(item[0])))) 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 syaml.syaml_list(sort_yaml_obj(x) for x in obj)
return obj return obj
@ -44,8 +39,8 @@ def matches(obj, proto):
Precondition: proto must not have any reference cycles Precondition: proto must not have any reference cycles
""" """
if isinstance(obj, collections_abc.Mapping): if isinstance(obj, Mapping):
if not isinstance(proto, collections_abc.Mapping): if not isinstance(proto, Mapping):
return False return False
return all( return all(
@ -53,10 +48,10 @@ def matches(obj, proto):
for key, val in proto.items() for key, val in proto.items()
) )
if (isinstance(obj, collections_abc.Sequence) and if (isinstance(obj, Sequence) and
not isinstance(obj, str)): not isinstance(obj, str)):
if not (isinstance(proto, collections_abc.Sequence) and if not (isinstance(proto, Sequence) and
not isinstance(proto, str)): not isinstance(proto, str)):
return False return False
@ -90,8 +85,8 @@ def subkeys(obj, proto):
Otherwise, obj is returned. Otherwise, obj is returned.
""" """
if not (isinstance(obj, collections_abc.Mapping) and if not (isinstance(obj, Mapping) and
isinstance(proto, collections_abc.Mapping)): isinstance(proto, Mapping)):
return obj return obj
new_obj = {} new_obj = {}
@ -104,7 +99,7 @@ def subkeys(obj, proto):
matches(proto[key], value)): matches(proto[key], value)):
continue continue
if isinstance(value, collections_abc.Mapping): if isinstance(value, Mapping):
new_obj[key] = subkeys(value, proto[key]) new_obj[key] = subkeys(value, proto[key])
continue continue
@ -132,7 +127,7 @@ def add_extends(yaml, key):
has_key = ('extends' in yaml) has_key = ('extends' in yaml)
extends = yaml.get('extends') 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 return
if extends is None: 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 The list is sorted in descending order by count, yielding the most
frequently occuring hashes first. frequently occuring hashes first.
""" """
buckets = collections.defaultdict(int) buckets = defaultdict(int)
values = {} values = {}
num_objects = 0 num_objects = 0

View file

@ -73,7 +73,7 @@ def ipython_interpreter(args):
support running a script or arguments support running a script or arguments
""" """
try: try:
import IPython import IPython # type: ignore[import]
except ImportError: except ImportError:
tty.die("ipython is not installed, install and try again.") tty.die("ipython is not installed, install and try again.")

View file

@ -30,13 +30,13 @@ class OpenMpi(Package):
import functools import functools
import os.path import os.path
import re import re
import sys
from typing import List, Set # novm from typing import List, Set # novm
import six import six
import llnl.util.lang import llnl.util.lang
import llnl.util.tty.color import llnl.util.tty.color
from llnl.util.compat import Sequence
import spack.error import spack.error
import spack.patch import spack.patch
@ -48,12 +48,6 @@ class OpenMpi(Package):
from spack.resource import Resource from spack.resource import Resource
from spack.version import Version, VersionChecksumError 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'] __all__ = ['DirectiveError', 'DirectiveMeta']
#: These are variant names used by Spack internally; packages can't use them #: These are variant names used by Spack internally; packages can't use them

View file

@ -11,6 +11,7 @@
import sys import sys
from llnl.util import tty 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.filesystem import mkdirp, remove_dead_links, remove_empty_directories
from llnl.util.lang import index_by, match_predicate from llnl.util.lang import index_by, match_predicate
from llnl.util.link_tree import LinkTree, MergeConflictError from llnl.util.link_tree import LinkTree, MergeConflictError
@ -29,12 +30,6 @@
) )
from spack.error import SpackError 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"] __all__ = ["FilesystemView", "YamlFilesystemView"]

View file

@ -21,12 +21,8 @@
import ruamel.yaml.error as yaml_error import ruamel.yaml.error as yaml_error
import six 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 import llnl.util.tty as tty
from llnl.util.compat import Mapping
from llnl.util.filesystem import mkdirp from llnl.util.filesystem import mkdirp
import spack.config import spack.config

View file

@ -1293,7 +1293,7 @@ def prefix(self):
"""Get the prefix into which this package should be installed.""" """Get the prefix into which this package should be installed."""
return self.spec.prefix return self.spec.prefix
@property # type: ignore @property # type: ignore[misc]
@memoized @memoized
def compiler(self): def compiler(self):
"""Get the spack.compiler.Compiler object used to build this package""" """Get the spack.compiler.Compiler object used to build this package"""

View file

@ -18,18 +18,13 @@
import types import types
from typing import Dict # novm 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 ruamel.yaml as yaml
import six
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import llnl.util.lang import llnl.util.lang
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.compat import Mapping
import spack.caches import spack.caches
import spack.config import spack.config

View file

@ -63,7 +63,7 @@ def _s3_open(url):
class UrllibS3Handler(urllib_request.HTTPSHandler): class UrllibS3Handler(urllib_request.HTTPSHandler):
def s3_open(self, req): def s3_open(self, req):
orig_url = req.get_full_url() orig_url = req.get_full_url()
from botocore.exceptions import ClientError from botocore.exceptions import ClientError # type: ignore[import]
try: try:
url, headers, stream = _s3_open(orig_url) url, headers, stream = _s3_open(orig_url)
return urllib_response.addinfourl(stream, headers, url) return urllib_response.addinfourl(stream, headers, url)

View file

@ -38,13 +38,9 @@ def parse(config_obj):
config_obj: a configuration dictionary conforming to the config_obj: a configuration dictionary conforming to the
schema definition for environment modifications schema definition for environment modifications
""" """
import sys from llnl.util.compat import Sequence
import spack.util.environment as ev 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() env = ev.EnvironmentModifications()
for command, variable in config_obj.items(): for command, variable in config_obj.items():

View file

@ -17,13 +17,15 @@
import archspec.cpu import archspec.cpu
from llnl.util.compat import Sequence
try: try:
import clingo import clingo # type: ignore[import]
# There may be a better way to detect this # There may be a better way to detect this
clingo_cffi = hasattr(clingo.Symbol, '_rep') clingo_cffi = hasattr(clingo.Symbol, '_rep')
except ImportError: except ImportError:
clingo = None # type: ignore clingo = None
clingo_cffi = False clingo_cffi = False
import llnl.util.lang import llnl.util.lang
@ -49,11 +51,6 @@
import spack.variant import spack.variant
import spack.version 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 # these are from clingo.ast and bootstrapped later
ASTType = None ASTType = None
parse_files = None parse_files = None

View file

@ -81,7 +81,6 @@
import operator import operator
import os import os
import re import re
import sys
import warnings import warnings
import ruamel.yaml as yaml import ruamel.yaml as yaml
@ -91,6 +90,7 @@
import llnl.util.lang as lang import llnl.util.lang as lang
import llnl.util.tty as tty import llnl.util.tty as tty
import llnl.util.tty.color as clr import llnl.util.tty.color as clr
from llnl.util.compat import Mapping
import spack.compiler import spack.compiler
import spack.compilers import spack.compilers
@ -117,12 +117,6 @@
import spack.variant as vt import spack.variant as vt
import spack.version as vn import spack.version as vn
if sys.version_info >= (3, 3):
from collections.abc import Mapping # novm
else:
from collections import Mapping
__all__ = [ __all__ = [
'CompilerSpec', 'CompilerSpec',
'Spec', 'Spec',

View file

@ -3,7 +3,6 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import collections
import itertools as it import itertools as it
import json import json
import os import os
@ -24,12 +23,6 @@
import spack.util.gpg import spack.util.gpg
import spack.util.spack_yaml as syaml 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 @pytest.fixture
def tmp_scope(): def tmp_scope():

View file

@ -41,7 +41,7 @@ def test_remote_versions_only():
@pytest.mark.usefixtures('mock_packages') @pytest.mark.usefixtures('mock_packages')
def test_new_versions_only(monkeypatch): def test_new_versions_only(monkeypatch):
"""Test a package for which new versions should be available.""" """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): def mock_fetch_remote_versions(*args, **kwargs):
mock_remote_versions = { mock_remote_versions = {

View file

@ -15,6 +15,7 @@
import shutil import shutil
import tempfile import tempfile
import xml.etree.ElementTree import xml.etree.ElementTree
from typing import Dict # novm
import py import py
import pytest import pytest
@ -50,8 +51,8 @@
# #
# Return list of shas for latest two git commits in local spack repo # Return list of shas for latest two git commits in local spack repo
# #
@pytest.fixture @pytest.fixture(scope='session')
def last_two_git_commits(scope='session'): def last_two_git_commits():
git = spack.util.executable.which('git', required=True) git = spack.util.executable.which('git', required=True)
spack_git_path = spack.paths.prefix spack_git_path = spack.paths.prefix
with working_dir(spack_git_path): with working_dir(spack_git_path):
@ -1488,7 +1489,7 @@ def mock_test_repo(tmpdir_factory):
class MockBundle(object): class MockBundle(object):
has_code = False has_code = False
name = 'mock-bundle' name = 'mock-bundle'
versions = {} # type: ignore versions = {} # type: Dict
@pytest.fixture @pytest.fixture

View file

@ -55,12 +55,12 @@ def test_package_class_names(self):
# Below tests target direct imports of spack packages from the # Below tests target direct imports of spack packages from the
# spack.pkg namespace # spack.pkg namespace
def test_import_package(self): 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): 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 # noqa
import spack.pkg.builtin.mock as m # 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 from spack.pkg.builtin import mock # noqa
def test_inheritance_of_diretives(self): def test_inheritance_of_diretives(self):
@ -109,12 +109,12 @@ def test_import_module_from_package(self):
def test_import_namespace_container_modules(self): def test_import_namespace_container_modules(self):
import spack.pkg # noqa import spack.pkg # noqa
import spack.pkg as p # noqa import spack.pkg as p # noqa
from spack import pkg # noqa
import spack.pkg.builtin # noqa import spack.pkg.builtin # noqa
import spack.pkg.builtin as b # 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 # noqa
import spack.pkg.builtin.mock as m # 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 from spack.pkg.builtin import mock # noqa

View file

@ -11,10 +11,11 @@
import ast import ast
import inspect import inspect
import os import os
import sys
import pytest import pytest
from llnl.util.compat import Iterable, Mapping
import spack.hash_types as ht import spack.hash_types as ht
import spack.spec import spack.spec
import spack.util.spack_json as sjson import spack.util.spack_json as sjson
@ -25,11 +26,6 @@
from spack.util.mock_package import MockPackageMultiRepo from spack.util.mock_package import MockPackageMultiRepo
from spack.util.spack_yaml import SpackYAMLError, syaml_dict 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): def check_yaml_round_trip(spec):
yaml_text = spec.to_yaml() yaml_text = spec.to_yaml()

View file

@ -25,6 +25,7 @@
import spack.platforms import spack.platforms
import spack.spec import spack.spec
import spack.util.executable as executable import spack.util.executable as executable
import spack.util.spack_json as sjson
system_paths = ['/', '/usr', '/usr/local'] system_paths = ['/', '/usr', '/usr/local']
suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64'] suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64']
@ -1027,13 +1028,7 @@ def _source_single_file(file_and_args, environment):
# If we're in python2, convert to str objects instead of unicode # 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. # like json gives us. We can't put unicode in os.environ anyway.
if sys.version_info[0] < 3: return sjson.encode_json_dict(environment)
environment = dict(
(k.encode('utf-8'), v.encode('utf-8'))
for k, v in environment.items()
)
return environment
current_environment = kwargs.get('env', dict(os.environ)) current_environment = kwargs.get('env', dict(os.environ))
for f in files: for f in files:
@ -1074,7 +1069,7 @@ def set_intersection(fullset, *args):
return subset return subset
# Don't modify input, make a copy instead # 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) # Retain (whitelist) has priority over prune (blacklist)
prune = set_intersection(set(environment), *blacklist) prune = set_intersection(set(environment), *blacklist)

View file

@ -103,7 +103,6 @@ def is_virtual(self, name, use_index=True):
return False return False
def repo_for_pkg(self, name): def repo_for_pkg(self, name):
import collections
Repo = collections.namedtuple('Repo', ['namespace']) Repo = collections.namedtuple('Repo', ['namespace'])
return Repo('mockrepo') return Repo('mockrepo')

View file

@ -5,12 +5,8 @@
import functools import functools
import inspect import inspect
import sys
if sys.version_info >= (3, 3): from llnl.util.compat import MutableSequence
from collections.abc import MutableSequence # novm
else:
from collections import MutableSequence
class Delegate(object): class Delegate(object):

View file

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

View file

@ -61,16 +61,16 @@ def create_s3_session(url, connection={}):
# NOTE(opadron): import boto and friends as late as possible. We don't # 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 # want to require boto as a dependency unless the user actually wants to
# access S3 mirrors. # access S3 mirrors.
from boto3 import Session from boto3 import Session # type: ignore[import]
from botocore.exceptions import ClientError from botocore.exceptions import ClientError # type: ignore[import]
s3_connection, s3_client_args = get_mirror_s3_connection_info(connection) s3_connection, s3_client_args = get_mirror_s3_connection_info(connection)
session = Session(**s3_connection) session = Session(**s3_connection)
# if no access credentials provided above, then access anonymously # if no access credentials provided above, then access anonymously
if not session.get_credentials(): if not session.get_credentials():
from botocore import UNSIGNED from botocore import UNSIGNED # type: ignore[import]
from botocore.client import Config from botocore.client import Config # type: ignore[import]
s3_client_args["config"] = Config(signature_version=UNSIGNED) s3_client_args["config"] = Config(signature_version=UNSIGNED)

View file

@ -5,13 +5,13 @@
"""Simple wrapper around JSON to guarantee consistent use of load/dump. """ """Simple wrapper around JSON to guarantee consistent use of load/dump. """
import json 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 import spack.error
__all__ = ['load', 'dump', 'SpackJSONError'] __all__ = ['load', 'dump', 'SpackJSONError', 'encode_json_dict', 'decode_json_dict']
_json_dump_args = { _json_dump_args = {
'indent': 2, 'indent': 2,
@ -20,27 +20,45 @@
def load(stream): def load(stream):
# type: (Any) -> Dict
"""Spack JSON needs to be ordered to support specs.""" """Spack JSON needs to be ordered to support specs."""
if isinstance(stream, string_types): if isinstance(stream, string_types):
load = json.loads load = json.loads # type: ignore[assignment]
else: else:
load = json.load load = json.load # type: ignore[assignment]
return _strify(load(stream, object_hook=_strify), ignore_dicts=True) 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): def dump(data, stream=None):
# type: (Dict, Optional[Any]) -> Optional[str]
"""Dump JSON with a reasonable amount of indentation and separation.""" """Dump JSON with a reasonable amount of indentation and separation."""
data = _strify(data)
if stream is None: if stream is None:
return json.dumps(data, **_json_dump_args) return json.dumps(data, **_json_dump_args) # type: ignore[arg-type]
else: json.dump(data, stream, **_json_dump_args) # type: ignore[arg-type]
return json.dump(data, stream, **_json_dump_args) 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): 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 # this is a no-op in python 3
if sys.version_info[0] >= 3: if PY3:
return data return data
# if this is a unicode string in python 2, return its string representation # 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.""" """Raised when there are issues with JSON parsing."""
def __init__(self, msg, json_error): def __init__(self, msg, json_error):
# type: (str, BaseException) -> None
super(SpackJSONError, self).__init__(msg, str(json_error)) super(SpackJSONError, self).__init__(msg, str(json_error))

View file

@ -15,30 +15,23 @@
import collections import collections
import ctypes import ctypes
import re import re
import sys
from typing import List # novm from typing import List # novm
import ruamel.yaml as yaml import ruamel.yaml as yaml
from ruamel.yaml import RoundTripDumper, RoundTripLoader from ruamel.yaml import RoundTripDumper, RoundTripLoader
from six import StringIO, string_types from six import StringIO, string_types
from llnl.util.compat import Mapping
from llnl.util.tty.color import cextra, clen, colorize from llnl.util.tty.color import cextra, clen, colorize
import spack.error 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 # Only export load and dump
__all__ = ['load', 'dump', 'SpackYAMLError'] __all__ = ['load', 'dump', 'SpackYAMLError']
# Make new classes so we can add custom attributes. # Make new classes so we can add custom attributes.
# Also, use OrderedDict instead of just dict. # Also, use OrderedDict instead of just dict.
class syaml_dict(collections.OrderedDict): class syaml_dict(collections.OrderedDict):
def __repr__(self): def __repr__(self):
mappings = ('%r: %r' % (k, v) for k, v in self.items()) mappings = ('%r: %r' % (k, v) for k, v in self.items())

View file

@ -11,17 +11,12 @@
import inspect import inspect
import itertools import itertools
import re import re
import sys
from six import StringIO 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.lang as lang
import llnl.util.tty.color import llnl.util.tty.color
from llnl.util.compat import Sequence
import spack.directives import spack.directives
import spack.error as error import spack.error as error

View file

@ -2,28 +2,22 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details. # Spack Project Developers. See the top-level COPYRIGHT file for details.
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import base64
import hashlib import hashlib
import os import os
import sys
import llnl.util.tty as tty import llnl.util.tty as tty
import spack.filesystem_view import spack.filesystem_view
import spack.store import spack.store
import spack.util.file_permissions as fp import spack.util.file_permissions as fp
import spack.util.py2 as compat
import spack.util.spack_json as sjson import spack.util.spack_json as sjson
def compute_hash(path): def compute_hash(path):
with open(path, 'rb') as f: with open(path, 'rb') as f:
sha1 = hashlib.sha1(f.read()).digest() sha1 = hashlib.sha1(f.read()).digest()
b32 = base64.b32encode(sha1) return compat.b32encode(sha1)
if sys.version_info[0] >= 3:
b32 = b32.decode()
return b32
def create_manifest_entry(path): def create_manifest_entry(path):

View file

@ -10,6 +10,7 @@ sections = [
known_first_party = "spack" known_first_party = "spack"
known_archspec = "archspec" known_archspec = "archspec"
known_llnl = "llnl" known_llnl = "llnl"
known_third_party = ["ruamel", "six"]
src_paths = "lib" src_paths = "lib"
honor_noqa = true honor_noqa = true