[devscripts] 02/03: Update Python unittests to support pylint 1.8

Benjamin Drung bdrung at moszumanska.debian.org
Sun Feb 4 22:45:11 UTC 2018


This is an automated email from the git hooks/post-receive script.

bdrung pushed a commit to branch master
in repository devscripts.

commit 6f363da04bfe27cb7376764e62d636b3588e6157
Author: Benjamin Drung <bdrung at debian.org>
Date:   Sun Feb 4 21:10:00 2018 +0100

    Update Python unittests to support pylint 1.8
    
    Import latest version from https://github.com/bdrung/snippets
    
    Also raise the maximum line length for pylint to 99 (flake8 already has this
    value set).
    
    Signed-off-by: Benjamin Drung <bdrung at debian.org>
---
 scripts/devscripts/test/__init__.py    | 64 +++++++++++++++++--------
 scripts/devscripts/test/pylint.conf    | 35 ++++++++++++--
 scripts/devscripts/test/test_pylint.py | 88 +++++++++++++++++-----------------
 scripts/setup.py                       |  2 +-
 4 files changed, 121 insertions(+), 68 deletions(-)

diff --git a/scripts/devscripts/test/__init__.py b/scripts/devscripts/test/__init__.py
index 3de1e9e..f8769fd 100644
--- a/scripts/devscripts/test/__init__.py
+++ b/scripts/devscripts/test/__init__.py
@@ -1,26 +1,21 @@
-# Test suite for devscripts
-#
-# Copyright (C) 2010, Stefano Rivera <stefanor at ubuntu.com>
+# Copyright (C) 2017, Benjamin Drung <benjamin.drung at profitbricks.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # copyright notice and this permission notice appear in all copies.
 #
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import inspect
 import os
 import sys
-
-if sys.version_info < (2, 7):
-    import unittest2 as unittest
-else:
-    import unittest
+import unittest
 
 SCRIPTS = [
     "debdiff-apply",
@@ -31,8 +26,37 @@ SCRIPTS = [
 ]
 
 
-def discover():
-    # import __main__ triggers code re-execution
-    __main__ = sys.modules['__main__']
-    setupDir = os.path.abspath(os.path.dirname(__main__.__file__))
-    return unittest.defaultTestLoader.discover(setupDir)
+def get_source_files():
+    """Return a list of sources files/directories (to check with flake8/pylint)"""
+    modules = ["devscripts"]
+    py_files = ["setup.py"]
+
+    files = []
+    for code_file in SCRIPTS + modules + py_files:
+        is_script = code_file in SCRIPTS
+        if not os.path.exists(code_file):
+            # The alternative path is needed for Debian's pybuild
+            alternative = os.path.join(os.environ.get("OLDPWD", ""), code_file)
+            code_file = alternative if os.path.exists(alternative) else code_file
+        if is_script:
+            with open(code_file, "rb") as script_file:
+                shebang = script_file.readline().decode("utf-8")
+            if ((sys.version_info[0] == 3 and "python3" in shebang) or
+                    ("python" in shebang and "python3" not in shebang)):
+                files.append(code_file)
+        else:
+            files.append(code_file)
+    return files
+
+
+def unittest_verbosity():
+    """Return the verbosity setting of the currently running unittest
+    program, or None if none is running.
+    """
+    frame = inspect.currentframe()
+    while frame:
+        self = frame.f_locals.get("self")
+        if isinstance(self, unittest.TestProgram):
+            return self.verbosity
+        frame = frame.f_back
+    return None
diff --git a/scripts/devscripts/test/pylint.conf b/scripts/devscripts/test/pylint.conf
index 984e234..67634b8 100644
--- a/scripts/devscripts/test/pylint.conf
+++ b/scripts/devscripts/test/pylint.conf
@@ -1,20 +1,47 @@
+[MESSAGES CONTROL]
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=fixme,invalid-name,locally-disabled,missing-docstring
+
+
+[REPORTS]
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+
 [TYPECHECK]
 
 # List of classes names for which member attributes should not be checked
 # (useful for classes with attributes dynamically set).
-# lpapicache classes, urlparse
-ignored-classes=Launchpad,BaseWrapper,PersonTeam,Distribution,Consumer,Credentials,ParseResult
+ignored-classes=apt_pkg,magic
+
 
 [FORMAT]
 
 # Maximum number of characters on a single line.
-max-line-length=80
+max-line-length=99
 
 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
 # tab).
 indent-string='    '
 
+
 [BASIC]
 
 # Allow variables called e, f, lp
-good-names=i,j,k,ex,Run,_,e,f,lp
+good-names=i,j,k,ex,Run,_,e,f,lp,fp
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=5
diff --git a/scripts/devscripts/test/test_pylint.py b/scripts/devscripts/test/test_pylint.py
index 591dfe0..6576df9 100644
--- a/scripts/devscripts/test/test_pylint.py
+++ b/scripts/devscripts/test/test_pylint.py
@@ -1,6 +1,5 @@
-# test_pylint.py - Run pylint in errors-only mode.
-#
-# Copyright (C) 2010, Stefano Rivera <stefanor at ubuntu.com>
+# Copyright (C) 2010, Stefano Rivera <stefanor at debian.org>
+# Copyright (C) 2017-2018, Benjamin Drung <bdrung at debian.org>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -14,57 +13,60 @@
 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
+"""test_pylint.py - Run pylint"""
+
+import os
 import re
 import subprocess
+import sys
 import unittest
 
-from . import SCRIPTS
+from . import get_source_files, unittest_verbosity
 
-WHITELIST = [re.compile(': %s$' % x) for x in (
-    # Wildcard import:
-    r"No name '\w+Error' in module 'launchpadlib\.errors'",
-    # https://www.logilab.org/ticket/51250:
-    r"Module 'hashlib' has no '(md5|sha(1|224|256|384|512))' member",
-    # mox:
-    r"Instance of '.+' has no '(WithSideEffects|MultipleTimes|AndReturn)' "
-    r"member",
-)]
+CONFIG = os.path.join(os.path.dirname(__file__), "pylint.conf")
 
 
 class PylintTestCase(unittest.TestCase):
+    """
+    This unittest class provides a test that runs the pylint code check
+    on the Python source code. The list of source files is provided by
+    the get_source_files() function and pylint is purely configured via
+    a config file.
+    """
+
     def test_pylint(self):
-        "Test: Run pylint on Python source code"
-        files = ['devscripts']
-        for script in SCRIPTS:
-            f = open(script, 'r', encoding='utf-8')
-            if 'python' in f.readline():
-                files.append(script)
-            f.close()
-        cmd = ['pylint3', '--rcfile=devscripts/test/pylint.conf', '-E',
-               '--include-ids=y', '--'] + files
-        process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                   stderr=subprocess.PIPE, close_fds=True)
+        """Test: Run pylint on Python source code"""
 
+        with open("/proc/self/cmdline", "r") as cmdline_file:
+            python_binary = cmdline_file.read().split("\0")[0]
+        cmd = [python_binary, "-m", "pylint", "--rcfile=" + CONFIG, "--"] + get_source_files()
+        env = os.environ.copy()
+        env["PYLINTHOME"] = ".pylint.d"
+        if unittest_verbosity() >= 2:
+            sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
+        process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                                   close_fds=True)
         out, err = process.communicate()
-        if err != '':
-            raise unittest.SkipTest('pylint crashed :/')
 
-        filtered_out = []
-        detected_in = ''
-        # pylint: disable=E1103
-        for line in out.splitlines():
-            # pylint: enable=E1103
-            if line.startswith('************* '):
-                detected_in = line
-                continue
+        if process.returncode != 0:
+            # Strip trailing summary (introduced in pylint 1.7). This summary might look like:
+            #
+            # ------------------------------------
+            # Your code has been rated at 10.00/10
+            #
+            out = re.sub("^(-+|Your code has been rated at .*)$", "", out.decode(),
+                         flags=re.MULTILINE).rstrip()
 
-            for reg_exp in WHITELIST:
-                if reg_exp.search(line):
-                    break
-            else:
-                filtered_out.append(detected_in)
-                filtered_out.append(line)
+            # Strip logging of used config file (introduced in pylint 1.8)
+            err = re.sub("^Using config file .*\n", "", err.decode()).rstrip()
 
-        self.assertEqual(filtered_out, [],
-                         "pylint found errors.\n"
-                         "Filtered Output:\n" + '\n'.join(filtered_out))
+            msgs = []
+            if err:
+                msgs.append("pylint exited with code {} and has unexpected output on stderr:\n{}"
+                            .format(process.returncode, err))
+            if out:
+                msgs.append("pylint found issues:\n{}".format(out))
+            if not msgs:
+                msgs.append("pylint exited with code {} and has no output on stdout or stderr."
+                            .format(process.returncode))
+            self.fail("\n".join(msgs))
diff --git a/scripts/setup.py b/scripts/setup.py
index b0e7bd2..5908616 100755
--- a/scripts/setup.py
+++ b/scripts/setup.py
@@ -25,5 +25,5 @@ if __name__ == '__main__':
         version=get_version(),
         scripts=SCRIPTS,
         packages=['devscripts', 'devscripts/test'],
-        test_suite='devscripts.test.discover',
+        test_suite='devscripts.test',
     )

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/devscripts.git



More information about the devscripts-devel mailing list