DebugClients/Python3/coverage/phystokens.py

Sun, 03 Jul 2011 18:01:53 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 03 Jul 2011 18:01:53 +0200
changeset 1166
a94b0a2fafd7
parent 29
391dc0bc4ae5
child 3495
fac17a82b431
permissions
-rw-r--r--

Extended the unit test interface to support skipped tests, expected failures and unexpected successes and to better cope with Python2 scripts when run from the eric IDE.

29
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1 """Better tokenizing for coverage.py."""
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
2
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
3 import keyword, re, token, tokenize
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
4 from .backward import StringIO # pylint: disable-msg=W0622
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
5
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
6 def phys_tokens(toks):
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
7 """Return all physical tokens, even line continuations.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
8
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
9 tokenize.generate_tokens() doesn't return a token for the backslash that
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
10 continues lines. This wrapper provides those tokens so that we can
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
11 re-create a faithful representation of the original source.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
12
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
13 Returns the same values as generate_tokens()
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
14
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
15 """
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
16 last_line = None
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
17 last_lineno = -1
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
18 last_ttype = None
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
19 for ttype, ttext, (slineno, scol), (elineno, ecol), ltext in toks:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
20 if last_lineno != elineno:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
21 if last_line and last_line[-2:] == "\\\n":
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
22 # We are at the beginning of a new line, and the last line
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
23 # ended with a backslash. We probably have to inject a
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
24 # backslash token into the stream. Unfortunately, there's more
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
25 # to figure out. This code::
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
26 #
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
27 # usage = """\
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
28 # HEY THERE
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
29 # """
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
30 #
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
31 # triggers this condition, but the token text is::
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
32 #
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
33 # '"""\\\nHEY THERE\n"""'
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
34 #
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
35 # so we need to figure out if the backslash is already in the
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
36 # string token or not.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
37 inject_backslash = True
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
38 if last_ttype == tokenize.COMMENT:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
39 # Comments like this \
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
40 # should never result in a new token.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
41 inject_backslash = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
42 elif ttype == token.STRING:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
43 if "\n" in ttext and ttext.split('\n', 1)[0][-1] == '\\':
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
44 # It's a multiline string and the first line ends with
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
45 # a backslash, so we don't need to inject another.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
46 inject_backslash = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
47 if inject_backslash:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
48 # Figure out what column the backslash is in.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
49 ccol = len(last_line.split("\n")[-2]) - 1
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
50 # Yield the token, with a fake token type.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
51 yield (
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
52 99999, "\\\n",
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
53 (slineno, ccol), (slineno, ccol+2),
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
54 last_line
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
55 )
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
56 last_line = ltext
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
57 last_ttype = ttype
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
58 yield ttype, ttext, (slineno, scol), (elineno, ecol), ltext
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
59 last_lineno = elineno
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
60
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
61
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
62 def source_token_lines(source):
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
63 """Generate a series of lines, one for each line in `source`.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
64
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
65 Each line is a list of pairs, each pair is a token::
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
66
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
67 [('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('), ... ]
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
68
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
69 Each pair has a token class, and the token text.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
70
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
71 If you concatenate all the token texts, and then join them with newlines,
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
72 you should have your original `source` back, with two differences:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
73 trailing whitespace is not preserved, and a final line with no newline
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
74 is indistinguishable from a final line with a newline.
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
75
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
76 """
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
77 ws_tokens = [token.INDENT, token.DEDENT, token.NEWLINE, tokenize.NL]
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
78 line = []
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
79 col = 0
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
80 tokgen = tokenize.generate_tokens(StringIO(source.expandtabs(8)).readline)
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
81 for ttype, ttext, (_, scol), (_, ecol), _ in phys_tokens(tokgen):
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
82 mark_start = True
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
83 for part in re.split('(\n)', ttext):
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
84 if part == '\n':
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
85 yield line
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
86 line = []
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
87 col = 0
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
88 mark_end = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
89 elif part == '':
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
90 mark_end = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
91 elif ttype in ws_tokens:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
92 mark_end = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
93 else:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
94 if mark_start and scol > col:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
95 line.append(("ws", " " * (scol - col)))
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
96 mark_start = False
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
97 tok_class = tokenize.tok_name.get(ttype, 'xx').lower()[:3]
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
98 if ttype == token.NAME and keyword.iskeyword(ttext):
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
99 tok_class = "key"
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
100 line.append((tok_class, part))
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
101 mark_end = True
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
102 scol = 0
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
103 if mark_end:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
104 col = ecol
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
105
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
106 if line:
391dc0bc4ae5 Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
107 yield line

eric ide

mercurial