Le Journal de Nikrou - Mot-clé - pythonCe journal n'est pas un blog!2024-01-09T15:52:56+01:00urn:md5:501048fab0be4d1978e39dded54e4f42DotclearCréation d'un produit zope minimalurn:md5:0acc1823b4faa5daedfca0f0065e01ad2006-08-28T12:54:32+00:002006-08-28T12:57:10+00:00NicolasPythonpythonzope<p>La création d'un produit dans <a href="http://www.zope.org/" hreflang="en">zope</a> n'est pas des plus aisée. Mais je vais tenter avec mes maigres et fraiches connaissances de vous expliquer pas à pas le moyen de créer un produit minimal.</p> <p>Je suppose que vous avez déjà installé <a href="http://fr.wikipedia.org/wiki/Zope" hreflang="fr">zope</a> et que vous avez créé une instance. J'ai développé l'exemple de produit dans un environnement GNU/Linux avec zope 2.9.4, et python 2.4.4. Je pense que c'est aisément portable sous un autre système. Je suppose aussi que vous connaissez un minimum zope: la <acronym title="Zope Managment Interface">ZMI</acronym>, démarrer/arréter le serveur, ...Je suppose que vous connaissez aussi un tout petit peu <a href="http://www.python.org/" hreflang="en">python</a>.</p>
<p>Encore une fois, je ne vais pas être très original: on va créer un produit qui affiche <a href="http://www2.latech.edu/~acm/HelloWorld.shtml">Hello World</a>! Un grand classique.</p>
<p>Le produit HelloWorld que l'on va créer va permettre de créer un objet zope. La "vue" de cet objet va simplement afficher "Bonjour le Monde"!</p>
<p>L'objet HelloWorld minimal (<i>hello.py</i>) pourrait ressembler à ça:</p>
<pre>
class Hello:
def index_html(self):
return "Bonjour le monde"
</pre>
<p>On a alors un objet python. Ce n'est pas encore un produit zope. La première chose à savoir est que zope ne publit pas les objets qui n'ont pas de chaînes de documentation. Tout objet zope doit avoir un identifiant unique. On va donc ajouter le constructeur de l'objet Hello qui assignera un identifiant à notre objet:</p>
<pre>
class Hello:
"Objet Hello plein de fonctionalités"
def __init__(self, id):
"Initialise l'objet"
self.id = id
def index_html(self):
"affiche Bonjour le monde"
return "Bonjour le monde"
</pre>
<p>On a maintenant un produit zope. Il ne reste plus qu'à le déclarer auprès de zope. Tout produit zope est organisé en "package". On va mettre notre classe dans un répertoire HelloWorld et on va placer le répertoire à l'endroit qui va bien. On peut placer le produit soit dans le répertoire <i>Products</i> de zope (<i>lib/python/Products/</i>) et le produit existera pour toutes les instances, soit le placer dans le répertoire <i>Products</i> de l'instance que l'on utilise et il n'existera que pour cette instance. Il y a juste une dernière chose à ajouter pour que notre produit apparaissent dans la liste des produits installables: lui donner un nom unique! Cela se fait avec la propriété <i>meta_type</i>. Notre objet installable ressemble désormais à ceci:</p>
<pre>
class Hello:
"Objet Hello plein de fonctionalités"
meta_type = "Hello World"
def __init__(self, id):
"Initialise l'objet"
self.id = id
def index_html(self):
"affiche Bonjour le monde"
return "Bonjour le monde"
</pre>
<p>Si on place le répertoire dans le répertoire <i>Products</i>, on doit voir apparaitre le produit dans la liste des produits installables. On va ajouter un peu de code pour créer une instance de notre objet. Tout d'abord pour bénéficier de plein de fonctionnalités (copier/coller, vue, support webdav, support ftp, support annuner (undo), ...) accessibles à partir de la <acronym>ZMI</acronym>, on va dériver la classe <i>SimpleItem</i> du package zope <i>OFS</i>. On va ajouter une méthode (add_HelloProduct) qui crée une instance de notre objet dans un dossier: <i>_setObject()</i>, qui est une méthode de la classe <i>ObjectManager</i>. Cette méthode attend deux paramètres: le premier est un identifiant (que je nommerais hello_id), le deuxième est l'appel au constructeur de l'objet:</p>
<pre>self._setObject('hello_id', Hello('hello_id'))</pre>
<p>Toutes les instances auront le même identifiant. C'est mal! Mais ce n'est qu'un objet minimal et on verra par la suite comment changer cela. On ne pourra évidemement créer qu'une seule instance de notre objet. Notre classe ressemble alors à ceci:</p>
<pre>
from OFS import SimpleItem
class Hello(SimpleItem.SimpleItem):
"Objet Hello minimal"
meta_type = "Hello World"
def __init__(self, id):
"""Initialise l'objet"""
self.id = id
def index_html(self):
"affiche Bonjour le monde"
return "Bonjour le monde"
def add_HelloProduct(self):
"""Ajout d'un produit Hello minimal"""
self._setObject('hello_id', Hello('hello_id'))
</pre>
<p>Il ne reste plus qu'à ajouter un constructeur (<i>__init__.py</i>) pour notre produit qui va automatiquement créer une instance lorsqu'on va sélectionner le produit pour l'ajouter. Lorsque l'on fait cela zope appelle une méthode <i>initialize()</i> qui reçoit le contexte (la classe <i>context</i>). On va utiliser la méthode <i>regsiterClass</i> de la classe <i>context</i> pour déclarer notre instance. Cette méthode attend en paramètres le nom de la classe du produit (<i>hello.Hello</i>) et une liste d'arguments permettant de créer l'instance. C'est là que l'on va faire appel à la méthode <i>add_HelloProduct</i>. Notre constructeur ressemble à ceci:</p>
<pre>
import hello
def initialize(context):
"Fonction pour ajouter le produit dans la liste des produits disponibles."
context.registerClass(hello.Hello,
constructors = (hello.add_HelloProduct,)
)
</pre>
<p>Le produit zope que l'on vient de créer à la structure suivante:</p>
HelloWorld
<ul>
<li><a href="https://www.nikrou.net/zope/HelloWorld/hello.py">hello.py</a></li>
<li><a href="https://www.nikrou.net/zope/HelloWorld/__init__.py">__init__.py</a></li>
</ul>
<p>Vous pouvez aussi récupérer directement <a href="https://www.nikrou.net/zope/HelloWorld.tar">le package</a> que vous désarchivez dans le répertoire <i>Products</i> de votre instance. Il suffit alors de redémarrer zope pour voir apparaitre le produit HelloWorld dans la liste des produits installables. On peut alors l'installer et créer une instance en ajoutant le produit. Pour avoir la vue de l'instance il suffit d'accéder à l'url suivante: <a href="http://localhost:8080/hello_id/index_html">index_html</a>. Mon instance tournant sur le port 8080.</p>
<p>Problèmes connus:</p>
<ul>
<li>Lorsqu'on ajoute le produit à partir de la liste des produits installables il ne se passe rien en apparence. En fait l'instance est bien créée mais comme la méthode <i>_setObject()</i> ne renvoie rien, on à l'impression qu'il ne se passe rien. Si vous listez le contenu du dossier dans lequel vous avez créer l'instance vous devriez voir un nouvel objet nommé <i>hello_id</i>.</li>
<li>Il n'y a pas d'onglet "Vue" dans les onglets accessibles pour l'objet <i>hello_id</i>, il faut y accéder manuellement en ajoutant index_html derrirère le nom de l'objet.</li>
<li>On ne peut créer qu'une seule instance. Si on essaie d'ajouter un nouvel objet <i>Hello World</i>, zope nous prévient qu'un objet de même identifiant existe déjà.</li>
</ul>Optimisation de la configuration de tracurn:md5:6241a2f3238dbc177ea7c86b4c96098b2006-06-10T09:04:00+00:002013-11-19T09:50:21+00:00NicolasOutilspythonsubversiontrac<p><a href="http://projects.edgewall.com/trac/" hreflang="en">trac</a> est un outil formidable pour gérer un projet mais on a l'impression que l'on se complique la vie lorsqu'on veut <a href="https://www.nikrou.net/post/2006/04/29/53-gestion-de-plusieurs-projets-avec-trac">gérer plusieurs projets</a> sur le même serveur. Avec le nombre de projets augmentant cela devient très rapidement rébarbatif mais heureusement il y a le <a href="http://www.modpython.org/" hreflang="en">mod python d'apache</a> pour trac!</p> <p>Si je garde mon exemple de quatre projets (projet1, projet2, projet3 et projet4) ayant chacun son dépot et son répertoire trac dédié sous le répertoire <em>/var/trac/projets/</em> alors la configuration d'apache peut se faire de la manière suivante:</p>
<pre><Location /projets><br /> SetHandler mod_python<br /> PythonHandler trac.web.modpython_frontend<br /> PythonOption TracEnvParentDir /var/trac/projets<br /> PythonOption TracUriRoot /projets<br /></Location><br /><br /><LocationMatch /projets/[^/]*/login><br /> AuthType Basic<br /> AuthName "Mes projets"<br /> AuthUserFile /path/2/dav_svn.users <br /> Require valid-user<br /></LocationMatch></pre>
<p>Il faut bien entendu que le <strong>mod python</strong> soit installé sur votre serveur (package libapache2-mod-python sur debian) pour que cela fonctionne. Pour prendre en compte un nouveau projet dans trac il suffit de créer l'environnement (avec trac-admin) sous le répertoire <em>/var/trac/projets/</em>. C'est tout!</p>Gestion de plusieurs projets avec tracurn:md5:c15ad1b3c26458feafa032fa041cfebb2006-04-29T09:32:52+00:002006-06-09T22:53:15+00:00NicolasOutilspythonsubversiontrac <p>Pour ajouter un projet dans trac, voici la marche à suivre:</p>
<ol>
<li>
<p>trac-admin /path/to/projetenv initenv (répertoire où sont placés les pages du wiki entre autre)</p>
<p>Il faut ensuite choisir un nom pour le projet ainsi que le chemin vers le dépôt subversion</p>
<p>Exemple: trac-admin /var/trac/projets/essai (le dépôt subverison correspondant est: /home/nicolas/projets/essai)</p>
</li>
<li>
<p>Modifier la conf d'apache</p>
<pre>
Alias /trac /usr/share/trac/htdocs/
AliasMatch /projets/(projet1|projet2|projet3|projet4)(/?.*) /var/trac/projets/$1/trac.cgi$2
<DirectoryMatch "/var/trac/projets/projet1/trac.cgi">
SetEnv TRAC_ENV "/var/trac/projets/projet1"
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</DirectoryMatch>
<DirectoryMatch "/var/trac/projets/projet2/trac.cgi">
SetEnv TRAC_ENV "/var/trac/projets/projet2"
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</DirectoryMatch>
<DirectoryMatch "/var/trac/projets/projet3/trac.cgi">
SetEnv TRAC_ENV "/var/trac/projets/projet3"
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</DirectoryMatch>
<DirectoryMatch "/var/trac/projets/projet4/trac.cgi">
SetEnv TRAC_ENV "/var/trac/projets/projet4"
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</DirectoryMatch>
</pre>
</li>
</ol>
<p>La configuration d'apache n'est pas optimale. On devrait pouvoir l'améliorer en factorisant les différents DirectoryMatch. De plus on utilise les mêmes fichiers de mots de passe pour tous les projets; on devrait pouvoir les séparer.</p>Gestion des sourcesurn:md5:18d38de1aa3484eef47eade7bfcf28a52006-03-22T21:08:29+00:002006-04-20T21:03:32+00:00NicolasOutilspythonsubversiontrac <p>Que l'on travaille seul ou à plusieurs sur un projet, le besoin se fait rapidement sentir de pouvoir garder un historique des modifications que l'on a faites. La méthode, qui consiste à commenter une partie du code pour éventuellement la réutiliser, atteint rapidement ses limites lorsqu'on travaille à plusieurs ou longtemps sur un même projet. En ayant pratiqué cette méthode je me suis retrouvé à un moment avec plus de commentaire que de code!</p>
<p>Pour un projet qui dure ou pour un projet collaboratif, la meilleure façon de travailler est d'utiliser un gestionnaire de versions tel que <a href="http://www.nongnu.org/cvs/" title="Concurrent Versions System" hreflang="en">C.V.S</a> ou <a href="http://subversion.tigris.org/" hreflang="en">Subversion</a>. Ma préférence va à Subversion surtout couplé avec <a href="http://projects.edgewall.com/trac/" hreflang="en">Trac</a> qui est une interface web à Subversion pour parcourir les sources. Trac intègre aussi un wiki, un gestionnaire de bugs, de tickets.</p>
<p>Pour débuter avec Subersion, rien ne vaut la lecture de <a href="http://svnbook.red-bean.com/" hreflang="en">la documentation</a>, sous licence <a href="http://creativecommons.org/licenses/by/2.0/" hreflang="en">Creative Commons</a>, publiée par <a href="http://www.oreilly.com/" hreflang="en">Oreilly</a>.</p>