Repository: coala/coala

Issue:
run_tests --html doesn't work in ubuntu
In ubuntu and debian systems, coverage isn't installed in `/usr/bin/coverage3` ... rather, it is installed as `/usr/bin/python3-coverage`. Hence, `--html` flag doesn't work. The corresponding launchpad bug is [here](https://bugs.launchpad.net/horizon/+bug/1241332)

It would be better to use `python3 -m coverage` as this is platform independent.



Discussion:
We have ubuntu systems for continuous integration and that works fine. But
the `python -m` thing seems cleaner indeed.

2015-05-19 4:16 GMT+02:00 AbdealiJK notifications@github.com:

> In ubuntu and debian systems, coverage isn't installed in
> /usr/bin/coverage3 ... rather, it is installed as
> /usr/bin/python3-coverage. Hence, --html flag doesn't work. The
> corresponding launchpad bug is here
> https://bugs.launchpad.net/horizon/+bug/1241332
> 
> It would be better to use python3 -m coverage as this is platform
> independent.
> 
> ## 
> 
> Reply to this email directly or view it on GitHub
> https://github.com/coala-analyzer/coala/issues/553.


Resolving patch:
diff --git a/coalib/misc/StringConstants.py b/coalib/misc/StringConstants.py
--- a/coalib/misc/StringConstants.py
+++ b/coalib/misc/StringConstants.py
@@ -1,5 +1,6 @@
 import inspect
 import os
+import sys
 
 from coalib.misc.i18n import _
 
@@ -53,3 +54,8 @@ class StringConstants:
     system_coafile = os.path.join(coalib_root, "default_coafile")
 
     user_coafile = os.path.join(os.path.expanduser("~"), ".coarc")
+
+    if sys.platform.startswith("win"):  # pragma: no cover
+        python_executable = "python"
+    else:
+        python_executable = "python3"


Test patch:
diff --git a/coalib/tests/TestHelper.py b/coalib/tests/TestHelper.py
--- a/coalib/tests/TestHelper.py
+++ b/coalib/tests/TestHelper.py
@@ -6,8 +6,9 @@
 import sys
 import shutil
 import webbrowser
-from coalib.misc.ContextManagers import suppress_stdout
-
+from coalib.misc.ContextManagers import (suppress_stdout,
+                                         preserve_sys_path)
+from coalib.misc.StringConstants import StringConstants
 
 class TestHelper:
     @staticmethod
@@ -64,15 +65,19 @@ def delete_coverage(self):
 
         :return: False if coverage3 cannot be executed.
         """
-        try:
-            subprocess.call(["coverage3", "erase"])
-            return True
-        except:
+        coverage_available = False
+        with suppress_stdout():
+            coverage_available = subprocess.call(
+                [StringConstants.python_executable,
+                 "-m",
+                 "coverage",
+                 "erase"]) == 0
+        if not coverage_available:
             print("Coverage failed. Falling back to standard unit tests."
                   "Install code coverage measurement for python3. Package"
                   "name should be something like: python-coverage3/coverage")
             self.args.cover = False  # Don't use coverage if this fails
-            return False
+        return coverage_available
 
     def run_tests(self, ignore_list):
         if self.args.cover:
@@ -133,12 +138,24 @@ def __resolve_implicit_args(self):
             self.args.test_only = []
 
     def __show_coverage_results(self):
-        subprocess.call(["coverage3", "combine"])
-        subprocess.call(["coverage3", "report", "-m"])
+        subprocess.call([StringConstants.python_executable,
+                         "-m",
+                         "coverage",
+                         "combine"])
+        subprocess.call([StringConstants.python_executable,
+                         "-m",
+                         "coverage",
+                         "report",
+                         "-m"])
         if self.args.html:
             shutil.rmtree(".htmlreport", ignore_errors=True)
             print("Generating HTML report to .htmlreport...")
-            subprocess.call(["coverage3", "html", "-d", ".htmlreport"])
+            subprocess.call([StringConstants.python_executable,
+                             "-m",
+                             "coverage",
+                             "html",
+                             "-d",
+                             ".htmlreport"])
             try:
                 webbrowser.open_new_tab(os.path.join(".htmlreport",
                                                      "index.html"))
@@ -160,14 +177,13 @@ def __print_output(self, command_array):
         return retval
 
     def __execute_python3_file(self, filename, ignored_files):
-        # On windows we won't find a python3 executable and don't use coverage
-        if sys.platform.startswith("win"):
-            return self.__print_output(["python", filename])
-
         if not self.args.cover:
-            return self.__print_output(["python3", filename])
+            return self.__print_output([StringConstants.python_executable,
+                                        filename])
 
-        return self.__print_output(["coverage3",
+        return self.__print_output([StringConstants.python_executable,
+                                    "-m",
+                                    "coverage",
                                     "run",
                                     "-p",  # make it collectable later
                                     "--branch",
@@ -177,23 +193,22 @@ def __execute_python3_file(self, filename, ignored_files):
 
     @staticmethod
     def __check_module_skip(filename):
-        module_dir = os.path.dirname(filename)
-        if module_dir not in sys.path:
-            sys.path.insert(0, module_dir)
+        with preserve_sys_path(), suppress_stdout():
+            module_dir = os.path.dirname(filename)
+            if module_dir not in sys.path:
+                sys.path.insert(0, module_dir)
 
-        try:
-            # Don't allow module code printing
-            with suppress_stdout():
+            try:
                 module = importlib.import_module(
                     os.path.basename(os.path.splitext(filename)[0]))
 
-            for name, object in inspect.getmembers(module):
-                if inspect.isfunction(object) and name == "skip_test":
-                    return object()
-        except ImportError as exception:
-            return str(exception)
+                for name, object in inspect.getmembers(module):
+                    if inspect.isfunction(object) and name == "skip_test":
+                        return object()
+            except ImportError as exception:
+                return str(exception)
 
-        return False
+            return False
 
     def __execute_test(self, filename, curr_nr, max_nr, ignored_files):
         """