File 0001-Python-3-compatibility-tweaks.patch of Package rpmlint

From 54235cd38e08c8a93de74e7884eea746ae002b2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Skytt=C3=A4?= <ville.skytta@iki.fi>
Date: Thu, 12 Sep 2013 21:27:55 +0300
Subject: [PATCH 1/3] Python 3 compatibility tweaks.

(cherry picked from commit cc6369dbafb27568802b8f0a60518a69d6738e3b)
---
 AbstractCheck.py |  4 +++-
 Filter.py        |  2 +-
 Pkg.py           | 37 ++++++++++++++++++++-----------------
 PostCheck.py     |  3 +--
 rpmdiff          |  8 ++++----
 rpmlint          | 40 +++++++++++++++++++++++-----------------
 6 files changed, 52 insertions(+), 42 deletions(-)

Index: rpmlint-1.5/AbstractCheck.py
===================================================================
--- rpmlint-1.5.orig/AbstractCheck.py
+++ rpmlint-1.5/AbstractCheck.py
@@ -9,7 +9,11 @@
 
 import re
 import socket
-import urllib2
+import sys
+try:
+    import urllib2
+except:
+    import urllib.request as urllib2
 
 from Filter import addDetails, printInfo, printWarning
 import Config
@@ -61,7 +65,8 @@ class AbstractCheck:
             opener.addheaders = [('User-Agent',
                                   'rpmlint/%s' % Config.__version__)]
             res = opener.open(_HeadRequest(url))
-        except Exception, e:
+        except Exception:
+            e = sys.exc_info()[1]
             errstr = str(e) or repr(e) or type(e)
             printWarning(pkg, 'invalid-url', '%s:' % tag, url, errstr)
         info = None
Index: rpmlint-1.5/Filter.py
===================================================================
--- rpmlint-1.5.orig/Filter.py
+++ rpmlint-1.5/Filter.py
@@ -123,7 +123,7 @@ def printAllReasons():
 _details = {}
 
 def addDetails(*details):
-    for idx in range(len(details)/2):
+    for idx in range(int(len(details)/2)):
         if not details[idx*2] in _details:
             _details[details[idx*2]] = details[idx*2+1]
 
Index: rpmlint-1.5/Pkg.py
===================================================================
--- rpmlint-1.5.orig/Pkg.py
+++ rpmlint-1.5/Pkg.py
@@ -8,14 +8,15 @@
 #                 the rpm file or by accessing the files contained inside.
 #############################################################################
 
-import commands
 import os
 import re
 import subprocess
 import sys
 import tempfile
-import types
-import urlparse
+try:
+    from urlparse import urljoin
+except:
+    from urllib.parse import urljoin
 
 try:
     import magic
@@ -73,18 +74,18 @@ def substitute_shell_vars(val, script):
     else:
         return val
 
-def getstatusoutput(cmd, stdoutonly = False):
+def getstatusoutput(cmd, stdoutonly = False, shell = False):
     '''A version of commands.getstatusoutput() which can take cmd as a
        sequence, thus making it potentially more secure.'''
     if stdoutonly:
-        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+        proc = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE, close_fds=True)
     else:
-        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+        proc = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT, close_fds=True)
     proc.stdin.close()
-    text = proc.stdout.read()
+    text = proc.stdout.read().decode()
     sts = proc.wait()
     if sts is None:
         sts = 0
@@ -192,7 +193,9 @@ def get_default_valid_rpmgroups(filename
     return groups
 
 # from yum 3.2.27, rpmUtils.miscutils, with rpmlint modifications
-def compareEVR((e1, v1, r1), (e2, v2, r2)):
+def compareEVR(evr1, evr2):
+    (e1, v1, r1) = evr1
+    (e2, v2, r2) = evr2
     # return 1: a is newer than b
     # 0: a and b are the same version
     # -1: b is newer than a
@@ -441,13 +444,13 @@ class Pkg:
                 os.close(fd)
             self.is_source = not self.header[rpm.RPMTAG_SOURCERPM]
 
-        self.name = self.header[rpm.RPMTAG_NAME]
+        self.name = self.header[rpm.RPMTAG_NAME].decode()
         if self.isNoSource():
             self.arch = 'nosrc'
         elif self.isSource():
             self.arch = 'src'
         else:
-            self.arch = self.header[rpm.RPMTAG_ARCH]
+            self.arch = self.header.format("%{ARCH}")
 
     # Return true if the package is a source package
     def isSource(self):
@@ -488,7 +491,7 @@ class Pkg:
             command_str = \
                 'rpm2cpio "%s" | (cd "%s"; cpio -id); chmod -R +rX "%s"' % \
                 (self.filename, self.dirname, self.dirname)
-            cmd = commands.getstatusoutput(command_str)
+            cmd = getstatusoutput(command_str, shell=True)
             self.extracted = True
             return cmd
 
@@ -507,14 +510,16 @@ class Pkg:
         in_file = None
         try:
             try:
-                in_file = open(self.dirName() + '/' + filename)
+                in_file = open(os.path.join(
+                    self.dirName() or '/', filename.lstrip('/')))
                 for line in in_file:
                     lineno += 1
                     if regex.search(line):
                         ret.append(str(lineno))
                         break
-            except Exception, e:
-                Filter.printWarning(self, 'read-error', filename, e)
+            except Exception:
+                Filter.printWarning(self, 'read-error', filename,
+                                    sys.exc_info()[1])
         finally:
             if in_file:
                 in_file.close()
@@ -525,7 +530,7 @@ class Pkg:
         # LANGUAGE trumps other env vars per GNU gettext docs, see also #166
         orig = os.environ.get('LANGUAGE')
         os.environ['LANGUAGE'] = lang
-        ret = self[tag]
+        ret = self[tag].decode()
         if orig is not None:
             os.environ['LANGUAGE'] = orig
         return ret
@@ -590,17 +595,17 @@ class Pkg:
         modes = self.header[rpm.RPMTAG_FILEMODES]
         users = self.header[rpm.RPMTAG_FILEUSERNAME]
         groups = self.header[rpm.RPMTAG_FILEGROUPNAME]
-        links = self.header[rpm.RPMTAG_FILELINKTOS]
+        links = [x.decode() for x in self.header[rpm.RPMTAG_FILELINKTOS]]
         sizes = self.header[rpm.RPMTAG_FILESIZES]
         md5s = self.header[rpm.RPMTAG_FILEMD5S]
         mtimes = self.header[rpm.RPMTAG_FILEMTIMES]
         rdevs = self.header[rpm.RPMTAG_FILERDEVS]
         langs = self.header[rpm.RPMTAG_FILELANGS]
         inodes = self.header[rpm.RPMTAG_FILEINODES]
-        requires = self.header[rpm.RPMTAG_FILEREQUIRE]
-        provides = self.header[rpm.RPMTAG_FILEPROVIDE]
-        files = self.header[rpm.RPMTAG_FILENAMES]
-        magics = self.header[rpm.RPMTAG_FILECLASS]
+        requires = [x.decode() for x in self.header[rpm.RPMTAG_FILEREQUIRE]]
+        provides = [x.decode() for x in self.header[rpm.RPMTAG_FILEPROVIDE]]
+        files = [x.decode() for x in self.header[rpm.RPMTAG_FILENAMES]]
+        magics = [x.decode() for x in self.header[rpm.RPMTAG_FILECLASS]]
         try: # rpm >= 4.7.0
             filecaps = self.header[rpm.RPMTAG_FILECAPS]
         except:
@@ -608,16 +613,14 @@ class Pkg:
 
         # rpm-python < 4.6 does not return a list for this (or FILEDEVICES,
         # FWIW) for packages containing exactly one file
-        if not isinstance(inodes, types.ListType):
+        if not isinstance(inodes, list):
             inodes = [inodes]
 
         if files:
             for idx in range(0, len(files)):
                 pkgfile = PkgFile(files[idx])
-                # Do not use os.path.join here, pkgfile.name can start with a
-                # / which would result in self.dirName being ignored
-                pkgfile.path = os.path.normpath(
-                    self.dirName() + '/' + pkgfile.name)
+                pkgfile.path = os.path.normpath(os.path.join(
+                    self.dirName() or '/', pkgfile.name.lstrip('/')))
                 pkgfile.flags = flags[idx]
                 pkgfile.mode = modes[idx]
                 pkgfile.user = users[idx]
@@ -652,7 +655,7 @@ class Pkg:
            PkgFile if it is found in this package, None if not."""
         result = pkgfile
         while result and result.linkto:
-            linkpath = urlparse.urljoin(result.name, result.linkto)
+            linkpath = urljoin(result.name, result.linkto)
             linkpath = safe_normpath(linkpath)
             result = self.files().get(linkpath)
         return result
@@ -713,12 +716,12 @@ class Pkg:
 
         if versions:
             for loop in range(len(versions)):
-                evr = stringToVersion(versions[loop])
+                name = names[loop].decode()
+                evr = stringToVersion(versions[loop].decode())
                 if prereq is not None and flags[loop] & PREREQ_FLAG:
-                    prereq.append((names[loop], flags[loop] & (~PREREQ_FLAG),
-                                   evr))
+                    prereq.append((name, flags[loop] & (~PREREQ_FLAG), evr))
                 else:
-                    list.append((names[loop], flags[loop], evr))
+                    list.append((name, flags[loop], evr))
 
     def _gatherDepInfo(self):
         if self._requires is None:
Index: rpmlint-1.5/PostCheck.py
===================================================================
--- rpmlint-1.5.orig/PostCheck.py
+++ rpmlint-1.5/PostCheck.py
@@ -10,7 +10,6 @@
 
 import os
 import re
-import types
 
 import rpm
 
@@ -107,7 +106,7 @@ class PostCheck(AbstractCheck.AbstractCh
         for tag in script_tags:
             script = pkg[tag[0]]
 
-            if not isinstance(script, types.ListType):
+            if not isinstance(script, list):
                 prog = pkg.scriptprog(tag[1])
                 if prog:
                     prog = prog.split()[0]
Index: rpmlint-1.5/rpmdiff
===================================================================
--- rpmlint-1.5.orig/rpmdiff
+++ rpmlint-1.5/rpmdiff
@@ -82,8 +82,8 @@ class Rpmdiff:
         try:
             old = self.__load_pkg(old).header
             new = self.__load_pkg(new).header
-        except KeyError, e:
-            Pkg.warn(str(e))
+        except KeyError:
+            Pkg.warn(str(sys.exc_info()[1]))
             sys.exit(2)
 
         # Compare single tags
@@ -107,8 +107,8 @@ class Rpmdiff:
 
         old_files_dict = self.__fileIteratorToDict(old.fiFromHeader())
         new_files_dict = self.__fileIteratorToDict(new.fiFromHeader())
-        files = list(set(itertools.chain(old_files_dict.iterkeys(),
-                                         new_files_dict.iterkeys())))
+        files = list(set(itertools.chain(iter(old_files_dict),
+                                         iter(new_files_dict))))
         files.sort()
 
         for f in files:
@@ -205,16 +205,20 @@ class Rpmdiff:
         if not isinstance(newflags, list): newflags = [ newflags ]
 
         o = zip(old[name], oldflags, old[name[:-1]+'VERSION'])
+        if not isinstance(o, list):
+            o = list(o)
         n = zip(new[name], newflags, new[name[:-1]+'VERSION'])
+        if not isinstance(n, list):
+            n = list(n)
 
         # filter self provides, TODO: self %name(%_isa) as well
         if name == 'PROVIDES':
             oldE = old['epoch'] is not None and str(old['epoch'])+":" or ""
-            oldNV = (old['name'], rpm.RPMSENSE_EQUAL,
-                     "%s%s-%s" % (oldE, old['version'], old['release']))
+            oldV = "%s%s" % (oldE, old.format("%{VERSION}-%{RELEASE}"))
+            oldNV = (old['name'], rpm.RPMSENSE_EQUAL, oldV.encode())
             newE = new['epoch'] is not None and str(new['epoch'])+":" or ""
-            newNV = (new['name'], rpm.RPMSENSE_EQUAL,
-                     "%s%s-%s" % (newE, new['version'], new['release']))
+            newV = "%s%s" % (newE, new.format("%{VERSION}-%{RELEASE}"))
+            newNV = (new['name'], rpm.RPMSENSE_EQUAL, newV.encode())
             o = [entry for entry in o if entry != oldNV]
             n = [entry for entry in n if entry != newNV]
 
@@ -224,16 +228,16 @@ class Rpmdiff:
                 if namestr == 'REQUIRES':
                     namestr = self.req2str(oldentry[1])
                 self.__add(self.DEPFORMAT,
-                           (self.REMOVED, namestr, oldentry[0],
-                            self.sense2str(oldentry[1]), oldentry[2]))
+                           (self.REMOVED, namestr, oldentry[0].decode(),
+                            self.sense2str(oldentry[1]), oldentry[2].decode()))
         for newentry in n:
             if not newentry in o:
                 namestr = name
                 if namestr == 'REQUIRES':
                     namestr = self.req2str(newentry[1])
                 self.__add(self.DEPFORMAT,
-                           (self.ADDED, namestr, newentry[0],
-                            self.sense2str(newentry[1]), newentry[2]))
+                           (self.ADDED, namestr, newentry[0].decode(),
+                            self.sense2str(newentry[1]), newentry[2].decode()))
 
     def __fileIteratorToDict(self, fi):
         result = {}
@@ -258,8 +262,8 @@ def main():
     try:
         opts, args = getopt.getopt(sys.argv[1:],
                                    "hti:", ["help", "ignore-times", "ignore="])
-    except getopt.GetoptError, e:
-        Pkg.warn("Error: %s" % e)
+    except getopt.GetoptError:
+        Pkg.warn("Error: %s" % sys.exc_info()[1])
         _usage()
 
     for option, argument in opts:
Index: rpmlint-1.5/rpmlint
===================================================================
--- rpmlint-1.5.orig/rpmlint
+++ rpmlint-1.5/rpmlint
@@ -157,10 +157,11 @@ def main():
                 Pkg.warn(
                     '(none): E: interrupted, exiting while reading %s' % arg)
                 sys.exit(2)
-            except Exception, e:
+            except Exception:
                 if isfile:
                     arg = os.path.abspath(arg)
-                Pkg.warn('(none): E: error while reading %s: %s' % (arg, e))
+                Pkg.warn('(none): E: error while reading %s: %s' %
+                         (arg, sys.exc_info()[1]))
                 pkgs = []
                 continue
 
@@ -192,13 +193,15 @@ def main():
                             Pkg.warn('(none): E: interrupted, exiting while ' +
                                      'reading %s' % fname)
                             sys.exit(2)
-                        except Exception, e:
+                        except Exception:
                             Pkg.warn(
-                                '(none): E: while reading %s: %s' % (fname, e))
+                                '(none): E: while reading %s: %s' %
+                                (fname, sys.exc_info()[1]))
                             continue
-            except Exception, e:
+            except Exception:
                 Pkg.warn(
-                    '(none): E: error while reading dir %s: %s' % (dname, e))
+                    '(none): E: error while reading dir %s: %s' %
+                    (dname, sys.exc_info()[1]))
                 continue
 
         if printAllReasons():
@@ -207,9 +210,9 @@ def main():
             sys.exit(66)
 
     finally:
-        print "%d packages and %d specfiles checked; %d errors, %d warnings." \
+        print("%d packages and %d specfiles checked; %d errors, %d warnings." \
               % (packages_checked, specfiles_checked,
-                 printed_messages["E"], printed_messages["W"])
+                 printed_messages["E"], printed_messages["W"]))
 
     if printed_messages["E"] > 0:
         sys.exit(64)
@@ -255,8 +258,8 @@ try:
                                'option=',
                                'rawout=',
                                ])
-except getopt.GetoptError, e:
-    Pkg.warn("%s: %s" % (sys.argv[0], e))
+except getopt.GetoptError:
+    Pkg.warn("%s: %s" % (sys.argv[0], sys.exc_info()[1]))
     usage(sys.argv[0])
     sys.exit(1)
 
@@ -290,11 +293,12 @@ else:
 
 for f in configs:
     try:
-        execfile(f)
+        exec(compile(open(f).read(), f, 'exec'))
     except IOError:
         pass
-    except Exception, E:
-        Pkg.warn('(none): W: error loading %s, skipping: %s' % (f, E))
+    except Exception:
+        Pkg.warn('(none): W: error loading %s, skipping: %s' %
+                 (f, sys.exc_info()[1]))
 # pychecker fix
 del f
 
@@ -340,11 +344,13 @@ for o in opt:
 
 # load user config file
 try:
-    execfile(os.path.expanduser(conf_file))
+    expconf = os.path.expanduser(conf_file)
+    exec(compile(open(expconf).read(), expconf, 'exec'))
 except IOError:
     pass
-except Exception,E:
-    Pkg.warn('(none): W: error loading %s, skipping: %s' % (conf_file, E))
+except Exception:
+    Pkg.warn('(none): W: error loading %s, skipping: %s' %
+             (conf_file, sys.exc_info()[1]))
 
 # apply config overrides
 for key, value in config_overrides.items():
@@ -361,7 +367,7 @@ if info_error:
     for c in Config.allChecks():
         loadCheck(c)
     for e in sorted(info_error):
-        print "%s:" % e
+        print("%s:" % e)
         printDescriptions(e)
     sys.exit(0)
 
Index: rpmlint-1.5/BinariesCheck.py
===================================================================
--- rpmlint-1.5.orig/BinariesCheck.py
+++ rpmlint-1.5/BinariesCheck.py
@@ -10,6 +10,7 @@
 import re
 import stat
 import os
+import sys
 
 import rpm
 
@@ -195,10 +196,11 @@ class BinaryInfo:
 
         fobj = None
         try:
-            fobj = open(path)
+            fobj = open(path, 'rb')
             fobj.seek(-12, 2) # 2 == os.SEEK_END, for python 2.4 compat (#172)
-            self.tail = fobj.read()
-        except Exception, e:
+            self.tail = fobj.read().decode()
+        except Exception:
+            e = sys.exc_info()[1]
             printWarning(pkg, 'binaryinfo-tail-failed %s: %s' % (file, e))
         if fobj:
             fobj.close()
@@ -291,9 +293,11 @@ class BinariesCheck(AbstractCheck.Abstra
         has_usr_lib_file = False
 
         multi_pkg = False
-        res = srcname_regex.search(pkg[rpm.RPMTAG_SOURCERPM] or '')
-        if res:
-            multi_pkg = (pkg.name != res.group(1))
+        srpm = pkg[rpm.RPMTAG_SOURCERPM]
+        if srpm:
+            res = srcname_regex.search(srpm.decode())
+            if res:
+                multi_pkg = (pkg.name != res.group(1))
 
         for fname, pkgfile in files.items():
 
Index: rpmlint-1.5/DocFilesCheck.py
===================================================================
--- rpmlint-1.5.orig/DocFilesCheck.py
+++ rpmlint-1.5/DocFilesCheck.py
@@ -43,7 +43,9 @@ class DocFilesCheck(AbstractCheck.Abstra
             core_reqs[dep.N()] = []
 
         # register things which are provided by the package
-        for i in pkg.header[rpm.RPMTAG_PROVIDES] + files.keys():
+        for i in pkg.header[rpm.RPMTAG_PROVIDES]:
+            core_reqs[i.decode()] = []
+        for i in files:
             core_reqs[i] = []
 
         for i in files:
Index: rpmlint-1.5/FilesCheck.py
===================================================================
--- rpmlint-1.5.orig/FilesCheck.py
+++ rpmlint-1.5/FilesCheck.py
@@ -9,16 +9,16 @@
 #############################################################################
 
 from datetime import datetime
-import commands
 import os
 import re
 import stat
 import string
+import sys
 
 import rpm
 
 from Filter import addDetails, printError, printWarning
-from Pkg import catcmd, is_utf8, is_utf8_str
+from Pkg import catcmd, getstatusoutput, is_utf8, is_utf8_str
 import AbstractCheck
 import Config
 
@@ -674,7 +674,7 @@ scalable_icon_regex = re.compile(r'^/usr
 
 # loosely inspired from Python Cookbook
 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/173220
-text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b"))
+text_characters = "".join(map(chr, range(32, 127))) + "\n\r\t\b"
 _null_trans = string.maketrans("", "")
 
 def peek(filename, pkg, length=1024):
@@ -686,7 +686,8 @@ def peek(filename, pkg, length=1024):
         fobj = open(filename, 'rb')
         chunk = fobj.read(length)
         fobj.close()
-    except IOError, e: # eg. https://bugzilla.redhat.com/209876
+    except IOError: # eg. https://bugzilla.redhat.com/209876
+        e = sys.exc_info()[1]
         printWarning(pkg, 'read-error', e)
         if fobj:
             fobj.close()
@@ -910,7 +911,8 @@ class FilesCheck(AbstractCheck.AbstractC
                         printError(pkg, 'compressed-symlink-with-wrong-ext',
                                    f, link)
 
-            perm = mode & 07777
+            perm = mode & int("7777", 8)
+            mode_is_exec = mode & int("111", 8)
 
             if log_regex.search(f):
                 log_file = f
@@ -935,17 +937,17 @@ class FilesCheck(AbstractCheck.AbstractC
                                     pkg[rpm.RPMTAG_GROUP]))):
                             printError(pkg, 'setgid-binary', f, group,
                                        oct(perm))
-                    if mode & 0777 != 0755:
+                    if mode & int("777", 8) != int("755", 8):
                         printError(pkg, 'non-standard-executable-perm', f,
                                    oct(perm))
 
                 # Prefetch scriptlets, strip quotes from them (#169)
-                postin = pkg[rpm.RPMTAG_POSTIN] or \
-                    pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
+                postin = (pkg[rpm.RPMTAG_POSTIN] or \
+                    pkg.scriptprog(rpm.RPMTAG_POSTINPROG)).decode()
                 if postin:
                     postin = quotes_regex.sub('', postin)
-                postun = pkg[rpm.RPMTAG_POSTUN] or \
-                    pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
+                postun = (pkg[rpm.RPMTAG_POSTUN] or \
+                    pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)).decode()
                 if postun:
                     postun = quotes_regex.sub('', postun)
 
@@ -1049,7 +1051,7 @@ class FilesCheck(AbstractCheck.AbstractC
 
                 res = bin_regex.search(f)
                 if res:
-                    if mode & 0111 == 0:
+                    if not mode_is_exec:
                         printWarning(pkg, 'non-executable-in-bin', f, oct(perm))
                     else:
                         exe = res.group(1)
@@ -1060,7 +1062,8 @@ class FilesCheck(AbstractCheck.AbstractC
                        (includefile_regex.search(f) or \
                         develfile_regex.search(f) or is_buildconfig):
                     printWarning(pkg, 'devel-file-in-non-devel-package', f)
-                if mode & 0444 != 0444 and perm & 07000 == 0:
+                if mode & int("444", 8) != int("444", 8) and \
+                   perm & int("7000", 8) == 0:
                     ok_nonreadable = False
                     for regex in non_readable_regexs:
                         if regex.search(f):
@@ -1072,7 +1075,7 @@ class FilesCheck(AbstractCheck.AbstractC
                         f not in ghost_files:
                     printError(pkg, 'zero-length', f)
 
-                if mode & 0002 != 0:
+                if mode & stat.S_IWOTH:
                     printError(pkg, 'world-writable', f, oct(perm))
 
                 if not perl_dep_error:
@@ -1144,10 +1147,10 @@ class FilesCheck(AbstractCheck.AbstractC
                         printWarning(pkg, 'python-bytecode-without-source', f)
 
                 # normal executable check
-                if mode & stat.S_IXUSR and perm != 0755:
+                if mode & stat.S_IXUSR and perm != int("755", 8):
                     printError(pkg, 'non-standard-executable-perm',
                                f, oct(perm))
-                if mode & 0111 != 0:
+                if mode_is_exec:
                     if f in config_files:
                         printError(pkg, 'executable-marked-as-config-file', f)
                     if not nonexec_file:
@@ -1179,11 +1182,12 @@ class FilesCheck(AbstractCheck.AbstractC
                     man_basenames.add(res.group(1))
                     if use_utf8 and chunk:
                         # TODO: better shell escaping or seq based invocation
-                        cmd = commands.getstatusoutput(
+                        cmd = getstatusoutput(
                             'env LC_ALL=C %s "%s" | gtbl | '
                             'env LC_ALL=en_US.UTF-8 groff -mtty-char -Tutf8 '
                             '-P-c -mandoc -w%s >/dev/null' %
-                            (catcmd(f), pkgfile.path, man_warn_category))
+                            (catcmd(f), pkgfile.path, man_warn_category),
+                            shell=True)
                         for line in cmd[1].split("\n"):
                             res = man_warn_regex.search(line)
                             if not res or man_nowarn_regex.search(line):
@@ -1213,12 +1217,11 @@ class FilesCheck(AbstractCheck.AbstractC
                             printError(pkg,
                                        'sourced-script-with-shebang', f,
                                        interpreter)
-                        if mode & 0111 != 0:
+                        if mode_is_exec:
                             printError(pkg, 'executable-sourced-script',
                                        f, oct(perm))
                     # ...but executed ones should
-                    elif interpreter or mode & 0111 != 0 or \
-                            script_regex.search(f):
+                    elif interpreter or mode_is_exec or script_regex.search(f):
                         if interpreter:
                             if mode & 0111 != 0 and not interpreter_regex.search(interpreter):
                                 printError(pkg, 'wrong-script-interpreter',
@@ -1228,7 +1231,7 @@ class FilesCheck(AbstractCheck.AbstractC
                                  f.endswith('.la')):
                             printError(pkg, 'script-without-shebang', f)
 
-                        if mode & 0111 == 0 and not is_doc:
+                        if not mode_is_exec and not is_doc:
                             printError(pkg, 'non-executable-script', f,
                                        oct(perm), interpreter)
                         if '\r' in chunk:
@@ -1256,9 +1259,9 @@ class FilesCheck(AbstractCheck.AbstractC
 
             # normal dir check
             elif stat.S_ISDIR(mode):
-                if mode & 01002 == 2: # world writable without sticky bit
+                if mode & int("1002", 8) == 2: # world writable w/o sticky bit
                     printError(pkg, 'world-writable', f, oct(perm))
-                if perm != 0755:
+                if perm != int("755", 8):
                     printError(pkg, 'non-standard-dir-perm', f, oct(perm))
                 if pkg.name not in filesys_packages and f in STANDARD_DIRS:
                     printError(pkg, 'standard-dir-owned-by-package', f)
@@ -1368,7 +1371,7 @@ class FilesCheck(AbstractCheck.AbstractC
                 if stat.S_ISLNK(mode):
                     printError(pkg, 'symlink-crontab-file', f)
 
-                if mode & 0111:
+                if mode_is_exec:
                     printError(pkg, 'executable-crontab-file', f)
 
                 if stat.S_IWGRP & mode or stat.S_IWOTH & mode:
Index: rpmlint-1.5/I18NCheck.py
===================================================================
--- rpmlint-1.5.orig/I18NCheck.py
+++ rpmlint-1.5/I18NCheck.py
@@ -79,7 +79,7 @@ class I18NCheck(AbstractCheck.AbstractCh
         if pkg.isSource():
             return
 
-        files = pkg.files().keys()
+        files = list(pkg.files().keys())
         files.sort()
         locales = []                      # list of locales for this packages
         webapp = False
Index: rpmlint-1.5/InitScriptCheck.py
===================================================================
--- rpmlint-1.5.orig/InitScriptCheck.py
+++ rpmlint-1.5/InitScriptCheck.py
@@ -10,6 +10,7 @@
 
 import os
 import re
+import sys
 
 import rpm
 
@@ -54,7 +55,7 @@ class InitScriptCheck(AbstractCheck.Abst
 
             basename = os.path.basename(fname)
             initscript_list.append(basename)
-            if pkgfile.mode & 0500 != 0500:
+            if pkgfile.mode & int("500", 8) != int("500", 8):
                 printError(pkg, 'init-script-non-executable', fname)
 
             if "." in basename:
@@ -87,7 +88,8 @@ class InitScriptCheck(AbstractCheck.Abst
             content = None
             try:
                 content = Pkg.readlines(pkgfile.path)
-            except Exception, e:
+            except Exception:
+                e = sys.exc_info()[1]
                 printWarning(pkg, 'read-error', e)
                 continue
             content_str = "".join(content)
Index: rpmlint-1.5/LSBCheck.py
===================================================================
--- rpmlint-1.5.orig/LSBCheck.py
+++ rpmlint-1.5/LSBCheck.py
@@ -31,12 +31,16 @@ class LSBCheck(AbstractCheck.AbstractChe
             printError(pkg, 'non-lsb-compliant-package-name', name)
 
         version = pkg[rpm.RPMTAG_VERSION]
-        if version and not version_regex.search(version):
-            printError(pkg, 'non-lsb-compliant-version', version)
+        if version:
+            version = version.decode()
+            if not version_regex.search(version):
+                printError(pkg, 'non-lsb-compliant-version', version)
 
         release = pkg[rpm.RPMTAG_RELEASE]
-        if release and not version_regex.search(release):
-            printError(pkg, 'non-lsb-compliant-release', release)
+        if release:
+            release = release.decode()
+            if not version_regex.search(release):
+                printError(pkg, 'non-lsb-compliant-release', release)
 
 # Create an object to enable the auto registration of the test
 check = LSBCheck()
Index: rpmlint-1.5/MenuCheck.py
===================================================================
--- rpmlint-1.5.orig/MenuCheck.py
+++ rpmlint-1.5/MenuCheck.py
@@ -178,9 +178,9 @@ class MenuCheck(AbstractCheck.AbstractCh
                 else:
                     if basename != pkg.name:
                         printWarning(pkg, 'non-coherent-menu-filename', fname)
-                    if mode & 0444 != 0444:
+                    if mode & int("444", 8) != int("444", 8):
                         printError(pkg, 'non-readable-menu-file', fname)
-                    if mode & 0111 != 0:
+                    if mode & int("111", 8):
                         printError(pkg, 'executable-menu-file', fname)
                     menus.append(fname)
             else:
Index: rpmlint-1.5/MenuXDGCheck.py
===================================================================
--- rpmlint-1.5.orig/MenuXDGCheck.py
+++ rpmlint-1.5/MenuXDGCheck.py
@@ -9,7 +9,10 @@
 from Filter import addDetails, printError, printWarning
 from Pkg import getstatusoutput, is_utf8
 import AbstractCheck
-from ConfigParser import RawConfigParser
+try:
+    from ConfigParser import RawConfigParser
+except:
+    from configparser import RawConfigParser
 import os
 
 STANDARD_BIN_DIRS = ['/bin/','/sbin/','/usr/bin/','/usr/sbin/']
Index: rpmlint-1.5/SourceCheck.py
===================================================================
--- rpmlint-1.5.orig/SourceCheck.py
+++ rpmlint-1.5/SourceCheck.py
@@ -14,7 +14,7 @@ import AbstractCheck
 import Config
 
 
-DEFAULT_VALID_SRC_PERMS = (0644, 0755)
+DEFAULT_VALID_SRC_PERMS = (int("644", 8), int("755", 8))
 
 source_regex = re.compile('\\.(tar|patch|tgz|diff)$')
 compress_ext = Config.getOption("CompressExtension", "bz2")
@@ -43,7 +43,7 @@ class SourceCheck(AbstractCheck.Abstract
                     not fname.endswith(compress_ext):
                 printWarning(pkg, 'source-or-patch-not-compressed',
                              compress_ext, fname)
-            perm = pkgfile.mode & 07777
+            perm = pkgfile.mode & int("7777", 8)
             if perm not in valid_src_perms:
                 printWarning(pkg, 'strange-permission', fname, oct(perm))
 
Index: rpmlint-1.5/TagsCheck.py
===================================================================
--- rpmlint-1.5.orig/TagsCheck.py
+++ rpmlint-1.5/TagsCheck.py
@@ -534,7 +534,7 @@ class TagsCheck(AbstractCheck.AbstractCh
     def _unexpanded_macros(self, pkg, tagname, value, is_url=False):
         if not value:
             return
-        for match in AbstractCheck.macro_regex.findall(str(value)):
+        for match in AbstractCheck.macro_regex.findall(value):
             # Do not warn about %XX URL escapes
             if is_url and re.match('^%[0-9A-F][0-9A-F]$', match, re.I):
                 continue
@@ -543,28 +543,33 @@ class TagsCheck(AbstractCheck.AbstractCh
     def check(self, pkg):
 
         packager = pkg[rpm.RPMTAG_PACKAGER]
-        self._unexpanded_macros(pkg, 'Packager', packager)
-        if not packager:
+        if packager:
+            packager = packager.decode()
+            self._unexpanded_macros(pkg, 'Packager', packager)
+            if Config.getOption('Packager') and \
+               not packager_regex.search(packager):
+                printWarning(pkg, 'invalid-packager', packager)
+        else:
             printError(pkg, 'no-packager-tag')
-        elif Config.getOption('Packager') and \
-                not packager_regex.search(packager):
-            printWarning(pkg, 'invalid-packager', packager)
 
         version = pkg[rpm.RPMTAG_VERSION]
-        self._unexpanded_macros(pkg, 'Version', version)
-        if not version:
-            printError(pkg, 'no-version-tag')
-        else:
+        if version:
+            version = version.decode()
+            self._unexpanded_macros(pkg, 'Version', version)
             res = invalid_version_regex.search(version)
             if res:
                 printError(pkg, 'invalid-version', version)
+        else:
+            printError(pkg, 'no-version-tag')
 
         release = pkg[rpm.RPMTAG_RELEASE]
-        self._unexpanded_macros(pkg, 'Release', release)
-        if not release:
+        if release:
+            release = release.decode()
+            self._unexpanded_macros(pkg, 'Release', release)
+            if release_ext and not extension_regex.search(release):
+                printWarning(pkg, 'not-standard-release-extension', release)
+        else:
             printError(pkg, 'no-release-tag')
-        elif release_ext and not extension_regex.search(release):
-            printWarning(pkg, 'not-standard-release-extension', release)
 
         epoch = pkg[rpm.RPMTAG_EPOCH]
         if epoch is None:
@@ -592,7 +597,7 @@ class TagsCheck(AbstractCheck.AbstractCh
         is_devel = FilesCheck.devel_regex.search(name)
         is_source = pkg.isSource()
         for d in deps:
-            value = apply(Pkg.formatRequire, d)
+            value = Pkg.formatRequire(*d)
             if use_epoch and d[1] and d[2][0] is None and \
                     not d[0].startswith('rpmlib('):
                 printWarning(pkg, 'no-epoch-in-dependency', value)
@@ -687,25 +692,31 @@ class TagsCheck(AbstractCheck.AbstractCh
         ignored_words.update((x[0] for x in pkg.conflicts()))
         ignored_words.update((x[0] for x in pkg.obsoletes()))
 
+        langs = pkg[rpm.RPMTAG_HEADERI18NTABLE]
+        if langs:
+            langs = [x.decode() for x in langs]
+
         summary = pkg[rpm.RPMTAG_SUMMARY]
-        if not summary:
-            printError(pkg, 'no-summary-tag')
-        else:
-            if not pkg[rpm.RPMTAG_HEADERI18NTABLE]:
+        if summary:
+            summary = summary.decode()
+            if not langs:
                 self._unexpanded_macros(pkg, 'Summary', summary)
             else:
-                for lang in pkg[rpm.RPMTAG_HEADERI18NTABLE]:
+                for lang in langs:
                     self.check_summary(pkg, lang, ignored_words)
+        else:
+            printError(pkg, 'no-summary-tag')
 
         description = pkg[rpm.RPMTAG_DESCRIPTION]
-        if not description:
-            printError(pkg, 'no-description-tag')
-        else:
-            if not pkg[rpm.RPMTAG_HEADERI18NTABLE]:
+        if description:
+            description = description.decode()
+            if not langs:
                 self._unexpanded_macros(pkg, '%description', description)
             else:
-                for lang in pkg[rpm.RPMTAG_HEADERI18NTABLE]:
+                for lang in langs:
                     self.check_description(pkg, lang, ignored_words)
+        else:
+            printError(pkg, 'no-description-tag')
 
         group = pkg[rpm.RPMTAG_GROUP]
         self._unexpanded_macros(pkg, 'Group', group)