def get_pylint_bin(settings_obj): """ returns a valid, runnable path to pylint, and its LooseVersion """ # settings_obj = sublime.load_settings("Pylint.sublime-settings") ver = None pylint_bin = multiconf.get(settings_obj, "pylint_bin", None) # umm, why is this /usr/bin/python, yet the autodiscover below works?? # print("!!", sub.check_output(["python", "--version"], stderr=sub.STDOUT)) # test that the pylint_bin path is good and check its version if pylint_bin is not None: try: ver = sub.check_output([pylint_bin, "--version"]).decode() ver = LooseVersion(re.search(r"([0-9]+\.?)+", ver).group()) if ver < MIN_PYLINT_VERSION: print("Pylint: pylint_bin version <", MIN_PYLINT_VERSION, ", trying autodiscover [", pylint_bin, "]") pylint_bin = None except (OSError, sub.CalledProcessError): print("Pylint: pylint_bin not found, trying autodiscover [", pylint_bin, "]") pylint_bin = None # of no pylint_bin or it's not a good version, try autodiscovering if pylint_bin is None: cmd = "from __future__ import print_function;" \ "import pylint; " \ "print(pylint.__path__[0])" try: python_bin = multiconf.get(settings_obj, "python_bin", "python") print("Pylint: using python [", python_bin, "]") module_path = sub.check_output([python_bin, "-c", cmd]).decode() pylint_bin = os.path.normpath(os.path.join( module_path, '..', '..', '..', '..', 'bin', 'pylint')) # check the version on the autodiscovered pylint ver = sub.check_output([pylint_bin, "--version"]).decode() ver = LooseVersion(re.search(r"([0-9]+\.?)+", ver).group()) if ver < MIN_PYLINT_VERSION: print("Pylint: autodiscover failed; version <", MIN_PYLINT_VERSION, "[", pylint_bin, "]") pylint_bin = None except (OSError, sub.CalledProcessError) as e: print("Pylint: autodiscover failed;", str(e)) if python_bin is not None: which_python = sub.check_output(["which", python_bin]).decode() print("Pylint: maybe pylint isn't installed for ", which_python.strip()) if pylint_bin is None: print("Pylint: Could not find pylint :(") return None, None print("Pylint: using executable at [", pylint_bin, "]") return pylint_bin, ver
def run(self, view): if self.pylint_bin is None: print("No pylint >", MIN_PYLINT_VERSION, "accessable, not linting") return None window = view.window() fname = view.file_name() file_info = message_manager.FileInfoDict() if not window.id() in self.messages: self.messages[window.id()] = {} # make a lookup for the order of severity # sev_lookup = OrderedDict(zip(self.markers.keys(), itertools.count())) cmd = [self.pylint_bin, "-r", "no", "--msg-template", "{path}:{line}:{C}:{msg_id}:{symbol}:{msg}"] disable_msgs = multiconf.get(self.settings, "disable", None) if disable_msgs is not None: disable_msgs = ",".join(disable_msgs) cmd += ["-d", disable_msgs] extra_args = multiconf.get(self.settings, "extra_args", []) cmd += extra_args cmd.append(fname) p = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.PIPE) raw_stdout, raw_stderr = p.communicate() # check stderr for a bad lint run err = raw_stderr.decode() err_lines = [line for line in err.splitlines() if line and not line.startswith('Using config file')] if len(err_lines) > 0: print("*******************") print("Fatal pylint error:") print("------------------") print("{0}".format(err)) print("*******************") sublime.error_message("Fatal pylint error, check console for " "details") return None ignore = multiconf.get(self.settings, "ignore", []) ignore = [t.lower() for t in ignore] out = raw_stdout.decode() for line in out.strip().splitlines(): if line.startswith("*************"): continue # print(line) m = re.match(self._output_re, line) if m: d = m.groupdict() # print(d) line_num = int(d['line']) # - 1 if d['errid'].lower() not in ignore and d['symbol'] not in ignore: if not line_num in file_info: file_info[line_num] = [] msg = "{0}: {1}".format(d["errid"], d["msg"].strip()) err_info = message_manager.ErrorInfo(self, line_num, d["cat"], msg, extra=True, errid=d['errid'], symbol=d['symbol']) file_info[line_num].append(err_info) file_info[line_num].sort(key=attrgetter("order"), reverse=True) # self.messages[window.id()] = window_container self.messages[window.id()][fname] = file_info self.mark_errors(window, view)