summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2007-03-28 00:30:15 (GMT)
committerGuido van Rossum <guido@python.org>2007-03-28 00:30:15 (GMT)
commitcef2098cfa01b7dac92fece89fcb7d3439454061 (patch)
tree473f90a448dd9232bc8eea260953f12cb4f44e0e
parente27dc7230845aa341d9a0bf323fa14912713cf33 (diff)
downloadcpython-cef2098cfa01b7dac92fece89fcb7d3439454061.zip
cpython-cef2098cfa01b7dac92fece89fcb7d3439454061.tar.gz
cpython-cef2098cfa01b7dac92fece89fcb7d3439454061.tar.bz2
Moving xreload to the sandbox for now.
-rw-r--r--Lib/test/test_xreload.py103
-rw-r--r--Lib/xreload.py190
2 files changed, 0 insertions, 293 deletions
diff --git a/Lib/test/test_xreload.py b/Lib/test/test_xreload.py
deleted file mode 100644
index dcd6569..0000000
--- a/Lib/test/test_xreload.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""Doctests for module reloading.
-
->>> from xreload import xreload
->>> from test.test_xreload import make_mod
->>> make_mod()
->>> import x
->>> C = x.C
->>> Cfoo = C.foo
->>> Cbar = C.bar
->>> Cstomp = C.stomp
->>> b = C()
->>> bfoo = b.foo
->>> b.foo()
-42
->>> bfoo()
-42
->>> Cfoo(b)
-42
->>> Cbar()
-42 42
->>> Cstomp()
-42 42 42
->>> make_mod(repl="42", subst="24")
->>> xreload(x)
-<module 'x' (built-in)>
->>> b.foo()
-24
->>> bfoo()
-24
->>> Cfoo(b)
-24
->>> Cbar()
-24 24
->>> Cstomp()
-24 24 24
-
-"""
-
-SAMPLE_CODE = """
-class C:
- def foo(self):
- print(42)
- @classmethod
- def bar(cls):
- print(42, 42)
- @staticmethod
- def stomp():
- print (42, 42, 42)
-"""
-
-import os
-import sys
-import shutil
-import doctest
-import xreload
-import tempfile
-from test.test_support import run_unittest
-
-tempdir = None
-save_path = None
-
-
-def setUp(unused=None):
- global tempdir, save_path
- tempdir = tempfile.mkdtemp()
- save_path = list(sys.path)
- sys.path.append(tempdir)
-
-
-def tearDown(unused=None):
- global tempdir, save_path
- if save_path is not None:
- sys.path = save_path
- save_path = None
- if tempdir is not None:
- shutil.rmtree(tempdir)
- tempdir = None
-
-
-def make_mod(name="x", repl=None, subst=None):
- if not tempdir:
- setUp()
- assert tempdir
- fn = os.path.join(tempdir, name + ".py")
- f = open(fn, "w")
- sample = SAMPLE_CODE
- if repl is not None and subst is not None:
- sample = sample.replace(repl, subst)
- try:
- f.write(sample)
- finally:
- f.close()
-
-
-def test_suite():
- return doctest.DocTestSuite(setUp=setUp, tearDown=tearDown)
-
-
-def test_main():
- run_unittest(test_suite())
-
-if __name__ == "__main__":
- test_main()
diff --git a/Lib/xreload.py b/Lib/xreload.py
deleted file mode 100644
index fea9a84..0000000
--- a/Lib/xreload.py
+++ /dev/null
@@ -1,190 +0,0 @@
-"""Alternative to reload().
-
-This works by executing the module in a scratch namespace, and then
-patching classes, methods and functions in place. This avoids the
-need to patch instances. New objects are copied into the target
-namespace.
-
-Some of the many limitiations include:
-
-- Global mutable objects other than classes are simply replaced, not patched
-
-- Code using metaclasses is not handled correctly
-
-- Code creating global singletons is not handled correctly
-
-- Functions and methods using decorators (other than classmethod and
- staticmethod) is not handled correctly
-
-- Renamings are not handled correctly
-
-- Dependent modules are not reloaded
-
-- When a dependent module contains 'from foo import bar', and
- reloading foo deletes foo.bar, the dependent module continues to use
- the old foo.bar object rather than failing
-
-- Frozen modules and modules loaded from zip files aren't handled
- correctly
-
-- Classes involving __slots__ are not handled correctly
-"""
-
-import imp
-import sys
-import types
-
-
-def xreload(mod):
- """Reload a module in place, updating classes, methods and functions.
-
- Args:
- mod: a module object
-
- Returns:
- The (updated) input object itself.
- """
- # Get the module name, e.g. 'foo.bar.whatever'
- modname = mod.__name__
- # Get the module namespace (dict) early; this is part of the type check
- modns = mod.__dict__
- # Parse it into package name and module name, e.g. 'foo.bar' and 'whatever'
- i = modname.rfind(".")
- if i >= 0:
- pkgname, modname = modname[:i], modname[i+1:]
- else:
- pkgname = None
- # Compute the search path
- if pkgname:
- # We're not reloading the package, only the module in it
- pkg = sys.modules[pkgname]
- path = pkg.__path__ # Search inside the package
- else:
- # Search the top-level module path
- pkg = None
- path = None # Make find_module() uses the default search path
- # Find the module; may raise ImportError
- (stream, filename, (suffix, mode, kind)) = imp.find_module(modname, path)
- # Turn it into a code object
- try:
- # Is it Python source code or byte code read from a file?
- if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
- # Fall back to built-in reload()
- return reload(mod)
- if kind == imp.PY_SOURCE:
- source = stream.read()
- code = compile(source, filename, "exec")
- else:
- code = marshal.load(stream)
- finally:
- if stream:
- stream.close()
- # Execute the code. We copy the module dict to a temporary; then
- # clear the module dict; then execute the new code in the module
- # dict; then swap things back and around. This trick (due to
- # Glyph Lefkowitz) ensures that the (readonly) __globals__
- # attribute of methods and functions is set to the correct dict
- # object.
- tmpns = modns.copy()
- modns.clear()
- modns["__name__"] = tmpns["__name__"]
- exec(code, modns)
- # Now we get to the hard part
- oldnames = set(tmpns)
- newnames = set(modns)
- # Update attributes in place
- for name in oldnames & newnames:
- modns[name] = _update(tmpns[name], modns[name])
- # Done!
- return mod
-
-
-def _update(oldobj, newobj):
- """Update oldobj, if possible in place, with newobj.
-
- If oldobj is immutable, this simply returns newobj.
-
- Args:
- oldobj: the object to be updated
- newobj: the object used as the source for the update
-
- Returns:
- either oldobj, updated in place, or newobj.
- """
- if oldobj is newobj:
- # Probably something imported
- return newobj
- if type(oldobj) is not type(newobj):
- # Cop-out: if the type changed, give up
- return newobj
- if hasattr(newobj, "__reload_update__"):
- # Provide a hook for updating
- return newobj.__reload_update__(oldobj)
- if isinstance(newobj, types.ClassType):
- return _update_class(oldobj, newobj)
- if isinstance(newobj, types.FunctionType):
- return _update_function(oldobj, newobj)
- if isinstance(newobj, types.MethodType):
- return _update_method(oldobj, newobj)
- if isinstance(newobj, classmethod):
- return _update_classmethod(oldobj, newobj)
- if isinstance(newobj, staticmethod):
- return _update_staticmethod(oldobj, newobj)
- # Not something we recognize, just give up
- return newobj
-
-
-# All of the following functions have the same signature as _update()
-
-
-def _update_function(oldfunc, newfunc):
- """Update a function object."""
- oldfunc.__doc__ = newfunc.__doc__
- oldfunc.__dict__.update(newfunc.__dict__)
- oldfunc.__code__ = newfunc.__code__
- oldfunc.__defaults__ = newfunc.__defaults__
- return oldfunc
-
-
-def _update_method(oldmeth, newmeth):
- """Update a method object."""
- # XXX What if im_func is not a function?
- _update(oldmeth.im_func, newmeth.im_func)
- return oldmeth
-
-
-def _update_class(oldclass, newclass):
- """Update a class object."""
- olddict = oldclass.__dict__
- newdict = newclass.__dict__
- oldnames = set(olddict)
- newnames = set(newdict)
- for name in newnames - oldnames:
- setattr(oldclass, name, newdict[name])
- for name in oldnames - newnames:
- delattr(oldclass, name)
- for name in oldnames & newnames - {"__dict__", "__doc__"}:
- setattr(oldclass, name, _update(olddict[name], newdict[name]))
- return oldclass
-
-
-def _update_classmethod(oldcm, newcm):
- """Update a classmethod update."""
- # While we can't modify the classmethod object itself (it has no
- # mutable attributes), we *can* extract the underlying function
- # (by calling __get__(), which returns a method object) and update
- # it in-place. We don't have the class available to pass to
- # __get__() but any object except None will do.
- _update(oldcm.__get__(0), newcm.__get__(0))
- return newcm
-
-
-def _update_staticmethod(oldsm, newsm):
- """Update a staticmethod update."""
- # While we can't modify the staticmethod object itself (it has no
- # mutable attributes), we *can* extract the underlying function
- # (by calling __get__(), which returns it) and update it in-place.
- # We don't have the class available to pass to __get__() but any
- # object except None will do.
- _update(oldsm.__get__(0), newsm.__get__(0))
- return newsm