Repository: SCons/scons

Issue:
deprecated import of Iterable
Another tracking/maintenance issue. From the python 3.7 Travis CI build:
```
/home/travis/build/SCons/scons/src/engine/SCons/Util.py:49: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import Iterable
```
From Python documentation:
https://docs.python.org/3/library/collections.html#module-collections

> Changed in version 3.3: Moved Collections Abstract Base Classes to the collections.abc module. For backwards compatibility, they continue to be visible in this module through Python 3.7. Subsequently, they will be removed entirely.

and
https://docs.python.org/3/library/collections.abc.html


Discussion:

Resolving patch:
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -107,6 +107,7 @@
 import subprocess
 import itertools
 import inspect
+from collections import OrderedDict
 
 import SCons.Debug
 from SCons.Debug import logInstanceCreation
@@ -1294,7 +1295,7 @@ def get_implicit_deps(self, target, source, env):
         return result
 
     def get_varlist(self, target, source, env, executor=None):
-        result = SCons.Util.OrderedDict()
+        result = OrderedDict()
         for act in self.list:
             for var in act.get_varlist(target, source, env, executor):
                 result[var] = True
diff --git a/src/engine/SCons/Tool/javac.py b/src/engine/SCons/Tool/javac.py
--- a/src/engine/SCons/Tool/javac.py
+++ b/src/engine/SCons/Tool/javac.py
@@ -34,6 +34,7 @@
 
 import os
 import os.path
+from collections import OrderedDict
 
 import SCons.Action
 import SCons.Builder
@@ -70,7 +71,7 @@ def emit_java_classes(target, source, env):
         if isinstance(entry, SCons.Node.FS.File):
             slist.append(entry)
         elif isinstance(entry, SCons.Node.FS.Dir):
-            result = SCons.Util.OrderedDict()
+            result = OrderedDict()
             dirnode = entry.rdir()
             def find_java_files(arg, dirpath, filenames):
                 java_files = sorted([n for n in filenames
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -37,21 +37,18 @@
 PY3 = sys.version_info[0] == 3
 
 try:
+    from collections import UserDict, UserList, UserString
+except ImportError:
     from UserDict import UserDict
-except ImportError as e:
-    from collections import UserDict
-
-try:
     from UserList import UserList
-except ImportError as e:
-    from collections import UserList
-
-from collections import Iterable
+    from UserString import UserString
 
 try:
-    from UserString import UserString
-except ImportError as e:
-    from collections import UserString
+    from collections.abc import Iterable
+except ImportError:
+    from collections import Iterable
+
+from collections import OrderedDict
 
 # Don't "from types import ..." these because we need to get at the
 # types module later to look for UnicodeType.
@@ -63,7 +60,7 @@
 FunctionType    = types.FunctionType
 
 try:
-    unicode
+    _ = type(unicode)
 except NameError:
     UnicodeType = str
 else:
@@ -1032,59 +1029,6 @@ def __radd__(self, other):
     def __str__(self):
         return ' '.join(self.data)
 
-# A dictionary that preserves the order in which items are added.
-# Submitted by David Benjamin to ActiveState's Python Cookbook web site:
-#     http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
-# Including fixes/enhancements from the follow-on discussions.
-class OrderedDict(UserDict):
-    def __init__(self, dict = None):
-        self._keys = []
-        UserDict.__init__(self, dict)
-
-    def __delitem__(self, key):
-        UserDict.__delitem__(self, key)
-        self._keys.remove(key)
-
-    def __setitem__(self, key, item):
-        UserDict.__setitem__(self, key, item)
-        if key not in self._keys: self._keys.append(key)
-
-    def clear(self):
-        UserDict.clear(self)
-        self._keys = []
-
-    def copy(self):
-        dict = OrderedDict()
-        dict.update(self)
-        return dict
-
-    def items(self):
-        return list(zip(self._keys, list(self.values())))
-
-    def keys(self):
-        return self._keys[:]
-
-    def popitem(self):
-        try:
-            key = self._keys[-1]
-        except IndexError:
-            raise KeyError('dictionary is empty')
-
-        val = self[key]
-        del self[key]
-
-        return (key, val)
-
-    def setdefault(self, key, failobj = None):
-        UserDict.setdefault(self, key, failobj)
-        if key not in self._keys: self._keys.append(key)
-
-    def update(self, dict):
-        for (key, val) in dict.items():
-            self.__setitem__(key, val)
-
-    def values(self):
-        return list(map(self.get, self._keys))
 
 class Selector(OrderedDict):
     """A callable ordered dictionary that maps file suffixes to


Test patch: