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é.

Unless you use some sort of integrated development environment, you
will end up *typing* Windows commands into what is variously referred
to as a "DOS window" or "Command prompt window".  Usually you can
create such a window from your search bar by searching for "cmd".  You
should be able to recognize when you have started such a window
because you will see a Windows "command prompt", which usually looks
like this:

   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 ?

First, you need to make sure that your command window recognises the
word "py" as an instruction to start the interpreter.  If you have
opened a command window, you should try entering the command "py" and
hitting return:

   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'

Many people use the interactive mode as a convenient yet highly
programmable calculator.  When you want to end your interactive Python
session, call the "exit()" function or hold the "Ctrl" key down while
you enter a "Z", then hit the ""Enter"" key to get back to your
Windows command prompt.

You may also find that you have a Start-menu entry such as Start ‣
Programs ‣ Python 3.x ‣ Python (command line) that results in you
seeing the ">>>" prompt in a new window.  If so, the window will
disappear after you call the "exit()" function or enter the "Ctrl-Z"
character; Windows is running a single "python" command in the window,
and closes it when you terminate the interpreter.

Now that we know the "py" command is recognized, you can give your
Python script to it. You'll have to give either an absolute or a
relative path to the Python script. Let's say your Python script is
located in your desktop and is named "hello.py", and your command
prompt is nicely opened in your home directory so you're seeing
something similar to:

   C:\Users\YourName>

So now you'll ask the "py" command to give your script to Python by
typing "py" followed by your script path:

   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 ?
==========================================================

See http://cx-freeze.sourceforge.net/ for a distutils extension that
allows you to create console and GUI executables from Python code.
py2exe, the most popular extension for building Python 2.x-based
executables, does not yet support Python 3 but a version that does is
in development.


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.
