Forcer l'interpréteur python à recharger un module de code

le cycle de développement de code Python OpenERP consiste à éditer votre code, redémarrer le serveur et le tester. Redémarrer le serveur est nécessaire, car c'est ce qui fait que votre code source doit être rechargé en mémoire, mais cela ajoute un retard gênant dans votre rythme de travail.

étant donné que python est un langage dynamique, je me demande s'il y a un moyen de forcer un interpréteur Python en cours d'exécution (le serveur app ) à recharger à la volée un module de code, de sorte qu'il puisse être testé sans redémarrer le serveur d'application?

mise à Jour: En suivant le chemin reload suggéré par @ecatmur, j'ai obtenu le code ci-dessous, mais il ne fonctionne toujours pas:

class module(osv.osv):
    _inherit = "ir.module.module"

    def action_reload(self, cr, uid, ids, context=None):
        for obj in self.browse(cr, uid, ids, context=context):
            modulename = 'openerp.addons.' + obj.name
            tmp = __import__(modulename)
            pycfile = tmp.__file__
            modulepath = string.replace(pycfile, ".pyc", ".py")
            code=open(modulepath, 'rU').read()
            compile(code, modulename, "exec")
            execfile(modulepath)
            reload( sys.modules[modulename] )
        openerp.modules.registry.RegistryManager.delete(cr.dbname)
        openerp.modules.registry.RegistryManager.new(cr.dbname)
20
demandé sur Daniel Reis 2012-09-26 12:01:41

5 réponses

mise à JOUR: depuis le v8 Odoo server fournit un --auto-reload option pour effectuer cette.

excellente question, je me suis souvent demandé la même chose. Je pense que le principal problème avec le code que vous avez posté est qu'il ne recharge que le fichier __init__.py du module OpenERP, pas tous les fichiers individuels. Le module reimport recommandé par ecatmur s'occupe de cela, et j'ai également dû désinscrire Les analyseurs de rapport du module et les classes de modèles avant de tout recharger.

j'ai posté mon module module_reload sur Launchpad . Il semble fonctionner pour les changements aux classes de modèle, osv_memory magiciens, et les analyseurs de rapport. Il ne fonctionne pas pour les sorciers de l'ancien style, et il peut y avoir d'autres scénarios qui ne fonctionnent pas.

Voici la méthode qui recharge le module.

def button_reload(self, cr, uid, ids, context=None):
    for module_record in self.browse(cr, uid, ids, context=context):
        #Remove any report parsers registered for this module.
        module_path = 'addons/' + module_record.name
        for service_name, service in Service._services.items():
            template = getattr(service, 'tmpl', '')
            if template.startswith(module_path):
                Service.remove(service_name)

        #Remove any model classes registered for this module
        MetaModel.module_to_models[module_record.name] = []                    

        #Reload all Python modules from the OpenERP module's directory.
        modulename = 'openerp.addons.' + module_record.name
        root = __import__(modulename)
        module = getattr(root.addons, module_record.name)

        reimport(module)
    RegistryManager.delete(cr.dbname)
    RegistryManager.new(cr.dbname)
    return {}
7
répondu Don Kirkby 2017-05-23 11:59:55

la fonction intégrée reload rechargera un seul module. Il existe diverses solutions pour recharger de façon récursive les paquets mis à jour; voir comment réimporter un paquet mis à jour alors qu'il est dans L'interpréteur Python?

une partie du problème réside dans le fait que les objets existants doivent être ajustés pour faire référence aux nouvelles classes, etc. des modules rechargés; reimport fait raisonnablement bien. In the IPython console interactive j'utilise l'extension autoreload , bien qu'elle ne soit pas conçue pour une utilisation en dehors D'IPython.

13
répondu ecatmur 2017-05-23 12:01:59

ipython dispose d'un module de chargement en profondeur, la documentation est ici: http://ipython.org/ipython-doc/stable/api/generated/IPython.lib.deepreload.html#module-IPython.lib.deepreload

je pense qu'il est utilisable en dehors de l'ipython REPL.

1
répondu rguillebert 2012-10-02 09:54:27

si vous ne faites que du développement, alors rechargez est OK, mais si vous êtes en déploiement, vous devriez éviter ces trucs, parce qu'ils ne fonctionneront jamais à 100% du temps. Il y aura toujours des subtilités, où les changements ne se propageront pas. Par exemple, si un code copie un objet au lieu de simplement utiliser des références, il restera le même après le rechargement. À l'inverse, si une référence ne se propage pas correctement vers l'avant, alors une comparaison is échouera quand elle être appelés à travailler, parce que l'un des objets de la "vieille" unreleased module. Le seul 100% sûre méthode pour recharger tout, ce qui est, essentiellement, un redémarrage du serveur est.

même si vous ne faites que du développement, vous rencontrerez occasionnellement de faux bogues qui ne sont que les effets secondaires d'un rechargement incomplet. S'il ne vous vient pas à l'esprit d'essayer un redémarrage propre, vous pouvez passer un long temps à essayer de suivre le bogue fantôme vers le bas. Donc si tu finis par faire ça, garde ça en tête.

1
répondu asmeurer 2012-10-03 19:04:46

la fonction de recharge intégrée Recharge un module ou un paquet. Dans le contexte D'OpenERP cependant, vous avez besoin d'un peu plus, car recharger un addon OpenERP nécessite le traitement des fichiers XML, etc. Mais je suis d'accord sur le fait que ce serait bien d'avoir ça à OpenERP.

0
répondu gurney alex 2012-09-26 09:27:18