eric7/DebugClients/Python/coverage/parser.py

branch
eric7
changeset 8929
fcca2fa618bf
parent 8775
0802ae193343
child 8991
2fc945191992
equal deleted inserted replaced
8928:d856023fbeb0 8929:fcca2fa618bf
11 import tokenize 11 import tokenize
12 12
13 from coverage import env 13 from coverage import env
14 from coverage.bytecode import code_objects 14 from coverage.bytecode import code_objects
15 from coverage.debug import short_stack 15 from coverage.debug import short_stack
16 from coverage.exceptions import NoSource, NotPython, StopEverything 16 from coverage.exceptions import NoSource, NotPython, _StopEverything
17 from coverage.misc import contract, join_regex, new_contract, nice_pair, one_of 17 from coverage.misc import contract, join_regex, new_contract, nice_pair, one_of
18 from coverage.phystokens import compile_unicode, generate_tokens, neuter_encoding_declaration 18 from coverage.phystokens import compile_unicode, generate_tokens, neuter_encoding_declaration
19 19
20 20
21 class PythonParser: 21 class PythonParser:
64 # number table in the bytecode. 64 # number table in the bytecode.
65 self.raw_statements = set() 65 self.raw_statements = set()
66 66
67 # The raw line numbers of excluded lines of code, as marked by pragmas. 67 # The raw line numbers of excluded lines of code, as marked by pragmas.
68 self.raw_excluded = set() 68 self.raw_excluded = set()
69
70 # The line numbers of class and function definitions.
71 self.raw_classdefs = set()
72 69
73 # The line numbers of docstring lines. 70 # The line numbers of docstring lines.
74 self.raw_docstrings = set() 71 self.raw_docstrings = set()
75 72
76 # Internal detail, used by lab/parser.py. 73 # Internal detail, used by lab/parser.py.
118 excluding_decorators = False 115 excluding_decorators = False
119 prev_toktype = token.INDENT 116 prev_toktype = token.INDENT
120 first_line = None 117 first_line = None
121 empty = True 118 empty = True
122 first_on_line = True 119 first_on_line = True
120 nesting = 0
123 121
124 tokgen = generate_tokens(self.text) 122 tokgen = generate_tokens(self.text)
125 for toktype, ttext, (slineno, _), (elineno, _), ltext in tokgen: 123 for toktype, ttext, (slineno, _), (elineno, _), ltext in tokgen:
126 if self.show_tokens: # pragma: debugging 124 if self.show_tokens: # pragma: debugging
127 print("%10s %5s %-20r %r" % ( 125 print("%10s %5s %-20r %r" % (
130 )) 128 ))
131 if toktype == token.INDENT: 129 if toktype == token.INDENT:
132 indent += 1 130 indent += 1
133 elif toktype == token.DEDENT: 131 elif toktype == token.DEDENT:
134 indent -= 1 132 indent -= 1
135 elif toktype == token.NAME:
136 if ttext == 'class':
137 # Class definitions look like branches in the bytecode, so
138 # we need to exclude them. The simplest way is to note the
139 # lines with the 'class' keyword.
140 self.raw_classdefs.add(slineno)
141 elif toktype == token.OP: 133 elif toktype == token.OP:
142 if ttext == ':': 134 if ttext == ':' and nesting == 0:
143 should_exclude = (elineno in self.raw_excluded) or excluding_decorators 135 should_exclude = (elineno in self.raw_excluded) or excluding_decorators
144 if not excluding and should_exclude: 136 if not excluding and should_exclude:
145 # Start excluding a suite. We trigger off of the colon 137 # Start excluding a suite. We trigger off of the colon
146 # token so that the #pragma comment will be recognized on 138 # token so that the #pragma comment will be recognized on
147 # the same line as the colon. 139 # the same line as the colon.
153 # A decorator. 145 # A decorator.
154 if elineno in self.raw_excluded: 146 if elineno in self.raw_excluded:
155 excluding_decorators = True 147 excluding_decorators = True
156 if excluding_decorators: 148 if excluding_decorators:
157 self.raw_excluded.add(elineno) 149 self.raw_excluded.add(elineno)
150 elif ttext in "([{":
151 nesting += 1
152 elif ttext in ")]}":
153 nesting -= 1
158 elif toktype == token.STRING and prev_toktype == token.INDENT: 154 elif toktype == token.STRING and prev_toktype == token.INDENT:
159 # Strings that are first on an indented line are docstrings. 155 # Strings that are first on an indented line are docstrings.
160 # (a trick from trace.py in the stdlib.) This works for 156 # (a trick from trace.py in the stdlib.) This works for
161 # 99.9999% of cases. For the rest (!) see: 157 # 99.9999% of cases. For the rest (!) see:
162 # http://stackoverflow.com/questions/1769332/x/1769794#1769794 158 # http://stackoverflow.com/questions/1769332/x/1769794#1769794
294 if l2 in self.excluded: 290 if l2 in self.excluded:
295 # Arcs to excluded lines shouldn't count. 291 # Arcs to excluded lines shouldn't count.
296 continue 292 continue
297 exit_counts[l1] += 1 293 exit_counts[l1] += 1
298 294
299 # Class definitions have one extra exit, so remove one for each:
300 for l in self.raw_classdefs:
301 # Ensure key is there: class definitions can include excluded lines.
302 if l in exit_counts:
303 exit_counts[l] -= 1
304
305 return exit_counts 295 return exit_counts
306 296
307 def missing_arc_description(self, start, end, executed_arcs=None): 297 def missing_arc_description(self, start, end, executed_arcs=None):
308 """Provide an English sentence describing a missing arc.""" 298 """Provide an English sentence describing a missing arc."""
309 if self._missing_arc_fragments is None: 299 if self._missing_arc_fragments is None:
364 354
365 # Alternative Python implementations don't always provide all the 355 # Alternative Python implementations don't always provide all the
366 # attributes on code objects that we need to do the analysis. 356 # attributes on code objects that we need to do the analysis.
367 for attr in ['co_lnotab', 'co_firstlineno']: 357 for attr in ['co_lnotab', 'co_firstlineno']:
368 if not hasattr(self.code, attr): 358 if not hasattr(self.code, attr):
369 raise StopEverything( # pragma: only jython 359 raise _StopEverything( # pragma: only jython
370 "This implementation of Python doesn't support code analysis.\n" + 360 "This implementation of Python doesn't support code analysis.\n" +
371 "Run coverage.py under another Python for this command." 361 "Run coverage.py under another Python for this command."
372 ) 362 )
373 363
374 def child_parsers(self): 364 def child_parsers(self):

eric ide

mercurial