~launchpad-pqm/launchpad/devel

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