Reloading on the fly: was: Re: Python Productivity over C++

Alex cut_me_out at hotmail.com
Sat Jun 10 10:35:04 EDT 2000


> Could you post an example of designing the main program to reload
> submodules? I'd like to get that working, too, and coming from
> languages where that's impossible, I've a bit of trouble coming up
> with a solution...

I posted something about that recently.  I've posted the code again
below.  I must admit, I haven't had much occasion to test it yet, as I
haven't been working on anything with complex module dependancies.
Also, if you had many modules, it would probably be a bit slow as it
stands.

import sys, string
from types import ModuleType

class Reloader:

    '''Here is my attempt at something that figures out an appropriate
    reloading order for you.  You create an instance of the class,
    call it 'rr', before you have imported any of the modules you'll
    be wanting to reload (the .pythonrc file would be a good place.)
    Then when you wish to reload the modules in a given namespace, you
    run the command

    exec (rr (globals ())) 

    In my case, the namespace would usually be __main__, so this would
    just go at the top of the script I'm currently working on in
    emacs.

    Alex.
    '''

    def __init__ (self):
        self.keepem = sys.modules.copy ()

    def get_new_modules (self):
        modules = {}
        for i, m in sys.modules.items():
            if (not self.keepem.has_key (i)) and \
               (type(m) == ModuleType):
                modules[i] = m
        return modules

    def clear_sys_modules (self):
        for i in self.modules.keys ():
            if sys.modules.has_key (i):
                del sys.modules[i]

    def get_dependancies (self, module_name):
        self.clear_sys_modules ()
        exec 'import ' + module_name
        new_modules = self.get_new_modules ()
        del new_modules[module_name]
        return new_modules

    def determine_reloads (self):
        self.return_commands = []
        while self.dependancies:
            for i, deps in self.dependancies.items ():
                if not deps:
                    break
            else:
                raise 'Cyclic dependancy(?)'
            exec 'import ' + i
            reload (eval (i))
            if self.namespace.has_key (i) and \
               (self.namespace[i] == self.modules[i]):
                self.return_commands.append (
                    'import %s; reload (%s)' % (i, i))
            del self.dependancies[i]
            for deps in self.dependancies.values ():
                while deps.count (i):
                    deps.remove (i)

    def __call__ (self, namespace):
        self.namespace = namespace
        self.modules = self.get_new_modules ()
        self.dependancies = {}
        for module_name in self.modules.keys ():
            deps = self.get_dependancies (module_name).keys ()
            self.dependancies[module_name] = deps
        self.determine_reloads ()
        return string.join (self.return_commands, ';')

rr = Reloader ()

if __name__ == '__main__':
    '''This is a test script, intended to be run with two modules, B.py
    and C.py somewhere in the directories in sys.path.  Their contents
    should be

    B.py:
    ######################################################################
    import C

    class B (C.C):
    
        def __init__ (self):
            C.C.__init__ (self)
        
    C.py:
    ######################################################################
    class C:

        def __init__ (self):
            pass
    '''
    import B, C

    bid = id (B.B)
    cid = id (C.C)
    exec (rr (globals ()))
    assert (bid != id (B.B)) and (cid != id (C.C))

    t = B.B ()



More information about the Python-list mailing list