Coder en Python dans un navigateur Web avec BRYTHON

JP Roy, mars 2022

1. Brython ?

Le nom ressemble à celui d'une station balnéaire de la côte anglaise. Heureusement, rien à voir avec le fish and chips, la dénomination provient de BRowser (navigateur) et pYTHON (le serpent à plumes, cf. PAA).

Il s'agit de pouvoir programmer en Python et obtenir le résultat dans une page Web (Safari, Firefox,...), sans passer par l'apprentissage laborieux de l'incontournable Javascript, pour une fois contourné. Quelques connaissances sur HTML (voire CSS) ne font pas de mal, mais on peut les apprendre sur le tas si le besoin s'en fait sentir. Le logiciel Brython est livré avec de nombreux exemples.

2. La programmation du DOM

En Python usuel, le résultat d'un programme peut être purement textuel, par exemple des résultats de calculs affichés à la console, ou bien apparaître dans une interface graphique (GUI) en utilisant le module tkinter. Ici, les affichages se feront dans la fenêtre du navigateur considérée comme un document contenant des objets : un DOM (Document Object Model). Le but d'un programme Brython est de construire un tel document. Le concept de DOM est indépendant du langage de programmation, les scripts (en général en Javascript, ici en Brython) sont là pour connaître et modifier le contenu du DOM. Le langage Brython est un Python augmenté de primitives concernant la manipulation du DOM.

Installons le logiciel en nous rendant sur brython.info. L'horloge que vous voyez apparaître est issue d'un script dans la page index.html, mais ce script est rédigé en Python et non en Javascript. Le menu Ressources contient un lien vers la page de téléchargement permettant de récupérer Brython-xxx.zip, que vous décompactez dans un dossier Brython-xxx. Ce dernier contiendra plusieurs fichiers, entre autres les quatre suivants.

Voici une variante du fichier index.html fourni.

1   <!doctype html>                                  prgm1.html
2   <html>
3
4   <head>
5   <meta charset="utf-8">
6   <script type="text/javascript" src="brython.js"></script>
7   <script type="text/javascript" src="brython_stdlib.js"></script>
8   </head>
9
10  <body onload="brython(1)">
11  <script type="text/python">
12  from browser import document
13  somme = sum(range(1,1001))
14  document <= f'1 + 2 + 3 + ... + 1000 = {somme}'       # dans le DOM
15  print('Ok ?')                          # dans la console Javascript
16  </script>
17  </body>
18
19  </html>

L'ouverture de cette page Web dans un navigateur engagera les calculs du script Python, puis affichera simplement la ligne :

1 + 2 + ... + 1000 = 500500

L'en-tête (header, lignes 4--8) contient le choix d'encodage des caractères en UTF-8 (Unicode, un fichier unicode.txt est fourni), puis sur deux lignes l'inclusion de la boîte à outils Python.

Les lignes 10--17 contiennent le corps (body) de la construction du DOM, par un appel à la fonction brython en ligne 10, ici avec un argument 1, cf. plus bas. La fonction brython permet d'écrire des scripts en Brython (du Python augmenté).

En lignes 11--16 se trouve un script rédigé en Brython. Attention, un peu de magie brythonesque en ligne 14 :

document <= ...

Dans ce contexte, le signe <= (qui se lit reçoit) n'est pas l'inégalité arithmétique mais une instruction propre à Brython envoyant un objet ... de type str dans le DOM. En remplaçant cette ligne par un print(...), l'effet serait différent : l'affichage se ferait à la console Javascript du navigateur et non dans la page Web. Console qui sert aussi à voir les messages d'erreur. L'opérateur <= dissimule un appel à la méthode attach, vous auriez pu écrire document.attach(...).

Pour voir la console Javascript, par exemple avec Safari, il faut installer les outils de développement de ce dernier. Dans les "Préférences", onglet "Avancées", cochez la ligne "Afficher le menu Développement", et ce nouveau menu proposera l'option "Afficher la console Javascript". Mécanisme analogue, à adapter à chaque navigateur.

L'argument 1 de la fonction brython en ligne 10 signifie : lancer Brython en mode debug et les messages d'erreur seront affichés dans la console Javascript. Si votre programme fonctionne bien, ne mettez aucun argument. L'argument 2 montrerait la traduction de Python vers Javascript, un peu cryptique (et c'est peu dire).

Pourquoi en effet refaire tout le travail de Javascript alors qu'il suffit d'une traduction entre langages assez semblables. Le lecteur avancé et très motivé pourra rechercher la vidéo "JavaScript as a compilation target" sur YouTube, et je salue Florian au passage pour sa réussite...

3. Exemple : un script tortue en Python pur à l'intérieur d'une page HTML

Avec le modèle de la page précédente, vous pourrez à l'intérieur même de la page insérer des scripts affichant des résultats de calculs en Python, ou bien dessiner avec la tortue, ou même programmer une interface graphique avec des fenêtres, boutons, etc. Comme en Python, sauf que tout cela sera contenu dans un DOM maître contenant une multitude d'objets.

<body onload="brython(1)">                            prgm2.html
<script type="text/python">
from turtle import *         # le module turtle usuel de Python
def poly(n,c):
    angle = 360.0/n
    for i in range(n):
        forward(c)
        left(angle)
bgcolor('lightgrey') ; up() ; goto(-50,-100) ; down()
poly(8,100)
done()                       # terminaison du programme graphique
</script>
</body>

Le script précédent est un pur programme tortue en Python dont l'exécution a lieu dans un navigateur. On ignore le DOM. Vous pouvez en faire une page Web et la publier sur Internet. Le programme s'exécutera automatiquement à l'ouverture de la page.

4. Mélange entre HTML et scripts Python

Typiquement pour réaliser un document scientifique exécutable dans une page Web. Cette fois, nous souhaitons faire un peu mieux. Utiliser des balises de structuration du texte (<h1>, <p>, <b>, etc.), mais aussi des scripts rédigés en Brython, donc essentiellement en Python, avec quelques modifications du DOM. Les affichages des résultats de calcul se feront avec <=, mais à quel endroit ? En fait, on ne les rajoute pas au document, mais à une zone du document, ci-dessous une zone vide <div id="..."></div> nommée par un identificateur.

Cet exemple comporte deux scripts de calcul Python. Le premier envoie ses résultats dans la zone div1 et le second dans la zone div2.

<body onload="brython(1)">                            prgm3.html
  <script type="text/python">
  from browser import document          # DOM
  somme = sum(range(1,1001))
  document["div1"] <= f'1 + 2 + 3 + ... + 1000 = {somme}'
  </script>
  
  <script type="text/python">
  from browser import document, html    # DOM + balises HTML
  def fac(n):
      res = 1
      for k in range(2,n+1): res *= k
      return res
  f50 = fac(50) ; n50 = len(str(f50))
  document["div2"] <= html.P(html.TT(f'50! = {f50}'))   # <p><tt>
  document["div2"] <= html.P(f'avec {n50} chiffres.')   # <p>
  </script>

<h1><font color="red">PRGM2 en Brython</font></h1>
<p>Je code en HTML avec des scripts en <b>Brython</b> qui est un 
mélange entre Python et gestion du DOM.</p>

<h2>Exemple 1</h2>
<div id="div1"></div>               <!-- zone div1 à remplir -->

<h2>Exemple 2</h2>
<p>Calcul en Python de la <i>factorielle</i> de 50 :</p>
<div id="div2"></div>               <!-- zone div2 à remplir -->
<p>Et c'est fini.</p>

</body>

Si vous souhaitez modifier le style par défaut de votre page Web, vous pouvez le faire à l'intérieur de la page en ajoutant une déclaration de style CSS propre à cette page. Insérez à la fin du header (juste avant la ligne </head>) la portion suivante :

<style>
body  {font-size: 1.5em; color: black;}
h1,TT {color: red;}
h2    {color: blue;}
</style>
Une autre façon de faire, si le style est ré-utilisable dans d'autres pages, consiste à placer les lignes de style dans un fichier style.css et d'insérer au début du header la ligne :
<link rel="stylesheet" href="style.css">

Voir le rendu ci-dessous. Plongez dans le tutoriel de Brython pour faire des choses plus sophistiquées (mais parfois faciles, comme placer un bouton et lier son action à un clic). Si vous enseignez Python, cela pourrait vous plaire et initier les élèves à la programmation côté client. Good luck...