From 40a40e0265d6704a7836aeb30a776d66da8f7fe6 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 1 Feb 2021 11:30:25 -0600 Subject: [PATCH] Python 3.10 support: collections.abc (#20441) --- lib/spack/external/_pytest/assertion/util.py | 7 +++++-- lib/spack/external/_pytest/main.py | 7 +++++-- lib/spack/external/_pytest/python_api.py | 5 ++++- lib/spack/external/jinja2/runtime.py | 8 ++++++-- lib/spack/external/jinja2/sandbox.py | 12 ++++++++++-- lib/spack/external/jinja2/tests.py | 7 ++++++- lib/spack/external/jinja2/utils.py | 8 ++++++-- lib/spack/external/markupsafe/__init__.py | 7 ++++++- lib/spack/external/ruamel/yaml/comments.py | 7 ++++++- lib/spack/external/ruamel/yaml/compat.py | 7 +++++-- lib/spack/external/ruamel/yaml/constructor.py | 19 ++++++++++++------- lib/spack/llnl/util/filesystem.py | 16 +++++++++++----- lib/spack/llnl/util/lang.py | 11 ++++++++--- lib/spack/spack/directives.py | 14 +++++++++++--- lib/spack/spack/solver/asp.py | 8 +++++++- lib/spack/spack/spec.py | 9 ++++++++- lib/spack/spack/test/spec_yaml.py | 9 +++++++-- lib/spack/spack/util/pattern.py | 10 ++++++++-- lib/spack/spack/util/spack_yaml.py | 11 +++++++++-- 19 files changed, 140 insertions(+), 42 deletions(-) diff --git a/lib/spack/external/_pytest/assertion/util.py b/lib/spack/external/_pytest/assertion/util.py index 9f00929073..c09eff06b0 100644 --- a/lib/spack/external/_pytest/assertion/util.py +++ b/lib/spack/external/_pytest/assertion/util.py @@ -5,9 +5,12 @@ import _pytest._code import py try: - from collections import Sequence + from collections.abc import Sequence except ImportError: - Sequence = list + try: + from collections import Sequence + except ImportError: + Sequence = list u = py.builtin._totext diff --git a/lib/spack/external/_pytest/main.py b/lib/spack/external/_pytest/main.py index eacae8dab1..98aa28eb34 100644 --- a/lib/spack/external/_pytest/main.py +++ b/lib/spack/external/_pytest/main.py @@ -10,9 +10,12 @@ import _pytest._code import py try: - from collections import MutableMapping as MappingMixin + from collections.abc import MutableMapping as MappingMixin except ImportError: - from UserDict import DictMixin as MappingMixin + try: + from collections import MutableMapping as MappingMixin + except ImportError: + from UserDict import DictMixin as MappingMixin from _pytest.config import directory_arg, UsageError, hookimpl from _pytest.outcomes import exit diff --git a/lib/spack/external/_pytest/python_api.py b/lib/spack/external/_pytest/python_api.py index cfc01193b0..a931b4d2c7 100644 --- a/lib/spack/external/_pytest/python_api.py +++ b/lib/spack/external/_pytest/python_api.py @@ -398,7 +398,10 @@ def approx(expected, rel=None, abs=None, nan_ok=False): __ https://docs.python.org/3/reference/datamodel.html#object.__ge__ """ - from collections import Mapping, Sequence + if sys.version_info >= (3, 3): + from collections.abc import Mapping, Sequence + else: + from collections import Mapping, Sequence from _pytest.compat import STRING_TYPES as String # Delegate the comparison to a class that knows how to deal with the type diff --git a/lib/spack/external/jinja2/runtime.py b/lib/spack/external/jinja2/runtime.py index f9d7a6806c..52dfeaebd6 100644 --- a/lib/spack/external/jinja2/runtime.py +++ b/lib/spack/external/jinja2/runtime.py @@ -315,10 +315,14 @@ def __repr__(self): # register the context as mapping if possible try: - from collections import Mapping + from collections.abc import Mapping Mapping.register(Context) except ImportError: - pass + try: + from collections import Mapping + Mapping.register(Context) + except ImportError: + pass class BlockReference(object): diff --git a/lib/spack/external/jinja2/sandbox.py b/lib/spack/external/jinja2/sandbox.py index 93fb9d45f3..b9e5ec495a 100644 --- a/lib/spack/external/jinja2/sandbox.py +++ b/lib/spack/external/jinja2/sandbox.py @@ -14,7 +14,7 @@ """ import types import operator -from collections import Mapping +import sys from jinja2.environment import Environment from jinja2.exceptions import SecurityError from jinja2._compat import string_types, PY2 @@ -23,6 +23,11 @@ from markupsafe import EscapeFormatter from string import Formatter +if sys.version_info >= (3, 3): + from collections.abc import Mapping +else: + from collections import Mapping + #: maximum number of items a range may produce MAX_RANGE = 100000 @@ -79,7 +84,10 @@ pass #: register Python 2.6 abstract base classes -from collections import MutableSet, MutableMapping, MutableSequence +if sys.version_info >= (3, 3): + from collections.abc import MutableSet, MutableMapping, MutableSequence +else: + from collections import MutableSet, MutableMapping, MutableSequence _mutable_set_types += (MutableSet,) _mutable_mapping_types += (MutableMapping,) _mutable_sequence_types += (MutableSequence,) diff --git a/lib/spack/external/jinja2/tests.py b/lib/spack/external/jinja2/tests.py index 0adc3d4dbc..d5d6b5b33f 100644 --- a/lib/spack/external/jinja2/tests.py +++ b/lib/spack/external/jinja2/tests.py @@ -10,11 +10,16 @@ """ import operator import re -from collections import Mapping +import sys from jinja2.runtime import Undefined from jinja2._compat import text_type, string_types, integer_types import decimal +if sys.version_info >= (3, 3): + from collections.abc import Mapping +else: + from collections import Mapping + number_re = re.compile(r'^-?\d+(\.\d+)?$') regex_type = type(number_re) diff --git a/lib/spack/external/jinja2/utils.py b/lib/spack/external/jinja2/utils.py index 502a311c08..cff4e783a8 100644 --- a/lib/spack/external/jinja2/utils.py +++ b/lib/spack/external/jinja2/utils.py @@ -482,10 +482,14 @@ def __reversed__(self): # register the LRU cache as mutable mapping if possible try: - from collections import MutableMapping + from collections.abc import MutableMapping MutableMapping.register(LRUCache) except ImportError: - pass + try: + from collections import MutableMapping + MutableMapping.register(LRUCache) + except ImportError: + pass def select_autoescape(enabled_extensions=('html', 'htm', 'xml'), diff --git a/lib/spack/external/markupsafe/__init__.py b/lib/spack/external/markupsafe/__init__.py index 68dc85f612..506326f450 100644 --- a/lib/spack/external/markupsafe/__init__.py +++ b/lib/spack/external/markupsafe/__init__.py @@ -10,10 +10,15 @@ """ import re import string -from collections import Mapping +import sys from markupsafe._compat import text_type, string_types, int_types, \ unichr, iteritems, PY2 +if sys.version_info >= (3, 3): + from collections.abc import Mapping +else: + from collections import Mapping + __version__ = "1.0" __all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent'] diff --git a/lib/spack/external/ruamel/yaml/comments.py b/lib/spack/external/ruamel/yaml/comments.py index b8a5010ad8..a517072087 100644 --- a/lib/spack/external/ruamel/yaml/comments.py +++ b/lib/spack/external/ruamel/yaml/comments.py @@ -9,7 +9,12 @@ a separate base """ -from collections import MutableSet +import sys + +if sys.version_info >= (3, 3): + from collections.abc import MutableSet +else: + from collections import MutableSet __all__ = ["CommentedSeq", "CommentedMap", "CommentedOrderedMap", "CommentedSet", 'comment_attrib', 'merge_attrib'] diff --git a/lib/spack/external/ruamel/yaml/compat.py b/lib/spack/external/ruamel/yaml/compat.py index a1778bef28..28a981dc43 100644 --- a/lib/spack/external/ruamel/yaml/compat.py +++ b/lib/spack/external/ruamel/yaml/compat.py @@ -12,9 +12,12 @@ from ruamel.ordereddict import ordereddict except: try: - from collections import OrderedDict + from collections.abc import OrderedDict except ImportError: - from ordereddict import OrderedDict + try: + from collections import OrderedDict + except ImportError: + from ordereddict import OrderedDict # to get the right name import ... as ordereddict doesn't do that class ordereddict(OrderedDict): diff --git a/lib/spack/external/ruamel/yaml/constructor.py b/lib/spack/external/ruamel/yaml/constructor.py index f809df4bf9..69ad0a74ac 100644 --- a/lib/spack/external/ruamel/yaml/constructor.py +++ b/lib/spack/external/ruamel/yaml/constructor.py @@ -3,7 +3,6 @@ from __future__ import absolute_import from __future__ import print_function -import collections import datetime import base64 import binascii @@ -26,6 +25,12 @@ from ruamel.yaml.scalarstring import * # NOQA +if sys.version_info >= (3, 3): + from collections.abc import Hashable +else: + from collections import Hashable + + __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor', 'ConstructorError', 'RoundTripConstructor'] @@ -163,7 +168,7 @@ def construct_mapping(self, node, deep=False): # keys can be list -> deep key = self.construct_object(key_node, deep=True) # lists are not hashable, but tuples are - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): if isinstance(key, list): key = tuple(key) if PY2: @@ -175,7 +180,7 @@ def construct_mapping(self, node, deep=False): "found unacceptable key (%s)" % exc, key_node.start_mark) else: - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): raise ConstructorError( "while constructing a mapping", node.start_mark, "found unhashable key", key_node.start_mark) @@ -959,7 +964,7 @@ def construct_mapping(self, node, maptyp, deep=False): # keys can be list -> deep key = self.construct_object(key_node, deep=True) # lists are not hashable, but tuples are - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): if isinstance(key, list): key = tuple(key) if PY2: @@ -971,7 +976,7 @@ def construct_mapping(self, node, maptyp, deep=False): "found unacceptable key (%s)" % exc, key_node.start_mark) else: - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): raise ConstructorError( "while constructing a mapping", node.start_mark, "found unhashable key", key_node.start_mark) @@ -1003,7 +1008,7 @@ def construct_setting(self, node, typ, deep=False): # keys can be list -> deep key = self.construct_object(key_node, deep=True) # lists are not hashable, but tuples are - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): if isinstance(key, list): key = tuple(key) if PY2: @@ -1015,7 +1020,7 @@ def construct_setting(self, node, typ, deep=False): "found unacceptable key (%s)" % exc, key_node.start_mark) else: - if not isinstance(key, collections.Hashable): + if not isinstance(key, Hashable): raise ConstructorError( "while constructing a mapping", node.start_mark, "found unhashable key", key_node.start_mark) diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index a116e2bed2..c7ecf09af2 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -23,6 +23,12 @@ 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', @@ -1106,7 +1112,7 @@ def find(root, files, recursive=True): Parameters: root (str): The root directory to start searching from - files (str or collections.Sequence): Library name(s) to search for + files (str or Sequence): Library name(s) to search for recurse (bool, optional): if False search only root folder, if True descends top-down from the root. Defaults to True. @@ -1169,7 +1175,7 @@ def _find_non_recursive(root, search_files): # Utilities for libraries and headers -class FileList(collections.Sequence): +class FileList(Sequence): """Sequence of absolute paths to files. Provides a few convenience methods to manipulate file paths. @@ -1412,7 +1418,7 @@ def find_headers(headers, root, recursive=False): """ if isinstance(headers, six.string_types): headers = [headers] - elif not isinstance(headers, collections.Sequence): + elif not isinstance(headers, Sequence): message = '{0} expects a string or sequence of strings as the ' message += 'first argument [got {1} instead]' message = message.format(find_headers.__name__, type(headers)) @@ -1567,7 +1573,7 @@ def find_system_libraries(libraries, shared=True): """ if isinstance(libraries, six.string_types): libraries = [libraries] - elif not isinstance(libraries, collections.Sequence): + elif not isinstance(libraries, Sequence): message = '{0} expects a string or sequence of strings as the ' message += 'first argument [got {1} instead]' message = message.format(find_system_libraries.__name__, @@ -1621,7 +1627,7 @@ def find_libraries(libraries, root, shared=True, recursive=False): """ if isinstance(libraries, six.string_types): libraries = [libraries] - elif not isinstance(libraries, collections.Sequence): + elif not isinstance(libraries, Sequence): message = '{0} expects a string or sequence of strings as the ' message += 'first argument [got {1} instead]' message = message.format(find_libraries.__name__, type(libraries)) diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py index 20bf613a30..17c1fe8427 100644 --- a/lib/spack/llnl/util/lang.py +++ b/lib/spack/llnl/util/lang.py @@ -9,13 +9,18 @@ import os import re import functools -import collections import inspect from datetime import datetime, timedelta from six import string_types import sys +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_modules = [r'^\.#', '~$'] @@ -189,7 +194,7 @@ def memoized(func): @functools.wraps(func) def _memoized_function(*args): - if not isinstance(args, collections.Hashable): + if not isinstance(args, Hashable): # Not hashable, so just call the function. return func(*args) @@ -264,7 +269,7 @@ def setter(name, value): @key_ordering -class HashableMap(collections.MutableMapping): +class HashableMap(MutableMapping): """This is a hashable, comparable dictionary. Hash is performed on a tuple of the values in the dictionary.""" diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index 3ed8c5c327..360448b851 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -28,10 +28,11 @@ class OpenMpi(Package): """ -import collections import functools import os.path import re +import sys + from six import string_types from typing import Set, List # novm @@ -48,6 +49,13 @@ class OpenMpi(Package): 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__ = [] #: These are variant names used by Spack internally; packages can't use them @@ -203,7 +211,7 @@ class Foo(Package): if isinstance(dicts, string_types): dicts = (dicts, ) - if not isinstance(dicts, collections.Sequence): + if not isinstance(dicts, Sequence): message = "dicts arg must be list, tuple, or string. Found {0}" raise TypeError(message.format(type(dicts))) # Add the dictionary names if not already there @@ -244,7 +252,7 @@ def remove_directives(arg): # ...so if it is not a sequence make it so values = result - if not isinstance(values, collections.Sequence): + if not isinstance(values, Sequence): values = (values, ) DirectiveMeta._directives_to_be_executed.extend(values) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 883234c7d3..25b2181708 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -40,6 +40,12 @@ import spack.version +if sys.version_info >= (3, 3): + from collections.abc import Sequence # novm +else: + from collections import Sequence + + class Timer(object): """Simple timer for timing phases of a solve""" def __init__(self): @@ -64,7 +70,7 @@ def write(self, out=sys.stdout): def issequence(obj): if isinstance(obj, string_types): return False - return isinstance(obj, (collections.Sequence, types.GeneratorType)) + return isinstance(obj, (Sequence, types.GeneratorType)) def listify(args): diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 670c491713..06767d6c7d 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -116,6 +116,13 @@ 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__ = [ 'Spec', 'parse', @@ -2120,7 +2127,7 @@ def validate_detection(self): # which likely means the spec was created with Spec.from_detection msg = ('cannot validate "{0}" since it was not created ' 'using Spec.from_detection'.format(self)) - assert isinstance(self.extra_attributes, collections.Mapping), msg + assert isinstance(self.extra_attributes, Mapping), msg # Validate the spec calling a package specific method validate_fn = getattr( diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py index 73b132eac3..c143ea8141 100644 --- a/lib/spack/spack/test/spec_yaml.py +++ b/lib/spack/spack/test/spec_yaml.py @@ -11,8 +11,7 @@ import ast import inspect import os - -from collections import Iterable, Mapping +import sys import pytest @@ -29,6 +28,12 @@ from spack.util.mock_package import MockPackageMultiRepo +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() spec_from_yaml = Spec.from_yaml(yaml_text) diff --git a/lib/spack/spack/util/pattern.py b/lib/spack/spack/util/pattern.py index 58b657b3a5..fc4b324b17 100644 --- a/lib/spack/spack/util/pattern.py +++ b/lib/spack/spack/util/pattern.py @@ -4,8 +4,14 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import inspect -import collections import functools +import sys + + +if sys.version_info >= (3, 3): + from collections.abc import MutableSequence # novm +else: + from collections import MutableSequence class Delegate(object): @@ -52,7 +58,7 @@ def composite(interface=None, method_list=None, container=list): # exception if it doesn't. The patched class returned by the decorator will # inherit from the container class to expose the interface needed to manage # objects composition - if not issubclass(container, collections.MutableSequence): + if not issubclass(container, MutableSequence): raise TypeError("Container must fulfill the MutableSequence contract") # Check if at least one of the 'interface' or the 'method_list' arguments diff --git a/lib/spack/spack/util/spack_yaml.py b/lib/spack/spack/util/spack_yaml.py index d0362cc808..e27c48860b 100644 --- a/lib/spack/spack/util/spack_yaml.py +++ b/lib/spack/spack/util/spack_yaml.py @@ -13,7 +13,7 @@ """ import ctypes -import collections +import sys from typing import List # novm from ordereddict_backport import OrderedDict @@ -26,6 +26,13 @@ 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'] @@ -344,7 +351,7 @@ def sorted_dict(dict_like): """ result = syaml_dict(sorted(dict_like.items())) for key, value in result.items(): - if isinstance(value, collections.Mapping): + if isinstance(value, Mapping): result[key] = sorted_dict(value) return result