def _buildResult(self, resultDict, leadingWS): """Convert a pycompile.py output resultDict to a KoILintResult. A pycompile.py dict looks like this: {'description': 'SyntaxError: invalid syntax', 'filename': 'foo.py', 'lineno': 1, 'offset': 8, # may be None 'severity': 'ERROR', 'text': 'asdf = \n'} """ r = KoLintResult() r.description = resultDict["description"] if leadingWS: resultDict['lineno'] -= 1 if resultDict['text'].startswith(leadingWS): resultDict['text'] = resultDict['text'][len(leadingWS):] if resultDict["offset"] is not None: if leadingWS: actualLineOffset = len(leadingWS) if resultDict['offset'] >= actualLineOffset: resultDict['offset'] -= actualLineOffset r.description += " (at column %d)" % resultDict["offset"] r.lineStart = resultDict['lineno'] r.lineEnd = resultDict['lineno'] # Would be nice to actually underline from teh given offset, but # then have to be smart abouve how far after that to underline. r.columnStart = 1 r.columnEnd = len(resultDict['text']) if resultDict['severity'] == "ERROR": r.severity = r.SEV_ERROR elif resultDict['severity'] == "WARNING": r.severity = r.SEV_WARNING return r
def _createAddResult(self, results, datalines, errorType, lineNo, desc, numDots): # build lint result object result = KoLintResult() if lineNo >= len(datalines): lineNo = len(datalines) - 1 # if the error is on the last line, work back to the last # character of the first nonblank line so we can display # the error somewhere while lineNo >= 0 and not datalines[lineNo]: lineNo -= 1 if lineNo < 0: return result.columnEnd = len(datalines[lineNo - 1]) + 1 result.columnStart = 1 lineNo += 1 else: if numDots is None: result.columnStart = 1 else: result.columnStart = numDots + 1 result.columnEnd = result.columnStart + 1 result.lineStart = lineNo result.lineEnd = lineNo if (errorType.lower().find('warning') >= 0): result.severity = result.SEV_WARNING else: result.severity = result.SEV_ERROR # This always results in a lint result spanning a single # character, which, given the squiggly reporting scheme is # almost invisible. Workaround: set the result to be the # whole line and append the column number to the description. result.description = "%s: %s (on column %d)" % (errorType,desc,result.columnStart) result.columnStart = 1 result.columnEnd = len(datalines[lineNo-1])+1 results.addResult(result)
def lint_with_text(self, request, text): if not text.strip(): return None cwd = request.cwd env = koprocessutils.getUserEnv() settingsDir = env.get("DJANGO_SETTINGS_MODULE", None) if not settingsDir: settingsDir = self._getSettingsDir(cwd) if settingsDir: # Save the current buffer to a temporary file. tmpFileName = tempfile.mktemp() fout = open(tmpFileName, 'wb') try: fout.write(text) fout.close() #XXX: How to tell whether we're using Python or Python3? prefName = "pythonExtraPaths" pythonPath = request.prefset.getString(prefName, "") pythonPathEnv = env.get("PYTHONPATH", "") if pythonPathEnv: if pythonPath: pythonPath += os.pathsep + pythonPathEnv else: pythonPath = pythonPathEnv if pythonPath: if sys.platform.startswith("win"): pythonPath = pythonPath.replace('\\', '/') env["PYTHONPATH"] = pythonPath elif env.has_key("PYTHONPATH"): del env["PYTHONPATH"] results = koLintResults() pythonExe = self._pythonInfo.getExecutableFromDocument(request.koDoc) argv = [pythonExe, self._djangoLinterPath, tmpFileName, settingsDir] p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None) output, error = p.communicate() #log.debug("Django output: output:[%s], error:[%s]", output, error) retval = p.returncode finally: os.unlink(tmpFileName) if retval == 1: if error: results.addResult(self._buildResult(text, error)) else: results.addResult(self._buildResult(text, "Unexpected error")) else: result = KoLintResult() result.lineStart = 1 result.lineEnd = 1 result.columnStart = 1 result.columnEnd = 1 + len(text.splitlines(1)[0]) result.description = "Can't find settings.py for this Django file" result.encodedDescription = result.description result.severity = result.SEV_ERROR results = koLintResults() results.addResult(result) return results
def _addMixedEOLWarnings(self, results, content, expectedEOL): """Add lint results (at the WARNING level) for each line that has an unexpected EOL. "results" in a koILintResults to which to add mixed EOL results. "content" is the content to analyze "expectedEOL" is the currently configured EOL for the document, this must be on of the EOL_LF, EOL_CR, EOL_CRLF constants. """ import eollib mixedEOLs = eollib.getMixedEOLLineNumbers(content, expectedEOL) if not mixedEOLs: return def collapseContinuousLineNumbers(lineNos): """Return a collapsed group of continuous line numbers.""" results = [] start = -10 last = -10 for lineNo in lineNos: if lineNo == last + 1: pass else: if start >= 0: results.append((start, last)) start = lineNo last = lineNo if start >= 0: results.append((start, last)) return results # Add a warning lint result for each such line. expectedEOLStr = eollib.eol2eolPref[expectedEOL] lines = content.splitlines(1) # For performance reasons, we collapse groups of continuous line # numbers into the one line result - bug 92733. for lineStart, lineEnd in collapseContinuousLineNumbers(mixedEOLs): r = KoLintResult() r.description = "This line does not end with the expected "\ "EOL: '%s' (select View | View EOL Markers)"\ % expectedEOLStr r.lineStart = lineStart + 1 r.lineEnd = lineEnd + 1 r.columnStart = 1 r.columnEnd = len(lines[lineEnd]) + 1 r.severity = r.SEV_WARNING results.addResult(r)
def _addMixedEOLWarnings(self, results, content, expectedEOL): """Add lint results (at the WARNING level) for each line that has an unexpected EOL. "results" in a koILintResults to which to add mixed EOL results. "content" is the content to analyze "expectedEOL" is the currently configured EOL for the document, this must be on of the EOL_LF, EOL_CR, EOL_CRLF constants. """ import eollib mixedEOLs = eollib.getMixedEOLLineNumbers(content, expectedEOL) if not mixedEOLs: return def collapseContinuousLineNumbers(lineNos): """Return a collapsed group of continuous line numbers.""" results = [] start = -10 last = -10 for lineNo in lineNos: if lineNo == last+1: pass else: if start >= 0: results.append((start, last)) start = lineNo last = lineNo if start >= 0: results.append((start, last)) return results # Add a warning lint result for each such line. expectedEOLStr = eollib.eol2eolPref[expectedEOL] lines = content.splitlines(1) # For performance reasons, we collapse groups of continuous line # numbers into the one line result - bug 92733. for lineStart, lineEnd in collapseContinuousLineNumbers(mixedEOLs): r = KoLintResult() r.description = "This line does not end with the expected "\ "EOL: '%s' (select View | View EOL Markers)"\ % expectedEOLStr r.lineStart = lineStart+1 r.lineEnd = lineEnd+1 r.columnStart = 1 r.columnEnd = len(lines[lineEnd]) + 1 r.severity = r.SEV_WARNING results.addResult(r)
indeces.append(index) offset = index + 1 log.debug("encoding errors at indeces %s", indeces) results = koLintResults() lines = content.splitlines(1) # keep line terminators offset = 0 # the current offset in the document for i in range(len(lines)): line = lines[i] while indeces and indeces[0] < offset + len(line): index = indeces.pop(0) # this index is on this line r = KoLintResult() r.description = "This character cannot be represented with "\ "the current encoding: '%s'"\ % encoding.python_encoding_name r.lineStart = i + 1 r.lineEnd = i + 1 r.columnStart = index - offset + 1 r.columnEnd = r.columnStart + 1 log.debug("encoding error: index=%d: %d,%d-%d,%d", index, r.lineStart, r.columnStart, r.lineEnd, r.columnEnd) r.severity = r.SEV_ERROR results.addResult(r) if not indeces: break offset += len(line) else: raise ValueError("Did not find line and column for one or " "more indeces in content: %s" % indeces) return results
indeces.append(index) offset = index + 1 log.debug("encoding errors at indeces %s", indeces) results = koLintResults() lines = content.splitlines(1) # keep line terminators offset = 0 # the current offset in the document for i in range(len(lines)): line = lines[i] while indeces and indeces[0] < offset + len(line): index = indeces.pop(0) # this index is on this line r = KoLintResult() r.description = "This character cannot be represented with "\ "the current encoding: '%s'"\ % encoding.python_encoding_name r.lineStart = i+1 r.lineEnd = i+1 r.columnStart = index - offset + 1 r.columnEnd = r.columnStart + 1 log.debug("encoding error: index=%d: %d,%d-%d,%d", index, r.lineStart, r.columnStart, r.lineEnd, r.columnEnd) r.severity = r.SEV_ERROR results.addResult(r) if not indeces: break offset += len(line) else: raise ValueError("Did not find line and column for one or " "more indeces in content: %s" % indeces) return results
def _TclPro_lint(self, lInput, lOutput): # TclPro output has the following header info: ################### #TclPro -- Version 1.4.1 #Copyright (C) Ajuba Solutions 1998-2001. All rights reserved. #This product is registered to: <user name> # #scanning: <filename> #checking: <filename> #<filename>:<lineNo> (<errorName>) <errorText> #<commandWithError> #<caret at col in command where error is> #[repeat above three until no more errors] ################### # The 'checking' line exists when the -onepass option isn't used i = 1 lastCol = -1 lastLine = -1 results = koLintResults() numLines = len(lOutput) while i < numLines: match = re.search(self._tclProRe, lOutput[i]) if not match: # We expect the first few lines to not match, while we # skip the header lines i += 1 # But if too many lines aren't matching, then we must have # unrecognizable input if i > 8: log.warn("couldn't recognize Tcl linter output format") break continue if i+2 >= numLines: log.error("unexpected return data format: short data") return cmd = lOutput[i+1].rstrip() col = lOutput[i+2].find('^') if col == -1: if i+3 == numLines: log.error("unexpected return data format: short data") return col = lOutput[i+3].find('^') if col == -1: log.warn("No column indicator following line %d:%r", i, lOutput[i]) i += 1 continue cmd = lOutput[i+2].rstrip() parseLineOffset = 1 else: parseLineOffset = 0 lineNo = match.group(1) # lInput is zero-based, whereas text display lines start at one, # so we adjust lineNo down one here. lineNo = int(lineNo) - 1 if lineNo != lastLine: lastLine = lineNo lastCol = 0 if col == -1: col = len(lInput[lineNo].rstrip()) startCol = lInput[lineNo].find(cmd, lastCol) if startCol == -1: # It's possible that we are throwing multiple warnings on # the same command. Let's check again, starting at col 0. # If something was found, ignore multiple warnings in the # same line, otherwise log a problem if lastCol == 0 or \ lInput[lineNo].find(cmd, 0) == -1: # Looks like we can't figure something out... log.debug('undecipherable lint output: %s,%s "%s" in "%s" last %s' \ % (lineNo+1, col, cmd, lInput[lineNo], lastCol)) i += parseLineOffset + 3 continue #print 'TclLint: %s,%s "%s" in "%s"' \ # % (lineNo+1, startCol, cmd, lInput[lineNo]) result = KoLintResult() msg = match.group(2) result.description = match.group(3).strip() result.lineStart = lineNo+1 # All our warnings stay on one line result.lineEnd = result.lineStart cmdLen = len(cmd) if msg.startswith("warn") or msg.startswith("nonPort"): result.severity = result.SEV_WARNING # In the warning case, go to the next char that we think # ends the word (not precise), starting at the caret. endCol = col while endCol < cmdLen and cmd[endCol] not in endWordSet: # might want to handle \ escapes endCol += 1 # readjust for where the command started endCol += startCol # and bump up the startCol to where the caret indicated startCol += col else: result.severity = result.SEV_ERROR # In the error case, highlight the entire command # The linter should only give one error per command endCol = startCol + cmdLen # Adjust by 1 as columns start at 1 for the text display result.columnStart = startCol + 1 result.columnEnd = endCol + 1 results.addResult(result) # Set lastCol to properly handle multiple similar code-blocks # with errors on the same line. lastCol = startCol+1 i += 3 # end while return results
def PerlWarnsToLintResults(warns, perlfilename, actualFileName, perlcode): perllines = perlcode.split('\n') # preprocess the perl warnings # - copy up '(Missing semicolon on previous line?)' to previous line # - remove 'perlfilename' #XXX it would be nice to find all hints and copy them up newwarns = [] for line in warns: # get rid if eols line = line[:-1] # handle multi-line string literals if newwarns and newwarns[-1] and newwarns[-1][-1] == "\r": #XXX we should print an EOL symbol newwarns[-1] = newwarns[-1][:-1] + '\r' + line ## this code is not handling hints correctly. In any case, hints make ## the error messages too long for the status bar #elif line.find('(Missing semicolon on previous line?)') != -1: # newwarns[-1] = newwarns[-1] + " " + line[1:] else: newline = line newwarns.append(newline) warns = newwarns results = [] if type(perlfilename) == unicode: perlfilename = perlfilename.encode('utf-8') escPerlName = re.escape(perlfilename) # Fix bug 96303 (again): Replace any runs of non-ascii characters with unescaped '.*' # The other parts of the filename do get escaped. perlfilename_ascii_parts = re.split(r'([^\x00-\x7f]+)', perlfilename) escaped_even_parts = [ re.escape(part) for part in perlfilename_ascii_parts[0::2] ] escPerlName = ".*?".join(escaped_even_parts) warnRe = re.compile( r'(?P<description>.*) at %s line (?P<lineNum>\d+)(?P<hint>.*)' % escPerlName) successRe = re.compile(r'%s syntax OK' % escPerlName) compilationFailedRe = re.compile(r'Compilation failed in require at %s' % escPerlName) compilationErrorsRe = re.compile(r'%s had compilation errors\.' % escPerlName) beginFailedRe = re.compile(r'BEGIN failed--compilation aborted') pendingLines = [] sawSyntaxOK = False sawSyntaxBad = False for warn in warns: if successRe.match(warn): sawSyntaxOK = True continue match = warnRe.search(warn) if match: if compilationFailedRe.match(warn) or beginFailedRe.match( warn) or compilationErrorsRe.match(warn): sawSyntaxBad = True if results: # Don't bother displaying this continue lineNum = int(match.group('lineNum')) varName = match.groupdict().get('varName', None) lr = KoLintResult() lr.description = _combineTextParts( pendingLines, match.group('description') + match.group('hint')).replace( perlfilename, actualFileName) pendingLines = [] while lr.description.endswith("\n"): lr.description = lr.description[:-1] lr.lineStart = lineNum lr.lineEnd = lineNum if varName: lr.columnStart = perllines[lr.lineStart - 1].find(varName) + 1 if lr.columnStart == -1: lr.columnEnd = -1 else: lr.columnEnd = lr.columnStart + len(varName) + 1 else: lr.columnStart = 1 lr.columnEnd = len(perllines[lr.lineStart - 1]) + 1 results.append(lr) else: pendingLines.append(warn) if pendingLines and results: results[-1].description = _combineTextParts( pendingLines, results[-1].description).replace(perlfilename, actualFileName) # XXX # # Whatever is caught by the next else block is (according to Aaron) additional information # re: the last error. It should be added to the lint warning, but isn't because the # status bar display isn't smart enough and it looks ugly. # Todo: 1) add the extra info to the lint description (possibly add a new attribute to LintResults # with this 'metadata' # 2) Update the status bar display and tooltip display to display the right info. # I'm commenting this block out because log.warn's impact speed. --david # # else: # if not (successRe.search(warn) or failureRe.search(warn)): # log.warn("Skipping Perl warning: %r", warn) # under some conditions, Perl will spit out messages after the # "syntax Ok", so check the entire output. if results: if sawSyntaxOK and not sawSyntaxBad: severity = KoLintResult.SEV_WARNING elif sawSyntaxBad and not sawSyntaxOK: severity = KoLintResult.SEV_ERROR elif successRe.search("\n".join(warns)): severity = KoLintResult.SEV_WARNING else: severity = KoLintResult.SEV_ERROR lintResults = koLintResults() for lr in results: lr.severity = severity lintResults.addResult(lr) return lintResults
def lint_with_text(self, request, text): if not text.strip(): return None cwd = request.cwd env = koprocessutils.getUserEnv() settingsDir = env.get("DJANGO_SETTINGS_MODULE", None) if not settingsDir: # Django wants to do something like "import project.settings", which # means "project/settings.py" needs to exist. First, try to find it. settingsDir = self._getSettingsDir(cwd) # Ultimately, Komodo's Django linter (djangoLinter.py) sets the # DJANGO_SETTINGS_MODULE env variable to be the basename of # "settingsDir", which needs to be a module in the PYTHONPATH (which # the linter will append the dirname of "settingsDir" to). Append # ".settings" so when Django tries to do something like # "import project.settings", it will behave as expected. settingsDir += ".settings" if settingsDir: # Save the current buffer to a temporary file. tmpFileName = tempfile.mktemp() fout = open(tmpFileName, 'wb') try: fout.write(text) fout.close() #XXX: How to tell whether we're using Python or Python3? prefName = "pythonExtraPaths" pythonPath = request.prefset.getString(prefName, "") pythonPathEnv = env.get("PYTHONPATH", "") if pythonPathEnv: if pythonPath: pythonPath += os.pathsep + pythonPathEnv else: pythonPath = pythonPathEnv if pythonPath: if sys.platform.startswith("win"): pythonPath = pythonPath.replace('\\', '/') env["PYTHONPATH"] = pythonPath elif env.has_key("PYTHONPATH"): del env["PYTHONPATH"] # First try to use Python2 to run the django linter. If django # is not found, use Python3 instead. results = koLintResults() pythonExe = self._pythonInfo.getExecutableFromDocument( request.koDoc) djangoLinterPath = self._djangoLinterPath if pythonExe: p = process.ProcessOpen([pythonExe, "-c", "import django"], env=env, stdin=None) output, error = p.communicate() #log.debug("Django output: output:[%s], error:[%s]", output, error) if error.find('ImportError:') >= 0 and \ self._python3Info.getExecutableFromDocument(request.koDoc): pythonExe = self._python3Info.getExecutableFromDocument( request.koDoc) djangoLinterPath = self._djangoLinter3Path else: pythonExe = self._python3Info.getExecutableFromDocument( request.koDoc) djangoLinterPath = self._djangoLinter3Path #log.debug("pythonExe = " + pythonExe) #log.debug("djangoLinterPath = " + djangoLinterPath) argv = [pythonExe, djangoLinterPath, tmpFileName, settingsDir] p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None) output, error = p.communicate() retval = p.returncode #log.debug("Django output: output:[%s], error:[%s], retval:%d", output, error) finally: os.unlink(tmpFileName) if error: results.addResult(self._buildResult(text, error)) elif retval != 0: results.addResult(self._buildResult(text, "Unexpected error")) else: result = KoLintResult() result.lineStart = 1 result.lineEnd = 1 result.columnStart = 1 result.columnEnd = 1 + len(text.splitlines(1)[0]) result.description = "Can't find settings.py for this Django file" result.encodedDescription = result.description result.severity = result.SEV_ERROR results = koLintResults() results.addResult(result) return results
def PerlWarnsToLintResults(warns, perlfilename, actualFileName, perlcode): perllines = perlcode.split('\n') # preprocess the perl warnings # - copy up '(Missing semicolon on previous line?)' to previous line # - remove 'perlfilename' #XXX it would be nice to find all hints and copy them up newwarns = [] for line in warns: # get rid if eols line = line[:-1] # handle multi-line string literals if newwarns and newwarns[-1] and newwarns[-1][-1] == "\r" : #XXX we should print an EOL symbol newwarns[-1] = newwarns[-1][:-1] + '\r' + line ## this code is not handling hints correctly. In any case, hints make ## the error messages too long for the status bar #elif line.find('(Missing semicolon on previous line?)') != -1: # newwarns[-1] = newwarns[-1] + " " + line[1:] else: newline = line newwarns.append(newline) warns = newwarns results = [] if type(perlfilename) == unicode: perlfilename = perlfilename.encode('utf-8') escPerlName = re.escape(perlfilename) # Fix bug 96303 (again): Replace any runs of non-ascii characters with unescaped '.*' # The other parts of the filename do get escaped. perlfilename_ascii_parts = re.split(r'([^\x00-\x7f]+)', perlfilename) escaped_even_parts = [re.escape(part) for part in perlfilename_ascii_parts[0::2]] escPerlName = ".*?".join(escaped_even_parts) warnRe = re.compile(r'(?P<description>.*) at %s line (?P<lineNum>\d+)(?P<hint>.*)' % escPerlName) successRe = re.compile(r'%s syntax OK' % escPerlName) compilationFailedRe = re.compile(r'Compilation failed in require at %s' % escPerlName) compilationErrorsRe = re.compile(r'%s had compilation errors\.' % escPerlName) beginFailedRe = re.compile(r'BEGIN failed--compilation aborted') pendingLines = [] sawSyntaxOK = False sawSyntaxBad = False for warn in warns: if successRe.match(warn): sawSyntaxOK = True continue match = warnRe.search(warn) if match: if compilationFailedRe.match(warn) or beginFailedRe.match(warn) or compilationErrorsRe.match(warn): sawSyntaxBad = True if results: # Don't bother displaying this continue lineNum = int(match.group('lineNum')) varName = match.groupdict().get('varName', None) lr = KoLintResult() lr.description = _combineTextParts(pendingLines, match.group('description') + match.group('hint')).replace(perlfilename, actualFileName) pendingLines = [] while lr.description.endswith("\n"): lr.description = lr.description[:-1] lr.lineStart = lineNum lr.lineEnd = lineNum if varName: lr.columnStart = perllines[lr.lineStart-1].find(varName) + 1 if lr.columnStart == -1: lr.columnEnd = -1 else: lr.columnEnd = lr.columnStart + len(varName) + 1 else: lr.columnStart = 1 lr.columnEnd = len(perllines[lr.lineStart-1]) + 1 results.append(lr) else: pendingLines.append(warn) if pendingLines and results: results[-1].description = _combineTextParts(pendingLines, results[-1].description).replace(perlfilename, actualFileName) # XXX # # Whatever is caught by the next else block is (according to Aaron) additional information # re: the last error. It should be added to the lint warning, but isn't because the # status bar display isn't smart enough and it looks ugly. # Todo: 1) add the extra info to the lint description (possibly add a new attribute to LintResults # with this 'metadata' # 2) Update the status bar display and tooltip display to display the right info. # I'm commenting this block out because log.warn's impact speed. --david # # else: # if not (successRe.search(warn) or failureRe.search(warn)): # log.warn("Skipping Perl warning: %r", warn) # under some conditions, Perl will spit out messages after the # "syntax Ok", so check the entire output. if results: if sawSyntaxOK and not sawSyntaxBad: severity = KoLintResult.SEV_WARNING elif sawSyntaxBad and not sawSyntaxOK: severity = KoLintResult.SEV_ERROR elif successRe.search("\n".join(warns)): severity = KoLintResult.SEV_WARNING else: severity = KoLintResult.SEV_ERROR lintResults = koLintResults() for lr in results: lr.severity = severity lintResults.addResult(lr) return lintResults
def lint_with_text(self, request, text): if not text.strip(): return None cwd = request.cwd env = koprocessutils.getUserEnv() settingsDir = env.get("DJANGO_SETTINGS_MODULE", None) if not settingsDir: # Django wants to do something like "import project.settings", which # means "project/settings.py" needs to exist. First, try to find it. settingsDir = self._getSettingsDir(cwd) # Ultimately, Komodo's Django linter (djangoLinter.py) sets the # DJANGO_SETTINGS_MODULE env variable to be the basename of # "settingsDir", which needs to be a module in the PYTHONPATH (which # the linter will append the dirname of "settingsDir" to). Append # ".settings" so when Django tries to do something like # "import project.settings", it will behave as expected. settingsDir += ".settings" if settingsDir: # Save the current buffer to a temporary file. tmpFileName = tempfile.mktemp() fout = open(tmpFileName, 'wb') try: fout.write(text) fout.close() #XXX: How to tell whether we're using Python or Python3? prefName = "pythonExtraPaths" pythonPath = request.prefset.getString(prefName, "") pythonPathEnv = env.get("PYTHONPATH", "") if pythonPathEnv: if pythonPath: pythonPath += os.pathsep + pythonPathEnv else: pythonPath = pythonPathEnv if pythonPath: if sys.platform.startswith("win"): pythonPath = pythonPath.replace('\\', '/') env["PYTHONPATH"] = pythonPath elif env.has_key("PYTHONPATH"): del env["PYTHONPATH"] # First try to use Python2 to run the django linter. If django # is not found, use Python3 instead. results = koLintResults() pythonExe = self._pythonInfo.getExecutableFromDocument(request.koDoc) djangoLinterPath = self._djangoLinterPath if pythonExe: p = process.ProcessOpen([pythonExe, "-c", "import django"], env=env, stdin=None) output, error = p.communicate() #log.debug("Django output: output:[%s], error:[%s]", output, error) if error.find('ImportError:') >= 0 and \ self._python3Info.getExecutableFromDocument(request.koDoc): pythonExe = self._python3Info.getExecutableFromDocument(request.koDoc) djangoLinterPath = self._djangoLinter3Path else: pythonExe = self._python3Info.getExecutableFromDocument(request.koDoc) djangoLinterPath = self._djangoLinter3Path #log.debug("pythonExe = " + pythonExe) #log.debug("djangoLinterPath = " + djangoLinterPath) argv = [pythonExe, djangoLinterPath, tmpFileName, settingsDir] p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None) output, error = p.communicate() retval = p.returncode #log.debug("Django output: output:[%s], error:[%s], retval:%d", output, error) finally: os.unlink(tmpFileName) if error: results.addResult(self._buildResult(text, error)) elif retval != 0: results.addResult(self._buildResult(text, "Unexpected error")) else: result = KoLintResult() result.lineStart = 1 result.lineEnd = 1 result.columnStart = 1 result.columnEnd = 1 + len(text.splitlines(1)[0]) result.description = "Can't find settings.py for this Django file" result.encodedDescription = result.description result.severity = result.SEV_ERROR results = koLintResults() results.addResult(result) return results