Dynamically reload class definition in Python

I wrote an IRC bot using Twisted and now I got to the point where I want to dynamically reload the functionality.

In my main program I am doing from bots.google import GoogleBot

and I have looked at how to use reload

to reload modules, but I still cannot figure out how to do dynamic re-import of classes.

So, given a Python class, how do I dynamically reload a class definition?

+3


source to share


7 replies


I got it, here is the code I'm using:



def reimport_class(self, cls):
    """
    Reload and reimport class "cls".  Return the new definition of the class.
    """

    # Get the fully qualified name of the class.
    from twisted.python import reflect
    full_path = reflect.qual(cls)

    # Naively parse the module name and class name.
    # Can be done much better...
    match = re.match(r'(.*)\.([^\.]+)', full_path)
    module_name = match.group(1)
    class_name = match.group(2)

    # This is where the good stuff happens.
    mod = __import__(module_name, fromlist=[class_name])
    reload(mod)

    # The (reloaded definition of the) class itself is returned.
    return getattr(mod, class_name)

      

+1


source


Reboot is unreliable and has many corner cases where it can fail. It is suitable for reloading simple, stand-alone scripts. If you want to dynamically reload your code without restarting, use forkloop instead:



http://opensourcehacker.com/2011/11/08/sauna-reload-the-most-awesomely-named-python-package-ever/

+2


source


When you execute from ... import ...

, it binds the object to the local namespace, so whatever you need it re-imports. However, since the module is already loaded, it just re-imports the same version of the class so that you also have to reload the module. So this should do it:

from bots.google import GoogleBot
...
# do stuff
...
reload(bots.google)
from bots.google import GoogleBot

      

If for some reason you don't know the name of the module, you can get it from GoogleBot. module .

0


source


Better still the plugin subprocess, and then hypervise the subprocess when the files change the plugin process reload.

Edit: cleaned up.

0


source


You cannot reload a module using reload(module)

when using a form from X import Y

. In this case, you need to do something like reload(sys.modules['module'])

.

This may not be the best way to do what you want, but it works!

import bots.google

class BotClass(irc.IRCClient):
    def __init__(self):
        global plugins
        plugins = [bots.google.GoogleBot()]

    def privmsg(self, user, channel, msg):
        global plugins
        parts = msg.split(' ')
        trigger = parts[0]
        if trigger == '!reload':
            reload(bots.google)
            plugins = [bots.google.GoogleBot()] 
            print "Successfully reloaded plugins"

      

0


source


You can use sys.modules

to dynamically reload modules based on user input.

Say you have a folder with multiple plugins, for example:

module/
  cmdtest.py
  urltitle.py
  ...

      

You can use sys.modules

this way to load / reload modules based on userinput:

import sys

if sys.modules['module.' + userinput]:
    reload(sys.modules['module.' + userinput])

else: 
    ' Module not loaded. Cannot reload '
    try:
        module = __import__("module." + userinput)
        module = sys.modules["module." + userinput]
    except:
        ' error when trying to load %s ' % userinput

      

0


source


def reload_class(class_obj):
    module_name = class_obj.__module__
    module = sys.modules[module_name]
    pycfile = module.__file__
    modulepath = string.replace(pycfile, ".pyc", ".py")
    code=open(modulepath, 'rU').read()
    compile(code, module_name, "exec")
    module = reload(module)
    return getattr(module,class_obj.__name__)

      

There are many mistakes you can make about this, if you use globals you may have to figure out what happens next.

0


source







All Articles