DocumentationCodeBonnesPratiques » Historique » Version 32
« Précédent -
Version 32/34
(diff) -
Suivant » -
Version actuelle
Benjamin Bohard, 25/04/2014 12:02
DocumentationCodeBonnesPratiques¶
cette page concerne la documentation développeur
(voir aussi TestsCodeBonnesPratiques pour les autres bonnes pratiques développeur)
Généralité¶
- La documentation technique doit être en anglais.
- Elle est placée dans les docstrings du code.
Description du module¶
La docstring du module est placée en haut du fichier juste après le shebang, la déclaration d’encodage des caractères et la licence du code.
#!/usr/bin/python # -*- coding: utf-8 -*- # ########################################################################## # <nom du projet> # Copyright © 2013 Pôle de compétences EOLE <eole@ac-dijon.fr> # # License CeCILL: # * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html # * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ##########################################################################La docstring doit contenir :
- description rapide en une phrase du module ;
- description avancée qui explique le rôle du module ;
- des exemples simples d'utilisation.
Les exemples peuvent être un prompt :
>>> is_locked() True
ou une portion de code :
:: from toto.titi import is_locked toto() is_locked()
Docstring des méthodes¶
Seules les méthodes publiques (qui ne commencent pas par "_") seront mises dans la documentation (mais les méthodes privées sont aussi à documenter).
La docstring doit contenir :
- description rapide en une phrase de la méthode ;
- si nécessaire une description avancée qui explique le rôle du module ;
- si nécessaire des exemples simples d'utilisation.
- les paramètres de la façon suivante (xxx étant le nom du paramètre et yyyyyy la description) :
:param xxx: yyyyyy
Si nécessaire les valeurs de retour (yyyyyy étant la description) :
:return: yyyyyy
plus d'info sur la syntaxe des docstrings: http://sphinx-doc.org/domains.html#info-field-lists
Docstring des classes¶
comme pour la docstring des modules (mais sans la licence)
Tips¶
il est possible de faire un lien portant directement sur le redmine de deux manières :
:issue:`410`
est un lien qui porte directement sur la demande 410
et
:eole:`/projects/creole/wiki/Lock24`
qui est simplement un raccourci vers http://dev-eole.ac-dijon.fr/projects/creole/wiki/Lock24
Exemples¶
Plusieurs fichiers sources ont reçu une attention assez particulière sur la documentation :
- python-pyeole:source:pyeole/decorator.py
- python-pyeole:source:pyeole/log.py
- python-pyeole:source:pyeole/lock.py
Traduction et python¶
Voici un petit aide mémoire pour traduire une application python de la manière la plus simple possible.
Pour traduire une application il faut avant tout une bibliothèque qui gère les traductions. La première
qui vient à l'esprit est gettext, donc logiquement nous allons nous tourner vers python-gettext.
Il faut noter qu'il est important de faire les choses dans l'ordre, les messages par défaut des applications doivent être dans une seule et unique langue, l'usage
est de tout écrire en anglais et ensuite de mettre une traduction pour les autres langues.
Le principe de gettext est de remplacer tous les messages par l'appel à une "fonction/méthode/whatever" qui va
faire les opérations de traduction.
Dans le monde gettext cette "fonction" a pour nom '_'.
La première chose à faire est de mettre à disposition une "fonction" '_' dans votre application python. (Les exemples suivants proviennent de pyeole)
i18n.py¶
On crée un "module" i18n.py (mais il pourrait très bien avoir un autre nom) et on y fait les déclarations et les initialisations nécessaires pour la traduction.
- Dans ce module on importe gettext et les modules nécessaires à la gestion de la traduction (python-gettext)
import gettext # Gettext lui même import os # Pour les variables d'environement LANG/LC_ALL import sys # Pour la gestion des fichiers de traduction import locale # Pour la gestion des "locale"
- On définit le nom du domaine de traduction (le plus souvent le nom de l'application)
APP_NAME = 'pyeole'
- On récupère les répertoires qui vont contentir les traductions
# Traduction dir APP_DIR = os.path.join(sys.prefix, 'share') LOCALE_DIR = os.path.join(APP_DIR, 'locale')
- On récupère la langue par défaut et on y ajoute l'anglais pour les messages non traduits
# Default Language DEFAULT_LANG = os.environ.get('LANG', '').split(':') DEFAULT_LANG += ['en_US']
- On définit la langue par défaut (je ne suis pas certain que cette partie ne soit pas inutile :)
languages = [] lc, encoding = locale.getdefaultlocale() if lc: languages = [lc] languages += DEFAULT_LANG
- On fait les initialisations gettext
mo_location = LOCALE_DIR gettext.find(APP_NAME, mo_location) # On cherche les traductions gettext.textdomain(APP_NAME) # On crée le domaine de traduction (où il va chercher les messages) gettext.bind_textdomain_codeset(APP_NAME, "UTF-8") # On définit le jeux de caractères des traductions (utf8)
- On initialise l'objet qui va réaliser les traductions pour notre application
t = gettext.translation(APP_NAME, fallback=True)
- Enfin on crée la "fonction/methode/whatever" '_' :
def _(msg): return t.ugettext(msg) # on retourne le résultat de la traduction ! ugettext peut poser problème il ne prend que des chaines utf8
Vous n'avez plus qu'à importer la "fonction/méthode" '_' dans vos fichier .py et l'utiliser
Exemple :
from pyeole.translation.i18n import _ # j'ai mis le module i18n.py dans un répertoire spécifique (pour le plaisir) .... msg = _(u'Install: {0}.') log.info(msg.format(u', '.join(to_install)))
let's translate¶
Une fois le code en place il faut créer les fichiers de traduction. Il existe plusieurs utilitaires pour faire de la traduction, personnellement j'utilise "poedit" (ou vim :)
Il faut générer le fichier de référence des messages, pour ce faire on utilise la commande xgettext.
On place les fichiers de traductions dans un répertoire translation à la racine du dépôt.
dev@host:~ $ cd code/pyeole dev@host:~/code/pyeole $ # mkdir translation dev@host:~/code/pyeole cd translation dev@host:~/code/pyeole/translation # xgettext --language=Python --keyword=_ --output=pyeole-next.pot --from-code=UTF-8 `find ../pyeole -name "*.py"`
Attention il est possible que xgettext plante à cause de certaines chaines de commentaire.
Une fois que la commande xgettext se termine, elle génère un fichier ".pot"
Pour générer les traductions on utilise poedit.
- Lancer poedit
- Fichier --> Nouveau depuis un fichier POT/PO
- Ouvrir votre fichier .pot
- Séléctionner la langue de traduction
- Traduire les chaines disponibles
- Sauvegarder le fichier de traduction dans le répertoire translation/<CODE_LANGUE>/<mon_appli>.po (translation/fr/pyeole.po)
plus qu'à installer¶
Pour que les fichiers de traductions soit pris en compte par la génération du paquet il faut faire des mises à jour dans le setup.py.
On ajoute une petite fonction qui va créer les fichiers de traduction à partir des .po. Et oui, les .po ne sont pas les fichiers
utilisés par gettext mais juste leur "code source". Il faut impérativement que la traduction soit la plus rapide possible donc qui dit
rapide dit fichiers binaires.
Voici le code qui génère les .mo
trad_root = "share/locale" trad_dir = "LC_MESSAGES" here = dirname(abspath(__file__)) def build_translation(): po_path = join(here, "translation") result = [] for top, dirs, files in walk(po_path): for directory in dirs: tr_dir = join(top, directory) # Search for .po file for a traduction trad_files = [] for pot_file in glob(join(tr_dir, "*.po")): mo_file = splitext(pot_file)[0] + ".mo" lang = basename(tr_dir) cmd = ["msgfmt", pot_file, "-o", mo_file] dest = join(trad_root, lang, trad_dir) trad_files.append(join("translation", lang, basename(mo_file))) call(cmd) result.append((dest, trad_files)) return result translations = build_translation()
Voici les directives supplémentaires pour la fonction setup()
data_files = translations
Des questions ?¶
Voila une fois que vous avez fait toutes ces opérations votre appli doit parler d'autres langues.
Noter que cette intégration a été faite sur un délais très court par un non-spécialiste (moi) et qu'elle ne représente absolument pas la meilleure solution
et encore moins la plus élégante. Elle a très certainements de grosses lacunes et des bugs, mais pour l'instant dans le cas présent
elle fonctionne et offre une solution rapide.
Si vous avez des questions cette partie à été écrite par Philippe "Puppet_Master" Caseiro.