Débug de zope avec ipython
Par gawel le 05/03/2005 18:11
Comment débuger zope avec ipython
Catégories : Zope
IPython c'est quoi ?
IPython n'est ni plus ni moin qu'un interpréteur python amélioré. Vous pouvez le trouver ici
Pourquoi utiliser IPython ? C'est très simple, il dispose de nombreuses fonctionalités qui mériterais un HowTo a lui seul.
En voici quelques une non exhaustives:
- auto completion
- aide en ligne en tapant un ? après n'importe quel object/méthode python
- édition de fichier en tapant ?? après n'importe quel object/métode python
Créer son propre IPython embed
Il est possible de customiser IPython pour ses propres besoins.Ici nous allons tout simplement ajouter des fonctionalités pour aider au débug de zope.
Voici un exemple de code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__version__ = '''zdb.py 1.0'''
__author__ = '''Gael Pasgrimaud <gael@gawel.org>'''
import sys
from IPython.Shell import IPShell
from IPython.iplib import InteractiveShell
class ZopeDebug(InteractiveShell):
''' Surclasse de l'interpréteur IPython '''
def _init_zope(self):
# ceci sert a récupérer l'app zope dans le bon espace de nom
# en effet, IPython place les variables trouver dans __main__
# dans son espace de nom interne (internal_ns)
if self.internal_ns.has_key('app'):
import Zope
self.user_ns['app'] = self.internal_ns['app']
self.user_ns['debug'] = Zope.debug
from AccessControl.SecurityManagement import newSecurityManager
self.user_ns['newSecurityManager'] = newSecurityManager
def magic_setuser(self,parameter_s=''):
# une fonction pour récupere une variable user dans son espace de nom
if not parameter_s:
print >> sys.stderr, 'Entrez un nom d\'utilisateur valid'
ns = self.user_ns
if hasattr(ns['app'],'portal'):
# si on a un objet portal (Plone) on récup wrap le user dans son context
ns['plone'] = ns['app'].plone.portal_url.getPortalObject()
ns['user'] = ns['app'].acl_users.getUser(parameter_s).__of__(ns['app'].plone.acl_users)
else:
# sinon on prends un user a la racine
ns['user'] = ns['app'].acl_users.getUserById(parameter_s)
# on initialise le context
ns['newSecurityManager'](None,ns['user'])
def post_config_initialization(self):
''' surcharge de post configiguration ipython '''
InteractiveShell.post_config_initialization(self)
# on ne veux pas de bannière
self.BANNER = ''
# on initialise notre espace de nom
self._init_zope()
# on creer un shell
ipshell = IPShell([],shell_class=ZopeDebug)
if __name__ != '__main__':
# nous sommes déjà dans un interpréteur
# on import __main__ pour se retrouver dans son espace de nom
import __main__
# on lance notre shell
ipshell.mainloop(sys_exit=1)
# -*- coding: utf-8 -*-
__version__ = '''zdb.py 1.0'''
__author__ = '''Gael Pasgrimaud <gael@gawel.org>'''
import sys
from IPython.Shell import IPShell
from IPython.iplib import InteractiveShell
class ZopeDebug(InteractiveShell):
''' Surclasse de l'interpréteur IPython '''
def _init_zope(self):
# ceci sert a récupérer l'app zope dans le bon espace de nom
# en effet, IPython place les variables trouver dans __main__
# dans son espace de nom interne (internal_ns)
if self.internal_ns.has_key('app'):
import Zope
self.user_ns['app'] = self.internal_ns['app']
self.user_ns['debug'] = Zope.debug
from AccessControl.SecurityManagement import newSecurityManager
self.user_ns['newSecurityManager'] = newSecurityManager
def magic_setuser(self,parameter_s=''):
# une fonction pour récupere une variable user dans son espace de nom
if not parameter_s:
print >> sys.stderr, 'Entrez un nom d\'utilisateur valid'
ns = self.user_ns
if hasattr(ns['app'],'portal'):
# si on a un objet portal (Plone) on récup wrap le user dans son context
ns['plone'] = ns['app'].plone.portal_url.getPortalObject()
ns['user'] = ns['app'].acl_users.getUser(parameter_s).__of__(ns['app'].plone.acl_users)
else:
# sinon on prends un user a la racine
ns['user'] = ns['app'].acl_users.getUserById(parameter_s)
# on initialise le context
ns['newSecurityManager'](None,ns['user'])
def post_config_initialization(self):
''' surcharge de post configiguration ipython '''
InteractiveShell.post_config_initialization(self)
# on ne veux pas de bannière
self.BANNER = ''
# on initialise notre espace de nom
self._init_zope()
# on creer un shell
ipshell = IPShell([],shell_class=ZopeDebug)
if __name__ != '__main__':
# nous sommes déjà dans un interpréteur
# on import __main__ pour se retrouver dans son espace de nom
import __main__
# on lance notre shell
ipshell.mainloop(sys_exit=1)
Et Zope la dedans ?
Jusqu'as présent nous avons un joli IPython customiser mais il ne nous sert a rien en dehors du context de zope.Pour récuperer son instance dans notre interpréteur, rien de plus simple. Il suffit de lancer le mode debug de zope.Attention de bien lancer zope depuis le répertoire ou se trouve zdb.py ou d'avoir zdb.py dans votre PYTHONPATH pour pouvoir l'importer.gawel@tabatha:~/python$ /home/zope/Zope-2.7.4-0/bin/zopectl debug
Starting debugger (the name "app" is bound to the top-level Zope object)
>>> import zdb
In [1]: # on sait jouer avec app
In [2]: app.objectIds()
Out[2]:
['acl_users',
'Control_Panel',
'temp_folder',
'session_data_manager',
'browser_id_manager',
'error_log',
'standard_html_header',
'standard_html_footer',
'standard_template.pt',
'index_html',
'standard_error_message',
'virtual_hosting',
'plone']
In [3]: # on sait récupérer un user
In [4]: %setuser gawel
In [5]: user.getId()
Out[5]: 'gawel'
In [6]: # on sait utiliser l'auto completion avec app
In [7]: app.object
app.objectIds app.objectItems app.objectMap app.objectValues__roles__
app.objectIds__roles__ app.objectItems__roles__ app.objectMap_d app.objectValues_d
app.objectIds_d app.objectItems_d app.objectValues
In [7]: app.objectVal
app.objectValues app.objectValues__roles__ app.objectValues_d
In [7]: app.objectValues
------> app.objectValues()
Out[7]:
[<UserFolder instance at 4179f800>,
<ApplicationManager instance at 417b7650>,
<SimpleTemporaryContainer instance at 417b7c20>,
<SessionDataManager instance at 417b72c0>,
<BrowserIdManager instance at 417b7530>,
<SiteErrorLog at /error_log>,
<DTMLMethod instance at 417b78f0>,
<DTMLMethod instance at 417b7860>,
<ZopePageTemplate at /standard_template.pt>,
<DTMLMethod instance at 417b7890>,
<DTMLMethod instance at 4179f6b0>,
<VirtualHostMonster instance at 4179f650>,
<PloneSite instance at 4179f710>]
In [8]:
Starting debugger (the name "app" is bound to the top-level Zope object)
>>> import zdb
In [1]: # on sait jouer avec app
In [2]: app.objectIds()
Out[2]:
['acl_users',
'Control_Panel',
'temp_folder',
'session_data_manager',
'browser_id_manager',
'error_log',
'standard_html_header',
'standard_html_footer',
'standard_template.pt',
'index_html',
'standard_error_message',
'virtual_hosting',
'plone']
In [3]: # on sait récupérer un user
In [4]: %setuser gawel
In [5]: user.getId()
Out[5]: 'gawel'
In [6]: # on sait utiliser l'auto completion avec app
In [7]: app.object
app.objectIds app.objectItems app.objectMap app.objectValues__roles__
app.objectIds__roles__ app.objectItems__roles__ app.objectMap_d app.objectValues_d
app.objectIds_d app.objectItems_d app.objectValues
In [7]: app.objectVal
app.objectValues app.objectValues__roles__ app.objectValues_d
In [7]: app.objectValues
------> app.objectValues()
Out[7]:
[<UserFolder instance at 4179f800>,
<ApplicationManager instance at 417b7650>,
<SimpleTemporaryContainer instance at 417b7c20>,
<SessionDataManager instance at 417b72c0>,
<BrowserIdManager instance at 417b7530>,
<SiteErrorLog at /error_log>,
<DTMLMethod instance at 417b78f0>,
<DTMLMethod instance at 417b7860>,
<ZopePageTemplate at /standard_template.pt>,
<DTMLMethod instance at 417b7890>,
<DTMLMethod instance at 4179f6b0>,
<VirtualHostMonster instance at 4179f650>,
<PloneSite instance at 4179f710>]
In [8]:
Débuger une external method
Voici un petit exemple pratique. On a une external method simple que l'on désir débuger.En voici le code:
# -*- coding: utf-8 -*-
import os, sys
def ext_meth(self):
''' une external method qui renvois os.name '''
return os.name
if __name__ == '__main__':
# si on est dans le namespace de __main__
# on récupère app et on exécute notre méthode
global app
print ext_meth(app)
Ensuite on sait la débuger/modifer dans IPython a l'aide de la commande IPython %ed qui lance votre éditeur favoris et éxécute le code à la sortieimport os, sys
def ext_meth(self):
''' une external method qui renvois os.name '''
return os.name
if __name__ == '__main__':
# si on est dans le namespace de __main__
# on récupère app et on exécute notre méthode
global app
print ext_meth(app)
In [8]: ed ext_meth.py
Editing... done. Executing edited code...
posix
In [9]: # on change os.name par sys.patform dans notre fichier
In [10]: ed ext_meth.py
Editing... done. Executing edited code...
---------------------------------------------------------------------------
exceptions.AttributeError Traceback (most recent call last)
/home/gawel/python/<console>
/usr/lib/python2.3/site-packages/IPython/Magic.py in magic_ed(self, parameter_s)
1469 def magic_ed(self,parameter_s = ''):
1470 """Alias to %edit."""
-> 1471 return self.magic_edit(parameter_s)
1472
1473 def magic_edit(self,parameter_s = '',last_call=['','']):
/usr/lib/python2.3/site-packages/IPython/Magic.py in magic_edit(self, parameter_s, last_call)
1701 except IOError:
1702 warn('File not found. Did you forget to save?')
-> 1703 return
1704 if use_temp:
1705 contents = open(filename).read()
/home/gawel/python/ext_meth.py
8 if __name__ == '__main__':
9 # si on est dans le namespace de __main__
10 # on récupère app et on exécute notre méthode
11 global app
---> 12 print ext_meth(app)
/home/gawel/python/ext_meth.py in ext_meth(self)
4 def ext_meth(self):
5 ''' une external method qui renvois os.name '''
----> 6 return sys.patform
7
8 if __name__ == '__main__':
AttributeError: 'module' object has no attribute 'patform'
In [11]: # oups, par sys.platform !
In [12]: ed ext_meth.py
Editing... done. Executing edited code...
linux2
In [11]:
Editing... done. Executing edited code...
posix
In [9]: # on change os.name par sys.patform dans notre fichier
In [10]: ed ext_meth.py
Editing... done. Executing edited code...
---------------------------------------------------------------------------
exceptions.AttributeError Traceback (most recent call last)
/home/gawel/python/<console>
/usr/lib/python2.3/site-packages/IPython/Magic.py in magic_ed(self, parameter_s)
1469 def magic_ed(self,parameter_s = ''):
1470 """Alias to %edit."""
-> 1471 return self.magic_edit(parameter_s)
1472
1473 def magic_edit(self,parameter_s = '',last_call=['','']):
/usr/lib/python2.3/site-packages/IPython/Magic.py in magic_edit(self, parameter_s, last_call)
1701 except IOError:
1702 warn('File not found. Did you forget to save?')
-> 1703 return
1704 if use_temp:
1705 contents = open(filename).read()
/home/gawel/python/ext_meth.py
8 if __name__ == '__main__':
9 # si on est dans le namespace de __main__
10 # on récupère app et on exécute notre méthode
11 global app
---> 12 print ext_meth(app)
/home/gawel/python/ext_meth.py in ext_meth(self)
4 def ext_meth(self):
5 ''' une external method qui renvois os.name '''
----> 6 return sys.patform
7
8 if __name__ == '__main__':
AttributeError: 'module' object has no attribute 'patform'
In [11]: # oups, par sys.platform !
In [12]: ed ext_meth.py
Editing... done. Executing edited code...
linux2
In [11]:
Mot de la fin
Voila vous savez utiliser IPython pour débuger zope. J'ai fais se tutoriel car je suis tombé amoureux de IPython. J'ai mon propre shell avec de nombreuses fonctionalités en plus qui me simplifie énormement la vie. J'en suis arrivé a m'en servir plus que bash :) J'espère que cela vous auras convaincu.Référence
Ceci est largement inspiré de la section DebuggingZopeWithPythonDebugger2 de zopewiki.org que je vous conseil de lire aussi.
Merci
Posté par
ogrisel
le
22/03/2005 23:00
Ca faisait un moment que je voulais m'écrire un code de custom pour lancer ipython dans le mode debug de zope. Merci pour ce bout de code,came fera gagner du temps !
Fantastic!!
Posté par
rompelstilchen
le
08/12/2006 12:43
Merci gawel pour ce tuto, par contre est-ce que les modifications sont appliquees dans la zodb, parceque quand je quitte (Ctrl+D) :
In [19]: %Quit
Unable to save IPython command history to file: '/root/.ipython/history'
*** ERROR *** persistent data saving failed.
In [19]: %Quit
Unable to save IPython command history to file: '/root/.ipython/history'
*** ERROR *** persistent data saving failed.
Problème import Zope
Posté par
fcarlier
le
14/09/2007 10:12
Je viens de tester sous Zope 2.9.7 et 2.10.4
Il apparait un probleme dans l'import de zdb.py sur 'import Zope'
Voici le message :
DeprecationWarning: The Zope package has been renamed to Zope2. Import of a package named 'Zope' is deprecated and will be disabled starting in Zope 2.11.
import Zope
In [1]: app.ObjectIds()
---------------------------------------------------------------------------
exceptions.AttributeError Traceback (most recent call last)
Il apparait un probleme dans l'import de zdb.py sur 'import Zope'
Voici le message :
DeprecationWarning: The Zope package has been renamed to Zope2. Import of a package named 'Zope' is deprecated and will be disabled starting in Zope 2.11.
import Zope
In [1]: app.ObjectIds()
---------------------------------------------------------------------------
exceptions.AttributeError Traceback (most recent call last)







