Mercurial > moin > 2.0
changeset 2762:f8e28b0f4c36
add template indentation checks to coding-std.py;
author | RogerHaase <haaserd@gmail.com> |
---|---|
date | Sun, 24 Aug 2014 08:39:54 -0700 |
parents | 31628ac3ec21 |
children | 161b73a84417 |
files | contrib/pep8/coding_std.py |
diffstat | 1 files changed, 123 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/pep8/coding_std.py Sun Aug 24 08:39:32 2014 -0700 +++ b/contrib/pep8/coding_std.py Sun Aug 24 08:39:54 2014 -0700 @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright: 2012 by MoinMoin:RogerHaase +# Copyright: 2012-2014 by MoinMoin:RogerHaase # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. """ @@ -8,8 +8,13 @@ - exactly one linefeed at file end, see PEP8 - DOS line endings on .bat and .cmd files, unix line endings everywhere else +Detect and write informative message: + - improper indentation of template files ending with .html suffix + Execute this script from the root directory of the moin2 repository or -from anywhere within the contrib path. +from anywhere within the contrib path to process all files in the repo. + +Or, pass a directory path on the command line. """ import sys @@ -24,14 +29,21 @@ class NoDupsLogger(object): - """Suppress duplicate messages.""" + """ + A simple report logger that suppresses duplicate headings and messages. + """ def __init__(self): - self.seen = set() + self.messages = set() + self.headings = set() - def log(self, msg): - if msg not in self.seen: - print msg - self.seen.add(msg) + def log(self, heading, message): + if heading and heading not in self.headings: + print u"\n%s" % heading + self.headings.add(heading) + + if message and message not in self.messages: + print u" ", message + self.messages.add(message) def directories_to_ignore(starting_dir): @@ -45,10 +57,97 @@ return ignore_dirs +def calc_indentation(line): + """ + Return tuple (length of indentation, line stripped of leading blanks). + """ + stripped = line.lstrip(' ') + indentation = len(line) - len(stripped) + return indentation, stripped + + +def check_template_indentation(lines, filename, logger): + """ + Identify non-standard indentation, print messages to assist user in manual correction. + + In simple cases, non-standard indent, non-standard dedent messages tells users which lines to indent. + """ + indent_after = ('{% block ', '{% if ', '{% elif ', '{% else ', '{% for ', '{% macro ', + '{%- block ', '{%- if ', '{%- elif ', '{%- else ', '{%- for ', '{%- macro ', '{{ gen.form.open', ) + indent_before = ('{% endblock ', '{% endif ', '{% endfor ', '{% endmacro', '</', + '{%- endblock ', '{%- endif ', '{%- endfor ', '{%- endmacro', '{{ gen.form.close', ) + block_endings = {'{% block': ('{% endblock %}', '{%- endblock %}', '{%- endblock -%}', '{% endblock -%}', ), + '{% if': ('{% endif %}', '{%- endif %}', '{%- endif -%}', '{% endif -%}', ), + '{% elif': ('{% endif %}', '{%- endif %}', '{%- endif -%}', '{% endif -%}', ), + '{% else': ('{% endif %}', '{%- endif %}', '{%- endif -%}', '{% endif -%}', ), + '{% for': ('{% endfor %}', '{%- endfor %}', '{%- endfor -%}', '{% endfor -%}', ), + '{% macro': ('{% endmacro %}', '{%- endmacro %}', '{%- endmacro -%}', '{% endmacro -%}', ), + '{{ gen.form.open': ('{{ gen.form.close }}', ), + } + ends = ('{% end', '{%- end') + + for idx, line in enumerate(lines): + indentation, stripped = calc_indentation(line) + + if stripped.startswith(indent_after): + # we have found the beginning of a block + incre = 1 + try: + while lines[idx + incre].strip() == '': + incre += 1 + next_indentation, next_line = calc_indentation(lines[idx + incre]) + if next_indentation <= indentation: + # next non-blank line does not have expected indentation + # truncate "{{ gen.form.open(form, ..." to "{{ gen.form.open"; "{%- if ..." to "{% if" + block_start = stripped.replace('-', '').split('(')[0].split(' ') + block_start = ' '.join(block_start[:2]) + block_end = block_endings.get(block_start) + if not block_end: + # should never get here, mismatched indent_after and block_endings + logger.log(filename, u"Unexpected block type '%s' discovered at line %d!" % (block_start, idx + 1)) + continue + if any(x in stripped for x in block_end): + # found line similar to: {% block ... %}...{% endblock %} + continue + if any(x in lines[idx + incre] for x in block_end): + # found 2 consecutive lines similar to: {% block....\n{% endblock %} + continue + logger.log(filename, u"Non-standard indent after line %d -- not fixed!" % (idx + 1)) + except IndexError: + # should never get here, there is an unclosed block near end of template + logger.log(filename, u"End of file reached with open block element at line %d!" % (idx + 1)) + + elif stripped.startswith(indent_before): + # we have found the end of a block + decre = -1 + while idx + decre >= 0 and lines[idx + decre].strip() == '': + decre -= 1 + if idx + decre < 0: + # should never get here; file begins with something like {% endblock %} or </div> + logger.log(filename, u"Beginning of file reached searching for block content at line %d!" % (idx + 1)) + continue + prior_indentation, prior_line = calc_indentation(lines[idx + decre]) + if prior_indentation <= indentation: + # prior non-blank line does not have expected indentation + if stripped.startswith('</'): + tag_open = stripped.split('>')[0].replace('/', '') # convert </div> to <div, etc. + if prior_line.startswith(tag_open): + # found lines similar to: <td>...\n</td> + continue + if stripped.startswith(ends): + # convert {% endif %} to tuple ('{% if', '{%- if') or similar + block_open = (stripped.split(' %}')[0].replace('end', '').replace('-', ''),) + block_open += ((block_open[0].replace('{%', '{%-')), ) + if prior_line.startswith(block_open): + # found lines similar to: {% block...\n{% endblock %} + continue + logger.log(filename, u"Non-standard dedent before line %d -- not fixed!" % (idx + 1)) + + def check_files(filename, suffix): - """Delete trailing blanks, - force a single linefeed at file end, - force line ending to be \r\n for bat files and \n for all others.""" + """ + Delete trailing blanks, single linefeed at file end, line ending to be \r\n for bat files and \n for all others. + """ suffix = suffix.lower() if suffix in WIN_SUFFIXES: line_end = "\r\n" @@ -59,32 +158,35 @@ with open(filename, "rb") as f: lines = f.readlines() + if filename.endswith('.html'): + check_template_indentation(lines, filename, logger) + # now look at file end and get rid of all whitespace-only lines there: while lines: if not lines[-1].strip(): del lines[-1] - logger.log(u"%s was changed to remove empty lines at eof" % filename) + logger.log(filename, u"Empty lines at eof removed.") else: break with open(filename, "wb") as f: - for line in lines: - length_line = len(line) + for idx, line in enumerate(lines): + line_length = len(line) line = line.replace('\t', ' ') - if len(line) != length_line: - logger.log(u"%s was changed to replace tab characters with 4 spaces" % filename) + if len(line) != line_length: + logger.log(filename, u"Tab characters replaced with 4 spaces.") pep8_line = line.rstrip() + line_end f.write(pep8_line) # if line was changed, issue warning once for each type of change if suffix in WIN_SUFFIXES and not line.endswith("\r\n"): - logger.log(u"%s was changed to DOS line endings" % filename) + logger.log(filename, u"Line endings changed to DOS style.") elif suffix not in WIN_SUFFIXES and line.endswith("\r\n"): - logger.log(u"%s was changed to Unix line endings" % filename) + logger.log(filename, u"Line endings changed to Unix style.") elif pep8_line != line: if len(pep8_line) < len(line): - logger.log(u"%s was changed to remove trailing blanks" % filename) + logger.log(filename, u"Trailing blanks removed.") else: - logger.log(u"%s was changed to add end of line character at end of file" % filename) + logger.log(filename, u"End of line character added at end of file.") def file_picker(starting_dir): @@ -110,5 +212,5 @@ else: starting_dir = os.path.abspath(os.path.dirname(__file__)) starting_dir = starting_dir.split(os.sep + 'contrib')[0] - NoDupsLogger().log(u"Starting directory is %s" % starting_dir) + NoDupsLogger().log(u"Starting directory is %s" % starting_dir, None) file_picker(starting_dir)