2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
1 |
# Copyright 2005 Canonical Ltd. All rights reserved.
|
2 |
||
3 |
"""Handlers for warnings, to be installed when testing."""
|
|
4 |
||
5 |
__metaclass__ = type |
|
6 |
||
7 |
import atexit |
|
8 |
import warnings |
|
9 |
import sys |
|
10 |
import inspect |
|
11 |
import StringIO |
|
12 |
||
13 |
class WarningReport: |
|
14 |
||
15 |
def __init__(self, message, info): |
|
16 |
self.message = message |
|
17 |
self.info = info |
|
18 |
||
19 |
def __str__(self): |
|
20 |
info = str(self.info) |
|
21 |
if info: |
|
22 |
return info |
|
23 |
else: |
|
24 |
return self.message |
|
25 |
||
26 |
class ImportantInfo: |
|
27 |
||
28 |
def __init__(self, expressiontext, viewclassname, templatefilename, |
|
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
29 |
requesturl, viewclassfilename, viewclasslineno, viewclassfunc, |
30 |
doctestname, doctestline): |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
31 |
self.expressiontext = expressiontext |
32 |
self.viewclassname = viewclassname |
|
33 |
self.viewclassfilename = viewclassfilename |
|
34 |
self.viewclasslineno = viewclasslineno |
|
35 |
self.templatefilename = templatefilename |
|
36 |
self.requesturl = requesturl |
|
37 |
self.viewclassfunc = viewclassfunc |
|
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
38 |
self.doctestname = doctestname |
39 |
self.doctestline = doctestline |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
40 |
|
41 |
def __str__(self): |
|
42 |
L = [] |
|
43 |
if self.expressiontext: |
|
44 |
L.append('The expression: %s in %s' % ( |
|
45 |
self.expressiontext, self.templatefilename)) |
|
46 |
if self.viewclassname: |
|
47 |
L.append('The method %s.%s' % ( |
|
48 |
self.viewclassname, self.viewclassfunc)) |
|
49 |
#L.append('at line %s of file %s' % (
|
|
50 |
# self.viewclasslineno, self.viewclassfilename)
|
|
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
51 |
if self.doctestname: |
52 |
L.append("The doctest %s, at the line:" % self.doctestname) |
|
53 |
L.append(" >>> %s" % self.doctestline) |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
54 |
if self.requesturl: |
55 |
L.append('request url: %s' % self.requesturl) |
|
56 |
return '\n'.join(L) |
|
57 |
||
58 |
# PageTemplateFile has .filename.
|
|
59 |
from zope.pagetemplate.pagetemplatefile import PageTemplateFile |
|
60 |
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile |
|
61 |
||
62 |
# PythonExpr has .text, the text of the expression.
|
|
63 |
from zope.tales.pythonexpr import PythonExpr |
|
64 |
||
65 |
# TrustedZopeContext has self.contexts, a dict with template, view, context,
|
|
66 |
# request, etc.
|
|
67 |
from zope.app.pagetemplate.engine import TrustedZopeContext |
|
68 |
||
69 |
# TALInterpreter has self.sourceFile, a filename of a page template.
|
|
70 |
from zope.tal.talinterpreter import TALInterpreter |
|
71 |
||
72 |
from zope.app.pagetemplate.simpleviewclass import simple |
|
73 |
||
74 |
def find_important_info(): |
|
75 |
stack = inspect.stack() |
|
76 |
try: |
|
77 |
important_classes = set([ |
|
78 |
PythonExpr, |
|
79 |
TrustedZopeContext, |
|
80 |
TALInterpreter, |
|
81 |
ViewPageTemplateFile, |
|
82 |
simple
|
|
83 |
])
|
|
84 |
important_objects = {} |
|
85 |
metadata = {} # cls -> (filename, lineno, funcname) |
|
86 |
||
87 |
for frame, filename, lineno, func_name, context, lineidx in stack: |
|
88 |
try: |
|
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
89 |
if (filename.startswith('<doctest ') and |
90 |
"doctest" not in important_objects): |
|
91 |
# Very fragile inspection of the state of the doctest
|
|
92 |
# runner. So, enclosed in a try-except so it will at
|
|
93 |
# least fail gracefully if it fails.
|
|
94 |
try: |
|
95 |
line = frame.f_back.f_locals['example'].source |
|
96 |
except KeyboardInterrupt: |
|
97 |
pass
|
|
98 |
except Exception: |
|
99 |
line = "# cannot get line of code" |
|
100 |
important_objects["doctest"] = (filename, line) |
|
101 |
metadata["doctest"] = (filename, lineno, func_name) |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
102 |
if 'self' in frame.f_locals: |
103 |
fself = frame.f_locals['self'] |
|
104 |
ftype = type(fself) |
|
105 |
for cls in list(important_classes): |
|
106 |
if isinstance(fself, cls): |
|
107 |
important_objects[cls] = fself |
|
108 |
metadata[cls] = (filename, lineno, func_name) |
|
109 |
important_classes.remove(cls) |
|
110 |
finally: |
|
111 |
del frame |
|
112 |
finally: |
|
113 |
del stack |
|
114 |
||
115 |
expressiontext = '' |
|
116 |
if PythonExpr in important_objects: |
|
117 |
expressiontext = important_objects[PythonExpr].text |
|
118 |
||
119 |
viewclassname = '' |
|
120 |
viewclassfilename = '' |
|
121 |
viewclasslineno = '' |
|
122 |
viewclassfunc = '' |
|
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
123 |
doctestname = '' |
124 |
doctestline = '' |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
125 |
if simple in important_objects: |
126 |
cls = important_objects[simple].__class__ |
|
127 |
if cls is not simple: |
|
128 |
viewclassname = cls.__mro__[1].__name__ |
|
129 |
viewclassfilename, viewclasslineno, viewclassfunc = ( |
|
130 |
metadata[simple]) |
|
131 |
||
132 |
templatefilename = '' |
|
133 |
if ViewPageTemplateFile in important_objects: |
|
134 |
templatefilename = important_objects[ViewPageTemplateFile].filename |
|
135 |
templatefilename = templatefilename.split('/')[-1] |
|
136 |
||
137 |
requesturl = '' |
|
138 |
if TrustedZopeContext in important_objects: |
|
139 |
ptcontexts = important_objects[TrustedZopeContext].contexts |
|
140 |
requesturl = ptcontexts['request'].getURL() |
|
141 |
||
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
142 |
if "doctest" in important_objects: |
143 |
doctestname, doctestline = important_objects["doctest"] |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
144 |
return ImportantInfo(expressiontext, viewclassname, templatefilename, |
2419
by Canonical.com Patch Queue Manager
[trivial] improved warning output for warnings that occur in doctests. the now show the offending line of code. |
145 |
requesturl, viewclassfilename, viewclasslineno, viewclassfunc, |
146 |
doctestname, doctestline) |
|
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
147 |
|
148 |
need_page_titles = [] |
|
149 |
no_order_by = [] |
|
150 |
other_warnings = [] |
|
151 |
||
152 |
old_show_warning = warnings.showwarning |
|
153 |
def launchpad_showwarning(message, category, filename, lineno, file=None): |
|
154 |
if file is None: |
|
155 |
file = sys.stderr |
|
156 |
stream = StringIO.StringIO() |
|
157 |
old_show_warning(message, category, filename, lineno, stream) |
|
158 |
warning_message = stream.getvalue() |
|
159 |
important_info = find_important_info() |
|
160 |
||
161 |
if isinstance(message, UserWarning): |
|
162 |
args = message.args |
|
163 |
if args: |
|
164 |
arg = args[0] |
|
165 |
if arg.startswith('No page title in '): |
|
166 |
global need_page_titles |
|
167 |
need_page_titles.append(arg) |
|
168 |
return
|
|
169 |
if arg == 'Getting a slice of an unordered set is unpredictable.': |
|
170 |
# find the page template and view class, if any
|
|
171 |
# show these, plus the request.
|
|
172 |
global no_order_by |
|
173 |
no_order_by.append( |
|
174 |
WarningReport(warning_message, important_info) |
|
175 |
)
|
|
176 |
return
|
|
177 |
other_warnings.append(WarningReport(warning_message, important_info)) |
|
178 |
||
179 |
def report_need_page_titles(): |
|
180 |
global need_page_titles |
|
181 |
if need_page_titles: |
|
182 |
print
|
|
183 |
print "The following pages need titles." |
|
184 |
for message in need_page_titles: |
|
185 |
print " ", message |
|
186 |
||
187 |
def report_no_order_by(): |
|
188 |
global no_order_by |
|
189 |
if no_order_by: |
|
190 |
print
|
|
191 |
print ("The following code has issues with" |
|
192 |
" ambiguous select results ordering.") |
|
193 |
for report in no_order_by: |
|
194 |
print
|
|
195 |
print report |
|
196 |
||
197 |
def report_other_warnings(): |
|
198 |
global other_warnings |
|
199 |
if other_warnings: |
|
200 |
print
|
|
2482
by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings. |
201 |
print "General warnings." |
2103
by Canonical.com Patch Queue Manager
[trivial] improved warning output for tests, and fixed a bunch of ambiguous use of select results warnings. some xxx comments left in person code. one untested codepath in hct backend. |
202 |
for warninginfo in other_warnings: |
203 |
print
|
|
204 |
print warninginfo.message, |
|
205 |
print warninginfo |
|
206 |
||
207 |
def report_warnings(): |
|
208 |
report_need_page_titles() |
|
209 |
report_no_order_by() |
|
210 |
report_other_warnings() |
|
211 |
||
212 |
def install_warning_handler(): |
|
213 |
warnings.showwarning = launchpad_showwarning |
|
214 |
atexit.register(report_warnings) |