1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
# Copyright 2006-2007 Nanorex, Inc. See LICENSE file for details.
"""
qt4transition.py - Useful markers and messages for Qt 4 transition work.
@author: Will
@version: $Id$
@copyright: 2006-2007 Nanorex, Inc. See LICENSE file for details.
"""
import sys
import traceback
import types
import utilities.debug_prefs as debug_prefs
import utilities.debug as debug
from utilities.objectBrowse import objectBrowse
__already = { }
def __linenum(always = False):
try:
raise Exception
except:
tb = sys.exc_info()[2]
f = tb.tb_frame
f = f.f_back
f = f.f_back
key = (f.f_code.co_filename, f.f_lineno)
got_key = True
if not __already.has_key(key):
__already[key] = 1
got_key = False
if got_key and not always:
return False
else:
print f.f_code.co_filename, f.f_code.co_name, f.f_lineno
return True
def qt4here(msg = None, show_traceback = False):
if show_traceback:
traceback.print_stack(None, None, sys.stdout)
if msg is not None:
print 'Qt 4 HERE: ' + msg
print
else:
__linenum(always = True)
if msg is not None:
print 'Qt 4 HERE: ' + msg
def qt4overhaul(msg):
if __linenum():
print 'Qt 4 MAJOR CONCEPTUAL OVERHAUL: ' + msg
def qt4message(msg, always = False):
if debug_prefs.debug_pref("Enable QT4 TODO messages",
debug_prefs.Choice_boolean_False,
prefs_key = True):
if __linenum(always):
print 'Qt 4 MESSAGE: ' + msg
def qt4todo(msg):
if debug_prefs.debug_pref("Enable QT4 TODO messages",
debug_prefs.Choice_boolean_False,
prefs_key = True):
if __linenum():
print 'Qt 4 TODO: ' + msg
else:
return
def multipane_todo(msg):
if __linenum():
print 'Multipane TODO: ' + msg
def qt4warning(msg):
if debug_prefs.debug_pref("Enable QT4 WARNING messages",
debug_prefs.Choice_boolean_False,
prefs_key = True):
if __linenum():
print 'Qt 4 WARNING: ' + msg
def qt4skipit(msg):
"""
Indicates something I don't think we need for Qt 4
"""
if __linenum():
print 'Qt 4 SKIP IT: ' + msg
__nomsg = '128931789ksadjfqwhrhlv128947890127408'
def qt4die(msg = __nomsg, browse = False):
traceback.print_stack(file = sys.stdout)
if msg == __nomsg:
print 'Qt 4 DIE'
elif browse:
print 'Qt 4 DIE:', msg
objectBrowse(msg, maxdepth = 1)
else:
if type(msg) is not types.StringType:
msg = repr(msg)
print 'Qt 4 DIE: ' + msg
sys.exit(0)
def qt4exception(msg):
"""
Indicates something I don't think we definitely shouldn't have for Qt 4
"""
raise Exception('Qt 4: ' + msg)
def qt4info(msg, name = None, maxdepth = 1, browse = False):
__linenum(always = True)
if type(msg) is type('abc'):
print 'Qt 4 INFO:', repr(msg)
else:
print 'Qt 4 INFO:',
if name is not None: print name,
print repr(msg)
if browse:
objectBrowse(msg, maxdepth = maxdepth, outf = sys.stdout)
def qt4warnDestruction(obj, name = ''):
message = '* * * * '
try:
raise Exception
except:
f = sys.exc_info()[2].tb_frame
f = f.f_back
message += f.f_code.co_filename + (':%d' % f.f_lineno)
if name:
message += ' ' + name
if debug_prefs.debug_pref("Enable QT4 WARNING messages",
debug_prefs.Choice_boolean_False,
prefs_key = True):
print 'Setting up destruction warning', message
def destruction(ignore, message = message):
print 'OBJECT DESTROYED (exiting)', message #bruce 070521 revised message
sys.exit(1)
from PyQt4.Qt import QObject, SIGNAL
QObject.connect(obj, SIGNAL("destroyed(QObject *)"), destruction)
def findDefiningClass(cls_or_method, method_name = None):
"""
Find which base class defines this method
>>> print findDefiningClass(DeepClass.foo)
__main__.BaseClass
>>> print findDefiningClass(ShallowClass.foo)
__main__.Base2Class
>>> print findDefiningClass(ShallowClass, 'foo')
__main__.Base2Class
>>> x = DeepClass()
>>> print findDefiningClass(x.foo)
__main__.BaseClass
"""
if method_name is not None:
if type(cls_or_method) is not types.ClassType:
cls_or_method = cls_or_method.__class__
method = getattr(cls_or_method, method_name)
elif type(cls_or_method) is types.MethodType:
method = getattr(cls_or_method.im_class, cls_or_method.im_func.func_name)
else:
method = cls_or_method
assert method.im_self is None, "Method must be a class method, not an instance mthod"
def hunt(klass, lst, depth, name = method.im_func.func_name, method = method):
if hasattr(klass, name) and method.im_func is getattr(klass, name).im_func:
lst.append((depth, klass))
for base in klass.__bases__:
hunt(base, lst, depth + 1)
lst = [ ]
hunt(method.im_class, lst, 0)
lst.sort()
return lst[-1][1]
def lineage(widget, die = True, depth = 0):
"""
Trace the parental lineage of a Qt 4 widget: parent,
grandparent... This is helpful in diagnosing "RuntimeError:
underlying C/C++ object has been deleted" errors. It is frequently
wise to kill the program at the first such deletion, so that is the
default behavior (switchable with die = False).
"""
if widget is not None:
from PyQt4.Qt import QObject, SIGNAL
print (depth * ' ') + repr(widget)
def destruction(ignore, die = die, message = repr(widget) + " was just destroyed"):
qt4here(message, show_traceback = True)
if die:
sys.exit(1)
QObject.connect(widget, SIGNAL("destroyed(QObject *)"), destruction)
lineage(widget.parent(), die, depth + 1)
# ==
if __name__ == '__main__':
# classes used to test findDefiningClass
class BaseClass:
def foo(self):
print 'bar'
class Base2Class:
def foo(self):
print 'BAR'
class MiddleClass(BaseClass):
pass
class DeepClass(MiddleClass, Base2Class):
pass
class ShallowClass(Base2Class, MiddleClass):
pass
import doctest
doctest.testmod()
# end
|