From 6d4ae18c4efb555df27901af10ece4d0e03612df Mon Sep 17 00:00:00 2001 From: Akshit jain Date: Thu, 14 Mar 2019 22:52:55 +0530 Subject: [PATCH] Pycheckbear.py: Add new PyCheckBear New Bear is added to find bugs in python file. Closes https://github.com/coala/coala-bears/issues/2151 --- .ci/deps.apt.sh | 1 + .travis.yml | 1 + bears/python/PyCheckerBear.py | 40 +++++++++++++++ tests/python/PycheckerBearTest.py | 51 +++++++++++++++++++ tests/python/pychecker_test_files/__init__.py | 0 tests/python/pychecker_test_files/bad_file.py | 5 ++ .../python/pychecker_test_files/good_file.py | 5 ++ 7 files changed, 103 insertions(+) create mode 100644 bears/python/PyCheckerBear.py create mode 100644 tests/python/PycheckerBearTest.py create mode 100644 tests/python/pychecker_test_files/__init__.py create mode 100644 tests/python/pychecker_test_files/bad_file.py create mode 100644 tests/python/pychecker_test_files/good_file.py diff --git a/.ci/deps.apt.sh b/.ci/deps.apt.sh index ac2a6920e2..67eb7c3428 100755 --- a/.ci/deps.apt.sh +++ b/.ci/deps.apt.sh @@ -10,6 +10,7 @@ set -x export DEBIAN_FRONTEND=noninteractive deps="libclang1-3.4 astyle indent mono-mcs chktex r-base julia golang-go luarocks verilator cppcheck flawfinder devscripts mercurial" +deps="libclang1-3.4 indent mono-mcs chktex r-base julia golang-go luarocks verilator cppcheck flawfinder devscripts pychecker" deps_infer="m4 opam" case $CIRCLE_BUILD_IMAGE in diff --git a/.travis.yml b/.travis.yml index 9544d7517b..505defd763 100644 --- a/.travis.yml +++ b/.travis.yml @@ -129,6 +129,7 @@ addons: - php-codesniffer - r-base - verilator + - pychecker cache: pip: true diff --git a/bears/python/PyCheckerBear.py b/bears/python/PyCheckerBear.py new file mode 100644 index 0000000000..370d9706c9 --- /dev/null +++ b/bears/python/PyCheckerBear.py @@ -0,0 +1,40 @@ +import shlex + +from coalib.bearlib.abstractions.Linter import linter +from dependency_management.requirements.DistributionRequirement import ( + DistributionRequirement) + + +@linter(executable='pychecker', + output_format='regex', + output_regex=r'(?P\w+\.py):(?P\d+): ' + r'(?P.*)') +class PyCheckerBear: + """ + Find bugs in your Python source code. + The code for each function, class, and method is checked for possible + problems. Checks for unused globals and locals(module or variable), unused + method arguments and using a variable before setting it or if you are + redefining a function/class/method in the same scope. + """ + LANGUAGES = {'Python', 'Python 2', 'Python 3'} + REQUIREMENTS = {DistributionRequirement(apt_get='pychecker')} + AUTHORS = {'The coala developers'} + AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} + LICENSE = 'AGPL-3.0' + CAN_DETECT = {'Unused method/function arguments', + 'No doc string', 'Redefining'} + SEE_MORE = 'http://pychecker.sourceforge.net/' + + @staticmethod + def create_arguments(filename, file, config_file, + pychecker_cli_options: str = ''): + """ + :param pychecker_cli_options: Command line options you wish to be + passed to pychecker. + """ + args = () + if pychecker_cli_options: + args += tuple(shlex.split(pychecker_cli_options)) + + return args + (filename,) diff --git a/tests/python/PycheckerBearTest.py b/tests/python/PycheckerBearTest.py new file mode 100644 index 0000000000..361e488f65 --- /dev/null +++ b/tests/python/PycheckerBearTest.py @@ -0,0 +1,51 @@ +from queue import Queue +import os.path + +from coalib.settings.Section import Section +from coalib.results.Result import Result +from coalib.testing.LocalBearTestHelper import LocalBearTestHelper +from coalib.testing.BearTestHelper import generate_skip_decorator + +from bears.python.PyCheckerBear import PyCheckerBear + + +def get_testfile_path(file): + return os.path.join(os.path.dirname(__file__), + 'pychecker_test_files', file) + + +def load_testfiles(name): + with open(get_testfile_path(name)) as f1: + contents = f1.read().splitlines(True) + + return contents + + +@generate_skip_decorator(PyCheckerBear) +class PyCheckerBearTest(LocalBearTestHelper): + + def setUp(self): + self.uut = PyCheckerBear(Section('name'), Queue()) + self.good_file = get_testfile_path('good_file.py') + self.bad_file = get_testfile_path('bad_file.py') + self.maxDiff = None + + def test_good_file(self): + self.check_results(self.uut, load_testfiles('good_file.py'), + [], + self.good_file) + + def test_bad_file(self): + self.check_results(self.uut, load_testfiles('bad_file.py'), + [Result.from_values('PyCheckerBear', + 'Parameter (c) not used', + self.bad_file, + line=1)], + self.bad_file) + + def test_cli_options(self): + self.check_results(self.uut, load_testfiles('bad_file.py'), + [], + self.bad_file, + settings={'pychecker_cli_options': '--argsused=off'} + ) diff --git a/tests/python/pychecker_test_files/__init__.py b/tests/python/pychecker_test_files/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/python/pychecker_test_files/bad_file.py b/tests/python/pychecker_test_files/bad_file.py new file mode 100644 index 0000000000..27f8bd30a4 --- /dev/null +++ b/tests/python/pychecker_test_files/bad_file.py @@ -0,0 +1,5 @@ +def multiply(a, b, c): + return a * b + + +result = multiply(1, 2, 3) diff --git a/tests/python/pychecker_test_files/good_file.py b/tests/python/pychecker_test_files/good_file.py new file mode 100644 index 0000000000..fe90cdc26a --- /dev/null +++ b/tests/python/pychecker_test_files/good_file.py @@ -0,0 +1,5 @@ +def multiply(a, b, c): + return a * b * c + + +result = multiply(1, 2, 3)