Example #1
0
    def execute(self):

        summary = {
            'started': datetime.now(),
        }
        summary.update(self.config.get_summary_information())

        found_files = find_python(self.config.ignores, self.config.paths,
                                  self.config.explicit_file_mode, self.config.workdir)

        # Run the tools
        messages = []
        for tool in self.config.get_tools(found_files):
            try:
                messages += tool.run(found_files)
            except Exception:  # pylint: disable=broad-except
                if self.config.die_on_tool_error:
                    raise
                else:
                    for name, cls in tools.TOOLS.items():
                        if cls == tool.__class__:
                            toolname = name
                            break
                    else:
                        toolname = 'Unknown'

                    loc = Location(self.config.workdir, None, None, None, None)
                    msg = 'Tool %s failed to run (exception was raised)' % (
                        toolname,
                    )
                    message = Message(
                        toolname,
                        'failure',
                        loc,
                        message=msg,
                    )
                    messages.append(message)

        messages = self.process_messages(found_files, messages)

        summary['message_count'] = len(messages)
        summary['completed'] = datetime.now()

        # Timedelta.total_seconds() is not available
        # on Python<=2.6 so we calculate it ourselves
        # See issue #60 and http://stackoverflow.com/a/3694895
        delta = (summary['completed'] - summary['started'])
        total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6
        summary['time_taken'] = '%0.2f' % total_seconds

        external_config = []
        for tool, configured_by in self.config.configured_by.items():
            if configured_by is not None:
                external_config.append((tool, configured_by))
        if len(external_config) > 0:
            summary['external_config'] = ', '.join(['%s: %s' % info for info in external_config])

        self.summary = summary
        self.messages = messages
Example #2
0
 def test_vulture_find_dead_code(self):
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "testfile.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     self.vulture_tool.configure(self.config, found_files)
     messages = self.vulture_tool.run(found_files)
     self.assertTrue(
         any(message.code in ["unused-variable", "unused-import"]
             for message in messages))
Example #3
0
 def test_absolute_path_is_computed_correctly(self):
     pylint_tool, config = _get_pylint_tool_and_prospector_config()
     root = os.path.join(os.path.dirname(__file__), "testpath", "test.py")
     root_sep_split = root.split(os.path.sep)
     root_os_split = os.path.split(root)
     found_files = find_python([], [root], explicit_file_mode=True)
     pylint_tool.configure(config, found_files)
     self.assertNotEqual(pylint_tool._args, [os.path.join(*root_sep_split)])
     self.assertEqual(pylint_tool._args, [os.path.join(*root_os_split)])
Example #4
0
 def test_hardcoded_password_string(self):
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "testfile.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     self.bandit_tool.configure(self.config, found_files)
     messages = self.bandit_tool.run(found_files)
     self.assertTrue(
         any(message.code in ["B107", "B105", "B106"]
             for message in messages))
Example #5
0
    def execute(self):

        summary = {
            'started': datetime.now(),
            'libraries': self.libraries,
            'strictness': self.strictness,
            'profiles': self.profiles,
            'adaptors': [adaptor.name for adaptor in self.adaptors],
            'tools': self.tools_to_run,
        }

        # Find the files and packages in a common way, so that each tool
        # gets the same list.
        found_files = find_python(self.ignores, self.path)

        # Prep the tools.
        for tool in self.tool_runners:
            tool.prepare(found_files, self.config, self.adaptors)

        # Run the tools
        messages = []
        for tool in self.tool_runners:
            try:
                messages += tool.run()
            except Exception:  # pylint: disable=W0703
                if self.config.die_on_tool_error:
                    raise
                else:
                    for name, cls in tools.TOOLS.items():
                        if cls == tool.__class__:
                            toolname = name
                            break
                    else:
                        toolname = 'Unknown'

                    loc = Location(self.path, None, None, None, None)
                    msg = 'Tool %s failed to run (exception was raised)' % (
                        toolname,
                    )
                    message = Message(
                        toolname,
                        'failure',
                        loc,
                        message=msg,
                    )
                    messages.append(message)

        messages = self.process_messages(messages)

        summary['message_count'] = len(messages)
        summary['completed'] = datetime.now()
        delta = (summary['completed'] - summary['started'])
        summary['time_taken'] = '%0.2f' % delta.total_seconds()

        self.summary = summary
        self.messages = messages
Example #6
0
 def test_pycodestyle_space_and_tabs(self):
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "test_space_tab.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     self.pep8_tool.configure(self.config, found_files)
     messages = self.pep8_tool.run([])
     self.assertTrue(any(message.code == "E101" for message in messages))
     self.assertTrue(any(message.code == "E111" for message in messages))
     self.assertTrue(any(message.code == "W191" for message in messages))
     self.assertTrue(all(message.source == "pep8" for message in messages))
Example #7
0
    def _run_test(self, name, expected):
        root = os.path.join(os.path.dirname(__file__), 'testdata', name)
        files = find_python([], root)

        expected = [os.path.join(root, e).rstrip(os.path.sep) for e in expected]
        actual = files.get_minimal_syspath()

        expected.sort(key=lambda x: len(x))

        self.assertEqual(actual, expected)
def _assert_find_files(name, expected, explicit_file_mode=False):
    root = _TEST_DIR / name
    files = find_python([], [str(root)], explicit_file_mode=explicit_file_mode)

    expected = [os.path.relpath(os.path.join(str(root), e).rstrip(os.path.sep)) for e in expected]
    expected.append(files.rootpath)
    actual = files.get_minimal_syspath()

    expected.sort(key=lambda x: len(x))
    assert actual == expected
 def test_absolute_path_is_computed_correctly(self):
     root = os.path.join(os.path.dirname(__file__), 'testpath', 'test.py')
     root_sep_split = root.split(os.path.sep)
     root_os_split = os.path.split(root)
     found_files = find_python([], [root], explicit_file_mode=True)
     self.pylint_tool.configure(self.config, found_files)
     self.assertNotEqual(self.pylint_tool._args,
                         [os.path.join(*root_sep_split)])
     self.assertEqual(self.pylint_tool._args,
                      [os.path.join(*root_os_split)])
Example #10
0
 def test_use_prospector_default_path_finder(self):
     workdir = "tests/tools/pylint/testpath/absolute-import/"
     with patch("os.getcwd", return_value=os.path.realpath(workdir)):
         pylint_tool, config = _get_pylint_tool_and_prospector_config(
             argv_patch=["", "-P", "prospector-default-finder"])
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "absolute-import", "pkg")
     found_files = find_python([], [root], False)
     pylint_tool.configure(config, found_files)
     messages = pylint_tool.run(found_files)
     self.assertEqual(messages[0].code, "no-name-in-module")
Example #11
0
 def test_wont_throw_false_positive_relative_beyond_top_level(self):
     with patch(
             "os.getcwd",
             return_value=os.path.realpath("tests/tools/pylint/testpath/")):
         pylint_tool, config = _get_pylint_tool_and_prospector_config()
     root = os.path.join(os.path.dirname(__file__), "testpath", "src",
                         "mcve", "foobar.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     pylint_tool.configure(config, found_files)
     messages = pylint_tool.run(found_files)
     self.assertListEqual(messages, [])
Example #12
0
    def _run_test(self, name, expected):
        root = os.path.join(os.path.dirname(__file__), 'testdata', name)
        files = find_python([], [root], explicit_file_mode=False)

        expected = [
            os.path.join(root, e).rstrip(os.path.sep) for e in expected
        ]
        actual = files.get_minimal_syspath()

        expected.sort(key=lambda x: len(x))

        self.assertEqual(actual, expected)
Example #13
0
 def test_find_pycodestyle_section_in_config(self):
     workdir = os.path.join(os.path.dirname(__file__), "testsettings",
                            "pycodestyle")
     root = os.path.join(os.path.dirname(__file__), "testsettings",
                         "pycodestyle", "testfile.py")
     found_files = find_python([], [root],
                               explicit_file_mode=True,
                               workdir=workdir)
     configured_by, _ = self.pep8_tool.configure(self.config, found_files)
     expected_config_path = os.path.join(workdir, "setup.cfg")
     self.assertEqual(configured_by,
                      "Configuration found at %s" % expected_config_path)
Example #14
0
 def test_no_duplicates_in_checkpath(self):
     """
     This checks that the pylint tool will not generate a list of packages and subpackages -
     if there is a hierarchy there is no need to duplicate sub-packages in the list to be checked
     """
     root = THIS_DIR / "duplicates_test"
     files = find_python([], [str(root)], explicit_file_mode=False)
     tool, config = _get_pylint_tool_and_prospector_config()
     check_paths = tool._get_pylint_check_paths(files)
     assert len(check_paths) == 1
     assert [str(Path(p).relative_to(root))
             for p in check_paths] == ["pkg1"]
Example #15
0
 def test_will_throw_useless_suppression(self):
     with patch(
             "os.getcwd",
             return_value=os.path.realpath("tests/tools/pylint/testpath/")):
         pylint_tool, config = _get_pylint_tool_and_prospector_config(
             argv_patch=["", "-t", "pylint"])
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "test_useless_suppression.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     pylint_tool.configure(config, found_files)
     messages = pylint_tool.run(found_files)
     assert any(
         m.code == "useless-suppression" for m in
         messages), "There should be at least one useless suppression"
Example #16
0
 def test_wont_throw_useless_suppression(self):
     with patch(
             "os.getcwd",
             return_value=os.path.realpath("tests/tools/pylint/testpath/")):
         pylint_tool, config = _get_pylint_tool_and_prospector_config(
             argv_patch=["", "-t", "pylint"])
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "test_useless_suppression.py")
     found_files = find_python([], [root], explicit_file_mode=True)
     pylint_tool.configure(config, found_files)
     messages = pylint_tool.run(found_files)
     for message in messages:
         if message.code == "useless-suppression":
             self.fail("useless-suppression was thrown")
Example #17
0
    def _assert_find_files(self, name, expected, explicit_file_mode=False):
        root = os.path.join(os.path.dirname(__file__), "testdata", name)
        files = find_python([], [root], explicit_file_mode=explicit_file_mode)

        expected = [
            os.path.relpath(os.path.join(root, e).rstrip(os.path.sep))
            for e in expected
        ]
        expected.append(files.rootpath)
        actual = files.get_minimal_syspath()

        expected.sort(key=lambda x: len(x))

        self.assertEqual(actual, expected)
Example #18
0
 def test_use_pylint_default_path_finder(self):
     workdir = os.path.realpath(
         "tests/tools/pylint/testpath/absolute-import/")
     pylint_tool, config = _get_pylint_tool_and_prospector_config(
         argv_patch=[
             "", "-P",
             os.path.join(workdir, ".prospector",
                          "pylint-default-finder.yml")
         ])
     root = os.path.join(os.path.dirname(__file__), "testpath",
                         "absolute-import", "pkg")
     found_files = find_python([], [root], False, workdir)
     pylint_tool.configure(config, found_files)
     messages = pylint_tool.run(found_files)
     self.assertListEqual(messages, [])
Example #19
0
    def test_pylint_config(self):
        """Verifies that prospector will configure pylint with any pylint-specific configuration if found"""
        def _has_message(msg_list, code):
            return any([
                message.code == code and message.source == "pylint"
                for message in msg_list
            ])

        for config_type in ("pylintrc", "pylintrc2", "pyproject", "setup.cfg"):
            root = THIS_DIR / "pylint_configs" / config_type

            with patch("os.getcwd", return_value=root.absolute()):
                pylint_tool, config = _get_pylint_tool_and_prospector_config()
            self.assertEqual(Path(config.workdir).absolute(), root.absolute())

            found_files = find_python([], [str(root)],
                                      explicit_file_mode=False,
                                      workdir=str(root))
            pylint_tool.configure(config, found_files)

            messages = pylint_tool.run(found_files)
            self.assertTrue(_has_message(messages, "line-too-long"),
                            msg=config_type)
Example #20
0
    def execute(self):

        summary = {
            'started': datetime.now(),
        }
        summary.update(self.config.get_summary_information())

        found_files = find_python(self.config.ignores, self.config.paths,
                                  self.config.explicit_file_mode, self.config.workdir)

        # Run the tools
        messages = []
        for tool in self.config.get_tools(found_files):
            for name, cls in tools.TOOLS.items():
                if cls == tool.__class__:
                    toolname = name
                    break
            else:
                toolname = 'Unknown'

            try:
                # Tools can output to stdout/stderr in unexpected places, for example,
                # pep257 emits warnings about __all__ and as pyroma exec's the setup.py
                # file, it will execute any print statements in that, etc etc...
                with capture_output(hide=not self.config.direct_tool_stdout) as capture:
                    messages += tool.run(found_files)
                    if self.config.include_tool_stdout:
                        loc = Location(self.config.workdir, None, None, None, None)

                        if capture.get_hidden_stderr():
                            msg = 'stderr from %s:\n%s' % (toolname, capture.get_hidden_stderr())
                            messages.append(Message(toolname, 'hidden-output', loc, message=msg))
                        if capture.get_hidden_stdout():
                            msg = 'stdout from %s:\n%s' % (toolname, capture.get_hidden_stdout())
                            messages.append(Message(toolname, 'hidden-output', loc, message=msg))

            except Exception:  # pylint: disable=broad-except
                if self.config.die_on_tool_error:
                    raise
                else:
                    loc = Location(self.config.workdir, None, None, None, None)
                    msg = 'Tool %s failed to run (exception was raised)' % (
                        toolname,
                    )
                    message = Message(
                        toolname,
                        'failure',
                        loc,
                        message=msg,
                    )
                    messages.append(message)

        messages = self.process_messages(found_files, messages)

        summary['message_count'] = len(messages)
        summary['completed'] = datetime.now()

        # Timedelta.total_seconds() is not available
        # on Python<=2.6 so we calculate it ourselves
        # See issue #60 and http://stackoverflow.com/a/3694895
        delta = (summary['completed'] - summary['started'])
        total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6
        summary['time_taken'] = '%0.2f' % total_seconds

        external_config = []
        for tool, configured_by in self.config.configured_by.items():
            if configured_by is not None:
                external_config.append((tool, configured_by))
        if len(external_config) > 0:
            summary['external_config'] = ', '.join(['%s: %s' % info for info in external_config])

        self.summary = summary
        self.messages = self.messages + messages
Example #21
0
    def execute(self):

        summary = {
            'started': datetime.now(),
        }
        summary.update(self.config.get_summary_information())

        found_files = find_python(self.config.ignores, self.config.paths,
                                  self.config.explicit_file_mode,
                                  self.config.workdir)

        # Run the tools
        messages = []
        for tool in self.config.get_tools(found_files):
            for name, cls in tools.TOOLS.items():
                if cls == tool.__class__:
                    toolname = name
                    break
            else:
                toolname = 'Unknown'

            try:
                # Tools can output to stdout/stderr in unexpected places, for example,
                # pep257 emits warnings about __all__ and as pyroma exec's the setup.py
                # file, it will execute any print statements in that, etc etc...
                with capture_output(
                        hide=not self.config.direct_tool_stdout) as capture:
                    messages += tool.run(found_files)

                    if self.config.include_tool_stdout:
                        loc = Location(self.config.workdir, None, None, None,
                                       None)

                        if capture.get_hidden_stderr():
                            msg = 'stderr from %s:\n%s' % (
                                toolname, capture.get_hidden_stderr())
                            messages.append(
                                Message(toolname,
                                        'hidden-output',
                                        loc,
                                        message=msg))
                        if capture.get_hidden_stdout():
                            msg = 'stdout from %s:\n%s' % (
                                toolname, capture.get_hidden_stdout())
                            messages.append(
                                Message(toolname,
                                        'hidden-output',
                                        loc,
                                        message=msg))

            except FatalProspectorException as fatal:
                sys.stderr.write(fatal.message)
                sys.exit(2)

            except Exception:  # pylint: disable=broad-except
                if self.config.die_on_tool_error:
                    raise
                else:
                    loc = Location(self.config.workdir, None, None, None, None)
                    msg = 'Tool %s failed to run (exception was raised)' % (
                        toolname, )
                    message = Message(
                        toolname,
                        'failure',
                        loc,
                        message=msg,
                    )
                    messages.append(message)

        messages = self.process_messages(found_files, messages)

        summary['message_count'] = len(messages)
        summary['completed'] = datetime.now()

        # Timedelta.total_seconds() is not available
        # on Python<=2.6 so we calculate it ourselves
        # See issue #60 and http://stackoverflow.com/a/3694895
        delta = (summary['completed'] - summary['started'])
        total_seconds = (delta.microseconds +
                         (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6
        summary['time_taken'] = '%0.2f' % total_seconds

        external_config = []
        for tool, configured_by in self.config.configured_by.items():
            if configured_by is not None:
                external_config.append((tool, configured_by))
        if len(external_config) > 0:
            summary['external_config'] = ', '.join(
                ['%s: %s' % info for info in external_config])

        self.summary = summary
        self.messages = self.messages + messages
Example #22
0
 def test_unrecognised_options(self):
     finder = find_python([], [], True, Path(__file__).parent.absolute())
     self.assertRaises(BadToolConfig,
                       self._get_config("mypy_bad_options").get_tools,
                       finder)
Example #23
0
    def execute(self):

        deprecated_names = self.config.replace_deprecated_tool_names()

        summary = {
            "started": datetime.now(),
        }
        summary.update(self.config.get_summary_information())

        found_files = find_python(
            self.config.ignores,
            self.config.paths,
            self.config.explicit_file_mode,
            self.config.workdir,
        )

        messages = []

        # see if any old tool names are run
        for deprecated_name in deprecated_names:
            loc = Location(self.config.workdir, None, None, None, None)
            new_name = DEPRECATED_TOOL_NAMES[deprecated_name]
            msg = (
                f"Tool {deprecated_name} has been renamed to {new_name}. "
                f"The old name {deprecated_name} is now deprecated and will be removed in Prospector 2.0. "
                f"Please update your prospector configuration.")

            message = Message(
                "prospector",
                "Deprecation",
                loc,
                message=msg,
            )
            messages.append(message)
            warnings.warn(msg, category=DeprecationWarning)

        # Run the tools
        for tool in self.config.get_tools(found_files):
            for name, cls in tools.TOOLS.items():
                if cls == tool.__class__:
                    toolname = name
                    break
            else:
                toolname = "Unknown"

            try:
                # Tools can output to stdout/stderr in unexpected places, for example,
                # pydocstyle emits warnings about __all__ and as pyroma exec's the setup.py
                # file, it will execute any print statements in that, etc etc...
                with CaptureOutput(
                        hide=not self.config.direct_tool_stdout) as capture:
                    messages += tool.run(found_files)

                    if self.config.include_tool_stdout:
                        loc = Location(self.config.workdir, None, None, None,
                                       None)

                        if capture.get_hidden_stderr():
                            msg = f"stderr from {toolname}:\n{capture.get_hidden_stderr()}"
                            messages.append(
                                Message(toolname,
                                        "hidden-output",
                                        loc,
                                        message=msg))
                        if capture.get_hidden_stdout():
                            msg = f"stdout from {toolname}:\n{capture.get_hidden_stdout()}"
                            messages.append(
                                Message(toolname,
                                        "hidden-output",
                                        loc,
                                        message=msg))

            except FatalProspectorException as fatal:
                sys.stderr.write(fatal.message)
                sys.exit(2)

            except Exception as ex:  # pylint:disable=broad-except
                if self.config.die_on_tool_error:
                    raise FatalProspectorException from ex

                loc = Location(self.config.workdir, None, None, None, None)
                msg = (
                    f"Tool {toolname} failed to run "
                    f"(exception was raised, re-run prospector with -X to see the stacktrace)"
                )
                message = Message(
                    toolname,
                    "failure",
                    loc,
                    message=msg,
                )
                messages.append(message)

        messages = self.process_messages(found_files, messages)

        summary["message_count"] = len(messages)
        summary["completed"] = datetime.now()

        # Timedelta.total_seconds() is not available
        # on Python<=2.6 so we calculate it ourselves
        # See issue #60 and http://stackoverflow.com/a/3694895
        delta = summary["completed"] - summary["started"]
        total_seconds = (delta.microseconds +
                         (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6
        summary["time_taken"] = "%0.2f" % total_seconds

        external_config = []
        for tool, configured_by in self.config.configured_by.items():
            if configured_by is not None:
                external_config.append((tool, configured_by))
        if len(external_config) > 0:
            summary["external_config"] = ", ".join(
                ["%s: %s" % info for info in external_config])

        self.summary = summary
        self.messages = self.messages + messages
Example #24
0
 def test_good_options(self):
     finder = find_python([], [], True, Path(__file__).parent.absolute())
     self._get_config("mypy_good_options").get_tools(finder)
Example #25
0
    def execute(self):

        summary = {
            'started': datetime.now(),
        }
        summary.update(self.config.get_summary_information())

        found_files = find_python(self.config.ignores, self.config.paths,
                                  self.config.explicit_file_mode,
                                  self.config.workdir)

        # Run the tools
        messages = []
        for tool in self.config.get_tools(found_files):
            try:
                messages += tool.run(found_files)
            except Exception:  # pylint: disable=broad-except
                if self.config.die_on_tool_error:
                    raise
                else:
                    for name, cls in tools.TOOLS.items():
                        if cls == tool.__class__:
                            toolname = name
                            break
                    else:
                        toolname = 'Unknown'

                    loc = Location(self.config.workdir, None, None, None, None)
                    msg = 'Tool %s failed to run (exception was raised)' % (
                        toolname, )
                    message = Message(
                        toolname,
                        'failure',
                        loc,
                        message=msg,
                    )
                    messages.append(message)

        messages = self.process_messages(found_files, messages)

        summary['message_count'] = len(messages)
        summary['completed'] = datetime.now()

        # Timedelta.total_seconds() is not available
        # on Python<=2.6 so we calculate it ourselves
        # See issue #60 and http://stackoverflow.com/a/3694895
        delta = (summary['completed'] - summary['started'])
        total_seconds = (delta.microseconds +
                         (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6
        summary['time_taken'] = '%0.2f' % total_seconds

        external_config = []
        for tool, configured_by in self.config.configured_by.items():
            if configured_by is not None:
                external_config.append((tool, configured_by))
        if len(external_config) > 0:
            summary['external_config'] = ', '.join(
                ['%s: %s' % info for info in external_config])

        self.summary = summary
        self.messages = messages