~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/python/rebuild.py

  • Committer: Bazaar Package Importer
  • Author(s): Moshe Zadka
  • Date: 2002-03-08 07:14:16 UTC
  • Revision ID: james.westby@ubuntu.com-20020308071416-oxvuw76tpcpi5v1q
Tags: upstream-0.15.5
ImportĀ upstreamĀ versionĀ 0.15.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
# Twisted, the Framework of Your Internet
 
3
# Copyright (C) 2001 Matthew W. Lefkowitz
 
4
#
 
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.
 
8
#
 
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.
 
13
#
 
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
 
17
 
 
18
"""
 
19
*Real* reloading support for Python.
 
20
"""
 
21
 
 
22
# System Imports
 
23
import sys
 
24
import types
 
25
import time
 
26
import linecache
 
27
 
 
28
# Sibling Imports
 
29
import log
 
30
 
 
31
lastRebuild = time.time()
 
32
 
 
33
class Sensitive:
 
34
 
 
35
    """A utility mixin that's sensitive to rebuilds.
 
36
 
 
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.
 
39
    """
 
40
 
 
41
    lastRebuild = lastRebuild
 
42
 
 
43
    def needRebuildUpdate(self):
 
44
        yn = (self.lastRebuild < lastRebuild)
 
45
        return yn
 
46
 
 
47
    def rebuildUpToDate(self):
 
48
        self.lastRebuild = time.time()
 
49
 
 
50
    def latestVersionOf(self, object):
 
51
        """Get the latest version of an object.
 
52
 
 
53
        This can handle just about anything callable; instances, functions,
 
54
        methods, and classes.
 
55
        """
 
56
        t = type(object)
 
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__)
 
62
            else:
 
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)
 
67
            return object
 
68
        elif t == types.ClassType:
 
69
            return latestClass(object)
 
70
        else:
 
71
            print 'warning returning object!'
 
72
            return object
 
73
 
 
74
_modDictIDMap = {}
 
75
 
 
76
def latestFunction(oldFunc):
 
77
    """Get the latest version of a function.
 
78
    """
 
79
    # This may be CPython specific, since I believe jython instantiates a new
 
80
    # module upon reload.
 
81
    dictID = id(oldFunc.func_globals)
 
82
    module = _modDictIDMap.get(dictID)
 
83
    if module is None:
 
84
        return oldFunc
 
85
    return getattr(module, oldFunc.__name__)
 
86
 
 
87
def latestClass(oldClass):
 
88
    """Get the latest version of a class.
 
89
    """
 
90
    module = __import__(oldClass.__module__, {}, {}, 'nothing')
 
91
    newClass = getattr(module, oldClass.__name__)
 
92
    newBases = []
 
93
    for base in newClass.__bases__:
 
94
        newBases.append(latestClass(base))
 
95
    newClass.__bases__ = tuple(newBases)
 
96
    return newClass
 
97
 
 
98
def updateInstance(self):
 
99
    """Updates an instance to be current
 
100
    """
 
101
    self.__class__ = latestClass(self.__class__)
 
102
 
 
103
def __getattr__(self, name):
 
104
    """A getattr method to cause a class to be refreshed.
 
105
    """
 
106
    updateInstance(self)
 
107
    log.msg("(rebuilding stale %s instance (%s))" % (str(self.__class__), name))
 
108
    result = getattr(self, name)
 
109
    return result
 
110
 
 
111
def rebuild(module, doLog=1):
 
112
    """Reload a module and do as much as possible to replace its references.
 
113
    """
 
114
    global lastRebuild
 
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."
 
120
    if doLog:
 
121
        log.msg( 'Rebuilding %s...' % str(module.__name__))
 
122
    d = module.__dict__
 
123
    _modDictIDMap[id(d)] = module
 
124
    classes = {}
 
125
    functions = {}
 
126
    values = {}
 
127
    if doLog:
 
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__:
 
134
                classes[v] = 1
 
135
                if doLog:
 
136
                    sys.stdout.write("c")
 
137
                    sys.stdout.flush()
 
138
        elif type(v) == types.FunctionType:
 
139
            if v.func_globals is module.__dict__:
 
140
                functions[v] = 1
 
141
                if doLog:
 
142
                    sys.stdout.write("f")
 
143
                    sys.stdout.flush()
 
144
 
 
145
    values.update(classes)
 
146
    values.update(functions)
 
147
    fromOldModule = values.has_key
 
148
    classes = classes.keys()
 
149
    functions = functions.keys()
 
150
 
 
151
    if doLog:
 
152
        print
 
153
        print '  (reload   %s)' % str(module.__name__)
 
154
 
 
155
    # Boom.
 
156
    reload(module)
 
157
    # Make sure that my traceback printing will at least be recent...
 
158
    linecache.clearcache()
 
159
 
 
160
    if doLog:
 
161
        print '  (cleaning %s): ' % str(module.__name__),
 
162
 
 
163
    for clazz in classes:
 
164
        if getattr(module, clazz.__name__) is clazz:
 
165
            print "WARNING: class %s not replaced by reload!" % str(clazz)
 
166
        else:
 
167
            if doLog:
 
168
                sys.stdout.write("x")
 
169
                sys.stdout.flush()
 
170
            clazz.__bases__ = ()
 
171
            clazz.__dict__.clear()
 
172
            clazz.__getattr__ = __getattr__
 
173
            clazz.__module__ = module.__name__
 
174
    if doLog:
 
175
        print
 
176
        print '  (fixing   %s): ' % str(module.__name__),
 
177
    modcount = 0
 
178
    for mk, mod in sys.modules.items():
 
179
        modcount = modcount + 1
 
180
        if mod == module or mod is None:
 
181
            continue
 
182
 
 
183
        if hasattr(mod, '__name__') and mod.__name__ != '__main__' and not hasattr(mod, '__file__'):
 
184
            # It's a builtin module; nothing to replace here.
 
185
            continue
 
186
        changed = 0
 
187
        for k, v in mod.__dict__.items():
 
188
            # print "checking for %s.%s" % (mod.__name__, k)
 
189
            try:
 
190
                hash(v)
 
191
            except TypeError:
 
192
                continue
 
193
            if fromOldModule(v):
 
194
                # print "Found a match! (%s.%s)" % (mod.__name__, k)
 
195
                if type(v) == types.ClassType:
 
196
                    if doLog:
 
197
                        sys.stdout.write("c")
 
198
                        sys.stdout.flush()
 
199
                    nv = latestClass(v)
 
200
                else:
 
201
                    if doLog:
 
202
                        sys.stdout.write("f")
 
203
                        sys.stdout.flush()
 
204
                    nv = latestFunction(v)
 
205
                changed = 1
 
206
                setattr(mod, k, nv)
 
207
            else:
 
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):
 
212
                            latestClass(v)
 
213
        if doLog and not changed and ((modcount % 10) ==0) :
 
214
            sys.stdout.write(".")
 
215
            sys.stdout.flush()
 
216
    if doLog:
 
217
        print
 
218
        print '   Rebuilt %s.' % str(module.__name__)
 
219
    return module