XD blog

blog page

~technical


2013-07-10 Donner envie de partager ses données personnelles

Je lisais cet article aujourd'hui MATRIX – Ce que nos données Gmail révèlent de notre vie sociale qui décrit un outil d'analyse des emails Immersion. Le titre de l'application est assez évocateur et le journaliste plutôt enthousiaste A bien y réfléchir, à moins d'avoir un réseau démesurément grand, les informations représentées au travers de cette application ne devraient pas surprendre. On peut raisonnablement penser que chacun est susceptible de connaître les différents réseaux avec lesquels il communique, les heures auxquelles les emails sont envoyés ou reçus. La nouveauté réside dans l'aspect visuel.

Je reconnais que l'application est plutôt ludique et qu'on a envie de voir ses propres emails (même si personnellement je ne l'ai pas fait). Le concepteur aussi pu choisir une application que l'utilisateur télécharge et installe sur son ordinateur en lui laissant de récupérer ses propres données. Il a préféré emballer le tout sous forme de service acceptant volontiers de récupérer vos données pour vous les montrer. Bien sûr, il s'engage à ne les partager avec qui que ce soit voire à les effacer. On peut supposer que le MIT qui héberge l'ensemble est un organisme à qui on peut faire confiance.

Choisir une application qui s'installer aurait sans doute nuit quelque peu à la facilité d'utilisation. Toutefois, cela montre comment, avec une application ludique, on peut inciter pas mal de gens à partager leur données. Ce service, déjà présenté dans plusieurs journaux, aura probablement été essayé par plusieurs journalistes, lesquels auront utilisé leur adresse gmail. C'est ainsi qu'en quelques jours, il aura été possible de dresser une carte des connexions entre les journalistes de la presse informatique.

On peut imaginer que l'application soit étendue aux données Facebook. Il est probable qu'on retrouve des réseaux similaires sur gmail et Facebook. Et en peu de temps et quelques algorithmes plus loin, on aura pu associer un profil facebook avec une adresse gmail.

2013-07-07 Build a Python 64 bit extension on Windows 8

I was using MinGW on Windows to build a Python extension including C++ code. The 32bit mode was working fine and I was using the following command line:

python setup.by build --compiler=mingw32
I thought it would be easy to run it with the Python 64 bit version. No change would be required. I was a little bit over confident.
Traceback (most recent call last):
  File "setup.py", line 11, in <module>
    author_email  = '...',
  File "c:\python33_x64\lib\distutils\core.py", line 148, in setup
    dist.run_commands()
  File "c:\python33_x64\lib\distutils\dist.py", line 929, in run_commands
    self.run_command(cmd)
  File "c:\python33_x64\lib\distutils\dist.py", line 948, in run_command
    cmd_obj.run()
  File "c:\python33_x64\lib\distutils\command\build_ext.py", line 323, in run
    force=self.force)
  File "c:\python33_x64\lib\distutils\ccompiler.py", line 1034, in new_compiler
    return klass(None, dry_run, force)
  File "c:\python33_x64\lib\distutils\cygwinccompiler.py", line 125, in __init__
    if self.ld_version >= "2.10.90":
TypeError: unorderable types: NoneType() >= str()
I decided to switch to Visual Studio Express 2012 to build my extension. but I went through some error related to the file vcvarsall.bat because Python was not able to find the file vsvars64.bat (for one very good reason, it does not exist). I read some blogs where people suggest to reinstall Visual Studio Express but I did not remember the setup asking me anything about options. When I checked the folder of Visual Studio, I found the following file vcvarsx86_amd64.bat. Then, after some research (stubborness is mandatory for those parts) and some tweaks, I discovered two mistakes in the package distutils. They need to be fixed in the file msvc9compiler.py: After the two modifications, it was working fine with the following command line:
python setup.by build --compiler=msvc --plat-name=win-amd64
And I understood why it was failing without any mysterious new installation. I checked about 64 bit version of MinGW but it looked a longer path than the one I chose. Who knows? You will find some others details here. I wrote a function which import a module written in one single C++ file. If the module does not exist, it compiles it inplace.

As a conclusion, I would say it was difficult to find the proper instructions. Maybe the number of documents related to that issue has increased, or the search engines I used were not able to give me the answer. All I know is I do not want to go through that again even if I know there will be a next time when I update Python or when I change my laptop. I hope next time I face that problem, search engines will show me my own page.

2013-07-01 Unit test, what a relief ?

To be honest, I hesitated. French, English, I was pissed off by own coding (I speak French in that case) but saved by a unit test...

Function signature are a bit tricky in python because this definition does not exist. There is only one function and you have to tweak around the parameters' type. So... this is an example of a case where unit tests were useful to me.

def function_nobody(input) :
    if isinstance (input, list) :
        for line in list :
            # ....
    elif isinstance (input ,str) :
        with open(input, "r", encoding="utf8") as f :
            for line in f :
                # ...
So basically, the previous function accepts a file or a list. But I wanted it to be more generic and to accept iterators:
import collections
def function_nobody(input) :
    if isinstance (input, list) or isinstance (file, collections.Iterable) :
        for line in list :
            # ....
    elif isinstance (input ,str) :
        with open(input, "r", encoding="utf8") as f :
            for line in f :
                # ...
I added isinstance (file, collections.Iterable). But a string falls under that condition which made the second case useless. But because I wrote unit tests, I was able to catch my mistake. I just reverted the two tests:
import collections
def function_nobody(input) :
    if isinstance (input ,str) :
        with open(input, "r", encoding="utf8") as f :
            for line in f :
                # ...
    elif isinstance (input, list) or isinstance (file, collections.Iterable) :
        for line in list :
            # ....
And it worked. I confess I did not lose two much time and I would not have lost any even without unit tests because I would not know my failure. However, I don't want to guess how much crazyness I could have gone through if one of my scripts fails because of that a month, two, three months later. How could I guess it is because of that...

Please do unit testing... Ok, it is late, my style might be overdramatic. But, please remember this when it is your time to experience one of these overdramatic scenarii. (I used the latin plural for scenario, don't know if it works in English).

2013-06-24 Installer pip pour Python

J'ai encore perdu des minutes pour installer le package pip qui permet d'installer tous les autres. Ca a l'air simple vu d'un premier abord sauf qu'il faut installer ses dépendances : setuptools. Et comme je ne fais pas ça tous les jours... J'ai perdu du temps à force d'être paresseux et je suis retombé sur cette page : Unofficial Windows Binaries for Python Extension Packages qui m'a permis de tout faire en trois clics. Il faut vraiment que je retienne cette page.

2013-06-23 Internet et la programmation

Je ne me souviens plus de ce qu'était la programmation avant internet. Aujourd'hui, je passe beaucoup de temps à comprendre comment marche un truc précis, je fais une centaine de requête en espérant qu'un autre fou comme moi ait un jour fait face au même problème et qu'il ait de surcroît penser à décrire sa solution. Les forums de discussions sont une source plutôt utiles. Il y a dix ans, internet n'était pas aussi fourni, on cherchait moins et on codait plus. Aujourd'hui, on passe la première partie d'un projet à chercher des briques qu'on pourrait réutiliser. Une fois qu'on les a trouvées, on passe à la seconde phase qui se résume à coder comme un fou. C'est un peu ce que résume le graphe qui suit.

A la fin, il est possible que tout se déroule comme prévu ou que, comme il arrive souvent, vous ne butiez sur un nouveau problème. Rebelotte, nouvelles séries de requêtes pour comprendre que ce petit détail qu'on n'avait pas gardé pour plus tard en n'anticipant pas sur le fait qu'il pourrait s'avérer redoutable... Et bizarrement, armé de nouveaux mots-clé, on finit par trouver la librairie qui aurait pu vous faire économiser pas mal de temps.

Cela explique la troisème partie. A ce stade, trois options s'offrent à vous. La première est de tout laisser tomber en vous disant qu'un jour quelqu'un aura le courage de surmonter ces épreuves mais que là, étant donné que la vie est courte, on va tout laissant en plan pour aller s'amuser. Ca finit par une bonne cuite pour oublier le temps perdu dans des trucs de geek inutile (la cuite va souvent de paire avec le dénigrement). La seconde est de se plonger dans la documentation du nouvel outil puis de repartir presque de zéro pour se dire finalement qu'au bout de toutes ces épreuves, vous aurez enfin sur les yeux ce que vous aviez en tête au départ, à moins qu'un nouvel obstacle n'apparaisse, un nouvel outil, l'enfer... Dans ce cas, la première tentation refait surface et en général l'emporte. La troisième option est celle des temps anciens : l'ignorance. On s'obstine à poursuivre le chemin déjà commencé et on se dit ce n'est pas une petite difficulté qui va tout remettre en question. Quand il n'y avait pas internet, j'avais souvent tendance à choisir cette dernière option. J'ai codé beaucoup de trucs inutiles mais l'essentiel était de ne pas l'apprendre trop tôt. Et puis ce n'était pas tout-à-fait perdu, j'ai appris pas mal aussi. Mais l'ignorance était vraiment le point important.

C'était pas mal sans internet. Je butais contre une machine pour trouver une solution. Aujourd'hui, je passe plus de temps à déchiffrer des explications succintes trouvées sur des blogs écrites par un développeur qui affirme avoir un bousin qui marche. Une heure après, convaincu que cela marche, je m'aperçois que mon truc et le sien ne fonctionnent pas sur la même version de Python. Ca ne m'étonne pas qu'on y perdent des nuits sur ces conneries.

Je me demande ce que tous ceux qui ont bossé sur le Vasa ont pensé au moment où ils ont vu leur oeuvre couler juste après la mis à l'eau.

2013-06-13 A template to create a Python module including Sphinx documentation and a setup

My students often struggle to debug their programs when two or three students need to synchronize their versions. A good way to avoid wasting too much time is to use a tool to keep track of the modifications such as github. It then becomes easy to synchronize multiple versions.

However, students still need to debug the program after a synchronization. A good practice is to write unit tests. Every time, you write a complex function or an easy one, a unit test should be written to ensure its behaviour will not change after many changes. But it means to add a file, to spend some time to do it right, and to frequently run all the unit tests. This is usually too painful when the project will only last a couple of months. Plus, you usually commit yourself to do it only after you went through the nightmare of debugging once.

Last but not least, my students usually do not add documentation to their code. Most of the time, they do not need it because the project is too short to lose track of the modifications and too small to not know it completely. Maybe another reason is because they cannot see a compiled version of the documentation. The best way is to use Sphinx ut using it means spending a couple of hours at least (a lot of more if you do it for the first time). Documentation can also be used to navigate through the program.

For those reasons, I made a kind of template for a Python module. It includes an easy mechanism to add a unit test and to run it. It generates with the documentation with no change and it also generated a setup (gz, exe) with no change either. You can get it here: Pieces of codes, libraries (section Code). After you downloaded it, a page gives the short list of instructions to tweak the template in order to make it yours: README.

2013-06-08 Apprendre la programmation avec la souris (avec Scratch)

Je cherchais des livres récents sur Python et je suis tombé là dessus : Super Scratch Programming Adventure!: Learn to Program by Making Cool Games!. Le livre est en anglais mais il présente un outil qui se décline dans toutes les langues et qu'on peut trouver ici : Scratch et qu'on peut télécharger sur toutes les plateformes ici : téléchargement.

Je suis toujours un peu sceptique sur les outils comme celui-ci. Ils sont soit très simples mais on ne peut pas faire grand chose, soit aussi complexe que d'autres (Apprendre à coder en Python : illustration) avec le désavantage de ne pas pouvoir utiliser plus tard ce qu'on apprend aujourd'hui (tout du moins pas en l'état car c'est une autre syntaxe). Malgré tout, c'est un outil intéressant, il offre une vue plus visuelle sur ce qu'est un algorithme comme cet exemple sur le calcul du PGCD (plus grand diviseur commun) : PGCD avec Scratch. Avec Scratch, on peut créer une scène et animer relativement facilement plusieurs objets dans cette scène : minotaure. On peut y ajouter des extensions : S4A : un projet pédagogique. On peut même trouver une traduction française du tutoriel : tutoriel en français. Et si vous avez la flemme de l'installer, vous pouvez l'utiliser en ligne : Scratch en ligne.

Tout est fait pour y être intuitif et ça marche plutôt bien. Cela dit, comme tout langage de programmation, il faudra quelques heures pour arriver à faire vraiment ce qu'on avait en tête au moment de commencer. Il manque selon mon avis deux fonctionnalités. La première serait de pouvoir aisément animer un personnage avec une séquence d'images. Dans scratch, chaque image serait un objet ce qui rend les choses un peut compliquées. L'autre option est de créer des costumes différents mais je ne sais pas trop comment Scratch gère la transparence des images. Il manque aussi les fonctions même s'il est encore possible de contourner l'obstacle : Creating a Function in Scratch using a Variable. Ce n'est pas l'idéal. L'autre option est d'utiliser Snap qui permet de créer ses propres blocs. Je n'ai pas réussi à télécharger l'outil, il est seulement disponible en ligne pour le moment (et en anglais). J'attendrais un peu.

Il n'est pas facile d'apprendre à programmation. Je n'ai pas encore trouvé de représentation qui ne soit pas abstraite. On comprend aisément ce que veut dire répéter une suite d'opérations mais un algorithme comprend souvent plusieurs répétitions, chacune d'entre elles pilotée par une condition différente. Les premiers pas sont plutôt simples comparés à l'assemblage de pas d'un programme qui fait quelque chose d'utile. Cette multitude devient nécessairement abstraite au-delà d'un certain point.

Il y a vingt ans, on enseignait la programmation au lycée avec le LSE dont la syntaxe était en français. Il n'a pas survécu probablement parce qu'il était dédié l'enseignement mais ne permettait pas vraiment de faire quoi que ce soit d'utile. Espérons que Scratch suive un destin différent. Et si on n'est pas convaincu, il est toujours possible de créer son propre langage A simple interpreter from scratch in Python, part 2, part 3, part 4.

2013-05-26 Processing (big) data with Hadoop

Big Data becomes very popular nowadays. If the concept seems very simple - use many machines to process big chunks of data -, pratically, it takes a couple of hours before being ready to run the first script on the grid. Hopefully, this article will help you saving some times. Here are some directions I looked to create and submit a job map/reduce.

Unless you are very strong, there is very little chance that you develop a script without making any mistake on the first try. Every run on the grid has a cost, plus accessing a distant cluster might take some time. That's why it is convenient to be able to develop a script on a local machine. I looked into several ways: Cygwin, a virtual machine with Cloudera, a virtual machine with HortonWorks, a local installation of Hadoop on Windows. As you may have understood, my laptop OS is Windows. Setting up a virtual machine is more complex but it gives a better overview of how Hadoop works.

Here are the points I will develop:

To go through all the steps, you need a machine with 30Gb free on your hard drive, and at least 4Gb memory. 64bit OS is better. I went through the steps with Windows 8 and it works on any other OS.

Contents:

I'll assume you are familiar with Map/Reduce concepts and you have heard about Hadoop and PIG.
more...

2013-05-25 Créer un GIF animé

Il y a quelques mois, j'ai écrit un article sur une façon de convertir des images en GIF animé. Il fallait télécharger deux fichiers. Maintenant, il suffit d'installer le module suivant : pyhome3 (il nécessite Python 3.3 et numpy). Ensuite, le code suivant fera le reste :

# coding: latin-1

# on prend les fichiers dans le répertoire
import os
files = os.listdir(".")
# on ne garde que les images
files = [ _ for _ in files if ".png" in _ ]
# on les tri : image_2.png doit être avant image_10.png 
# (ce qui n'est pas l'ordre alphatétique)
# en enlève tout ce qui n'est pas un chiffre, on convertit un entier
# puis on trie une liste de couples ( numéro, images )
files = [ ( int (_.replace("image_","").replace(".png","")), _) for _ in files ]
files.sort()
files = [ _[1] for _ in files ]

# ici, on renomme les fichiers car ImageMagick utilise l'ordre alphabétique
files = [ ( "image_%03d.png" % i, _) for i,_ in enumerate(files) ]
for new_name, old_name in files :
    if new_name != old_name :
        os.rename(old_name, new_name)
        
# on reprend la nouvelle liste de fichiers        
files = [ _ for _ in os.listdir(".") if ".png" in _ ]
files.sort()

# il faut supprimer ces lignes et installer le module disponible ici
# http://www.xavierdupre.fr/site2013/index_code.html (pyhome3)
# qui ne marche qu'avec python 3.3 + numpy
import sys
sys.path.append(r"D:\Dupre\_data\program\pyhome")

# on importe la fonction qu'il faut
from pyhome3 import create_animated_gif, HalLOG

# la fonction télécharge image magick et cela prend du temps, pour voir
# ce qu'il se passe, il faut utilise la fonction suivante
# le téléchargement n'est plus nécessaiire dès la seconde exécution
HalLOG(OutputPrint=True)

# et on l'exécute
create_animated_gif(files, "final.gif", resize = (400,300))

Si vous avez commencé votre programme avec Python 2.x, vous pouvez toujours exéctuer le programme comme ceci :

import os
os.system("c:\python33\python le_programme_precedent.py")

Afficher le GIF animé en utilisant Python n'est pas facile. On pourrait recréer l'animation manuellement en affichant les images les unes après les autres via tkinter, on pourrait utiliser d'autres modules de type pyQt. Par paresse, j'ai choisi le code suivant :

with open("image_res.html", "w") as f :
    f.write("\n")
    f.write("\n")
    f.write('<img src="final.gif" />\n')
    f.write("\n")    
    f.write("\n")
    
import os
os.system("image_res.html")
Il crée un fichier html puis l'exécute : le navigateur par défaut se chargera de l'afficher.

2013-05-20 Quelques blogs intéressants pour la programmation Python

Le blog Les articles pour apprendre Python, dans le bon ordre regroupe de nombreux articles techniques sur la programmation Python. Les articles sont très détaillés autour d'un sujet précis :

Le même article récapitulatif existe pour ceux qui veulent programmer avec django : Les articles pour apprendre Django, dans le bon ordre :-). Cela m'amène à citer le module suivant IPython que je vois revenir souvent depuis quelques temps. Il change la présentation de la ligne de commande pour la faire ressembler à celle d'un Matlab ou d'un R, il permet de récupérer les commandes précédentes. Il propose également de facilement distribuer un calcul sur plusieurs machines avec la librairie MPI. Cette fonctionnalité n'est pas encore disponible avec Python 3 mais cela devrait vite arriver. Il a sa page Wikipedia. Certaines présentations l'utilisent pour toutes les copies d'écran. On l'utilise beaucoup avec PyTables. Ce dernier module utilise blosc qui optimise les transferts de données entre la mémoire et le CPU en compressant les données. Pour conclure ce patchwork, ces lectures m'ont amené à dénicher cette page : 100 sites de Consommation Collaborative où on trouve des sites comme celui-ci CoLunching.

2013-05-16 Modules for Python

I recently discovered this page Unofficial Windows Binaries for Python Extension Packages which provides a link to many Windows installer for Python extensions. It provides installer even when the official website does give any. It saved me sometimes while trying to build Rpy2 for Python 3.3. It was the only place I was able to find a Windows version for Python 3.3. I put here the official website for each module. The first page links to the latest installer for each of them. Here is a short not no short list of scientific extensions.

Some others to draw maps or 3D graphs: Some GUI (Graphic User Interface): About datamining: Various extensions:

2014/07/01 - an updated version of this page but in French: Modules intéressants (pour un ENSAE.

2013-05-14 Programmation : gagner du temps maintenant ou plus tard ?

Lorsqu'on programme, on veut avant tout arriver à construire un truc qui tourne et qui produise les résultats attendus. Ce faisant, certains raccourcis font parfois perdre du temps plus tard.

Par exemple, pour éviter que les élèves passent par des étapes intermédiaires fastidieuses (lecture de fichiers, récupération de données), je leur propose des fonctions toutes prêtes.

def download_data(dataset_name) :
    ...
    return dataset
Comme il est parfois difficile d'écrire une fonction qui tourne sur plusieurs environnement (chez moi, à l'école, sur différente versions de Python), les élèves doivent parfois bidouiller, quitte à aller au plus simple:
def download_data() :
    ...
    ... bidouille
    ...
    return dataset_qui_marce

data1 = download_data()
Et puis, on a besoin d'un autre jeux de données, le programme devient :
def download_data() :
    ...
    ... bidouille
    ...
    return dataset_qui_marce

data1 = download_data()

def download_data() :
    ...
    ... autre bidouille
    ...
    return dataset_qui_marche

data2 = download_data()
Et puis un troisième...

Les élèves m'assurent que tout fonctionne comme prévu, je suggère de passer à l'étape suivante et de tester l'algorithme sur une dizaine de jeux de données. Comme je suppose qu'ils ont utilisé la fonction que je leur avais donnée, tester sur une dizaine de jeux de données revient dans mon esprit à écrire quelque chose de ce style :

datasetname  = [ "data1.txt", ... ]
datasets = [ download_data(name) for name in datasetname ]
Mais dans leur cas, la première réaction fut un soupir devant ma requête quelque peu fastidieuse.

Je pense que c'est à ce moment-là qu'on retient le mieux une certaine façon d'organiser un programme qui fait perdre un peu de temps mais qui en fait gagner plus plus tard. L'inconvénient est que ce qu'on appris servira le plus souvent pour le projet suivant. Pour le projet courant, il est trop tard pour tout changer avant le rendu.

Laisser faire des erreurs ou donner une solution qui manquera de consistence tant qu'on n'aura pas saisi le fond du problème...

Ce n'est qu'un programme informatique. Cela dit, il faut parfois une grosse crise pour chacun prenne conscience de l'étendue du problème.

2013-05-13 Trie in Python

I was looking for extensions to use tries in Python and I found an interesting page: Fast Non-Standard Data Structures for Python. The winner seems to be MARISA-trie. The library is self contained and can be installed using pip (I did not try yet). The code can be compiled either in 32 or 64 bits.

2013-05-12 Les stations Vélib à Paris un jeudi soir

Les données Vélib sont ouvertes (depuis peu) et on peut disposer de l'état des stations (vélos et places disponibles) au moment où accède au service. J'ai collecté les données pendant plusieurs consécutives. Elles ressemblent à celles qui suivent.

addressavailable bike standsavailable bikesbankingbike standsbonuslast updatelatlngnamenumberstatus
3 AVENUE BOSQUET - 75007 PARIS571206902013-05-09 22:58:4748.86164049957622.3022503441759507022 - PONT DE L'ALMA7022OPEN
18 RUE MARIE ANDREE LAGROUA - 75013 PARIS52706102013-05-09 22:53:3448.82859528385742.3802206062661113055 - LAGROUA13055OPEN
25 RUE LOUIS LE GRAND - 75002 PARIS121903102013-05-09 22:55:3848.87050893720392.3340544619393302015 - OPERA - CAPUCINES2015OPEN
2 RUE DE LA REPUBLIQUE - 92170 VANVES02502502013-05-09 23:01:0348.82170269989312.2853956248283921704 - REPUBLIQUE (VANVES)21704OPEN
96 RUE DE LAGNY - 93100 MONTREUIL20402702013-05-09 22:55:2148.84923030086482.4214299400070331001 - LAGNY (MONTREUIL)31001OPEN

Je me suis aperçu que l'état des stations est mis à jour de façon désynchronisée. A priori à chaque fois qu'un vélo arrive ou part et régulièrement toutes les dix minutes. Projeté sur un graphe, cela donne l'image suivante et pour voir l'animation, il suffit de cliquer sur le lien.


more...

2013-05-10 Installer un package simplement avec Python : pip

Pour installer les packages ou modules sous Python, il est possible d'utiliser un installer (.exe ou .msi sous Windows), de télécharger les sources puis de taper depuis une fenêtre de commande :

python setup.py install
Lorsque le package contient des extensions à compiler, il faut parfois taper. Par défaut, c'est le compilateur MingGW qui utilisé ou gcc sous Linux :
python setup.py build
python setup.py install

Python facilite l'installation en évitant l'étape de téléchargement. Il faut pour cela d'abord intaller deux packages (comme mentionné ci-dessus) :

Ensuite, il suffit de se placer dans le répertoire <python>/Scripts et taper :
pip install <module_name>
L'avantage de cette méthode est la gestion automatique des dépedendances qui sont installées si besoin. (voir plus bas pour la sortie d'écran après l'exécution de la commande pip install jinja2).

Remarque : certains modules (numpy) contiennent des fichiers C++ qui devront être compilés. Cette compilation nécessite l'installation de MingGW et la définition de certaines variables environnement. Il est préférable d'utiliser les setups tout préparés qui incluent les mêmes fichiers déjà compilés.

Tester une installation

Parfois, on veut juste tester un module et ne pas dégrader son environnement. C'est possible avec le module virtualenv. Il faut d'abord l'installer :

pip install virtualenv
Ensuite, on crée un répertoire pour les différents environnements virtuels :
mkdir c:\python33vir
On crée un environnement virtuel :
virtualenv c:\python33vir\virt1 --system-site-packages
L'option --system-site-packages permet d'utiliser les modules déjà installés dans le répertoire de Python. Puis on va dans le répertoire python33vir/vir1/Script, on peut installer le module à tester :
pip install jinja2
Si vous obtenez une erreur (bad sum), il est préférable de recommencer avant de chercher une autre erreur. Il suffit ensuite d'utiliser le programme python33vir/vir1/Script/python.exe (ou pythonw.exe) pour exécuter ses propres scripts.


more...
<-- -->

Xavier Dupré