FAQ : Python et Windows
***********************


Comment exécuter un programme Python sous Windows ?
===================================================

Ce n'est pas forcément une question simple. Si vous êtes déjà familier
avec le lancement de programmes depuis la ligne de commande de Windows
alors tout semblera évident ; sinon, vous pourriez avoir besoin d'être
un peu guidé.

À moins que vous n'utilisiez une sorte d'environnement de
développement, vous finirez par *taper* des commandes Windows dans ce
qui est diversement appelé une "fenêtre DOS" ou "invite de commande
Windows". En général vous pouvez ouvrir un telle fenêtre depuis votre
barre de recherche en cherchant "cmd". Vous devriez être capable de
reconnaitre quand vous avez lancé une telle fenêtre parce que vous
verrez une invite de commande Windows, qui en en général ressemble à
ça :

   C:\>

La lettre peut être différente, et il peut y avoir d'autres choses à
la suite, alors il se peut que ça ressemble également à ça :

   D:\YourName\Projects\Python>

selon la configuration de votre ordinateur et ce que vous avez
récemment fait avec. Une fois que vous avez ouvert cette fenêtre, vous
êtes bien partis pour pouvoir lancer des programmes Python.

Retenez que vos scripts Python doivent être traités par un autre
programme appelé "l’interpréteur" Python. L’interpréteur lit votre
script, le compile en *bytecode*, et exécute le *bytecode* pour faire
tourner votre programme. Alors, comment faire pour donner votre code
Python à l'interpréteur ?

Tout d'abord, vous devez vous assurer que votre fenêtre d'invite de
commande reconnaît le mot "python" comme une instruction pour démarrer
l'interpréteur. Si vous avez ouvert une invite de commande, entrez la
commande "py", puis appuyez sur entrée :

   C:\Users\YourName> py

Vous devez voir quelque chose comme ça :

   Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
   Type "help", "copyright", "credits" or "license" for more information.
   >>>

Vous avez lancé l'interpréteur dans son "mode interactif". Cela
signifie que vous pouvez entrer des instructions ou des expressions
Python de manière interactive pour qu'elles soient exécutées. Il
s'agit là d'une des plus puissantes fonctionnalités de Python. Vous
pouvez le vérifier en entrant quelques commandes de votre choix et en
regardant le résultat :

   >>> print("Hello")
   Hello
   >>> "Hello" * 3
   'HelloHelloHello'

Beaucoup de gens utilisent le mode interactif comme une calculatrice
pratique mais néanmoins hautement programmable. Lorsque vous souhaitez
mettre fin à votre session Python interactive, appelez la fonction
"exit()" ou maintenez la touche "Ctrl" enfoncée pendant que vous
entrez un "Z", puis appuyez sur la touche ""Enter"" pour revenir à
votre invite de commande Windows.

Peut-être avez-vous remarqué une nouvelle entrée dans votre menu
Démarrer telle que Démarrer ‣ Programmes ‣ Python 3.x ‣ Python (ligne
de commande) qui a pour résultat que vous voyez l'invite ">>>" dans
une nouvelle fenêtre.  Si oui, la fenêtre va disparaître quand vous
appellerez la fonction "exit()" ou entrez le caractère "Ctrl-Z" ;
Windows exécute une commande "python" dans la fenêtre et ferme celle-
ci lorsque vous fermez l'interpréteur.

Maintenant que nous savons que la commande "py" est reconnue, vous
pouvez lui donner votre script Python. Vous devez donner le chemin
absolu ou relatif du script Python. Disons que votre script Python est
situé sur votre bureau et est nommé "hello.py", et votre invite de
commande est bien ouvert dans votre répertoire d’accueil, alors vous
voyez quelque chose comme :

   C:\Users\YourName>

Alors maintenant, vous demanderez à la commande "py" de donner votre
script à Python en tapant "py" suivi de votre chemin de script :

   C:\Users\YourName> py Desktop\hello.py
   hello


Comment rendre des scripts Python exécutables ?
===============================================

Sous Windows, l'installateur Python associe l'extension *.py* avec un
type de fichier (Python.File) et une commande qui lance l’interpréteur
("D:\Program Files\Python\python.exe "%1" %*"). Cela suffit pour
pouvoir exécuter les scripts Python depuis la ligne de commande en
saisissant *foo.py*. Si vous souhaitez pouvoir exécuter les scripts en
saisissant simplement *foo* sans l’extension, vous devez ajouter *.py*
au paramètre d’environnement PATHEXT.


Pourquoi Python met-il du temps à démarrer ?
============================================

Normalement, sous Windows, Python se lance très rapidement, mais
parfois des rapports d'erreurs indiquent que Python commence soudain à
prendre beaucoup de temps pour démarrer. C'est d'autant plus intrigant
que Python fonctionne correctement avec d'autres Windows configurés de
façon similaire.

Le problème peut venir d'un antivirus mal configuré. Certains
antivirus sont connus pour doubler le temps de démarrage lorsqu'ils
sont configurés pour surveiller toutes les lectures du système de
fichiers. Essayez de regarder si les antivirus des deux machines sont
bien paramétrés à l'identique. *McAfee* est particulièrement
problématique lorsqu'il est paramétré pour surveiller toutes les
lectures du système de fichiers.


Comment construire un exécutable depuis un script Python ?
==========================================================

Regardez cx_Freeze pour une extension *distutils* qui permet de créer
des exécutables console et IUG à partir de code Python. py2exe est
l'extension la plus populaire pour construire des exécutables basés
sur Python 2.x mais l'implémentation en Python 3 est en cours de
développement.


Est-ce qu'un fichier "*.pyd" est la même chose qu'une DLL ?
===========================================================

Oui, les fichiers *.pyd* sont des fichiers *dll*, mais il y a quelques
différences.  Si vous avez une *DLL* "foo.pyd", celle-ci doit posséder
une fonction "PyInit_foo()".  Vous pouvez alors écrire en Python «
*import foo* » et Python recherchera le fichier *foo.pyd* (ainsi que
*foo.py* et *foo.pyc*); s'il le trouve, il tentera d'appeler
"PyInit_foo()" pour l'initialiser.  Ne liez pas votre *.exe* avec
*foo.lib* car dans ce cas Windows aura besoin de la DLL.

Notez que le chemin de recherche pour *foo.pyd* est *PYTHONPATH*, il
est différent de celui qu'utilise Windows pour rechercher *foo.dll*.
De plus, *foo.pyd* n'a pas besoin d'être présent pour que votre
programme s'exécute alors que si vous avez lié votre programme avec
une *dll* celle-ci est requise.  Bien sûr *foo.pyd* est nécessaire si
vous écrivez "import foo".  Dans une *DLL* le lien est déclaré dans le
code source avec "__declspec(dllexport)". Dans un *.pyd* la liaison
est définie dans une liste de fonctions disponibles.


Comment puis-je intégrer Python dans une application Windows ?
==============================================================

L'intégration de l'interpréteur Python dans une application Windows
peut se résumer comme suit :

1. Ne compilez **pas** Python directement dans votre fichier *.exe*.
   Sous Windows, Python doit être une DLL pour pouvoir importer des
   modules qui sont eux-mêmes des DLL (ceci constitue une information
   de première importance non documentée). Au lieu de cela faites un
   lien vers "python*NN*.dll" qui est généralement placé dans
   "C:\Windows\System".  *NN* étant la version Python, par exemple «
   33 » pour Python 3.3.

   Vous pouvez créer un lien vers Python de deux manières différentes.
   Un lien au moment du chargement signifie pointer vers
   "python*NN*.lib", tandis qu'un lien au moment de l'exécution
   signifie pointer vers "python*NN*.dll".  (Note générale :
   "python*NN*.lib" est le soi-disant « *import lib* » correspondant à
   "python*NN*.dll".  Il définit simplement des  liens symboliques
   pour l'éditeur de liens.)

   La liaison en temps réel simplifie grandement les options de
   liaison ; tout se passe au moment de l'exécution.  Votre code doit
   charger "python*NN*.dll" en utilisant la routine Windows
   "LoadLibraryEx()".  Le code doit aussi utiliser des routines
   d'accès et des données dans "python*NN*.dll" (c'est-à-dire les API
   C de Python) en utilisant des pointeurs obtenus par la routine
   Windows "GetProcAddress()".  Les macros peuvent rendre
   l'utilisation de ces pointeurs transparente à tout code C qui
   appelle des routines dans l'API C de Python.

   Note Borland : convertir "python*NN*.lib" au format OMF en
   utilisant *Coff2Omf.exe* en premier.

2. Si vous utilisez SWIG, il est facile de créer un « module
   d'extension » Python qui rendra les données et les méthodes de
   l'application disponibles pour Python.  SWIG s'occupera de tous les
   détails ennuyeux pour vous.  Le résultat est du code C que vous
   liez *dans* votre *fichier.exe* (!) Vous n'avez **pas** besoin de
   créer un fichier DLL, et cela simplifie également la liaison.

3. SWIG va créer une fonction d'initialisation (fonction en C) dont le
   nom dépend du nom du module d'extension.  Par exemple, si le nom du
   module est *leo*, la fonction *init* sera appelée *initleo()*.  Si
   vous utilisez des classes *shadow* SWIG, comme vous le devriez, la
   fonction *init* sera appelée *initleoc()*.  Ceci initialise une
   classe auxiliaire invisible utilisée par la classe *shadow*.

   La raison pour laquelle vous pouvez lier le code C à l'étape 2 dans
   votre *fichier.exe* est que l'appel de la fonction d'initialisation
   équivaut à importer le module dans Python ! (C'est le deuxième fait
   clé non documenté.)

4. En bref, vous pouvez utiliser le code suivant pour initialiser
   l'interpréteur Python avec votre module d'extension.

      #include "python.h"
      ...
      Py_Initialize();  // Initialize Python.
      initmyAppc();  // Initialize (import) the helper class.
      PyRun_SimpleString("import myApp");  // Import the shadow class.

5. Il y a deux problèmes avec l'API C de Python qui apparaîtront si
   vous utilisez un compilateur autre que MSVC, le compilateur utilisé
   pour construire *pythonNN.dll*.

   Problème 1 : Les fonctions dites de "Très Haut Niveau" qui prennent
   les arguments FILE * ne fonctionneront pas dans un environnement
   multi-compilateur car chaque compilateur aura une notion différente
   de la structure de FILE.  Du point de vue de l'implémentation, il
   s'agit de fonctions de très bas niveau.

   Problème 2 : SWIG génère le code suivant lors de la génération
   *d'encapsuleurs* pour annuler les fonctions :

      Py_INCREF(Py_None);
      _resultobj = Py_None;
      return _resultobj;

   Hélas, *Py_None* est une macro qui se développe en référence à une
   structure de données complexe appelée *_Py_NoneStruct* dans
   *pythonNN.dll*.  Encore une fois, ce code échouera dans un
   environnement multi-compilateur.  Remplacez ce code par :

      return Py_BuildValue("");

   Il est possible d'utiliser la commande "%typemap" de SWIG pour
   effectuer le changement automatiquement, bien que je n'ai pas
   réussi à le faire fonctionner (je suis un débutant complet avec
   SWIG).

6. Utiliser un script shell Python pour créer une fenêtre
   d'interpréteur Python depuis votre application Windows n'est pas
   une bonne idée ; la fenêtre résultante sera indépendante du système
   de fenêtrage de votre application.  Vous (ou la classe
   *wxPythonWindow*) devriez plutôt créer une fenêtre d'interpréteur «
   native ».  Il est facile de connecter cette fenêtre à
   l'interpréteur Python.  Vous pouvez rediriger l'entrée/sortie de
   Python vers *n'importe quel* objet qui supporte la lecture et
   l'écriture, donc tout ce dont vous avez besoin est un objet Python
   (défini dans votre module d'extension) qui contient les méthodes
   *read()* et *write()*.


Comment empêcher mon éditeur d'utiliser des tabulations dans mes fichiers Python ?
==================================================================================

La FAQ ne recommande pas l'utilisation des indentations et le guide
stylistique de Python, la **PEP 8**, recommande l'utilisation de 4
espaces dans les codes Python. C'est aussi le comportement par défaut
d'Emacs avec Python.

Quel que soit votre éditeur, mélanger des tabulations et des espaces
est une mauvaise idée. *Visual C++*, par exemple, peut être facilement
configuré pour utiliser des espaces : allez dans Tools ‣ Options ‣
Tabs et pour le type de fichier par défaut, vous devez mettre *Tab
size* et *Indent size* à 4, puis sélectionner *Insert spaces*.

Python va lever "IndentationError" ou "TabError" si un mélange de
tabulation et d’indentation pose problème en début de ligne. Vous
pouvez aussi utiliser le module  "tabnanny" pour détecter ces erreurs.


Comment puis-je vérifier de manière non bloquante qu'une touche a été pressée ?
===============================================================================

Utilisez le module "msvcrt". C'est une extension standard spécifique à
Windows, qui définit une fonction "kbhit()" qui vérifie si une
pression de touche s'est produite,  et "getch()" qui récupère le
caractère sans l'afficher.
