[GRASS-SVN] r60678 - sandbox/wenzeslaus/gunittest
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Jun 2 20:51:54 PDT 2014
Author: wenzeslaus
Date: 2014-06-02 20:51:54 -0700 (Mon, 02 Jun 2014)
New Revision: 60678
Added:
sandbox/wenzeslaus/gunittest/grass_py_static_check.py
Log:
gunittest: script to run Python source code static analysis and generate a HTML report (first prototype)
Added: sandbox/wenzeslaus/gunittest/grass_py_static_check.py
===================================================================
--- sandbox/wenzeslaus/gunittest/grass_py_static_check.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/grass_py_static_check.py 2014-06-03 03:51:54 UTC (rev 60678)
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+#
+############################################################################
+#
+# MODULE: grass_py_static_check
+# AUTHOR(S): Vaclav Petras <wenzeslaus gmail com>
+# PURPOSE: Static source code analysis of Python code for GRASS GIS
+# COPYRIGHT: (C) 2014 by Vaclav Petras and the GRASS Development Team
+#
+# This program is free software under the GNU General Public
+# License (>=v2). Read the file COPYING that comes with GRASS
+# for details.
+#
+#############################################################################
+
+"""
+Can run only from the source code top level directory.
+"""
+
+import sys
+import os
+from subprocess import Popen, PIPE
+import re
+
+
+def ensure_dir(directory):
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+
+
+def pylint(target, output_dir):
+ cmd = ['pylint', '--rcfile=tools/pylintrc.txt', '--output-format=html',
+ '--ignore=.svn']
+ cmd = cmd + [target]
+ # result
+ ensure_dir(output_dir)
+ output_file = open(output_dir + '/pylint_report.html', 'w')
+ # Path to the directory where the persistent for the run will be stored.
+ env = os.environ.copy()
+ env['PYLINTHOME'] = output_dir
+ proc = Popen(cmd, stdout=output_file, env=env)
+ ret = proc.wait()
+ if ret == 32:
+ raise RuntimeError("pylint usage error")
+ elif ret & 1:
+ cmd = ['pylint', '--rcfile=tools/pylintrc.txt', '--ignore=.svn']
+ cmd = cmd + [target]
+ proc = Popen(cmd, stdout=PIPE, env=env)
+ stdout, stderr = proc.communicate()
+ pylint_status = "pylint fatal message was issued and prevented pytlint from working"
+ msg = "{target}: {stat}\n{o}".format(stat=pylint_status, target=target, o=stdout)
+ raise RuntimeError(msg)
+ return get_num_of_messages_from_pylint_file(output_dir + '/pylint_report.html')
+
+
+def pylint_errors(target, output_dir):
+ # this ignores rcfile?
+ cmd = ['pylint', '--errors-only', '--rcfile=tools/pylintrc.txt', '--output-format=html',
+ '--ignore=.svn']
+ cmd = cmd + [target]
+ # result
+ ensure_dir(output_dir)
+ output_file = open(output_dir + '/pylint_errors_report.html', 'w')
+ # Path to the directory where the persistent for the run will be stored.
+ env = os.environ.copy()
+ env['PYLINTHOME'] = output_dir
+ proc = Popen(cmd, stdout=output_file, env=env)
+ ret = proc.wait()
+ if ret == 32:
+ raise RuntimeError("pylint usage error")
+ elif ret & 1:
+ cmd = ['pylint', '--rcfile=tools/pylintrc.txt', '--ignore=.svn']
+ cmd = cmd + [target]
+ proc = Popen(cmd, stdout=PIPE, env=env)
+ stdout, stderr = proc.communicate()
+ pylint_status = "pylint fatal message was issued and prevented pytlint from working"
+ msg = "{target}: {stat}\n{o}".format(stat=pylint_status, target=target, o=stdout)
+ raise RuntimeError(msg)
+ return get_num_of_messages_from_pylint_file(output_dir + '/pylint_errors_report.html')
+
+
+def remove_absolute_path_from_pep8(txt_file):
+ txt = open(txt_file, 'r')
+ content = txt.read()
+ txt.close()
+
+ # this would need to be more sophisticated for being crossplatform
+ # and to be a general function
+ gisbase = os.environ['GISBASE']
+ assert gisbase
+ exp = re.compile('%s/?' % (gisbase))
+ content = exp.sub('', content)
+
+ txt = open(txt_file, 'w')
+ txt.write(content)
+ txt.close()
+
+
+def get_num_of_messages_from_pep8_file(txt_file):
+ count = 0
+ txt = open(txt_file, 'r')
+ exp = re.compile(r'^.+.py:[0-9]+: \[[EW][0-9]{1,3}\] .+$')
+ for line in txt.readlines():
+ if exp.match(line):
+ count += 1
+ txt.close()
+ return count
+
+
+def get_num_of_messages_from_pylint_file(html_file):
+ count = 0
+ txt = open(html_file, 'r')
+ exp = re.compile(r'<td>(error|warning|refactor|convention)</td>')
+ for line in txt.readlines():
+ if exp.match(line):
+ count += 1
+ #print count, line, re.template
+ txt.close()
+ return count
+
+
+def pep8txt_to_html(txt_file, html_file):
+ txt = open(txt_file, 'r')
+ html = open(html_file, 'w')
+ html.write('<html><body>')
+ html.write('<pre>')
+ html.write(txt.read())
+ html.write('</pre>')
+ html.write('</body></html>')
+ txt.close()
+ html.close()
+
+
+def pep8(target, output_dir):
+ cmd = ['pep8', '--config=tools/pep8config.txt', '--format=pylint']
+ cmd = cmd + [target]
+ # result
+ ensure_dir(output_dir)
+ output_file = open(output_dir + '/pep8_report.txt', 'w')
+ # Path to the directory where the persistent for the run will be stored.
+ env = os.environ.copy()
+ proc = Popen(cmd, stdout=output_file, env=env)
+ proc.wait()
+ # pep8 always returns 1 when some error occurred
+ output_file.close()
+ remove_absolute_path_from_pep8(output_dir + '/pep8_report.txt')
+ pep8txt_to_html(output_dir + '/pep8_report.txt', output_dir + '/pep8_report.html')
+ return get_num_of_messages_from_pep8_file(output_dir + '/pep8_report.txt')
+
+
+def main():
+ gisbase = os.environ['GISBASE']
+ ensure_dir('pylint_report')
+
+ main_index = open('pylint_report/index.html', 'w')
+
+ # a lot of special treatment is needed to get packages nicely shown
+
+ grass_packages = ['script', 'pygrass', 'temporal']
+ #, 'imaging', 'pydispatch', 'lib']
+ ensure_dir('pylint_report/grass')
+ index = open('pylint_report/grass/index.html', 'w')
+ for package in grass_packages:
+ num_pylint = pylint('grass.' + package, 'pylint_report/grass/' + package)
+ num_errors = pylint_errors('grass.' + package, 'pylint_report/grass/' + package)
+ num_pep8 = pep8(gisbase + '/etc/python/grass/' + package, 'pylint_report/grass/' + package)
+ index.write('{pkg}'.format(pkg=package))
+ index.write(' <a href="{pkg}/pylint_report.html">pylint</a> ({num})'.format(pkg=package, num=num_pylint))
+ index.write(' <a href="{pkg}/pylint_errors_report.html">pylint errors only</a> ({num})'.format(pkg=package, num=num_errors))
+ index.write(' <a href="{pkg}/pep8_report.html">pep8</a> ({num})<br>'.format(pkg=package, num=num_pep8))
+ index.close()
+ main_index.write('<a href="grass/index.html">grass</a><br>'.format(pkg=package))
+
+ dirlist = os.listdir(gisbase + '/gui/wxpython')
+ packages = []
+ directories = []
+ for f in dirlist:
+ if os.path.isdir('gui/wxpython/' + f):
+ if os.path.isfile('gui/wxpython/' + f + '/__init__.py'):
+ packages.append(f)
+ else:
+ directories.append(f)
+
+ # this is generated but not used
+ modules = [f for f in dirlist if f.endswith('.py')]
+ subdirs_with_modules = {}
+ for d in directories:
+ subdirlist = os.listdir(gisbase + '/gui/wxpython/' + d)
+ subdir_modules = [f for f in dirlist if os.path.isfile(gisbase + '/gui/wxpython/' + d + '/' + f) and f.endswith('.py')]
+ if subdir_modules:
+ subdirs_with_modules[d] = subdir_modules
+
+ grass_wxgui_package = ['gui']
+ ensure_dir('pylint_report/gui/wxpython')
+ gui_dir = gisbase + '/gui/wxpython/'
+ index = open('pylint_report/gui/wxpython/index.html', 'w')
+ for package in packages:
+ num_pylint = pylint(gui_dir + package, 'pylint_report/gui/wxpython/' + package)
+ num_errors = pylint_errors(gui_dir + package, 'pylint_report/gui/wxpython/' + package)
+ num_pep8 = pep8(gisbase + '/gui/wxpython/' + package, 'pylint_report/gui/wxpython/' + package)
+ index.write('{pkg}'.format(pkg=package))
+ index.write(' <a href="{pkg}/pylint_report.html">pylint</a> ({num})'.format(pkg=package, num=num_pylint))
+ index.write(' <a href="{pkg}/pylint_errors_report.html">pylint errors only</a> ({num})'.format(pkg=package, num=num_errors))
+ index.write(' <a href="{pkg}/pep8_report.html">pep8</a> ({num})<br>'.format(pkg=package, num=num_pep8))
+ index.close()
+ main_index.write('<a href="gui/wxpython/index.html">GRASS wxGUI</a><br>'.format(pkg=package))
+
+ #pylint(grass_wxgui_packages_path, 'pylint_report/gui/scripts')
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
Property changes on: sandbox/wenzeslaus/gunittest/grass_py_static_check.py
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
More information about the grass-commit
mailing list