Migrating to Python v3

 - support for Python v3.8.x
 - support for Python v3.5.x
 - new tag, 2019.2.8
 - updates class generation and iterators
 - unittests updated with coverage >75%
 - new coverage routines
 - unittests profiling
 - full fake data for unittests
 - unittest testrun is ~1.5 seconds long

Bugfixes
 - 34834, proper use of 'sudo' option
 - multiple proper iterator use
 - 37919, show warning when installed and candidate versions
   are newer comparing to release version

Change-Id: Idd6b889f7ce94ae0c832e2f0a0346e4fdc3264a3
Related-PROD: PROD-34834 PROD-34664 PROD-34919
diff --git a/cfg_checker/modules/reclass/comparer.py b/cfg_checker/modules/reclass/comparer.py
index 8ef8894..47e4baf 100644
--- a/cfg_checker/modules/reclass/comparer.py
+++ b/cfg_checker/modules/reclass/comparer.py
@@ -5,8 +5,9 @@
 import itertools
 import os
 
+from functools import reduce
+
 from cfg_checker.common import logger, logger_cli
-from cfg_checker.reports import reporter
 
 import yaml
 
@@ -197,13 +198,13 @@
                     # use ifilterfalse to compare lists of dicts
                     try:
                         _removed = list(
-                            itertools.ifilterfalse(
+                            itertools.filterfalse(
                                 lambda x: x in dict2[k],
                                 dict1[k]
                             )
                         )
                         _added = list(
-                            itertools.ifilterfalse(
+                            itertools.filterfalse(
                                 lambda x: x in dict1[k],
                                 dict2[k]
                             )
@@ -271,9 +272,10 @@
                     except TypeError as e:
                         logger.warning(
                             "One of the values is not a dict: "
-                            "{}, {}".format(
+                            "{}, {}; {}".format(
                                 str(dict1),
-                                str(dict2)
+                                str(dict2),
+                                e.message
                             ))
                         match = False
                     if not match:
@@ -331,38 +333,3 @@
 
         _diff_report["diff_names"] = [self.model_name_1, self.model_name_2]
         return _diff_report
-
-    def compare_models(self):
-        # Do actual compare using model names from the class
-        self.load_model_tree(
-            self.model_name_1,
-            self.model_path_1
-        )
-        self.load_model_tree(
-            self.model_name_2,
-            self.model_path_2
-        )
-        # Models should have similar structure to be compared
-        # classes/system
-        # classes/cluster
-        # nodes
-
-        diffs = self.generate_model_report_tree()
-
-        report_file = \
-            self.model_name_1 + "-vs-" + self.model_name_2 + ".html"
-        # HTML report class is post-callable
-        report = reporter.ReportToFile(
-            reporter.HTMLModelCompare(),
-            report_file
-        )
-        logger_cli.info("...generating report to {}".format(report_file))
-        # report will have tabs for each of the comparable entities in diffs
-        report({
-            "nodes": {},
-            "rc_diffs": diffs,
-        })
-        # with open("./gen_tree.json", "w+") as _out:
-        #     _out.write(json.dumps(mComparer.generate_model_report_tree))
-
-        return