3232
3333LOGGER = logging .getLogger (__name__ )
3434
35+ PARENT_DIR = os .path .dirname (os .path .realpath (__file__ ))
36+ ROOT_DIR = os .path .abspath (os .path .join (PARENT_DIR , '..' ))
37+
3538CHECKERS = {}
3639
3740CHECKER_PROPS = {"severity" : 1 , "falsepositives" : False }
155158 )
156159)
157160
161+ ENV_DIRS = frozenset (filter (None , [
162+ os .path .join (ROOT_DIR , 'env' ),
163+ os .path .join (ROOT_DIR , 'env27' ),
164+ os .path .join (ROOT_DIR , '.tox' ),
165+ os .getenv ('VIRTUAL_ENV' , None ),
166+ os .path .join (ROOT_DIR , 'venv' ),
167+ os .path .join (ROOT_DIR , '.venv' ),
168+ os .path .join (ROOT_DIR , '.idea' ),
169+ os .path .join (ROOT_DIR , '.git' ),
170+ os .path .join (ROOT_DIR , '.github' ),
171+ "__pycache__"
172+ ]))
173+
158174
159175def checker (* suffixes , ** kwargs ):
160176 """Decorator to register a function as a checker.
@@ -262,7 +278,7 @@ def check_leaked_markup(_, lines):
262278 yield lno + 1 , "possibly leaked markup: {0!r}" .format (line )
263279
264280
265- def rstlint (path , false_pos = False , ignore = None , severity = 1 , verbose = False ):
281+ def lint (path , false_pos = False , ignore = ENV_DIRS , severity = 1 , verbose = False ):
266282 """Check for stylistic and formal issues in .rst and .py files
267283 included in the documentation.
268284
@@ -277,26 +293,55 @@ def rstlint(path, false_pos=False, ignore=None, severity=1, verbose=False):
277293 (defaultdict of int,int): Severity and Error Hit Count.
278294 """
279295 count = defaultdict (int )
296+ totals = {
297+ "checked" : 0 ,
298+ "skipped" : 0 ,
299+ "ignored" : 0 ,
300+ "errors" : 0 ,
301+ "total" : 0
302+ }
303+
280304 for root , dirs , files in os .walk (path ):
305+
281306 # ignore subdirectories in ignore list
282307 if abspath (root ) in ignore :
308+ if verbose :
309+ sys .stdout .write ("[-] IGNORING: {0}\n " .format (root ))
283310 del dirs [:]
311+ totals ["ignored" ] += 1
284312 continue
285313
314+ if os .path .basename (os .path .dirname (abspath (root ))) in ignore :
315+ if verbose :
316+ sys .stdout .write ("[-] IGNORING: {0}\n " .format (root ))
317+ del dirs [:]
318+ totals ["total" ] += 1
319+ continue
320+
321+ files .sort ()
286322 for fn in files :
323+ totals ["total" ] += 1
324+
287325 fn = join (root , fn )
288326 if fn [:2 ] == "./" :
289327 fn = fn [2 :]
290328
291329 if abspath (fn ) in ignore :
330+ if verbose :
331+ sys .stdout .write ("[-] IGNORING: {0}\n " .format (fn ))
332+ totals ["ignored" ] += 1
292333 continue # ignore files in ignore list
293334
294335 checker_list = CHECKERS .get (splitext (fn )[1 ], None )
295336 if not checker_list :
337+ if verbose :
338+ sys .stdout .write ("[-] SKIPPING: {0}\n " .format (fn ))
339+ totals ["skipped" ] += 1
296340 continue
297341
298342 if verbose :
299- sys .stdout .write ("[-] CHECKING: {0}...\n " .format (fn ))
343+ sys .stdout .write ("[-] CHECKING: {0}\n " .format (fn ))
344+ totals ["checked" ] += 1
300345
301346 # LOGGER.debug("checking: %s", fn)
302347
@@ -307,6 +352,7 @@ def rstlint(path, false_pos=False, ignore=None, severity=1, verbose=False):
307352 # LOGGER.error("%s cannot open %s", fn, err)
308353 sys .stderr .write ("[!] ERROR: {0}: cannot open: {1}\n " .format (fn , err ))
309354 count [4 ] += 1
355+ totals ["errors" ] += 1
310356 continue
311357
312358 for _checker in checker_list :
@@ -315,24 +361,29 @@ def rstlint(path, false_pos=False, ignore=None, severity=1, verbose=False):
315361 c_sev = _checker .severity
316362 if c_sev >= severity :
317363 for n , msg in _checker (fn , lines ):
318- sys .stdout .write (
319- "[{0:d}] PROBLEMS: {1}:{2:d}: {3}\n " .format (c_sev , fn , n , msg )
320- )
364+ sys .stdout .write ("[{0:d}] PROBLEMS: {1}:{2:d}: {3}\n " .format (c_sev , fn , n , msg ))
321365 count [c_sev ] += 1
322366
323367 if not count :
324368 if severity > 1 :
325- sys .stdout .write (
326- "No Problems With Severity >= {0:d} Found.\n " .format (severity )
327- )
369+ sys .stdout .write ("[-] No Problems With Severity >= {0:d} Found.\n " .format (severity ))
328370 else :
329- sys .stdout .write ("No Problems Found.\n " )
371+ sys .stdout .write ("[-] No Problems Found.\n " )
330372 else :
331373 for severity in sorted (count ):
332374 number = count [severity ]
333375 sys .stdout .write ("{0:d} Problem{1} With Severity {2:d} Found.\n " .format (
334376 number , "s" if number > 1 else "" , severity
335377 ))
378+
379+ if verbose :
380+ sys .stdout .write ("\n [-] Summary:\n " )
381+ sys .stdout .write (" Total: {0}\n " .format (totals ["total" ]))
382+ sys .stdout .write (" Checked: {0}\n " .format (totals ["checked" ]))
383+ sys .stdout .write (" Skipped: {0}\n " .format (totals ["skipped" ]))
384+ sys .stdout .write (" Ignored: {0}\n " .format (totals ["ignored" ]))
385+ sys .stdout .write (" Errors: {0}\n " .format (totals ["errors" ]))
386+ sys .stdout .write (os .linesep )
336387 return count
337388
338389
@@ -348,7 +399,7 @@ def _parse_args(argv):
348399 arg_d = {
349400 "verbose" : False ,
350401 "severity" : 1 ,
351- "ignore" : [] ,
402+ "ignore" : ENV_DIRS ,
352403 "false_pos" : False ,
353404 }
354405 for opt , val in opts :
@@ -370,9 +421,28 @@ def _parse_args(argv):
370421 return 2
371422
372423 if not exists (arg_d ["path" ]):
373- sys .stderr .write ("ERROR: path {0} does not exist\n " .format (arg_d ["path" ]))
424+ sys .stderr .write ("[!] ERROR: path {0} does not exist\n " .format (arg_d ["path" ]))
374425 return 2
375426
427+ if arg_d ["verbose" ]:
428+ sys .stdout .write ("[-] ARGUMENTS:\n " )
429+ sys .stdout .write (" path: {0}\n " .format (arg_d ["path" ]))
430+ sys .stdout .write (" severity: {0}\n " .format (arg_d ["severity" ]))
431+ sys .stdout .write (" false positives: {0}\n " .format (arg_d ["false_pos" ]))
432+ sys .stdout .write (" ignore: \n " )
433+ for path in arg_d ["ignore" ]:
434+ sys .stdout .write (" {0}\n " .format (path ))
435+ sys .stdout .write (" verbose: {0}\n " .format (arg_d ["verbose" ]))
436+ sys .stdout .write (os .linesep )
437+
438+ sys .stdout .write ("[-] CHECKERS:\n " )
439+ for suffix , checkers in CHECKERS .items ():
440+ sys .stdout .write (" {0} ({1})\n " .format (suffix , len (checkers )))
441+ for _checker in checkers :
442+ sys .stdout .write (" {0}: severity={1} falsepositives={2}\n " .format (
443+ _checker .__name__ , _checker .severity , _checker .falsepositives
444+ ))
445+ sys .stdout .write (os .linesep )
376446 return arg_d
377447
378448
@@ -381,6 +451,8 @@ def main():
381451 """
382452 import signal
383453
454+ logging .basicConfig (level = logging .INFO )
455+
384456 def _shutdown_handler (signum , _ ):
385457 """Handle Shutdown.
386458
@@ -405,7 +477,7 @@ def _shutdown_handler(signum, _):
405477 if args_dict ["verbose" ]:
406478 logging .basicConfig (level = logging .DEBUG )
407479
408- return int (bool (rstlint (** args_dict )))
480+ return int (bool (lint (** args_dict )))
409481
410482
411483if __name__ == "__main__" :
0 commit comments