DebugClients/Python/coverage/debug.py

changeset 4491
0d8612e24fef
parent 4489
d0d6e4ad31bd
child 5051
3586ebd9fac8
equal deleted inserted replaced
4487:4ba7a8ab24f2 4491:0d8612e24fef
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3
1 """Control of and utilities for debugging.""" 4 """Control of and utilities for debugging."""
2 5
6 import inspect
3 import os 7 import os
8 import sys
4 9
5 10
6 # When debugging, it can be helpful to force some options, especially when 11 # When debugging, it can be helpful to force some options, especially when
7 # debugging the configuration mechanisms you usually use to control debugging! 12 # debugging the configuration mechanisms you usually use to control debugging!
8 # This is a list of forced debugging options. 13 # This is a list of forced debugging options.
9 FORCED_DEBUG = [] 14 FORCED_DEBUG = []
15
16 # A hack for debugging testing in sub-processes.
17 _TEST_NAME_FILE = "" # "/tmp/covtest.txt"
10 18
11 19
12 class DebugControl(object): 20 class DebugControl(object):
13 """Control and output for debugging.""" 21 """Control and output for debugging."""
14 22
15 def __init__(self, options, output): 23 def __init__(self, options, output):
16 """Configure the options and output file for debugging.""" 24 """Configure the options and output file for debugging."""
17 self.options = options 25 self.options = options
18 self.output = output 26 self.output = output
19 27
28 def __repr__(self):
29 return "<DebugControl options=%r output=%r>" % (self.options, self.output)
30
20 def should(self, option): 31 def should(self, option):
21 """Decide whether to output debug information in category `option`.""" 32 """Decide whether to output debug information in category `option`."""
22 return (option in self.options or option in FORCED_DEBUG) 33 return (option in self.options or option in FORCED_DEBUG)
23 34
24 def write(self, msg): 35 def write(self, msg):
25 """Write a line of debug output.""" 36 """Write a line of debug output."""
26 if self.should('pid'): 37 if self.should('pid'):
27 msg = "pid %5d: %s" % (os.getpid(), msg) 38 msg = "pid %5d: %s" % (os.getpid(), msg)
28 self.output.write(msg+"\n") 39 self.output.write(msg+"\n")
40 if self.should('callers'):
41 dump_stack_frames(self.output)
29 self.output.flush() 42 self.output.flush()
30 43
31 def write_formatted_info(self, info): 44 def write_formatted_info(self, header, info):
32 """Write a sequence of (label,data) pairs nicely.""" 45 """Write a sequence of (label,data) pairs nicely."""
46 self.write(info_header(header))
33 for line in info_formatter(info): 47 for line in info_formatter(info):
34 self.write(" %s" % line) 48 self.write(" %s" % line)
49
50
51 def info_header(label):
52 """Make a nice header string."""
53 return "--{0:-<60s}".format(" "+label+" ")
35 54
36 55
37 def info_formatter(info): 56 def info_formatter(info):
38 """Produce a sequence of formatted lines from info. 57 """Produce a sequence of formatted lines from info.
39 58
40 `info` is a sequence of pairs (label, data). The produced lines are 59 `info` is a sequence of pairs (label, data). The produced lines are
41 nicely formatted, ready to print. 60 nicely formatted, ready to print.
42 61
43 """ 62 """
44 label_len = max([len(l) for l, _d in info]) 63 info = list(info)
64 if not info:
65 return
66 label_len = max(len(l) for l, _d in info)
45 for label, data in info: 67 for label, data in info:
46 if data == []: 68 if data == []:
47 data = "-none-" 69 data = "-none-"
48 if isinstance(data, (list, tuple)): 70 if isinstance(data, (list, set, tuple)):
49 prefix = "%*s:" % (label_len, label) 71 prefix = "%*s:" % (label_len, label)
50 for e in data: 72 for e in data:
51 yield "%*s %s" % (label_len+1, prefix, e) 73 yield "%*s %s" % (label_len+1, prefix, e)
52 prefix = "" 74 prefix = ""
53 else: 75 else:
54 yield "%*s: %s" % (label_len, label, data) 76 yield "%*s: %s" % (label_len, label, data)
55 77
78
79 def short_stack(): # pragma: debugging
80 """Return a string summarizing the call stack.
81
82 The string is multi-line, with one line per stack frame. Each line shows
83 the function name, the file name, and the line number:
84
85 ...
86 start_import_stop : /Users/ned/coverage/trunk/tests/coveragetest.py @95
87 import_local_file : /Users/ned/coverage/trunk/tests/coveragetest.py @81
88 import_local_file : /Users/ned/coverage/trunk/coverage/backward.py @159
89 ...
90
91 """
92 stack = inspect.stack()[:0:-1]
93 return "\n".join("%30s : %s @%d" % (t[3], t[1], t[2]) for t in stack)
94
95
96 def dump_stack_frames(out=None): # pragma: debugging
97 """Print a summary of the stack to stdout, or some place else."""
98 out = out or sys.stdout
99 out.write(short_stack())
100 out.write("\n")
101
56 # 102 #
57 # eflag: FileType = Python2 103 # eflag: FileType = Python2

eric ide

mercurial