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/packages/checker.py b/cfg_checker/modules/packages/checker.py
index 92d9e1c..8f30f3c 100644
--- a/cfg_checker/modules/packages/checker.py
+++ b/cfg_checker/modules/packages/checker.py
@@ -8,7 +8,7 @@
 from cfg_checker.nodes import salt_master
 from cfg_checker.reports import reporter
 
-from versions import DebianVersion, PkgVersions, VersionCmpResult
+from .versions import DebianVersion, PkgVersions, VersionCmpResult
 
 
 class CloudPackageChecker(object):
@@ -78,6 +78,7 @@
             # sort packages
             _pn, _val = all_packages.popitem()
             _c = _val['desc']['section']
+            _rkeys = _val['results'].keys()
 
             if not full:
                 # Check if this packet has errors
@@ -125,9 +126,9 @@
                 _data['unlisted'].update({
                     _pn: _val
                 })
-                _eu += _val['results'].keys().count(const.VERSION_ERR)
-                _wu += _val['results'].keys().count(const.VERSION_WARN)
-                _du += _val['results'].keys().count(const.VERSION_DOWN)
+                _eu += sum(x == const.VERSION_ERR for x in _rkeys)
+                _wu += sum(x == const.VERSION_WARN for x in _rkeys)
+                _du += sum(x == const.VERSION_DOWN for x in _rkeys)
             # mirantis/critical
             # elif len(_c) > 0 and _c != 'System':
             elif _val['is_mirantis']:
@@ -135,25 +136,25 @@
                 _data['critical'].update({
                     _pn: _val
                 })
-                _ec += _val['results'].keys().count(const.VERSION_ERR)
-                _wc += _val['results'].keys().count(const.VERSION_WARN)
-                _dc += _val['results'].keys().count(const.VERSION_DOWN)
+                _ec += sum(x == const.VERSION_ERR for x in _rkeys)
+                _wc += sum(x == const.VERSION_WARN for x in _rkeys)
+                _dc += sum(x == const.VERSION_DOWN for x in _rkeys)
             # system
             elif _c == 'System':
                 _data['system'].update({
                     _pn: _val
                 })
-                _es += _val['results'].keys().count(const.VERSION_ERR)
-                _ws += _val['results'].keys().count(const.VERSION_WARN)
-                _ds += _val['results'].keys().count(const.VERSION_DOWN)
+                _es += sum(x == const.VERSION_ERR for x in _rkeys)
+                _ws += sum(x == const.VERSION_WARN for x in _rkeys)
+                _ds += sum(x == const.VERSION_DOWN for x in _rkeys)
             # rest
             else:
                 _data['other'].update({
                     _pn: _val
                 })
-                _eo += _val['results'].keys().count(const.VERSION_ERR)
-                _wo += _val['results'].keys().count(const.VERSION_WARN)
-                _do += _val['results'].keys().count(const.VERSION_DOWN)
+                _eo += sum(x == const.VERSION_ERR for x in _rkeys)
+                _wo += sum(x == const.VERSION_WARN for x in _rkeys)
+                _do += sum(x == const.VERSION_DOWN for x in _rkeys)
 
         _progress.end()
 
@@ -244,7 +245,7 @@
         _total_processed = 0
         # Collect packages from all of the nodes in flat dict
         _all_packages = {}
-        for node_name, node_value in salt_master.nodes.iteritems():
+        for node_name, node_value in salt_master.nodes.items():
             _uniq_len = len(_all_packages.keys())
             _progress_index += 1
             # progress updates shown before next node only
@@ -256,7 +257,7 @@
                     _total_processed
                 )
             )
-            for _name, _value in node_value['packages'].iteritems():
+            for _name, _value in node_value['packages'].items():
                 _total_processed += 1
                 # Parse versions from nodes
                 _ver_ins = DebianVersion(_value['installed'])
@@ -309,9 +310,9 @@
                     _vs = {}
                     _sections = {}
                     _apps = {}
-                    for s, apps in _r.iteritems():
-                        for a, versions in apps.iteritems():
-                            for v, repos in versions.iteritems():
+                    for s, apps in _r.items():
+                        for a, versions in apps.items():
+                            for v, repos in versions.items():
                                 for repo in repos:
                                     if v not in _vs:
                                         _vs[v] = []
@@ -324,11 +325,13 @@
                                     _apps[v].append(a)
                     # search for the newest version among filtered
                     _r_desc = []
-                    _vs_keys = _vs.keys()
-                    if _vs_keys:
-                        _newest = _newest = DebianVersion(_vs_keys.pop())
-                    else:
+                    _vs_keys = iter(_vs.keys())
+                    # get next version, if any
+                    try:
+                        _newest = DebianVersion(next(_vs_keys))
+                    except StopIteration:
                         _newest = DebianVersion('')
+                    # iterate others, if any
                     for v in _vs_keys:
                         _this = DebianVersion(v)
                         if _this > _newest: