Sam & Max » template http://sametmax.com Du code, du cul Sat, 07 Nov 2015 10:56:13 +0000 en-US hourly 1 http://wordpress.org/?v=4.1 Templates de projet avec cookiecutter 10 http://sametmax.com/templates-de-projet-avec-cookiecutter/ http://sametmax.com/templates-de-projet-avec-cookiecutter/#comments Thu, 11 Jun 2015 21:49:11 +0000 http://sametmax.com/?p=16371 cookiecutter.]]> Beaucoup de frameworks viennent avec des templates de projets maintenant. Django vient avec django-admin startproject --template, tandis que crossbar vient avec crossbar init --template. L’idée d’avoir de templates pour ses projets n’a rien de nouveau, d’ailleurs la plupart des OS modernes ont au moins ça intégré pour des fichiers. Ainsi Ubuntu à un dossière “Modèles”, et tout ce qu’il y a dedans peut être dupliqué ailleurs via un clic droit dans Nautilus.

Néanmoins la meilleure solution à ce jour vient de Audrey Roy, qui est avant tout connue pour avoir co-écrit le livre Two scoops of Django, et qui a aussi pondu cookiecutter.

L’outil est très simple. D’abord un pip pour l’installer :

pip install cookiecutter

Notez que bien que le projet soit en Python, les templates peuvent être en n’importe quel langage, cookiecutter s’en branle. Lui, il va juste copier le contenu du template dans un dossier, et remplacer les variables notées {{}} dedans.

Pour commencer, on créé un dossier nommé {{cookiecutter.repo_name}} qui va contenir le template de son projet. Oui, le nom du dossier est {{cookiecutter.repo_name}}. En effet les noms de dossiers et fichiers sont aussi templatisables, et passés à la moulinette de jinja2.

Dans ce dossier, on peut mettre tous les fichiers qu’on veut, avec des noms normaux, ou avec des variables. Le contenu des fichiers peut, bien entendu, contenir aussi des variables. Les variables sont toujours de la forme {{cookiecutter.nom_de_variable}}.

Ensuite, à côté de notre dossier nommé {{cookiecutter.repo_name}} (le dossier du template), on peut créer un fichier cookiecutter.json qui va contenir les valeurs par défaut de nos variables :

{
    "repo_name": "nouveau_projet",
    "version": "0.1.0",
    "autre_variable": "Bidule"
}

Enfin pour récolter les fruits de son labeur, on lance cookiecutter /chemin/vers/template et l’outil va vous poser tout un tas de question pour remplir les variables, puis va générer le nouveau projet dans le dossier courant.

Cookiecutter accepte aussi des urls de repo git et mercurial comme source de template, et l’auteur de l’outil fournit un template de projet Python très complet par ce biais.

On va l’utiliser comme exemple.

Voici son contenu :

├── cookiecutter.json <= valeur par défaut des variables
├── {{cookiecutter.repo_name}} <= template du projet
│   ├── AUTHORS.rst
│   ├── CONTRIBUTING.rst
│   ├── {{cookiecutter.repo_name}}
│   │   ├── {{cookiecutter.repo_name}}.py
│   │   └── __init__.py
│   ├── docs
│   │   ├── authors.rst
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── history.rst
│   │   ├── index.rst
│   │   ├── installation.rst
│   │   ├── make.bat
│   │   ├── Makefile
│   │   ├── readme.rst
│   │   └── usage.rst
│   ├── HISTORY.rst
│   ├── LICENSE
│   ├── Makefile
│   ├── MANIFEST.in
│   ├── README.rst
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests
│   │   ├── __init__.py
│   │   └── test_{{cookiecutter.repo_name}}.py
│   └── tox.ini
└── README.rst

Certains usages de variables sont assez évident, comme par exemple le fichier __init__:

# -*- coding: utf-8 -*-
 
__author__ = '{{ cookiecutter.full_name }}'
__email__ = '{{ cookiecutter.email }}'
__version__ = '{{ cookiecutter.version }}'

D'autres sont assez malines et inattendues comme le fichier de test :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
test_{{ cookiecutter.repo_name }}
----------------------------------
Tests for `{{ cookiecutter.repo_name }}` module.
"""
 
import unittest
 
from {{ cookiecutter.repo_name }} import {{ cookiecutter.repo_name }}
 
 
class Test{{ cookiecutter.repo_name|capitalize }}(unittest.TestCase):
 
    def setUp(self):
        pass
 
    def test_something(self):
        pass
 
    def tearDown(self):
        pass
 
if __name__ == '__main__':
    unittest.main()

On note l'usage du filtre jinja capitalize. Tous les outils de jinja sont à disposition, ce serait con de s'en priver.

Pour utiliser le template on fait $ cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git, ce qui nous donne :

Clonage dans 'cookiecutter-pypackage'...
remote: Counting objects: 505, done.
remote: Total 505 (delta 0), reused 0 (delta 0), pack-reused 505
Réception d'objets: 100% (505/505), 77.89 KiB | 0 bytes/s, done.
Résolution des deltas: 100% (265/265), done.
Vérification de la connectivité... fait.
full_name (default is "Audrey Roy")? Sam
email (default is "audreyr@gmail.com")? lesametlemax@gmail.com
github_username (default is "audreyr")? sam
project_name (default is "Python Boilerplate")? essai
repo_name (default is "boilerplate")? essai
project_short_description (default is "Python Boilerplate contains all the boilerplate you need to create a Python package.")? C'est un essai j'ai dis
release_date (default is "2015-01-11")? 
year (default is "2015")? 
version (default is "0.1.0")? 

Notez les valeurs par défaut du fichier JSON, qui sont celles de l'auteur.

Le résultat généré :

├── essai
│   ├── AUTHORS.rst
│   ├── CONTRIBUTING.rst
│   ├── docs
│   │   ├── authors.rst
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── history.rst
│   │   ├── index.rst
│   │   ├── installation.rst
│   │   ├── make.bat
│   │   ├── Makefile
│   │   ├── readme.rst
│   │   └── usage.rst
│   ├── essai
│   │   ├── essai.py
│   │   └── __init__.py
│   ├── HISTORY.rst
│   ├── LICENSE
│   ├── Makefile
│   ├── MANIFEST.in
│   ├── README.rst
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests
│   │   ├── __init__.py
│   │   └── test_essai.py
│   └── tox.ini
└── README.rst

Le fichier __init__ est devenu :

# -*- coding: utf-8 -*-
 
__author__ = 'Sam'
__email__ = 'lesametlemax@gmail.com'
__version__ = '0.1.0'

Et le fichier de test :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
test_essai
----------------------------------
 
Tests for `essai` module.
"""
 
import unittest
 
from essai import essai
 
 
class TestEssai(unittest.TestCase):
 
    def setUp(self):
        pass
 
    def test_something(self):
        pass
 
    def tearDown(self):
        pass
 
if __name__ == '__main__':
    unittest.main()

L'outil accepte un beau degré de customisation, avec un fichier de configuration général au niveau de l'utilisateur (et donc des valeurs par défaut par utilisateur), une API programmable en Python, des hooks pre et post generation (qui permettent d'injecter des variables dynamiquement comme par exemple un uuid ou un timestamp).

Donc si vous recréez souvent les mêmes layout de projet encore et encore, pensez à cookiecutter.

Mais surtout, surtout, si vous codez votre propre framework, ne faites pas comme Django, utilisez l'API de cookiecutter au lieu de réinventer la roue.

]]>
http://sametmax.com/templates-de-projet-avec-cookiecutter/feed/ 10
Templite, le moteur de template Python qui tient dans un fichier 8 http://sametmax.com/templite-le-moteur-de-template-python-qui-tient-dans-un-fichier/ http://sametmax.com/templite-le-moteur-de-template-python-qui-tient-dans-un-fichier/#comments Tue, 25 Feb 2014 10:34:27 +0000 http://sametmax.com/?p=9235 pas écris templite, je l'ai juste mis sur pypi et github en respectant sa paternité car il restait sous forme de snippet perdu depuis trop longtemps. ]]> pip install templite

from templite import Templite
 
template = """
This is the place where all the ${variable}$ go...
The time goes fast but everything is slow...
${for woho in whohos:}$
    ${woho}$
${:end-for}$
"""
 
t = Templite(template)
print t.render(variable="junkies", whohos=["woo hoo", "woo hoo", "woo hoo hoo hoo"])

Ce qui donne :

This is the place where all the junkies go...
The time goes fast but everything is slow...

    woo hoo

    woo hoo

    woo hoo hoo hoo

Je n’ai pas écrit templite, je l’ai juste mis sur pypi et github en respectant sa paternité car il restait sous forme de snippet perdu depuis trop longtemps.

Vous pouvez le piper mais vraiment, ce n’est pas obligatoire, comme peewee et bottle, il tient dans un fichier, donc on peut juste dumper le module dans son code source.

]]>
http://sametmax.com/templite-le-moteur-de-template-python-qui-tient-dans-un-fichier/feed/ 8
Cog, l’anti langage de template Python 4 http://sametmax.com/cog-lanti-langage-de-template-python/ http://sametmax.com/cog-lanti-langage-de-template-python/#comments Mon, 27 Jan 2014 17:45:38 +0000 http://sametmax.com/?p=8903 Cog est un outil Python en ligne de commande qui permet d'insérer du code Python dans un fichier, afin qu'il génère une partie de ce fichier]]> Cog est un outil Python en ligne de commande qui permet d’insérer du code Python dans un fichier, afin qu’il génère une partie de ce fichier.

A priori, ça ressemble à un langage de template. Là où ça diffère, c’est que cog ne cherche pas à générer un fichier différent, il insère le code généré dans le fichier original, et garde le code de génération.

Exemple, vous avez envie d’insérer un warning en haut de plusieurs fichiers de code. Vos choix :

  • Copier-coller le warning.
  • Créer un script de build qui insère le warning.

L’alternative des bricoleurs qui ont juste besoin de quelques insertions, c’est Cog. Par exemple, votre fichier contient :

# [[[cog for l in open('warning.txt'): cog.out("# " + l) ]]]
# [[[end]]]
 
import vostrucs
 
vostrucs.faire_vos_machins()

Après un cog.py -r votre_fichier.py, votre fichier sera :

# [[[cog for l in open('warning.txt'): cog.out("# " + l) ]]]
# Attention, ceci est un avertissmement super important.
# Ce logiciel ne vient avec aucune garantie. Il vomira dans votre salon.
# Violera votre femme, lui collera l'hépatite C et offrira un CD de one direction
# à vos enfants.
# [[[end]]]
 
import vostrucs
 
vostrucs.faire_vos_machins()

cog vient avec plusieurs options, par exemple la possibilité de retirer le code de génération ou de lire le précédent texte généré depuis le code de génération.

La véritable force de l’outil c’est qu’il peut utiliser n’importe quel module Python, et donc générer du texte à partir d’un contenu en ligne ou un fichier CSV. Il est d’ailleurs né parce que l’auteur était codeur C et avait besoin de générer du code à partir d’un fichier XML.

Le seul défaut de Cog, c’est que c’est verbeux. Et moche.

]]>
http://sametmax.com/cog-lanti-langage-de-template-python/feed/ 4
Django, une app à la fois – faire une app de base 3 http://sametmax.com/django-une-app-a-la-fois-faire-une-app-de-base/ http://sametmax.com/django-une-app-a-la-fois-faire-une-app-de-base/#comments Sat, 18 Jan 2014 15:22:24 +0000 http://sametmax.com/?p=8789 Ca faisait longtemps que je n’avais pas fait avancer le projet django, an app at a time.

Voici donc un nouveau morceau qui montre comment écrire une petite app de base avec un template et une vue réutilisables qui serviront donc dans les prochaines apps du projet.

Comme d’hab, vous pouvez récupérer le code sur la teub de Guy et il y a une version française et anglaise.

]]>
http://sametmax.com/django-une-app-a-la-fois-faire-une-app-de-base/feed/ 3
Ignorer certains caractères spéciaux dans un template django 6 http://sametmax.com/ignorer-certains-caracteres-speciaux-dans-un-template-django/ http://sametmax.com/ignorer-certains-caracteres-speciaux-dans-un-template-django/#comments Mon, 09 Dec 2013 07:04:51 +0000 http://sametmax.com/?p=8268 Hier Max me demandait comment mettre un template Javascript dans un template Django s’ils utilisent la même syntaxe.

La réponse : utiliser le tag “verbatim” :

{% verbatim %}
  Mettre ici le code que django doit afficher tel quel, sans interpréter.
{% endverbatim %}
]]>
http://sametmax.com/ignorer-certains-caracteres-speciaux-dans-un-template-django/feed/ 6