Pour BUTT j’ai voulu un mini système de plugins/modules afin de rajouter ou modifier du code sans redémarrer mon process. Et Python propose nativement cela grâce au module imp. On va utiliser spécifiquement la procédure load_source qui permet de charger un fichier source, de le parser, et de retourner son objet Module.
Illustrons. Voici le code du très simple module à importer:
class TestModule:
def __init__(self):
pass
def myfunction(self):
print "Calling myfunction"
Procédure de chargement du module:
import os, shutil
import imp
def load_module(module_name):
print "Loading module %s" % module_name
modfile = os.path.join(os.getcwd(), module_name + '.py')
module = imp.load_source(module_name, modfile)
print module
# Returns <module 'test' from '/home/mycroft/imp/test.pyc'>
print dir(module)
# Permet de lister les differents attributs de l'objet importé.
# Returns ['TestModule', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
for objname in dir(module):
# Je veux specifiquement les modules suffixés "Module":
if objname.endswith('Module'):
modclass = getattr(module, objname)
print modclass
# Returns test.TestModule
print dir(modlass)
# Returns ['__doc__', '__init__', '__module__', 'myfunction']
return modclass
return None
Il ne reste plus qu’à montrer par l’exemple le fonctionnement et le reload d’un module dans le main:
modclass = load_module('test')
instance = modclass()
instance.myfunction()
# We move away test.py, and copy test_new.py to test.py.
shutil.move('test.py', 'test_old.py')
shutil.move('test_new.py', 'test.py')
modclass = load_module('test')
instance = modclass()
instance.myfunction()
shutil.move('test.py', 'test_new.py')
shutil.move('test_old.py', 'test.py')
Qui nous donnera:
Loading module test
<module 'test' from '/home/mycroft/imp/test.py'>
['TestModule', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
test.TestModule
['__doc__', '__init__', '__module__', 'myfunction']
Calling myfunction
Loading module test
<module 'test' from '/home/mycroft/imp/test.py'>
['TestModule', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
test.TestModule
['__doc__', '__init__', '__module__', 'myfunction']
Calling (new) myfunction
Le code modifié (ici test.py a été remplacé par test_new.py, qui contient du code modifié) a bien été relu par python et est à présent utilisé.