Esempio n. 1
0
class PEP8NotebookBear(LocalBear):
    LANGUAGES = {'Python', 'Python 2', 'Python 3'}
    REQUIREMENTS = {PipRequirement('autopep8', '1.2'),
                    PipRequirement('nbformat', '4.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/83333'
    CAN_FIX = {'Formatting'}

    def run(self, filename, file,
            max_line_length: int=79,
            indent_size: int=SpacingHelper.DEFAULT_TAB_WIDTH,
            pep_ignore: typed_list(str)=(),
            pep_select: typed_list(str)=(),
            local_pep8_config: bool=False):
        """
        Detects and fixes PEP8 incompliant code in Jupyter Notebooks. This bear
        will not change functionality of the code in any way.

        :param max_line_length:   Maximum number of characters for a line.
        :param indent_size:       Number of spaces per indent level.
        :param pep_ignore:        A list of errors/warnings to ignore.
        :param pep_select:        A list of errors/warnings to exclusively
                                  apply.
        :param local_pep8_config: Set to true if autopep8 should use a config
                                  file as if run normally from this directory.
        """
        options = {'ignore': pep_ignore,
                   'select': pep_select,
                   'max_line_length': max_line_length,
                   'indent_size': indent_size}
        notebook_node = notebook_node_from_string_list(file)
        cells = notebook_node['cells']

        for cell in cells:
            if cell['cell_type'] != 'code':
                continue
            cell['source'] = autopep8_fix_code_cell(cell['source'],
                                                    local_pep8_config,
                                                    options)

        corrected = notebook_node_to_string_list(notebook_node)

        # If newline at eof in `file` but not in `corrected`, add
        # final newline character to `corrected` to make sure this difference
        # does not pop up in `diffs`.
        if file[-1].endswith('\n') and not corrected[-1].endswith('\n'):
            corrected[-1] += '\n'

        diffs = Diff.from_string_arrays(file, corrected).split_diff()

        for diff in diffs:
            yield Result(self,
                         'The code does not comply to PEP8.',
                         affected_code=(diff.range(filename),),
                         diffs={filename: diff})
Esempio n. 2
0
class PyUnusedCodeBear(LocalBear):
    LANGUAGES = {'Python', 'Python 2', 'Python 3'}
    REQUIREMENTS = {PipRequirement('autoflake', '0.6')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Unused Code'}

    def run(self, filename, file,
            remove_all_unused_imports: bool=False):
        """
        Detects unused code. By default this functionality is limited to:

        - Unneeded pass statements.
        - Unneeded builtin imports.

        :param remove_all_unused_imports:
            True removes all unused imports - might have side effects
        """

        corrected = autoflake.fix_code(
                       ''.join(file),
                       additional_imports=None,
                       remove_all_unused_imports=remove_all_unused_imports,
                       remove_unused_variables=True
                       ).splitlines(True)

        for diff in Diff.from_string_arrays(file, corrected).split_diff():
            yield Result(self,
                         'This file contains unused source code.',
                         affected_code=(diff.range(filename),),
                         diffs={filename: diff})
Esempio n. 3
0
class YAMLLintBear:
    """
    Check yaml code for errors and possible problems.

    You can read more about capabilities at
    <http://yamllint.readthedocs.org/en/latest/rules.html>.
    """

    LANGUAGES = {"YAML"}
    REQUIREMENTS = {PipRequirement('yamllint', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Formatting'}

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         yamllint_config: str = ''):
        """
        :param yamllint_config: Path to a custom configuration file.
        """
        args = ('-f', 'parsable', filename)
        if yamllint_config:
            args += ('--config=' + yamllint_config, )
        return args
Esempio n. 4
0
class RSTcheckBear:
    """
    Check syntax of ``reStructuredText`` and code blocks
    nested within it.

    Check <https://pypi.python.org/pypi/rstcheck> for more information.
    """

    LANGUAGES = {'reStructuredText'}
    REQUIREMENTS = {PipRequirement('rstcheck', '2.2')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Syntax'}
    ASCIINEMA_URL = 'https://asciinema.org/a/8ntlaqubk2qkrn9mm0dh07rlk?speed=2'

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         code_block_language_ignore: list = ()):
        """
        :param code_block_language_ignore:
            Comma seperated list for languages of which code blocks
            should be ignored. Code block of following languages
            can be detected: ``bash``, ``c``, ``cpp``, ``json``,
            ``python``, ``rst``.
        """
        args = ()
        if code_block_language_ignore:
            args = ('--ignore-language=' +
                    ','.join(code_block_language_ignore), )
        return args + (filename, )
Esempio n. 5
0
class SpellCheckBear:
    """
    Lints files to check for incorrect spellings using ``scspell``.

    scspell is a spell checker for source code.
    When applied to a code written in most popular programming languages
    while using most typical naming conventions, this algorithm will
    usually catch many errors without an annoying false positive rate.

    In an effort to catch more spelling errors, scspell is able to
    check each file against a set of dictionary words selected
    specifically for that file.

    See <https://pypi.python.org/pypi/scspell3k> for more information.
    """
    LANGUAGES = {'Natural Language'}
    REQUIREMENTS = {PipRequirement('scspell3k', '2.0')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/87753'
    CAN_DETECT = {'Spelling'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '--report-only', filename
Esempio n. 6
0
class reSTLintBear(LocalBear):
    LANGUAGES = {'reStructuredText'}
    REQUIREMENTS = {PipRequirement('restructuredtext_lint', '0.17')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Syntax'}

    def run(self, filename, file):
        """
        Lints reStructuredText.
        """
        content = ''.join(file)
        errors = lint(content)

        for error in errors:
            severity = {
                1: RESULT_SEVERITY.INFO,
                2: RESULT_SEVERITY.NORMAL,
                3: RESULT_SEVERITY.MAJOR,
                4: RESULT_SEVERITY.MAJOR}.get(error.level,
                                              RESULT_SEVERITY.NORMAL)
            yield Result.from_values(
                self,
                error.message,
                file=filename,
                line=error.line,
                debug_msg=error.full_message,
                severity=severity)
Esempio n. 7
0
class CMakeLintBear:
    """
    Check CMake code for syntactical or formatting issues.

    For more information consult <https://github.com/richq/cmake-lint>.
    """
    LANGUAGES = {'CMake'}
    REQUIREMENTS = {PipRequirement('cmakelint', '1.3')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Formatting'}

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         cmakelint_config: path = ''):
        """
        :param cmakelint_config: The location of the cmakelintrc config file.
        """
        args = ()
        if cmakelint_config:
            args += ('--config=' + cmakelint_config, )
        return args + (filename, )
Esempio n. 8
0
class LanguageToolBear(LocalBear):
    LANGUAGES = {"Natural Language"}
    REQUIREMENTS = {PipRequirement('guess-language-spirit', '0.5.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Spelling', 'Grammar'}

    @classmethod
    def check_prerequisites(cls):
        if shutil.which("java") is None:
            return "java is not installed."
        else:
            return True

    @deprecate_settings(language='locale')
    def run(self,
            filename,
            file,
            language: str='auto',
            languagetool_disable_rules: typed_list(str)=()):
        '''
        Checks the code with LanguageTool.

        :param language:                   A locale representing the language
                                           you want to have checked. If set to
                                           'auto' the language is guessed.
                                           If the language cannot be guessed,
                                           'en-US' is used.
        :param languagetool_disable_rules: List of rules to disable checks for.
        '''
        joined_text = "".join(file)
        language = (guess_language(joined_text)
                    if language == 'auto' else language)
        language = 'en-US' if not language else language

        tool = LanguageTool(language, motherTongue="en_US")
        tool.disabled.update(languagetool_disable_rules)

        matches = tool.check(joined_text)
        for match in matches:
            if not match.replacements:
                diffs = None
            else:
                replaced = correct(joined_text, [match]).splitlines(True)
                diffs = {filename:
                         Diff.from_string_arrays(file, replaced)}

            rule_id = match.ruleId
            if match.subId is not None:
                rule_id += '[{}]'.format(match.subId)

            message = match.msg + ' (' + rule_id + ')'
            source_range = SourceRange.from_values(filename,
                                                   match.fromy+1,
                                                   match.fromx+1,
                                                   match.toy+1,
                                                   match.tox+1)
            yield Result(self, message, diffs=diffs,
                         affected_code=(source_range,))
Esempio n. 9
0
class CPPLintBear:
    """
    Check C++ code for Google's C++ style guide.

    For more information, consult <https://github.com/theandrewdavis/cpplint>.
    """

    LANGUAGES = {"C++"}
    REQUIREMENTS = {PipRequirement('cpplint', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting'}

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         max_line_length: int = 79,
                         cpplint_ignore: typed_list(str) = (),
                         cpplint_include: typed_list(str) = ()):
        """
        :param max_line_length: Maximum number of characters for a line.
        :param cpplint_ignore:  List of checkers to ignore.
        :param cpplint_include: List of checkers to explicitly enable.
        """
        ignore = ','.join('-' + part.strip() for part in cpplint_ignore)
        include = ','.join('+' + part.strip() for part in cpplint_include)
        return ('--filter=' + ignore + ',' + include,
                '--linelength=' + str(max_line_length), filename)
Esempio n. 10
0
class BanditBear:
    """
    Performs security analysis on Python source code, utilizing the ``ast``
    module from the Python standard library.
    """
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('bandit', '1.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Security'}

    @staticmethod
    def create_arguments(
        filename,
        file,
        config_file,
        bandit_skipped_tests: typed_list(str) = ('B105', 'B106', 'B107',
                                                 'B404', 'B603', 'B606',
                                                 'B607')):
        """
        :param bandit_skipped_tests:
            The IDs of the tests ``bandit`` shall not perform. You can get
            information about the available builtin codes at
            https://github.com/openstack/bandit#usage.
        """
        args = (filename, '-f', 'json')

        if bandit_skipped_tests:
            args += ('-s', ','.join(bandit_skipped_tests))

        return args

    severity_map = {
        'HIGH': RESULT_SEVERITY.MAJOR,
        'MEDIUM': RESULT_SEVERITY.NORMAL,
        'LOW': RESULT_SEVERITY.INFO
    }

    confidence_map = {'HIGH': 90, 'MEDIUM': 70, 'LOW': 50}

    def process_output(self, output, filename, file):
        output = json.loads(output)

        for error in output['errors']:
            yield Result.from_values(origin=self,
                                     file=filename,
                                     severity=RESULT_SEVERITY.MAJOR,
                                     message=error['reason'])

        for issue in output['results']:
            yield Result.from_values(
                origin=issue['test_id'],
                file=filename,
                message=issue['issue_text'],
                severity=self.severity_map[issue['issue_severity']],
                confidence=self.confidence_map[issue['issue_confidence']],
                line=issue['line_range'][0],
                end_line=issue['line_range'][-1])
Esempio n. 11
0
class ClangBear(LocalBear):
    LANGUAGES = {
        "C", "C++", "Objective-C", "Objective-C++", "OpenMP", "OpenCL", "CUDA"
    }
    REQUIREMENTS = {PipRequirement('libclang-py3', '0.2')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_FIX = {'Variable Misuse', 'Syntax'}

    check_prerequisites = classmethod(clang_available)

    def run(self, filename, file, clang_cli_options: typed_list(str) = None):
        """
        Check code for syntactical or semantical problems using Clang.

        This bear supports automatic fixes.

        :param clang_cli_options: Any options that will be passed through to
                                  Clang.
        """
        index = Index.create()
        diagnostics = index.parse(filename,
                                  args=clang_cli_options,
                                  unsaved_files=[(filename, ''.join(file))
                                                 ]).diagnostics
        for diag in diagnostics:
            severity = {
                0: RESULT_SEVERITY.INFO,
                1: RESULT_SEVERITY.INFO,
                2: RESULT_SEVERITY.NORMAL,
                3: RESULT_SEVERITY.MAJOR,
                4: RESULT_SEVERITY.MAJOR
            }.get(diag.severity)
            affected_code = tuple(
                SourceRange.from_clang_range(range) for range in diag.ranges)

            diffs = None
            fixits = list(diag.fixits)
            if len(fixits) > 0:
                # FIXME: coala doesn't support choice of diffs, for now
                # append first one only, often there's only one anyway
                diffs = {filename: Diff.from_clang_fixit(fixits[0], file)}

                # No affected code yet? Let's derive it from the fix!
                if len(affected_code) == 0:
                    affected_code = diffs[filename].affected_code(filename)

            # Still no affected code? Position is the best we can get...
            if len(affected_code) == 0 and diag.location.file is not None:
                affected_code = (SourceRange.from_values(
                    diag.location.file.name, diag.location.line,
                    diag.location.column), )

            yield Result(self,
                         diag.spelling,
                         severity=severity,
                         affected_code=affected_code,
                         diffs=diffs)
Esempio n. 12
0
class MypyBear:
    """
    Type-checks your Python files!

    Checks optional static typing using the mypy tool.
    See <http://mypy.readthedocs.io/en/latest/basics.html> for info on how to
    add static typing.
    """

    LANGUAGES = {'Python', 'Python 2', 'Python 3'}
    AUTHORS = {'Petr Viktorin'}
    REQUIREMENTS = {PipRequirement('mypy-lang', '0.4')}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/90736'

    # This detects typing errors, which is pretty unique -- it doesn't
    # make sense to add a category for it.
    CAN_DETECT = set()

    @add_param_docs(FLAG_MAP)
    def create_arguments(self,
                         filename,
                         file,
                         config_file,
                         language: str = 'Python 3',
                         python_version: str = None,
                         allow_untyped_functions: bool = True,
                         allow_untyped_calls: bool = True,
                         check_untyped_function_bodies: bool = False,
                         strict_optional: bool = False):
        """
        :param language:
            Set to ``Python`` or ``Python 3`` to check Python 3.x source.
            Use ``Python 2`` for Python 2.x.
        :param python_version:
            Set the specific Python version, e.g. ``3.5``.
        """
        args = ['-m', 'mypy']
        if language.lower() == 'python 2':
            args.append('--py2')
        elif language.lower() not in ('python 3', 'python'):
            # Ideally, this would fail the check, but there's no good
            # way to fail from create_arguments.
            # See https://github.com/coala-analyzer/coala/issues/2573
            self.err(
                'Language needs to be "Python", "Python 2" or "Python 3". '
                'Assuming Python 3.')
        if python_version:
            args.extend(['--python-version', python_version])
        loc = locals()
        args.extend(flag.arg for name, flag in FLAG_MAP.items()
                    if flag.want_flag(loc[name]))
        args.append(filename)
        return args
Esempio n. 13
0
class ProseLintBear:
    """
    Lints the file using ``proselint``.
    """
    LANGUAGES = {"Natural Language"}
    REQUIREMENTS = {PipRequirement('proselint', '0.3.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Spelling', 'Syntax', 'Formatting', 'Grammar'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 14
0
class YAMLLintBear:
    """
    Check yaml code for errors and possible problems.

    You can read more about capabilities at
    <http://yamllint.readthedocs.org/en/latest/rules.html>.
    """

    LANGUAGES = {"YAML"}
    REQUIREMENTS = {PipRequirement('yamllint', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Formatting'}

    @staticmethod
    def generate_config(filename, file, document_start: bool = False):
        """
        :param document_start:
            Use this rule to require or forbid the use of document start
            marker (---).
        """
        yamllint_configs = {
            'extends': 'default',
            'rules': {
                'document-start': {
                    'present': False
                }
            }
        }
        if document_start:
            yamllint_configs['rules']['document-start']['present'] = True

        return yaml.dump(yamllint_configs)

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         yamllint_config: str = ''):
        """
        :param yamllint_config: Path to a custom configuration file.
        """
        args = ('-f', 'parsable', filename)
        if yamllint_config:
            args += ('--config-file=' + yamllint_config, )
        else:
            args += ('--config-file=' + config_file, )
        return args
Esempio n. 15
0
class ProseLintBear:
    """
    Lints the file using `proselint <https://github.com/amperser/proselint>`__.
    Works only with English language text.
    """
    LANGUAGES = {'Natural Language'}
    REQUIREMENTS = {PipRequirement('proselint', '0.7')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Spelling', 'Syntax', 'Formatting', 'Grammar'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 16
0
class RadonBear(LocalBear):
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('radon', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Complexity'}

    def run(self,
            filename,
            file,
            radon_ranks_info: typed_list(str) = (),
            radon_ranks_normal: typed_list(str) = ('C', 'D'),
            radon_ranks_major: typed_list(str) = ('E', 'F')):
        """
        Uses radon to compute complexity of a given file.

        :param radon_ranks_info:   The ranks (given by radon) to
                                   treat as severity INFO.
        :param radon_ranks_normal: The ranks (given by radon) to
                                   treat as severity NORMAL.
        :param radon_ranks_major:  The ranks (given by radon) to
                                   treat as severity MAJOR.
        """
        severity_map = {
            RESULT_SEVERITY.INFO: radon_ranks_info,
            RESULT_SEVERITY.NORMAL: radon_ranks_normal,
            RESULT_SEVERITY.MAJOR: radon_ranks_major
        }
        for visitor in radon.complexity.cc_visit("".join(file)):
            rank = radon.complexity.cc_rank(visitor.complexity)
            severity = None
            for result_severity, rank_list in severity_map.items():
                if rank in rank_list:
                    severity = result_severity
            if severity is None:
                continue

            col = visitor.col_offset if visitor.col_offset else None
            visitor_range = SourceRange.from_values(filename, visitor.lineno,
                                                    col, visitor.endline)
            message = "{} has a cyclomatic complexity of {}".format(
                visitor.name, rank)

            yield Result(self,
                         message,
                         severity=severity,
                         affected_code=(visitor_range, ))
Esempio n. 17
0
class SpellCheckBear:
    """
    Lints files to check for incorrect spellings using ``scspell``.

    See <https://pypi.python.org/pypi/scspell> for more information.
    """
    LANGUAGES = {"Natural Language"}
    REQUIREMENTS = {PipRequirement('scspell3k', '2.0')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Spelling'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '--report-only', filename
Esempio n. 18
0
class PEP8Bear(LocalBear):
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('autopep8', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_FIX = {'Formatting'}

    @deprecate_settings(indent_size='tab_width')
    def run(self,
            filename,
            file,
            max_line_length: int = 79,
            indent_size: int = SpacingHelper.DEFAULT_TAB_WIDTH,
            pep_ignore: typed_list(str) = (),
            pep_select: typed_list(str) = (),
            local_pep8_config: bool = False):
        """
        Detects and fixes PEP8 incompliant code. This bear will not change
        functionality of the code in any way.

        :param max_line_length:   Maximum number of characters for a line.
        :param indent_size:       Number of spaces per indentation level.
        :param pep_ignore:        A list of errors/warnings to ignore.
        :param pep_select:        A list of errors/warnings to exclusively
                                  apply.
        :param local_pep8_config: Set to true if autopep8 should use a config
                                  file as if run normally from this directory.
        """
        options = {
            "ignore": pep_ignore,
            "select": pep_select,
            "max_line_length": max_line_length,
            "indent_size": indent_size
        }

        corrected = autopep8.fix_code(''.join(file),
                                      apply_config=local_pep8_config,
                                      options=options).splitlines(True)

        diffs = Diff.from_string_arrays(file, corrected).split_diff()

        for diff in diffs:
            yield Result(self,
                         "The code does not comply to PEP8.",
                         affected_code=(diff.range(filename), ),
                         diffs={filename: diff})
Esempio n. 19
0
class PyFlakesBear:
    """
    Checks Python files for errors using ``pyflakes``.

    See https://github.com/PyCQA/pyflakes for more info.
    """
    LANGUAGES = {'Python', 'Python 3'}
    REQUIREMENTS = {PipRequirement('pyflakes', '1.3.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/92503'
    CAN_DETECT = {'Syntax', 'Unused Code', 'Undefined Element'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 20
0
class VultureBear:
    """
    Checks Python code for unused variables and functions using ``vulture``.

    See <https://bitbucket.org/jendrikseipp/vulture> for more information.
    """
    LANGUAGES = {"Python", "Python 3"}
    REQUIREMENTS = {PipRequirement('happiness', '0.10.0')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/82256'
    CAN_DETECT = {'Unused Code'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 21
0
class VintBear:
    """
    Check vimscript code for possible style problems.

    See <https://github.com/Kuniwak/vint> for more information.
    """

    LANGUAGES = {"VimScript"}
    REQUIREMENTS = {PipRequirement('vim-vint', '0.3.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 22
0
class PyLintBear:
    """
    Checks the code with pylint. This will run pylint over each file
    separately.
    """
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('pylint', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {
        'Unused Code', 'Formatting', 'Duplication', 'Security', 'Syntax'
    }

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         pylint_disable: typed_list(str) = None,
                         pylint_enable: typed_list(str) = None,
                         pylint_cli_options: str = "",
                         pylint_rcfile: str = ""):
        """
        :param pylint_disable:     Disable the message, report, category or
                                   checker with the given id(s).
        :param pylint_enable:      Enable the message, report, category or
                                   checker with the given id(s).
        :param pylint_cli_options: Any command line options you wish to be
                                   passed to pylint.
        :param pylint_rcfile:      The rcfile for PyLint.
        """
        args = ('--reports=n', '--persistent=n',
                '--msg-template="L{line}C{column}: {msg_id} - {msg}"')
        if pylint_disable:
            args += ('--disable=' + ','.join(pylint_disable), )
        if pylint_enable:
            args += ('--enable=' + ','.join(pylint_enable), )
        if pylint_cli_options:
            args += tuple(shlex.split(pylint_cli_options))
        if pylint_rcfile:
            args += ('--rcfile=' + pylint_rcfile, )
        else:
            args += ('--rcfile=' + os.devnull, )

        return args + (filename, )
Esempio n. 23
0
class CPPCleanBear:
    """
    Find problems in C++ source code that slow down development in large code
    bases. This includes finding unused code, among other features.

    Read more about available routines at
    <https://github.com/myint/cppclean#features>.
    """

    LANGUAGES = {'C++'}
    REQUIREMENTS = {PipRequirement('cppclean', '0.12')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Smell', 'Unused Code', 'Security'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 24
0
class PyCommentedCodeBear(LocalBear):
    LANGUAGES = {'Python', 'Python 2', 'Python 3'}
    REQUIREMENTS = {PipRequirement('eradicate', '0.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Commented Code'}

    def run(self, filename, file):
        """
        Detects commented out source code in Python.
        """
        corrected = tuple(eradicate.filter_commented_out_code(''.join(file)))

        for diff in Diff.from_string_arrays(file, corrected).split_diff():
            yield Result(self,
                         'This file contains commented out source code.',
                         affected_code=(diff.range(filename), ),
                         diffs={filename: diff})
Esempio n. 25
0
class PycodestyleBear:
    """
    A wrapper for the tool ``pycodestyle`` formerly known as ``pep8``.
    """
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('pycodestyle')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting'}

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         pycodestyle_ignore: str = "",
                         pycodestyle_select: str = "",
                         max_line_length: int = 79):
        """
        :param pycodestyle_ignore:
            Comma separated list of errors to ignore.
            See ``pydocstyle`` documentation for a complete list of errors.
        :param pycodestyle_select:
            Comma separated list of errors to detect. If given only
            these errors are going to be detected.
            See ``pydocstyle`` documentation for a complete list of errors.
        :param max_line_length:
            Limit lines to this length.
        """
        arguments = [r"--format='%(row)d %(col)d %(code)s %(text)s'"]

        if pycodestyle_ignore:
            arguments.append("--ignore=" + pycodestyle_ignore)

        if pycodestyle_select:
            arguments.append("--select=" + pycodestyle_select)

        arguments.append("--max-line-length=" + str(max_line_length))

        arguments.append(filename)

        return arguments
Esempio n. 26
0
class PyDocStyleBear(LocalBear, Lint):
    executable = 'pydocstyle'
    output_regex = r'(.*\.py):(?P<line>\d+) (.+):\n\s+(?P<message>.*)'
    use_stderr = True
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('pydocstyle', '1.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Documentation'}

    def run(self,
            filename,
            file,
            pydocstyle_select: typed_list(str) = (),
            pydocstyle_ignore: typed_list(str) = ()):
        '''
        Checks python docstrings.

        :param pydocstyle_select:      List of checked errors by specifying
                                       which errors to check for.
        :param pydocstyle_ignore:      List of checked errors by specifying
                                       which errors to ignore.

        Note: pydocstyle_select and pydocstyle_ignore are mutually exclusive.
              They cannot be used together.

        '''
        self.arguments = '{filename}'
        if pydocstyle_ignore and pydocstyle_select:
            self.err("The arguments pydocstyle_select and pydocstyle_ignore "
                     "are both given but mutually exclusive.")
            return
        elif pydocstyle_ignore:
            ignore = ','.join(part.strip() for part in pydocstyle_ignore)
            self.arguments += " --ignore={}".format(ignore)
        elif pydocstyle_select:
            select = ','.join(part.strip() for part in pydocstyle_select)
            self.arguments += " --select={} ".format(select)
        return self.lint(filename, file)
Esempio n. 27
0
class PyUnusedCodeBear(LocalBear):
    LANGUAGES = {"Python", "Python 2", "Python 3"}
    REQUIREMENTS = {PipRequirement('autoflake', '0.6.*')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Unused Code'}

    def run(self, filename, file):
        """
        Detects unused code. This functionality is limited to:

        - Unneeded pass statements.
        - Unneeded builtin imports. (Others might have side effects.)
        """
        corrected = autoflake.fix_code(''.join(file)).splitlines(True)

        for diff in Diff.from_string_arrays(file, corrected).split_diff():
            yield Result(self,
                         "This file contains unused source code.",
                         affected_code=(diff.range(filename),),
                         diffs={filename: diff})
Esempio n. 28
0
class PyDocStyleBear:
    """
    Checks python docstrings.
    """
    LANGUAGES = {'Python', 'Python 2', 'Python 3'}
    REQUIREMENTS = {PipRequirement('pydocstyle', '1.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Documentation'}

    def create_arguments(self,
                         filename,
                         file,
                         config_file,
                         pydocstyle_select: typed_list(str) = (),
                         pydocstyle_ignore: typed_list(str) = ()):
        """
        :param pydocstyle_select:
            List of checked errors by specifying which errors to check for.
            Can't be used together with ``pydocstyle_ignore``.
        :param pydocstyle_ignore:
            List of checked errors by specifying which errors to ignore. Can't
            be used together with ``pydocstyle_select``.
        """
        args = (filename, )
        if pydocstyle_ignore and pydocstyle_select:
            self.err('The arguments pydocstyle_select and pydocstyle_ignore '
                     'are both given but mutually exclusive.')
            return
        elif pydocstyle_ignore:
            ignore = ','.join(part.strip() for part in pydocstyle_ignore)
            args += ('--ignore=' + ignore, )
        elif pydocstyle_select:
            select = ','.join(part.strip() for part in pydocstyle_select)
            args += ('--select=' + select, )

        return args
Esempio n. 29
0
class VultureBear(GlobalBear):
    LANGUAGES = {'Python', 'Python 3'}
    REQUIREMENTS = {PipRequirement('vulture', '0.10.0')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/82256'
    CAN_DETECT = {'Unused Code'}

    EXECUTABLE = 'vulture'
    OUTPUT_REGEX = re.compile(
        r'(?P<filename>.*):(?P<line>.*):\s*(?P<message>.*)')

    @classmethod
    def check_prerequisites(cls):
        return ('Vulture is missing. Make sure to install it using '
                '`pip3 install vulture`.'
                if which('vulture') is None else True)

    def run(self):
        """
        Check Python code for unused variables and functions using `vulture`.

        See <https://bitbucket.org/jendrikseipp/vulture> for more information.
        """
        stdout_output, _ = run_shell_command(
            (self.EXECUTABLE,) +
            tuple(filename for filename in self.file_dict.keys()),
            cwd=self.get_config_dir())

        for match in re.finditer(self.OUTPUT_REGEX, stdout_output):
            groups = match.groupdict()
            yield Result.from_values(origin=self,
                                     message=groups['message'],
                                     file=groups['filename'],
                                     line=int(groups['line']))
Esempio n. 30
0
class HTMLLintBear:
    """
    Check HTML source code for invalid or misformatted code.

    See also <https://pypi.python.org/pypi/html-linter>.
    """

    _html_lint = which('html_lint.py')

    LANGUAGES = {'HTML'}
    REQUIREMENTS = {PipRequirement('html-linter', '0.3')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Formatting'}

    @staticmethod
    def create_arguments(filename, file, config_file,
                         htmllint_ignore: typed_list(str)=()):
        """
        :param htmllint_ignore: List of checkers to ignore.
        """
        ignore = ','.join(part.strip() for part in htmllint_ignore)
        return HTMLLintBear._html_lint, '--disable=' + ignore, filename