summaryrefslogtreecommitdiff
path: root/lab/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'lab/parser.py')
-rw-r--r--lab/parser.py76
1 files changed, 50 insertions, 26 deletions
diff --git a/lab/parser.py b/lab/parser.py
index 662183a7..1a679e8c 100644
--- a/lab/parser.py
+++ b/lab/parser.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Parser.py: a main for invoking code in coverage/parser.py"""
from __future__ import division
@@ -14,6 +17,7 @@ from coverage.python import get_python_source
opcode_counts = collections.Counter()
+
class ParserMain(object):
"""A main for code parsing experiments."""
@@ -62,10 +66,9 @@ class ParserMain(object):
if options.histogram:
total = sum(opcode_counts.values())
- print("{} total opcodes".format(total))
+ print("{0} total opcodes".format(total))
for opcode, number in opcode_counts.most_common():
- print("{:20s} {:6d} {:.1%}".format(opcode, number, number/total))
-
+ print("{0:20s} {1:6d} {2:.1%}".format(opcode, number, number/total))
def one_file(self, options, filename):
"""Process just one file."""
@@ -82,7 +85,7 @@ class ParserMain(object):
self.disassemble(bp, histogram=options.histogram)
arcs = bp._all_arcs()
- if options.chunks:# and not options.dis:
+ if options.chunks:
chunks = bp._all_chunks()
if options.recursive:
print("%6d: %s" % (len(chunks), filename))
@@ -93,33 +96,35 @@ class ParserMain(object):
if options.source or options.tokens:
cp = PythonParser(filename=filename, exclude=r"no\s*cover")
cp.show_tokens = options.tokens
- cp._raw_parse()
+ cp.parse_source()
if options.source:
+ arc_width = 0
+ arc_chars = {}
if options.chunks:
- arc_width, arc_chars = self.arc_ascii_art(arcs)
- else:
- arc_width, arc_chars = 0, {}
+ arc_chars = self.arc_ascii_art(arcs)
+ if arc_chars:
+ arc_width = max(len(a) for a in arc_chars.values())
exit_counts = cp.exit_counts()
for lineno, ltext in enumerate(cp.lines, start=1):
m0 = m1 = m2 = m3 = a = ' '
- if lineno in cp.statement_starts:
+ if lineno in cp.statements:
+ m0 = '='
+ elif lineno in cp.raw_statements:
m0 = '-'
exits = exit_counts.get(lineno, 0)
if exits > 1:
m1 = str(exits)
- if lineno in cp.docstrings:
+ if lineno in cp.raw_docstrings:
m2 = '"'
- if lineno in cp.classdefs:
+ if lineno in cp.raw_classdefs:
m2 = 'C'
- if lineno in cp.excluded:
+ if lineno in cp.raw_excluded:
m3 = 'x'
a = arc_chars[lineno].ljust(arc_width)
- print("%4d %s%s%s%s%s %s" %
- (lineno, m0, m1, m2, m3, a, ltext)
- )
+ print("%4d %s%s%s%s%s %s" % (lineno, m0, m1, m2, m3, a, ltext))
def disassemble(self, byte_parser, histogram=False):
"""Disassemble code, for ad-hoc experimenting."""
@@ -158,10 +163,11 @@ class ParserMain(object):
def arc_ascii_art(self, arcs):
"""Draw arcs as ascii art.
- Returns a width of characters needed to draw all the arcs, and a
- dictionary mapping line numbers to ascii strings to draw for that line.
+ Returns a dictionary mapping line numbers to ascii strings to draw for
+ that line.
"""
+
arc_chars = collections.defaultdict(str)
for lfrom, lto in sorted(arcs):
if lfrom < 0:
@@ -176,7 +182,8 @@ class ParserMain(object):
l1, l2 = lfrom, lto
else:
l1, l2 = lto, lfrom
- w = max(len(arc_chars[l]) for l in range(l1, l2+1))
+ #w = max(len(arc_chars[l]) for l in range(l1, l2+1))
+ w = first_all_blanks(arc_chars[l] for l in range(l1, l2+1))
for l in range(l1, l2+1):
if l == lfrom:
ch = '<'
@@ -184,16 +191,33 @@ class ParserMain(object):
ch = '>'
else:
ch = '|'
- arc_chars[l] = arc_chars[l].ljust(w) + ch
- arc_width = 0
+ arc_chars[l] = set_char(arc_chars[l], w, ch)
- if arc_chars:
- arc_width = max(len(a) for a in arc_chars.values())
- else:
- arc_width = 0
+ return arc_chars
+
+
+def set_char(s, n, c):
+ """Set the nth char of s to be c, extending s if needed."""
+ s = s.ljust(n)
+ return s[:n] + c + s[n+1:]
+
+
+def blanks(s):
+ """Return the set of positions where s is blank."""
+ return set(i for i, c in enumerate(s) if c == " ")
+
+
+def first_all_blanks(ss):
+ """Find the first position that is all blank in the strings ss."""
+ ss = list(ss)
+ blankss = blanks(ss[0])
+ for s in ss[1:]:
+ blankss &= blanks(s)
+ if blankss:
+ return min(blankss)
+ else:
+ return max(len(s) for s in ss)
- return arc_width, arc_chars
if __name__ == '__main__':
ParserMain().main(sys.argv[1:])
-