Repository: aws-cloudformation/cfn-lint

Issue:
Fix 'imp' Warning on Python 3
*cfn-lint version: (`cfn-lint --version`)* 0.26.2

*Description of issue.*

I see this warning on Python 3.7:

```
.../cfnlint/helpers.py:11: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
    import imp
```

On Python 3 you can use `importlib` to the same effect as the usage of `imp`.



Discussion:

Resolving patch:
diff --git a/src/cfnlint/helpers.py b/src/cfnlint/helpers.py
--- a/src/cfnlint/helpers.py
+++ b/src/cfnlint/helpers.py
@@ -8,13 +8,15 @@
 import fnmatch
 import json
 import os
-import imp
 import datetime
 import logging
 import re
 import inspect
 import gzip
 from io import BytesIO
+import six
+from cfnlint.decode.node import dict_node, list_node, str_node
+from cfnlint.data import CloudSpecs
 try:
     from urllib.request import urlopen
 except ImportError:
@@ -24,9 +26,10 @@
 except ImportError:
     # Try backported to PY<37 `importlib_resources`.
     import importlib_resources as pkg_resources
-import six
-from cfnlint.data import CloudSpecs
-from cfnlint.decode.node import dict_node, list_node, str_node
+if sys.version_info < (3,):
+    import imp
+else:
+    import importlib  # pylint: disable=ungrouped-imports
 
 LOGGER = logging.getLogger(__name__)
 
@@ -280,10 +283,48 @@ def create_rules(mod):
     return result
 
 
+if sys.version_info < (3,):
+    def import_filename(pluginname, root):
+        """ import_filename imports a module from a file"""
+        fh = None
+        try:
+            fh, filename, desc = imp.find_module(pluginname, [root])
+            mod = imp.load_module(pluginname, fh, filename, desc)
+            return mod
+        finally:
+            if fh:
+                fh.close()
+
+        return None
+
+else:
+    loader_details = (
+        importlib.machinery.SourceFileLoader,  # pylint: disable=no-member
+        importlib.machinery.SOURCE_SUFFIXES  # pylint: disable=no-member
+    )
+
+    def import_filename(pluginname, root):
+        """ import_filename imports a module from a file"""
+        mod_finder = importlib.machinery.FileFinder(  # pylint: disable=no-member
+            root, loader_details)
+
+        mod_spec = mod_finder.find_spec(pluginname)
+        if mod_spec is not None:
+            if sys.version_info < (3, 5):
+                # for python 2.7 disabling pylint checks
+                mod = mod_spec.loader.load_module()  # pylint: disable=no-member
+                return mod
+            # for python 2.7 disabling pylint checks
+            mod = importlib.util.module_from_spec(mod_spec)  # pylint: disable=no-member
+            mod_spec.loader.exec_module(mod)
+            return mod
+
+        return None
+
+
 def load_plugins(directory):
     """Load plugins"""
     result = []
-    fh = None
 
     def onerror(os_error):
         """Raise an error"""
@@ -291,14 +332,9 @@ def onerror(os_error):
 
     for root, _, filenames in os.walk(directory, onerror=onerror):
         for filename in fnmatch.filter(filenames, '[A-Za-z]*.py'):
-            pluginname = filename.replace('.py', '')
-            try:
-                fh, filename, desc = imp.find_module(pluginname, [root])
-                mod = imp.load_module(pluginname, fh, filename, desc)
+            mod = import_filename(filename.replace('.py', ''), root)
+            if mod is not None:
                 result.extend(create_rules(mod))
-            finally:
-                if fh:
-                    fh.close()
 
     return result
 


Test patch: