blob: fea9a841b8b477be6cc217f415fdb1b27d3ce5f5 [file] [log] [blame]
Guido van Rossumebbc01e2007-02-25 05:08:26 +00001"""Alternative to reload().
2
3This works by executing the module in a scratch namespace, and then
Guido van Rossume8ef4e12007-02-26 16:57:52 +00004patching classes, methods and functions in place. This avoids the
5need to patch instances. New objects are copied into the target
6namespace.
7
8Some of the many limitiations include:
9
10- Global mutable objects other than classes are simply replaced, not patched
11
12- Code using metaclasses is not handled correctly
13
14- Code creating global singletons is not handled correctly
15
16- Functions and methods using decorators (other than classmethod and
17 staticmethod) is not handled correctly
18
19- Renamings are not handled correctly
20
21- Dependent modules are not reloaded
22
23- When a dependent module contains 'from foo import bar', and
24 reloading foo deletes foo.bar, the dependent module continues to use
25 the old foo.bar object rather than failing
26
27- Frozen modules and modules loaded from zip files aren't handled
28 correctly
29
30- Classes involving __slots__ are not handled correctly
Guido van Rossumebbc01e2007-02-25 05:08:26 +000031"""
32
33import imp
34import sys
35import types
36
37
38def xreload(mod):
39 """Reload a module in place, updating classes, methods and functions.
40
41 Args:
42 mod: a module object
43
44 Returns:
45 The (updated) input object itself.
46 """
47 # Get the module name, e.g. 'foo.bar.whatever'
48 modname = mod.__name__
49 # Get the module namespace (dict) early; this is part of the type check
50 modns = mod.__dict__
51 # Parse it into package name and module name, e.g. 'foo.bar' and 'whatever'
52 i = modname.rfind(".")
53 if i >= 0:
54 pkgname, modname = modname[:i], modname[i+1:]
55 else:
56 pkgname = None
57 # Compute the search path
58 if pkgname:
59 # We're not reloading the package, only the module in it
60 pkg = sys.modules[pkgname]
61 path = pkg.__path__ # Search inside the package
62 else:
63 # Search the top-level module path
64 pkg = None
65 path = None # Make find_module() uses the default search path
66 # Find the module; may raise ImportError
67 (stream, filename, (suffix, mode, kind)) = imp.find_module(modname, path)
68 # Turn it into a code object
69 try:
70 # Is it Python source code or byte code read from a file?
Guido van Rossumebbc01e2007-02-25 05:08:26 +000071 if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
72 # Fall back to built-in reload()
73 return reload(mod)
74 if kind == imp.PY_SOURCE:
75 source = stream.read()
76 code = compile(source, filename, "exec")
77 else:
78 code = marshal.load(stream)
79 finally:
80 if stream:
81 stream.close()
Guido van Rossum5c0a6de2007-02-25 21:22:21 +000082 # Execute the code. We copy the module dict to a temporary; then
83 # clear the module dict; then execute the new code in the module
84 # dict; then swap things back and around. This trick (due to
85 # Glyph Lefkowitz) ensures that the (readonly) __globals__
86 # attribute of methods and functions is set to the correct dict
87 # object.
88 tmpns = modns.copy()
89 modns.clear()
90 modns["__name__"] = tmpns["__name__"]
91 exec(code, modns)
Guido van Rossumebbc01e2007-02-25 05:08:26 +000092 # Now we get to the hard part
Guido van Rossum5c0a6de2007-02-25 21:22:21 +000093 oldnames = set(tmpns)
94 newnames = set(modns)
95 # Update attributes in place
Guido van Rossumebbc01e2007-02-25 05:08:26 +000096 for name in oldnames & newnames:
Guido van Rossum5c0a6de2007-02-25 21:22:21 +000097 modns[name] = _update(tmpns[name], modns[name])
Guido van Rossumebbc01e2007-02-25 05:08:26 +000098 # Done!
99 return mod
100
101
102def _update(oldobj, newobj):
103 """Update oldobj, if possible in place, with newobj.
104
105 If oldobj is immutable, this simply returns newobj.
106
107 Args:
108 oldobj: the object to be updated
109 newobj: the object used as the source for the update
110
111 Returns:
112 either oldobj, updated in place, or newobj.
113 """
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000114 if oldobj is newobj:
115 # Probably something imported
116 return newobj
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000117 if type(oldobj) is not type(newobj):
118 # Cop-out: if the type changed, give up
119 return newobj
120 if hasattr(newobj, "__reload_update__"):
121 # Provide a hook for updating
122 return newobj.__reload_update__(oldobj)
123 if isinstance(newobj, types.ClassType):
124 return _update_class(oldobj, newobj)
125 if isinstance(newobj, types.FunctionType):
126 return _update_function(oldobj, newobj)
127 if isinstance(newobj, types.MethodType):
128 return _update_method(oldobj, newobj)
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000129 if isinstance(newobj, classmethod):
130 return _update_classmethod(oldobj, newobj)
131 if isinstance(newobj, staticmethod):
132 return _update_staticmethod(oldobj, newobj)
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000133 # Not something we recognize, just give up
134 return newobj
135
136
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000137# All of the following functions have the same signature as _update()
138
139
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000140def _update_function(oldfunc, newfunc):
141 """Update a function object."""
142 oldfunc.__doc__ = newfunc.__doc__
143 oldfunc.__dict__.update(newfunc.__dict__)
Neal Norwitz221085d2007-02-25 20:55:47 +0000144 oldfunc.__code__ = newfunc.__code__
145 oldfunc.__defaults__ = newfunc.__defaults__
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000146 return oldfunc
147
148
149def _update_method(oldmeth, newmeth):
150 """Update a method object."""
151 # XXX What if im_func is not a function?
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000152 _update(oldmeth.im_func, newmeth.im_func)
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000153 return oldmeth
154
155
156def _update_class(oldclass, newclass):
157 """Update a class object."""
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000158 olddict = oldclass.__dict__
159 newdict = newclass.__dict__
160 oldnames = set(olddict)
161 newnames = set(newdict)
162 for name in newnames - oldnames:
163 setattr(oldclass, name, newdict[name])
164 for name in oldnames - newnames:
165 delattr(oldclass, name)
166 for name in oldnames & newnames - {"__dict__", "__doc__"}:
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000167 setattr(oldclass, name, _update(olddict[name], newdict[name]))
Guido van Rossumebbc01e2007-02-25 05:08:26 +0000168 return oldclass
Guido van Rossum9a7e7742007-02-25 16:19:20 +0000169
170
171def _update_classmethod(oldcm, newcm):
172 """Update a classmethod update."""
173 # While we can't modify the classmethod object itself (it has no
174 # mutable attributes), we *can* extract the underlying function
175 # (by calling __get__(), which returns a method object) and update
176 # it in-place. We don't have the class available to pass to
177 # __get__() but any object except None will do.
178 _update(oldcm.__get__(0), newcm.__get__(0))
179 return newcm
180
181
182def _update_staticmethod(oldsm, newsm):
183 """Update a staticmethod update."""
184 # While we can't modify the staticmethod object itself (it has no
185 # mutable attributes), we *can* extract the underlying function
186 # (by calling __get__(), which returns it) and update it in-place.
187 # We don't have the class available to pass to __get__() but any
188 # object except None will do.
189 _update(oldsm.__get__(0), newsm.__get__(0))
190 return newsm