Back to index

moin  1.9.0~rc2
test_sourcecode.py
Go to the documentation of this file.
00001 """
00002 Verify that the MoinMoin source files conform (mostly) to PEP8 coding style.
00003 
00004 Additionally, we check that the files have no crlf (Windows style) line endings.
00005 
00006 @copyright: 2006 by Armin Rigo (originally only testing for tab chars),
00007             2007 adapted and extended (calling the PEP8 checker for most stuff) by MoinMoin:ThomasWaldmann.
00008 @license: MIT licensed
00009 """
00010 
00011 import os, re, time, stat
00012 
00013 import pep8
00014 
00015 from MoinMoin.conftest import moindir
00016 
00017 ROOT = str(moindir)
00018 
00019 EXCLUDE = [
00020     '/contrib/DesktopEdition/setup_py2exe.py', # has crlf
00021     '/contrib/TWikiDrawPlugin', # 3rd party java stuff
00022     '/contrib/flup-server', # 3rd party WSGI adapters
00023     '/MoinMoin/support', # 3rd party libs or non-broken stdlib stuff
00024     '/MoinMoin/web/static/htdocs', # this is our dist static stuff
00025     '/tests/wiki', # this is our test wiki
00026     '/wiki/data/pages', # wiki pages, there may be .py attachments
00027 ]
00028 
00029 TRAILING_SPACES = 'nochange' # 'nochange' or 'fix'
00030                              # use 'fix' with extreme caution and in a separate changeset!
00031 FIX_TS_RE = re.compile(r' +$', re.M) # 'fix' mode: everything matching the trailing space re will be removed
00032 
00033 try:
00034     import xattr
00035     if not hasattr(xattr, "xattr"): # there seem to be multiple modules with that name
00036         raise ImportError
00037     def mark_file_ok(path, mtime):
00038         x = xattr.xattr(path)
00039         try:
00040             x.set('user.moin-pep8-tested-mtime', '%d' % mtime)
00041         except IOError:
00042             # probably not supported
00043             mark_file_ok = lambda path, mtime: None
00044 
00045     def should_check_file(path, mtime):
00046         x = xattr.xattr(path)
00047         try:
00048             mt = x.get('user.moin-pep8-tested-mtime')
00049             mt = long(mt)
00050             return mtime > mt
00051         except IOError:
00052             # probably not supported
00053             should_check_file = lambda path, mtime: True
00054         return True
00055 except ImportError:
00056     def mark_file_ok(path, mtime):
00057         pass
00058     def should_check_file(path, mtime):
00059         return True
00060 
00061 RECENTLY = time.time() - 7 * 24*60*60 # we only check stuff touched recently.
00062 #RECENTLY = 0 # check everything!
00063 
00064 # After doing a fresh clone, this procedure is recommended:
00065 # 1. Run the tests once to see if everything is OK (as cloning updates the mtime,
00066 #    it will test every file).
00067 # 2. Before starting to make new changes, use "touch" to change all timestamps
00068 #    to a time before <RECENTLY>.
00069 # 3. Regularly run the tests, they will run much faster now.
00070 
00071 def pep8_error_count(path):
00072     # process_options initializes some data structures and MUST be called before each Checker().check_all()
00073     pep8.process_options(['pep8', '--ignore=E202,E221,E222,E241,E301,E302,E401,E501,E701,W391,W601,W602', '--show-source', 'dummy_path'])
00074     error_count = pep8.Checker(path).check_all()
00075     return error_count
00076 
00077 def check_py_file(reldir, path, mtime):
00078     if TRAILING_SPACES == 'fix':
00079         f = file(path, 'rb')
00080         data = f.read()
00081         f.close()
00082         fixed = FIX_TS_RE.sub('', data)
00083 
00084         # Don't write files if there's no need for that,
00085         # as altering timestamps can be annoying with some tools.
00086         if fixed == data:
00087             return
00088 
00089         f = file(path, 'wb')
00090         f.write(fixed)
00091         f.close()
00092     # Please read and follow PEP8 - rerun this test until it does not fail any more,
00093     # any type of error is only reported ONCE (even if there are multiple).
00094     error_count = pep8_error_count(path)
00095     assert error_count == 0
00096     mark_file_ok(path, mtime)
00097 
00098 def test_sourcecode():
00099     def walk(reldir):
00100         if reldir in EXCLUDE:
00101             #print "Skippping %r..." % reldir
00102             return
00103         if reldir:
00104             path = os.path.join(ROOT, *reldir.split('/'))
00105         else:
00106             path = ROOT
00107         st = os.stat(path)
00108         mode = st.st_mode
00109         if stat.S_ISREG(mode): # is a regular file
00110             if (path.lower().endswith('.py') and st.st_mtime >= RECENTLY and
00111                 should_check_file(path, st.st_mtime)):
00112                 yield check_py_file, reldir, path, st.st_mtime
00113         elif stat.S_ISDIR(mode): # is a directory
00114             for entry in os.listdir(path):
00115                 if not entry.startswith('.'):
00116                     for _ in walk('%s/%s' % (reldir, entry)):
00117                         yield _
00118 
00119     global EXCLUDE
00120     EXCLUDE = dict([(path, True) for path in EXCLUDE]) # dict lookup is faster
00121     for _ in walk(''):
00122         yield _
00123