Beispiel #1
0
    def check(self, code, filename):
        """Run flake8 on code and return the output."""

        options = {
            'reporter': self.get_report()
        }

        type_map = {
            'select': [],
            'ignore': [],
            'builtins': '',
            'max-line-length': 0,
            'max-complexity': 0
        }

        self.build_options(options, type_map, transform=lambda s: s.replace('-', '_'))

        if persist.debug_mode():
            persist.printf('{} options: {}'.format(self.name, options))

        if self.pyflakes_checker_class is not None:
            # Reset the builtins to the initial value used by pyflakes.
            builtins = set(self.pyflakes_checker_module.builtin_vars).union(self.pyflakes_checker_module._MAGIC_GLOBALS)
            self.pyflakes_checker_class.builtIns = builtins

        linter = self.module.get_style_guide(**options)

        return linter.input_file(
            filename=os.path.basename(filename),
            lines=code.splitlines(keepends=True)
        )
    def run(self, cmd, code):
        """Check if file is 'lintable' and perform linting."""
        # It has to start with `"syntax_test"`
        # and has a specific first line, technically.
        # We only require one of each
        # (to also lint unsaved views).
        basename = os.path.basename(self.filename)
        if not basename or not basename.startswith("syntax_test"):
            # This actually gets reported by the test runner,
            # so we only check for an additionally qualifying file
            # if the filename check fails.
            first_line = code[:code.find("\n")]
            match = re.match(r'^(\S*) SYNTAX TEST "([^"]*)"', first_line)
            if not match:
                return

        # The syntax test runner only operates on resource files that the resource loader can load,
        # which must reside in a "Packages" folder
        # and has the restriction of only working on saved files.
        # Instead, we create a temporary file somewhere in the packages folder
        # and pass that.
        with _temporary_resource_file(code,
                                      prefix="syntax_test_") as resource_path:
            assertions, test_output_lines = sublime_api.run_syntax_test(
                resource_path)

        output = "\n".join(test_output_lines)
        if persist.debug_mode():
            persist.printf('{}: "{}" assertions: {}'.format(
                p_name, basename, assertions))
            # SublimeLinter internally already prints the output we return
            # persist.printf('{}: "{}" output: \n  {}'.format(p_name, basename,
            #                                                 "\n  ".join(test_output_lines)))

        return output
    def find_gopaths(self):
        """ search for potential GOPATHs. """
        # collect existing Go path info
        goroot = set(os.path.normpath(s) for s in os.environ.get('GOROOT', '').split(os.pathsep))
        gopath = set(os.path.normpath(s) for s in os.environ.get('GOPATH', '').split(os.pathsep))
        if '.' in gopath:
            gopath.remove('.')
        gopath = list(gopath)

        # search for potential GOPATHs upstream from filename
        # (reversed to ensure deepest path is first searched)
        dirparts = os.path.dirname(self.filename).split(os.sep)
        for i in range(len(dirparts) - 1, 1, -1):
            if dirparts[i].lower() != "src":
                continue
            p = os.path.normpath(os.sep.join(dirparts[:i]))
            if p not in goroot and p not in gopath:
                gopath.append(p)

        if persist.debug_mode():
            persist.printf("{}: {} {}".format(self.name,
                                              os.path.basename(self.filename or '<unsaved>'),
                                              "guessed GOPATH=" + os.pathsep.join(gopath)))

        return os.pathsep.join(gopath)
def _temporary_resource_file(text, prefix='', suffix=''):
    """Create a temporary file in ST's "resource" folder, using tempfile.mkstemp.

    Yields the relative resource path as a context manager
    and removes it when the scope is exited.

    Files are stored in a Temp folder relative to the Data folder,
    which is removed afterwards if it does not contain any other files.
    """
    import tempfile

    # Ensure the folder exists
    if not os.path.exists(_temp_path):
        os.mkdir(_temp_path)

    try:
        fd, temp_file_path = tempfile.mkstemp(prefix=prefix,
                                              suffix=suffix,
                                              dir=_temp_path)
        if persist.debug_mode():
            persist.printf("{}: created temporary file at {}".format(
                p_name, temp_file_path))

        try:
            with open(fd, 'w', encoding='utf-8') as f:
                f.write(text)
            temp_file_resource_path = "/".join(
                ["Packages", _temp_dir_name,
                 os.path.basename(temp_file_path)])
            yield temp_file_resource_path
        finally:
            os.remove(temp_file_path)
    except FileNotFoundError:
        _remove_temp_path()
    finally:
        # And remove the folder, if it's empty.
        # Otherwise wait for a "restart".
        try:
            os.rmdir(_temp_path)
        except OSError as e:
            if persist.debug_mode():
                persist.printf(
                    "{}: unable to delete temporary folder; {}".format(
                        p_name, e))
    def check(self, code, filename):
        """Run pycodestyle on code and return the output."""
        options = {'reporter': self.get_report()}

        type_map = {
            'select': [],
            'ignore': [],
            'max-line-length': 0,
            'max-complexity': 0
        }

        self.build_options(options,
                           type_map,
                           transform=lambda s: s.replace('-', '_'))

        final_options = options.copy()

        # Try to read options from pycodestyle default configuration files (.pycodestyle, tox.ini).
        # If present, they will override the ones defined by Sublime Linter's config.
        try:
            # `onError` will be called by `process_options` when no pycodestyle configuration file is found.
            # Override needed to supress OptionParser.error() output in the default parser.
            def onError(msg):
                pass

            from pycodestyle import process_options, get_parser
            parser = get_parser()
            parser.error = onError
            pycodestyle_options, _ = process_options([os.curdir],
                                                     True,
                                                     True,
                                                     parser=parser)

            # Merge options only if the pycodestyle config file actually exists;
            # pycodestyle always returns a config filename, even when it doesn't exist!
            if os.path.isfile(pycodestyle_options.config):
                pycodestyle_options = vars(pycodestyle_options)
                pycodestyle_options.pop('reporter', None)
                for opt_n, opt_v in pycodestyle_options.items():
                    if isinstance(final_options.get(opt_n, None), list):
                        final_options[opt_n] += opt_v
                    else:
                        final_options[opt_n] = opt_v
        except SystemExit:
            # Catch and ignore parser.error() when no config files are found.
            pass

        if persist.debug_mode():
            persist.printf('{} ST options: {}'.format(self.name, options))
            persist.printf('{} options: {}'.format(self.name, final_options))

        checker = self.module.StyleGuide(**final_options)

        return checker.input_file(filename=os.path.basename(filename),
                                  lines=code.splitlines(keepends=True))
Beispiel #6
0
    def check(self, code, filename):
        """Run pep8 on code and return the output."""
        options = {
            'reporter': self.get_report()
        }

        type_map = {
            'select': [],
            'ignore': [],
            'max-line-length': 0,
            'max-complexity': 0
        }

        self.build_options(options, type_map, transform=lambda s: s.replace('-', '_'))

        final_options = options.copy()

        # Try to read options from pep8 default configuration files (.pep8, tox.ini).
        # If present, they will override the ones defined by Sublime Linter's config.
        try:
            # `onError` will be called by `process_options` when no pep8 configuration file is found.
            # Override needed to supress OptionParser.error() output in the default parser.
            def onError(msg):
                pass

            from pep8 import process_options, get_parser
            parser = get_parser()
            parser.error = onError
            pep8_options, _ = process_options([os.curdir], True, True, parser=parser)

            # Merge options only if the pep8 config file actually exists;
            # pep8 always returns a config filename, even when it doesn't exist!
            if os.path.isfile(pep8_options.config):
                pep8_options = vars(pep8_options)
                pep8_options.pop('reporter', None)
                for opt_n, opt_v in pep8_options.items():
                    if isinstance(final_options.get(opt_n, None), list):
                        final_options[opt_n] += opt_v
                    else:
                        final_options[opt_n] = opt_v
        except SystemExit:
            # Catch and ignore parser.error() when no config files are found.
            pass

        if persist.debug_mode():
            persist.printf('{} ST options: {}'.format(self.name, options))
            persist.printf('{} options: {}'.format(self.name, final_options))

        checker = self.module.StyleGuide(**final_options)

        return checker.input_file(
            filename=os.path.basename(filename),
            lines=code.splitlines(keepends=True)
        )
    def run(self, cmd, code):
        """ transparently add potential GOPATHs before running. """
        self.env = {'GOPATH': self.find_gopaths()}

        # copy debug output from Linter.run()
        if persist.debug_mode():
            persist.printf('{}: {} {}'.format(self.name,
                                              os.path.basename(self.filename or '<unsaved>'),
                                              cmd or '<builtin>'))

        return self.tmpfile(cmd, code, suffix=self.get_tempfile_suffix())
    def check(self, code, filename):
        """Run frosted.check on code and return the output."""
        output = StringIO()
        Reporter = self.get_reporter()

        options = {
            'filename': filename,
            'reporter': Reporter(output, output),
            'verbose': True
        }

        type_map = {
            'ignore': []
        }

        transform = lambda s: self.__transform_options.get(s, s.replace('-', '_'))
        self.build_options(options, type_map, transform)

        if persist.debug_mode():
            persist.printf('{} options: {}'.format(self.name, options))

        self.module.check(code, **options)
        return output.getvalue()
Beispiel #9
0
    def run(self, cmd, code):
        """
        Search code for annotations, mark lines that contain them.

        We do the marking here since there is no point in searching
        the lines twice.

        We return nothing (None) to abort any further processing.

        """

        options = {}

        type_map = {'errors': [], 'warnings': []}

        self.build_options(options, type_map)

        for option in options:
            values = []

            for value in options[option]:
                if value:
                    # Add \b word separator fences around the value
                    # if it begins or ends with a word character.
                    value = re.escape(value)

                    if value[0].isalnum() or value[0] == '_':
                        value = r'\b' + value

                    if value[-1].isalnum() or value[-1] == '_':
                        value += r'\b'

                    values.append(value)

            options[option] = '|'.join(values)

        regex = re.compile(self.match_re.format_map(options))

        output = []

        for i, line in enumerate(code.splitlines()):
            match = regex.match(line)

            if match:
                col = match.start('message')
                word = match.group('error')
                message = match.group('message')

                if word:
                    error_type = highlight.ERROR
                else:
                    word = match.group('warning')
                    error_type = highlight.WARNING

                if persist.debug_mode():
                    output.append('line {}, col {}: {}'.format(
                        i + 1, col + 1, message))

                self.highlight.range(i,
                                     col,
                                     length=len(word),
                                     error_type=error_type)
                self.error(i, col, message, error_type)

        if output and persist.debug_mode():
            persist.printf('{}: {} output:\n{}'.format(
                self.name, os.path.basename(self.filename), '\n'.join(output)))
    def run(self, cmd, code):
        """
        Search code for annotations, mark lines that contain them.

        We do the marking here since there is no point in searching
        the lines twice.

        We return nothing (None) to abort any further processing.

        """

        options = {}

        type_map = {
            'errors': [],
            'warnings': []
        }

        self.build_options(options, type_map)

        for option in options:
            values = []

            for value in options[option]:
                if value:
                    # Add \b word separator fences around the value
                    # if it begins or ends with a word character.
                    value = re.escape(value)

                    if value[0].isalnum() or value[0] == '_':
                        value = r'\b' + value

                    if value[-1].isalnum() or value[-1] == '_':
                        value += r'\b'

                    values.append(value)

            options[option] = '|'.join(values)

        regex = re.compile(self.match_re.format_map(options))

        output = []

        for i, line in enumerate(code.splitlines()):
            match = regex.match(line)

            if match:
                col = match.start('message')
                word = match.group('error')
                message = match.group('message')

                if word:
                    error_type = highlight.ERROR
                else:
                    word = match.group('warning')
                    error_type = highlight.WARNING

                if persist.debug_mode():
                    output.append('line {}, col {}: {}'.format(i + 1, col + 1, message))

                self.highlight.range(i, col, length=len(word), error_type=error_type)
                self.error(i, col, message, error_type)

        if output and persist.debug_mode():
            persist.printf('{}: {} output:\n{}'.format(self.name, os.path.basename(self.filename), '\n'.join(output)))