/usr/share/pyshared/spyderlib/utils/codeanalysis.py is in python-spyderlib 2.1.9-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | # -*- coding: utf-8 -*-
#
# Copyright © 2011 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see spyderlib/__init__.py for details)
"""
Source code analysis utilities
"""
import sys
import re
import os
from subprocess import Popen, PIPE
import tempfile
# Local import
from spyderlib.utils import programs
#==============================================================================
# Pyflakes/pep8 code analysis
#==============================================================================
TASKS_PATTERN = r"(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP)( |:)([^#]*)"
#TODO: this is a test for the following function
def find_tasks(source_code):
"""Find tasks in source code (TODO, FIXME, XXX, ...)"""
results = []
for line, text in enumerate(source_code.splitlines()):
for todo in re.findall(TASKS_PATTERN, text):
results.append((todo[-1].strip().capitalize(), line+1))
return results
def check_with_pyflakes(source_code, filename=None):
"""Check source code with pyflakes
Returns an empty list if pyflakes is not installed"""
if filename is None:
filename = '<string>'
source_code += '\n'
import _ast
from pyflakes.checker import Checker
# First, compile into an AST and handle syntax errors.
try:
tree = compile(source_code, filename, "exec", _ast.PyCF_ONLY_AST)
except SyntaxError, value:
# If there's an encoding problem with the file, the text is None.
if value.text is None:
return []
else:
return [(value.args[0], value.lineno)]
else:
# Okay, it's syntactically valid. Now check it.
w = Checker(tree, filename)
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
results = []
lines = source_code.splitlines()
for warning in w.messages:
if 'analysis:ignore' not in lines[warning.lineno-1]:
results.append((warning.message % warning.message_args,
warning.lineno))
return results
# Required version: Why 0.5.0? Because it's based on _ast (thread-safe)
PYFLAKES_REQVER = '0.5.0'
def is_pyflakes_installed():
"""Return True if pyflakes required version is installed"""
return programs.is_module_installed('pyflakes', PYFLAKES_REQVER)
def get_checker_executable(name):
"""Return checker executable in the form of a list of arguments
for subprocess.Popen"""
if programs.is_program_installed(name):
# Checker is properly installed
return [name]
else:
path1 = programs.python_script_exists(package=None,
module=name+'_script')
path2 = programs.python_script_exists(package=None, module=name)
if path1 is not None: # checker_script.py is available
# Checker script is available but has not been installed
# (this may work with pyflakes)
return [sys.executable, path1]
elif path2 is not None: # checker.py is available
# Checker package is available but its script has not been
# installed (this works with pep8 but not with pyflakes)
return [sys.executable, path2]
def check(args, source_code, filename=None, options=None):
"""Check source code with checker defined with *args* (list)
Returns an empty list if checker is not installed"""
if args is None:
return []
if options is not None:
args += options
source_code += '\n'
if filename is None:
# Creating a temporary file because file does not exist yet
# or is not up-to-date
tempfd = tempfile.NamedTemporaryFile(suffix=".py", delete=False)
tempfd.write(source_code)
tempfd.close()
args.append(tempfd.name)
else:
args.append(filename)
output = Popen(args, stdout=PIPE, stderr=PIPE
).communicate()[0].strip().splitlines()
if filename is None:
os.unlink(tempfd.name)
results = []
lines = source_code.splitlines()
for line in output:
lineno = int(re.search(r'(\:[\d]+\:)', line).group()[1:-1])
if 'analysis:ignore' not in lines[lineno-1]:
message = line[line.find(': ')+2:]
results.append((message, lineno))
return results
def check_with_pep8(source_code, filename=None):
"""Check source code with pep8"""
args = get_checker_executable('pep8')
return check(args, source_code, filename=filename, options=['-r'])
if __name__ == '__main__':
fname = __file__
code = file(fname, 'U').read()
check_results = check_with_pyflakes(code, fname)+\
check_with_pep8(code, fname)+find_tasks(code)
for message, line in check_results:
print "Message: %s -- Line: %s" % (message, line)
|