[Python-3000-checkins] r54592 - in python/branches/p3yk/Lib: test/test_xreload.py xreload.py

guido.van.rossum python-3000-checkins at python.org
Wed Mar 28 02:30:16 CEST 2007


Author: guido.van.rossum
Date: Wed Mar 28 02:30:15 2007
New Revision: 54592

Removed:
   python/branches/p3yk/Lib/test/test_xreload.py
   python/branches/p3yk/Lib/xreload.py
Log:
Moving xreload to the sandbox for now.


Deleted: /python/branches/p3yk/Lib/test/test_xreload.py
==============================================================================
--- /python/branches/p3yk/Lib/test/test_xreload.py	Wed Mar 28 02:30:15 2007
+++ (empty file)
@@ -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()

Deleted: /python/branches/p3yk/Lib/xreload.py
==============================================================================
--- /python/branches/p3yk/Lib/xreload.py	Wed Mar 28 02:30:15 2007
+++ (empty file)
@@ -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


More information about the Python-3000-checkins mailing list