From c7b1c99b06a453af879f4768e347ac89000cce42 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 19 Oct 2013 21:35:33 -0400 Subject: Get rid of our backward implementation of set, sorted, reversed, and rpartition. --HG-- branch : 4.0 --- coverage/parser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 581c8518..2663baca 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -2,9 +2,8 @@ import dis, re, sys, token, tokenize -from coverage.backward import set, sorted, StringIO # pylint: disable=W0622 +from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 -from coverage.backward import reversed # pylint: disable=W0622 from coverage.backward import bytes_to_ints from coverage.bytecode import ByteCodes, CodeObjects from coverage.misc import nice_pair, expensive, join_regex -- cgit v1.2.1 From b3df60a544a54b4dd604d34137ff08e02b815e81 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 19 Oct 2013 21:52:22 -0400 Subject: Now I can use decorators. --HG-- branch : 4.0 --- coverage/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 2663baca..0873e7af 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -65,13 +65,13 @@ class CodeParser(object): # Lazily-created ByteParser self._byte_parser = None - def _get_byte_parser(self): + @property + def byte_parser(self): """Create a ByteParser on demand.""" if not self._byte_parser: self._byte_parser = \ ByteParser(text=self.text, filename=self.filename) return self._byte_parser - byte_parser = property(_get_byte_parser) def lines_matching(self, *regexes): """Find the lines matching one of a list of regexes. -- cgit v1.2.1 From bad63e02b113626a048ea5eb253293c61902e291 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 19 Oct 2013 22:08:37 -0400 Subject: Generator expressons are ok now. --HG-- branch : 4.0 --- coverage/parser.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 0873e7af..010cd73a 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -365,7 +365,7 @@ class ByteParser(object): """ children = CodeObjects(self.code) - return [ByteParser(code=c, text=self.text) for c in children] + return (ByteParser(code=c, text=self.text) for c in children) def _bytes_lines(self): """Map byte offsets to line numbers in `code`. @@ -409,7 +409,7 @@ class ByteParser(object): def _block_stack_repr(self, block_stack): """Get a string version of `block_stack`, for debugging.""" blocks = ", ".join( - ["(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack] + "(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack ) return "[" + blocks + "]" @@ -547,9 +547,9 @@ class ByteParser(object): def validate_chunks(self, chunks): """Validate the rule that chunks have a single entrance.""" # starts is the entrances to the chunks - starts = set([ch.byte for ch in chunks]) + starts = set(ch.byte for ch in chunks) for ch in chunks: - assert all([(ex in starts or ex < 0) for ex in ch.exits]) + assert all((ex in starts or ex < 0) for ex in ch.exits) def _arcs(self): """Find the executable arcs in the code. @@ -562,7 +562,7 @@ class ByteParser(object): chunks = self._split_into_chunks() # A map from byte offsets to chunks jumped into. - byte_chunks = dict([(c.byte, c) for c in chunks]) + byte_chunks = dict((c.byte, c) for c in chunks) # There's always an entrance at the first chunk. yield (-1, byte_chunks[0].line) -- cgit v1.2.1 From 35cfd9334d381d06e8a5364a2eaa4b7b8d7b0bbc Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Oct 2013 07:38:41 -0400 Subject: Now I can use collections.defaultdict --HG-- branch : 4.0 --- coverage/parser.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 010cd73a..6332f637 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -1,6 +1,6 @@ """Code parsing for Coverage.""" -import dis, re, sys, token, tokenize +import collections, dis, re, sys, token, tokenize from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 @@ -242,7 +242,7 @@ class CodeParser(object): """ excluded_lines = self.first_lines(self.excluded) - exit_counts = {} + exit_counts = collections.defaultdict(int) for l1, l2 in self.arcs(): if l1 < 0: # Don't ever report -1 as a line number @@ -253,8 +253,6 @@ class CodeParser(object): if l2 in excluded_lines: # Arcs to excluded lines shouldn't count. continue - if l1 not in exit_counts: - exit_counts[l1] = 0 exit_counts[l1] += 1 # Class definitions have one extra exit, so remove one for each: -- cgit v1.2.1 From 2e5688eedd1576e9b100386c0a9ae30828123f73 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Oct 2013 07:40:37 -0400 Subject: My own decorators can be decorators --HG-- branch : 4.0 --- coverage/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 6332f637..37beeded 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -219,6 +219,7 @@ class CodeParser(object): return lines, excluded_lines + @expensive def arcs(self): """Get information about the arcs available in the code. @@ -233,8 +234,8 @@ class CodeParser(object): if fl1 != fl2: all_arcs.append((fl1, fl2)) return sorted(all_arcs) - arcs = expensive(arcs) + @expensive def exit_counts(self): """Get a mapping from line numbers to count of exits from that line. @@ -262,7 +263,6 @@ class CodeParser(object): exit_counts[l] -= 1 return exit_counts - exit_counts = expensive(exit_counts) ## Opcodes that guide the ByteParser. -- cgit v1.2.1 From 6b6a4488adc12d390c5e0c8f13829dd9bf125309 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Oct 2013 07:58:57 -0400 Subject: with statements: no more finally close --HG-- branch : 4.0 --- coverage/parser.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 37beeded..d0fe9976 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -25,11 +25,8 @@ class CodeParser(object): self.text = text if not self.text: try: - sourcef = open_source(self.filename) - try: + with open_source(self.filename) as sourcef: self.text = sourcef.read() - finally: - sourcef.close() except IOError: _, err, _ = sys.exc_info() raise NoSource( @@ -328,11 +325,8 @@ class ByteParser(object): else: if not text: assert filename, "If no code or text, need a filename" - sourcef = open_source(filename) - try: + with open_source(filename) as sourcef: text = sourcef.read() - finally: - sourcef.close() self.text = text try: -- cgit v1.2.1 From 6dfbb755d1f6994ccec9ae56ad7f2eedad2ed0d6 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Oct 2013 08:23:52 -0400 Subject: Except clause can now use 'as', no need for lots of sys.exc_info --HG-- branch : 4.0 --- coverage/parser.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index d0fe9976..7e194705 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -1,6 +1,6 @@ """Code parsing for Coverage.""" -import collections, dis, re, sys, token, tokenize +import collections, dis, re, token, tokenize from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 @@ -27,8 +27,7 @@ class CodeParser(object): try: with open_source(self.filename) as sourcef: self.text = sourcef.read() - except IOError: - _, err, _ = sys.exc_info() + except IOError as err: raise NoSource( "No source for code: '%s': %s" % (self.filename, err) ) @@ -202,8 +201,7 @@ class CodeParser(object): """ try: self._raw_parse() - except (tokenize.TokenError, IndentationError): - _, tokerr, _ = sys.exc_info() + except (tokenize.TokenError, IndentationError) as tokerr: msg, lineno = tokerr.args raise NotPython( "Couldn't parse '%s' as Python source: '%s' at %s" % @@ -333,8 +331,7 @@ class ByteParser(object): # Python 2.3 and 2.4 don't like partial last lines, so be sure # the text ends nicely for them. self.code = compile(text + '\n', filename, "exec") - except SyntaxError: - _, synerr, _ = sys.exc_info() + except SyntaxError as synerr: raise NotPython( "Couldn't parse '%s' as Python source: '%s' at line %d" % (filename, synerr.msg, synerr.lineno) -- cgit v1.2.1 From 7c66441eab3af17539c478a2cb4e19cd93ba0cf4 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 23 Oct 2013 22:35:51 -0400 Subject: enumerate has a start parameter! --HG-- branch : 4.0 --- coverage/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'coverage/parser.py') diff --git a/coverage/parser.py b/coverage/parser.py index 7e194705..f2885c07 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -79,9 +79,9 @@ class CodeParser(object): """ regex_c = re.compile(join_regex(regexes)) matches = set() - for i, ltext in enumerate(self.lines): + for i, ltext in enumerate(self.lines, start=1): if regex_c.search(ltext): - matches.add(i+1) + matches.add(i) return matches def _raw_parse(self): -- cgit v1.2.1