2
# Twisted, the Framework of Your Internet
3
# Copyright (C) 2001 Matthew W. Lefkowitz
5
# This library is free software; you can redistribute it and/or
6
# modify it under the terms of version 2.1 of the GNU Lesser General Public
7
# License as published by the Free Software Foundation.
9
# This library is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
# Lesser General Public License for more details.
14
# You should have received a copy of the GNU Lesser General Public
15
# License along with this library; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*Real* reloading support for Python.
31
lastRebuild = time.time()
35
"""A utility mixin that's sensitive to rebuilds.
37
This is a mixin for classes (usually those which represent collections of
38
callbacks) to make sure that their code is up-to-date before running.
41
lastRebuild = lastRebuild
43
def needRebuildUpdate(self):
44
yn = (self.lastRebuild < lastRebuild)
47
def rebuildUpToDate(self):
48
self.lastRebuild = time.time()
50
def latestVersionOf(self, object):
51
"""Get the latest version of an object.
53
This can handle just about anything callable; instances, functions,
57
if t == types.FunctionType:
58
return latestFunction(object)
59
elif t == types.MethodType:
60
if object.im_self is None:
61
return getattr(object.im_class, object.__name__)
63
return getattr(object.im_self, object.__name__)
64
elif t == types.InstanceType:
65
# Kick it, if it's out of date.
66
getattr(object, 'nothing', None)
68
elif t == types.ClassType:
69
return latestClass(object)
71
print 'warning returning object!'
76
def latestFunction(oldFunc):
77
"""Get the latest version of a function.
79
# This may be CPython specific, since I believe jython instantiates a new
81
dictID = id(oldFunc.func_globals)
82
module = _modDictIDMap.get(dictID)
85
return getattr(module, oldFunc.__name__)
87
def latestClass(oldClass):
88
"""Get the latest version of a class.
90
module = __import__(oldClass.__module__, {}, {}, 'nothing')
91
newClass = getattr(module, oldClass.__name__)
93
for base in newClass.__bases__:
94
newBases.append(latestClass(base))
95
newClass.__bases__ = tuple(newBases)
98
def updateInstance(self):
99
"""Updates an instance to be current
101
self.__class__ = latestClass(self.__class__)
103
def __getattr__(self, name):
104
"""A getattr method to cause a class to be refreshed.
107
log.msg("(rebuilding stale %s instance (%s))" % (str(self.__class__), name))
108
result = getattr(self, name)
111
def rebuild(module, doLog=1):
112
"""Reload a module and do as much as possible to replace its references.
115
lastRebuild = time.time()
116
if hasattr(module, 'ALLOW_TWISTED_REBUILD'):
117
# Is this module allowed to be rebuilt?
118
if not module.ALLOW_TWISTED_REBUILD:
119
raise RuntimeError, "I am not allowed to be rebuilt."
121
log.msg( 'Rebuilding %s...' % str(module.__name__))
123
_modDictIDMap[id(d)] = module
128
print ' (scanning %s): ' % str(module.__name__),
129
for k, v in d.items():
130
if type(v) == types.ClassType:
131
# Failure condition -- instances of classes with buggy
132
# __hash__/__cmp__ methods referenced at the module level...
133
if v.__module__ == module.__name__:
136
sys.stdout.write("c")
138
elif type(v) == types.FunctionType:
139
if v.func_globals is module.__dict__:
142
sys.stdout.write("f")
145
values.update(classes)
146
values.update(functions)
147
fromOldModule = values.has_key
148
classes = classes.keys()
149
functions = functions.keys()
153
print ' (reload %s)' % str(module.__name__)
157
# Make sure that my traceback printing will at least be recent...
158
linecache.clearcache()
161
print ' (cleaning %s): ' % str(module.__name__),
163
for clazz in classes:
164
if getattr(module, clazz.__name__) is clazz:
165
print "WARNING: class %s not replaced by reload!" % str(clazz)
168
sys.stdout.write("x")
171
clazz.__dict__.clear()
172
clazz.__getattr__ = __getattr__
173
clazz.__module__ = module.__name__
176
print ' (fixing %s): ' % str(module.__name__),
178
for mk, mod in sys.modules.items():
179
modcount = modcount + 1
180
if mod == module or mod is None:
183
if hasattr(mod, '__name__') and mod.__name__ != '__main__' and not hasattr(mod, '__file__'):
184
# It's a builtin module; nothing to replace here.
187
for k, v in mod.__dict__.items():
188
# print "checking for %s.%s" % (mod.__name__, k)
194
# print "Found a match! (%s.%s)" % (mod.__name__, k)
195
if type(v) == types.ClassType:
197
sys.stdout.write("c")
202
sys.stdout.write("f")
204
nv = latestFunction(v)
208
# Replace bases of non-module classes just to be sure.
209
if type(v) == types.ClassType:
210
for base in v.__bases__:
211
if fromOldModule(base):
213
if doLog and not changed and ((modcount % 10) ==0) :
214
sys.stdout.write(".")
218
print ' Rebuilt %s.' % str(module.__name__)