Skip to content

Instantly share code, notes, and snippets.

@marshallward
Last active August 19, 2021 00:49
Show Gist options
  • Save marshallward/8215f7947e184712e729de5e1828004e to your computer and use it in GitHub Desktop.
Save marshallward/8215f7947e184712e729de5e1828004e to your computer and use it in GitHub Desktop.
trailer2.py
#!/usr/bin/env python
"""Subroutines for Validating the whitespace of the source code."""
import argparse
import sys
import flint
def parse_command_line():
"""Parse the command line positional and optional arguments.
This is the highest level procedure invoked from the very end of the
script.
"""
# Arguments
parser = argparse.ArgumentParser(
description='trailer.py checks Fortran files for trailing white '
'space.',
epilog='Written by A.Adcroft, 2017.'
)
parser.add_argument(
'files_or_dirs', type=str, nargs='+',
metavar='FILE|DIR',
help='Fortran files or directory in which to search for Fortran files '
'(with .f, .f90, .F90 suffixes).'''
)
parser.add_argument(
'-e', '--exclude_dir', type=str, action='append',
metavar='DIR',
help='''Exclude directories from search that end in DIR.'''
)
parser.add_argument(
'-l', '--line_length', type=int, default=512,
help='''Maximum allowed length of a line.'''
)
parser.add_argument(
'-s', '--source_line_length', type=int, default=132,
help='''Maximum allowed length of a source line excluding comments.'''
)
parser.add_argument(
'-d', '--debug', action='store_true',
help='turn on debugging information.'
)
args = parser.parse_args()
main(args)
def main(args):
"""Do the actual work."""
if args.debug:
print(args)
proj = flint.parse(*args.files_or_dirs, excludes=args.exclude_dir)
if args.debug:
print('Found: ', [src.path for src in proj.sources])
# For each file, check for trailing white space
fail = False
for src in proj.sources:
this = scan_file(src, line_length=args.line_length,
source_line_length=args.source_line_length)
fail = fail or this
if fail:
sys.exit(1)
def scan_file(source, line_length=512, source_line_length=132):
"""Scan file for trailing white space."""
def msg(filename, lineno, mesg, line=None):
log = '{}, line {}: {}'.format(filename, lineno, mesg)
if line is not None:
log += ' "{}"'.format(''.join(line))
print(log)
white_space_detected = False
tabs_space_detected = False
long_line_detected = False
lineno = 0
for line in source.lines:
lineno += 1
# Report trailing whitespace
if line and line[-1] and line[-1][-1].isspace():
white_space_detected = True
if all(tok.isspace() for tok in line):
msg(source.path, lineno, 'Blank line contains spaces')
else:
msg(source.path, lineno, 'Trailing space detected', line)
# Report any tab stop characters
# NOTE: This also reports tab stops in comments and strings.
if any('\t' in tok for tok in line):
tab_space_detected = True
if all(tok.isspace() for tok in line):
msg(source.path, lineno, 'Blank line contains tabs')
else:
msg(source.path, lineno, 'Tab detected', line)
# Report excessive line length
if sum(len(tok) for tok in line) > line_length:
long_line_detected = True
if all(tok.isspace() for tok in line):
msg(source.path, lineno,
'Blank line exceeds line length limit')
else:
msg(source.path, lineno, 'Line length exceeded', line)
# Report excessive source line length
# NOTE: Source line test includes whitespace preceding comments
srclen = sum(len(tok) for tok in line if not tok.startswith('!'))
if srclen > source_line_length:
msg(source.path, lineno, 'Non-comment line length exceeded', line)
return white_space_detected or tabs_space_detected or long_line_detected
# Invoke parse_command_line(), the top-level procedure
if __name__ == '__main__':
parse_command_line()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment