Formation gratuite Python
- Épisode 204 StaticFrame, comme les pandas mais plus sûr
- Épisode # 50 Web grattant à l'échelle avec Scrapy et ScrapingHub
- Utilisez QThread de PyQt pour empêcher le gel des interfaces graphiques – Real Python
- Quand un site Web doit-il publier chaque?
- Je ne suis pas en podfading. Je ne suis pas! Je ne suis pas! Je ne suis pas!
Si vous êtes un développeur Web qui préfère écrire Python plutôt que JavaScript, Brython, une implémentation Python qui s'exécute dans le navigateur, peut être une option intéressante.
JavaScript est le langage de facto de développement web front-end. Les moteurs JavaScript sophistiqués font partie intégrante de tous les navigateurs Internet modernes et incitent naturellement les développeurs à coder des applications Web frontales en JavaScript. Brython offre le meilleur des deux mondes en faisant de Python un langage citoyen de première classe dans le navigateur et en ayant accès à toutes les bibliothèques JavaScript et API existantes disponibles dans le navigateur.
Dans ce didacticiel, vous apprendrez à:
- Installez Brython dans votre environnement local
- Utilisation Python dans un navigateur
- Écrivez du code Python qui interagit avec JavaScript
- Déployer Python avec votre application Web
- Créer extensions de navigateur avec Python
- Comparez Brython avec autres implémentations Python pour les applications Web
En tant que développeur Python intermédiaire familiarisé avec le développement Web, vous tirerez le meilleur parti de ce didacticiel si vous avez également des connaissances en HTML et JavaScript. Pour un rappel JavaScript, consultez Python vs JavaScript pour les pythonistes.
Vous pouvez télécharger le matériel source des exemples de ce didacticiel en cliquant sur le lien ci-dessous:
Exécuter Python dans le navigateur: les avantages
Bien que JavaScript soit le langage omniprésent du développement Web frontal, les points suivants peuvent s'appliquer à vous:
- Vous n'aimez peut-être pas écrire du code en JavaScript.
- Vous voudrez peut-être tirer parti de vos compétences Python.
- Vous ne voudrez peut-être pas passer le temps d'apprendre JavaScript pour explorer les technologies de navigation.
- Vous n'aimerez peut-être pas être obligé d'apprendre et d'utiliser JavaScript pour implémenter une application Web.
Quelle que soit la raison, de nombreux développeurs préféreraient une alternative basée sur Python à JavaScript pour tirer parti de la puissance du navigateur.
Il existe plusieurs avantages à exécuter Python dans le navigateur. Il vous permet de:
- Exécutez le même code Python dans le serveur et le navigateur
- Travailler avec diverses API de navigateur en utilisant Python
- Manipuler le modèle d'objet de document (DOM) avec Python
- Utilisez Python pour interagir avec les bibliothèques JavaScript existantes telles que Vue.js et jQuery
- Enseigner le langage Python aux étudiants Python avec l'éditeur Brython
- Gardez le sens du plaisir lors de la programmation en Python
Un effet secondaire de l'utilisation de Python dans le navigateur est une perte de performances par rapport au même code en JavaScript. Cependant, cet inconvénient ne l'emporte sur aucun des avantages décrits ci-dessus.
Implémentation du développement Web isomorphe
JavaScript isomorphe, ou JavaScript universel, souligne que les applications JavaScript doivent s'exécuter à la fois sur le client et sur le serveur. Cela suppose que le back-end est basé sur JavaScript, à savoir un serveur Node. Les développeurs Python utilisant Flask ou Django peuvent également appliquer les principes de l'isomorphisme à Python, à condition qu'ils puissent exécuter Python dans le navigateur.
Brython vous permet de créer le frontal en Python et de partager des modules entre le client et le serveur. Par exemple, vous pouvez partager des fonctions de validation, comme le code suivant qui normalise et valide les numéros de téléphone américains:
1importer ré
2
3def normalize_us_phone(téléphone: str) -> str:
4 "" "Extraire les numéros et les chiffres d'un numéro de téléphone donné" ""
5 revenir ré.sous(r"[^da-zA-z]", "", téléphone)
6
7def is_valid_us_phone(téléphone: str) -> booléen:
8 "" "Valider le numéro de téléphone à 10 chiffres" ""
9 normalized_number = normalize_us_phone(téléphone)
dix revenir ré.correspondre(r"^ ddix$ ", normalized_number) est ne pas Aucun
normalize_us_phone ()
élimine tous les caractères non alphanumériques, alors que is_valid_us_phone ()
Retour Vrai
si la chaîne d'entrée contient exactement dix chiffres et aucun caractère alphabétique. Le même code peut être partagé entre les processus exécutés sur un serveur Python et un client construit avec Brython.
Accéder aux API Web
Les navigateurs Internet exposent des API Web standardisées à JavaScript. Ces normes font partie du HTML Living Standard. Certains exemples d'API Web incluent:
Brython vous permet à la fois d'utiliser les API Web et d'interagir avec JavaScript. Vous travaillerez avec certaines des API Web dans une section ultérieure.
Prototypage et bibliothèques JavaScript
Python est souvent utilisé pour prototyper des extraits de code, des constructions de langage ou des idées plus importantes. Avec Brython, cette pratique de codage courante devient disponible dans votre navigateur. Par exemple, vous pouvez utiliser la console Brython ou l'éditeur interactif pour expérimenter un extrait de code.
Ouvrez l'éditeur en ligne et tapez le code suivant:
1de le navigateur importer Ajax
2
3def on_complete(demande):
4 impression(demande.texte)
5
6Langue = "fr"
7
8Ajax.obtenir(F"https://fourtonfish.com/hellosalut/?lang=Langue",
9 blocage=Vrai,
dix incomplet=on_complete)
Voici comment ce code fonctionne:
- Ligne 1 importe le
Ajax
module. - Ligne 3 définit
on_complete ()
, la fonction de rappel qui est appelée après avoir obtenu la réponse deajax.get ()
. - Ligne 6 appels
ajax.get ()
pour récupérer la traduction de «hello» en français à l'aide de l'API HelloSalut. Notez queblocage
peut êtreVrai
ouFaux
lorsque vous exécutez ce code dans l'éditeur Brython. Il doit êtreVrai
si vous exécutez le même code dans la console Brython.
Cliquez sur Courir au-dessus du volet de sortie pour voir le résultat suivant:
"code":"fr","Bonjour":"Salut"
<completeré jen 5,00 ms>
Essayez de modifier la langue de fr
à es
et observez le résultat. Les codes de langue pris en charge par cette API sont répertoriés dans la documentation HelloSalut.
Vous pouvez modifier l'extrait de code dans l'éditeur en ligne pour utiliser une autre API publique. Par exemple, essayez d'extraire une API publique aléatoire du projet API publiques:
1de le navigateur importer Ajax
2
3def on_complete(demande):
4 impression(demande.texte)
5
6Ajax.obtenir("https://api.publicapis.org/random",
7 blocage=Vrai,
8 incomplet=on_complete)
Copiez le code ci-dessus dans l'éditeur Brython en ligne et cliquez sur Courir pour afficher le résultat. Voici un exemple au format JSON:
"compter": 1,
"entrées": [[[[
"API": «Gouvernement ouvert, États-Unis»,
"Description": "Données ouvertes du gouvernement des États-Unis",
"Auth": "",
"HTTPS": vrai,
"Cors": "inconnu",
"Lien": "https://www.data.gov/",
"Catégorie": "Gouvernement"
]
Étant donné que le point de terminaison récupère un projet aléatoire, vous obtiendrez probablement un résultat différent. Pour plus d'informations sur le format JSON, consultez Utilisation des données JSON en Python.
Vous pouvez utiliser le prototypage pour essayer du code Python normal comme vous le feriez dans l'interpréteur Python. Parce que vous êtes dans le contexte d'un navigateur, Brython fournit également des moyens de:
En tant que raccourci, vous pouvez profiter de la plupart des fonctionnalités décrites ci-dessus en ouvrant la console ou l'éditeur disponible sur le site Web de Brython. Cela ne vous oblige pas à installer ou exécuter quoi que ce soit sur votre ordinateur local. Au lieu de cela, il vous donne un terrain de jeu en ligne pour interagir avec les technologies Python et Web.
Enseigner Python aux étudiants
Brython est à la fois un compilateur Python et un interpréteur écrit en JavaScript. En conséquence, vous pouvez compiler et exécuter du code Python dans le navigateur. Un bon exemple de cette fonctionnalité est illustré par l'éditeur en ligne disponible sur le site Web de Brython.
Avec l'éditeur en ligne, Python s'exécute dans le navigateur. Il n'est pas nécessaire d'installer Python sur une machine et il n'est pas nécessaire d'envoyer du code au serveur pour qu'il soit exécuté. Les commentaires sont immédiats pour l'utilisateur et cette approche n'expose pas le back-end à des scripts malveillants. Les étudiants peuvent expérimenter Python sur n'importe quel appareil doté d'un navigateur fonctionnel, comme les téléphones ou les Chromebooks, même avec une connexion Internet irrégulière.
Prendre en compte la performance
Le site Brython note que la vitesse d’exécution de l’implémentation est comparable à celle de CPython. Mais Brython est exécuté dans le navigateur et la référence dans cet environnement est JavaScript intégré au moteur de navigateur. En conséquence, attendez-vous à ce que Brython soit plus lent que le JavaScript écrit à la main et bien réglé.
Brython compile le code Python en JavaScript, puis exécute le code généré. Ces étapes ont un impact sur les performances globales et Brython peut ne pas toujours répondre à vos exigences de performances. Dans certains cas, vous devrez peut-être déléguer l'exécution de code à JavaScript ou même à WebAssembly. Vous verrez comment créer WebAssembly et comment utiliser le code résultant en Python dans la section sur WebAssembly.
Cependant, ne laissez pas les performances perçues vous empêcher d'utiliser Brython. Par exemple, l'importation de modules Python peut entraîner le téléchargement du module correspondant à partir du serveur. Pour illustrer cette situation, ouvrez la console Brython et exécutez le code suivant:
Le délai avant l'affichage de l'invite (390 ms sur une machine de test) est perceptible. Cela est dû au fait que Brython doit télécharger uuid
et ses dépendances, puis compilez les ressources téléchargées. Cependant, à partir de ce moment, il n’ya plus de retard lors de l’exécution des fonctions disponibles dans uuid
. Par exemple, vous pouvez générer un identifiant unique universel aléatoire, UUID version 4, avec le code suivant:
>>> uuid.uuid4()
UUID ('291930f9-0c79-4c24-85fd-f76f2ada0b2a')
Appel uuid.uuid4 ()
génère un UUID
objet, dont la représentation sous forme de chaîne est imprimée dans la console. Appel uuid.uuid4 ()
revient immédiatement et est beaucoup plus rapide que l'importation initiale du uuid
module.
S'amuser
Si vous lisez ce didacticiel, vous êtes probablement intéressé par l'écriture de code Python dans le navigateur. Voir le code Python exécuté dans le navigateur est passionnant pour la plupart des pythonistes et éveille un sentiment de plaisir et de possibilités infinies.
L'auteur de Brython, Pierre Quentel, et les contributeurs du projet ont également gardé à l'esprit le plaisir de Python tout en entreprenant l'énorme tâche de rendre ce langage compatible avec le navigateur Web.
Pour le prouver, pointez votre navigateur vers la console interactive Brython et à l'invite Python, tapez ce qui suit:
Semblable à l'expérience de Python sur votre machine locale, Brython compile et exécute les instructions à la volée et imprime The Zen of Python. Il se déroule dans le navigateur et l'exécution du code Python ne nécessite aucune interaction avec un serveur back-end:

Vous pouvez également essayer un autre œuf de Pâques Python classique dans le même environnement de navigateur avec le code suivant:
Brython embrasse les mêmes morceaux d'humour que vous trouverez dans l'implémentation de référence Python.
Maintenant que vous êtes familiarisé avec les bases de l'utilisation de Brython, vous allez explorer des fonctionnalités plus avancées dans les sections suivantes.
Installer Brython
Tester la console en ligne de Brython est un bon début, mais cela ne vous permettra pas de déployer votre code Python. Il existe plusieurs options différentes pour installer Brython dans un environnement local:
Les instructions pour chacune de ces méthodes sont décrites ci-dessous, mais n'hésitez pas à passer directement à l'approche que vous préférez si vous avez déjà pris une décision.
Installation CDN
Un réseau de diffusion de contenu (CDN) est un réseau de serveurs qui permet d'améliorer les performances et les vitesses de téléchargement du contenu en ligne. Vous pouvez installer des bibliothèques Brython à partir de quelques CDN différents:
Vous pouvez choisir cette installation si vous souhaitez déployer un site Web statique et ajouter des comportements dynamiques à vos pages avec une surcharge minimale. Vous pouvez considérer cette option comme un substitut à jQuery, sauf en utilisant Python plutôt que JavaScript.
Pour illustrer l'utilisation de Brython avec un CDN, vous utiliserez CDNJS. Créez un fichier avec le code HTML suivant:
1
2<html>
3 <diriger>
4 <scénario
5 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.js">
6 </scénario>
7 </diriger>
8 <corps en charge="brython ()">
9 <scénario taper="texte / python">
dix importer le navigateur
11 le navigateur.alerte("Bonjour le vrai Python!")
12 </scénario>
13 </corps>
14</html>
Voici les éléments clés de cette page HTML:
-
Ligne 5 charges
brython.js
de CDNJS. -
Ligne 8 exécute
brython ()
une fois le chargement du document terminé.brython ()
lit le code Python dans la portée actuelle et le compile en JavaScript. Consultez la section Comprendre le fonctionnement de Brython pour plus de détails. -
Ligne 9 définit le type de script sur
texte / python
. Cela indique à Brython quel code doit être compilé et exécuté. -
Ligne 10 importations
le navigateur
, un module Brython qui expose des objets et des fonctions permettant une interaction avec le navigateur. -
Ligne 11 appels
alerte()
, qui affiche une boîte de message avec le texte"Bonjour le vrai Python!"
Enregistrez le fichier sous index.html
, puis double-cliquez sur le fichier pour l'ouvrir avec votre navigateur Internet par défaut. Le navigateur affiche une boîte de message avec "Bonjour le vrai Python!"
Cliquez sur d'accord pour fermer la boîte de message:

Pour réduire la taille du fichier téléchargé, en particulier en production, pensez à utiliser la version réduite de brython.js
:
1<scénario
2 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js">
3</scénario>
La version réduite réduira le temps de téléchargement et la latence perçue du point de vue de l'utilisateur. Dans Comprendre le fonctionnement de Brython, vous apprendrez comment Brython est chargé par le navigateur et comment le code Python ci-dessus est exécuté.
Installation de GitHub
L'installation de GitHub est très similaire à l'installation CDN, mais elle vous permet d'implémenter des applications Brython avec la dernière version de développement. Vous pouvez copier l'exemple précédent et modifier l'URL dans le diriger
élément pour obtenir ce qui suit index.html
:
<html>
<diriger>
<scénario
src="https://raw.githack.com/brython-dev/brython/master/www/src/brython.js">
</scénario>
</diriger>
<corps en charge="brython ()">
<scénario taper="texte / python">
importer le navigateur
le navigateur.alerte("Bonjour le vrai Python!")
</scénario>
</corps>
</html>
Après avoir enregistré ce fichier dans un répertoire local, double-cliquez sur index.html
pour rendre dans le navigateur la même page que vous avez obtenue avec l'installation CDN.
Installation de PyPI
Jusqu'à présent, vous n'avez rien installé dans votre environnement local. Au lieu de cela, vous avez indiqué dans le fichier HTML où le navigateur peut trouver le package Brython. Lorsque le navigateur ouvre la page, il télécharge le fichier JavaScript Brython à partir de l'environnement approprié, à partir d'un CDN ou de GitHub.
Brython est également disponible pour une installation locale sur PyPI. L'installation PyPI est faite pour vous si:
- Vous avez besoin de plus de contrôle et de personnalisation de l'environnement Brython au-delà de ce qui est disponible lorsque vous pointez vers un fichier CDN.
- Votre expérience est en Python et vous connaissez
pépin
. - Vous souhaitez qu'une installation locale minimise la latence du réseau pendant le développement.
- Vous souhaitez gérer votre projet et vos livrables de manière plus granulaire.
Installation de Brython à partir d'installations PyPI brython_cli
, un outil de ligne de commande que vous pouvez utiliser pour automatiser des fonctions telles que la génération d'un modèle de projet ou l'empaquetage et le regroupement de modules pour simplifier le déploiement d'un projet Brython.
Pour plus de détails, vous pouvez consulter la documentation d'installation locale pour voir les capacités de brython-cli
qui sont disponibles dans votre environnement après l'installation. brython-cli
est disponible uniquement avec ce type d'installation. Il n'est pas disponible si vous installez à partir d'un CDN ou avec npm. Tu verras brython-cli
en action plus tard dans le didacticiel.
Avant d'installer Brython, vous souhaitez créer un environnement virtuel Python pour ce projet.
Sous Linux ou macOS, exécutez les commandes suivantes:
$ python3 -m venv .venv --prompt brython
$ la source .venv / bin / activer
(brython) $ python -m pip install --upgrade pip
Collecte de pip
Téléchargement de pip-20.2.4-py2.py3-none-any.whl (1,5 Mo)
| ████████████████████████████████ | 1,5 Mo 1,3 Mo / s
Installation des packages collectés: pip
Tentative de désinstallation: pip
Installation existante trouvée: pip 20.2.3
Désinstallation de pip-20.2.3:
Pip-20.2.3 correctement désinstallé
Sous Windows, vous pouvez procéder comme suit:
> python3 -m venv .venv --prompt brython
> .venv Scripts activate
(brython) > python -m pip install --upgrade pip
Collecte de pip
Téléchargement de pip-20.2.4-py2.py3-none-any.whl (1,5 Mo)
| ████████████████████████████████ | 1,5 Mo 1,3 Mo / s
Installation des packages collectés: pip
Tentative de désinstallation: pip
Installation existante trouvée: pip 20.2.3
Désinstallation de pip-20.2.3:
Pip-20.2.3 correctement désinstallé
Vous venez de créer un environnement Python dédié pour votre projet et de le mettre à jour pépin
avec la dernière version.
Dans les étapes suivantes, vous allez installer Brython et créer un projet par défaut. Les commandes sont les mêmes sous Linux, macOS et Windows:
(brython) $ python -m pip installer brython
Collecter du brython
Téléchargement de brython-3.9.0.tar.gz (1,2 Mo)
| ████████████████████████████████ | 1,2 Mo 1,4 Mo / s
Utilisation de l'ancien 'setup.py install' pour brython, depuis le paquet 'wheel'
N'est pas installé.
Installation des paquets collectés: brython
Exécution de l'installation de setup.py pour brython ... terminé
(brython) $ mkdir web
(brython) $ CD la toile
(brython) $ brython-cli --install
Installation de Brython 3.9.0
Fini
Vous avez installé Brython à partir de PyPI, créé un dossier vide nommé la toile
et a généré le squelette du projet par défaut en exécutant le brython-cli
copié dans votre environnement virtuel lors de l'installation.
Dans le la toile
dossier, brython-cli --install
a créé un modèle de projet et généré les fichiers suivants:
Déposer | Description |
---|---|
README.txt |
Documentation sur la façon d'exécuter un serveur HTTP Python et d'ouvrir demo.html |
brython.js |
Moteur Brython principal (compilateur, runtime et interface de navigateur) |
brython_stdlib.js |
Bibliothèque standard Brython |
demo.html |
Code source de la page HTML de démonstration Brython |
index.html |
Exemple de base que vous pouvez utiliser comme page de départ pour un projet |
unicode.txt |
Base de données de caractères Unicode (UCD) utilisée par unicodedata |
Pour tester ce projet Web nouvellement créé, vous pouvez démarrer un serveur Web Python local avec les commandes suivantes:
(brython) $ python -m http.server
Servant HTTP sur :: port 8000 (http: //[::]: 8000 /) ...
Lorsque vous exécutez python -m http.server
, Python démarre un serveur Web sur le port 8000. La page par défaut attendue est index.html
. Pointez votre navigateur Internet sur http: // localhost: 8000
pour afficher une page avec le texte Bonjour
:

Pour un exemple plus complet, vous pouvez modifier l'URL de la barre d'adresse du navigateur en http: // localhost: 8000 / demo.html
. Vous devriez voir une page similaire à la page de démonstration Brython:

Avec cette approche, les fichiers JavaScript Brython sont chargés directement à partir de votre environnement local. Remarquez le src
attribut dans le diriger
élément de index.html
:
1
2<html>
3 <diriger>
4 <méta jeu de caractères="utf-8">
5 <scénario taper="texte / javascript" src="brython.js"> </scénario>
6 <scénario taper="texte / javascript" src="brython_stdlib.js"> </scénario>
7 </diriger>
8 <corps en charge="brython (1)">
9 <scénario taper="texte / python">
dix de le navigateur importer document
11 document <= "Bonjour"
12 </scénario>
13 </corps>
14</html>
Le code HTML ci-dessus est mis en retrait pour améliorer la lisibilité de ce didacticiel. La commande brython_cli --install
ne met pas en retrait le modèle HTML initial qu'il génère.
Le fichier HTML présente quelques nouvelles fonctionnalités Brython:
-
Ligne 6 charges
brython_stdlib.js
, la bibliothèque standard Python compilée en JavaScript. -
Ligne 8 invoque
brython ()
avec l'argument1
pour imprimer des messages d'erreur sur la console du navigateur. -
Ligne 10 importe le
document
module dele navigateur
. Les fonctions d'accès au DOM sont disponibles dansdocument
. -
Ligne 11 affiche un nouveau symbole (
<=
) ajouté à Python en tant que sucre syntaxique. Dans cet exemple,document <= "Bonjour"
est un substitut àdocument.body.appendChild (document.createTextNode ("Bonjour"))
. Pour plus de détails sur ces fonctions DOM, consultezDocument.createTextNode
.
L'opérateur <=
est utilisé pour ajouter un nœud enfant à un élément du DOM. Vous verrez plus de détails sur l'utilisation d'opérateurs spécifiques à Brython dans l'API DOM en Brython.
Installation de npm
Si vous connaissez bien l'écosystème JavaScript, l'installation de npm pourrait vous plaire. Node.js et npm sont requis avant d'effectuer cette installation.
L'installation avec npm rendra les modules JavaScript Brython disponibles dans votre projet comme tous les autres modules JavaScript. Vous pourrez ensuite tirer parti de vos outils JavaScript préférés pour tester, empaqueter et déployer l'interpréteur et les bibliothèques Brython. Cette installation est idéale si vous avez déjà des bibliothèques JavaScript existantes installées avec npm.
Noter: Si vous n'avez pas installé Node.js et npm sur votre système, envisagez de lire le reste de cette section à titre informatif uniquement, car vous pouvez ignorer l'installation elle-même en toute sécurité. Le reste du didacticiel ne dépend de la méthode d'installation de npm pour aucun des exemples.
En supposant que npm est installé sur votre système, créez un package.json
fichier en appelant npm init - oui
dans un répertoire vide:
$ npm init - oui
Écrit dans /Users/john/projects/brython/npm_install/package.json:
"nom": "npm_install",
"version": "1.0.0",
"la description": "",
"main": "index.js",
"scripts":
"test": "echo " Erreur: aucun test spécifié "&& exit 1"
,
"mots clés": [],
"auteur": "",
"licence": "ISC"
Pour intégrer Brython dans votre projet, exécutez la commande suivante:
$ npm installer brython
npm a créé un fichier de verrouillage sous le nom package-lock.json. Vous devez valider ce fichier.
npm WARN npm_install@1.0.0 Aucune description
npm WARN npm_install@1.0.0 Aucun champ de référentiel.
+ brython@3.9.0
ajouté 1 package de 1 contributeur et audité 1 package en 1.778s
trouvé 0 vulnérabilités
Vous pouvez ignorer les avertissements et noter que Brython a été ajouté à votre projet. Pour confirmer, ouvrez package.json
et assurez-vous d'avoir un dépendances
propriété pointant vers un objet contenant un brython
entrée:
1
2 "Nom": "npm_install",
3 "version": "1.0.0",
4 "la description": "",
5 "principale": "index.js",
6 "scripts":
7 "test": "echo " Erreur: aucun test spécifié "&& exit 1"
8 ,
9 "auteur": "",
dix "Licence": "ISC",
11 "dépendances":
12 "brython": «^ 3,9,0»
13
14
Comme pour les exemples précédents, vous pouvez créer les éléments suivants index.html
et ouvrez-le avec votre navigateur. Un serveur Web n'est pas nécessaire pour cet exemple, car le navigateur peut charger le fichier JavaScript node_modules / brython / brython.js
localement:
1
2<html>
3<diriger>
4 <méta jeu de caractères="utf-8">
5 <scénario
6 taper="texte / javascript"
7 src="node_modules / brython / brython.js" reporter>
8 </scénario>
9</diriger>
dix<corps en charge="brython ()">
11<scénario taper="texte / python">
12de le navigateur importer document
13document <= "Bonjour"
14</scénario>
15</corps>
16</html>
Le navigateur rend index.html
et charges brython.js
du scénario
URL dans index.html
. Dans cet exemple, vous avez vu une autre façon d'installer Brython qui tire parti de l'écosystème JavaScript. Pour le reste du didacticiel, vous allez écrire du code qui repose sur l'installation CDN ou sur l'installation PyPI.
Récapitulatif des options d'installation de Brython
Brython a un pied dans le monde Python et un autre en JavaScript. Les différentes options d'installation illustrent cette situation inter-technologique. Choisissez l'installation qui vous semble la plus intéressante en fonction de votre expérience.
Le tableau suivant vous fournit quelques conseils:
Type d'installation | Le contexte |
---|---|
CDN | Vous souhaitez déployer un site Web statique et ajouter des comportements dynamiques à vos pages avec une surcharge minimale. Vous pouvez considérer cette option comme un substitut à jQuery, sauf en utilisant Python plutôt que JavaScript. |
GitHub | Ceci est similaire à l'installation CDN, mais vous souhaitez expérimenter la version de pointe de Brython. |
PyPI | Votre expérience est en Python. Vous connaissez pépin et comment créer des environnements virtuels Python. Votre projet peut nécessiter certaines personnalisations que vous souhaitez conserver dans un environnement local ou dans votre référentiel de code source. Vous voulez avoir plus de contrôle sur le package que vous allez distribuer. Vous souhaitez déployer dans un environnement fermé sans accès à Internet. |
npm | Votre expérience est en JavaScript. Vous connaissez les outils JavaScript, en particulier Node.js et npm. Votre projet peut nécessiter certaines personnalisations que vous souhaitez conserver dans un environnement local ou dans votre référentiel de code source. Vous voulez avoir plus de contrôle sur les packages que vous distribuerez. Vous souhaitez déployer dans un environnement fermé sans accès à Internet. |
Ce tableau résume les différentes options d'installation qui s'offrent à vous. Dans la section suivante, vous en apprendrez plus sur le fonctionnement de Brython.
Comprendre le fonctionnement de Brython
Votre visite des différentes façons d'installer Brython vous a donné des indices de haut niveau sur le fonctionnement de l'implémentation. Voici un résumé de certaines des caractéristiques que vous avez découvertes jusqu'à présent dans ce didacticiel:
- C'est une implémentation Python en JavaScript.
- C'est un traducteur Python vers JavaScript et un runtime s'exécutant dans le navigateur.
- Il expose deux bibliothèques principales disponibles sous forme de fichiers JavaScript:
brython.js
est le cœur du langage Brython, comme détaillé dans Brython Core Components.brython_stdlib.js
est la bibliothèque standard de Brython.
- Il invoque
brython ()
, qui compile le code Python contenu dans lescénario
tags avec letexte / python
taper.
Dans les sections suivantes, vous examinerez plus en détail le fonctionnement de Brython.
Composants principaux de Brython
Le noyau de Brython est contenu dans brython.js
ou dans brython.min.js
, la version réduite du moteur Brython. Les deux comprennent les éléments clés suivants:
-
brython ()
est la principale fonction JavaScript exposée dans l'espace de noms global JavaScript. Vous ne pouvez exécuter aucun code Python sans appeler cette fonction. C'est la seule fonction JavaScript que vous devriez avoir à appeler explicitement. -
__BRYTHON__
est un objet global JavaScript qui contient tous les objets internes nécessaires pour exécuter des scripts Python. Cet objet n’est pas utilisé directement lorsque vous écrivez des applications Brython. Si vous examinez le code Brython, à la fois JavaScript et Python, vous verrez des occurrences régulières de__BRYTHON__
. Vous n'avez pas besoin d'utiliser cet objet, mais vous devez en être conscient lorsque vous voyez une erreur ou lorsque vous souhaitez déboguer votre code dans la console du navigateur. -
Types intégrés sont des implémentations des types intégrés Python dans JavaScript. Par exemple, py_int.js, py_string.js et py_dicts.js sont des implémentations respectives de
int
,str
etdict
. -
le navigateur
est le module de navigateur qui expose les objets JavaScript couramment utilisés dans une application Web frontale, comme les interfaces DOM utilisantdocument
et la fenêtre du navigateur utilisant lela fenêtre
objet.
Vous verrez chacun de ces composants en action au fil des exemples de ce didacticiel.
Bibliothèque standard Brython
Maintenant que vous avez une idée générale du fichier Brython principal, brython.js
, vous allez découvrir son fichier compagnon, brython_stdlib.js
.
brython_stdlib.js
expose la bibliothèque standard Python. Au fur et à mesure que ce fichier est généré, Brython compile la bibliothèque standard Python en JavaScript et concatène le résultat dans le bundle brython_stdlib.js
.
Brython est destiné à être aussi proche que possible de CPython, l'implémentation de référence Python. Pour plus d'informations sur CPython, consultez votre guide sur le code source CPython et les composants internes CPython.
Comme Brython s'exécute dans le contexte d'un navigateur Web, il présente certaines limitations. Par exemple, le navigateur n'autorise pas l'accès direct au système de fichiers, donc l'ouverture d'un fichier avec os.open ()
ce n’est pas possible. Les fonctions qui ne sont pas pertinentes pour un navigateur Web peuvent ne pas être mises en œuvre. Par exemple, le code ci-dessous s'exécute dans un environnement Brython:
>>> import os
>>> os.unlink()
Traceback (most recent call last):
Déposer , line 1, in
NotImplementedError: posix.unlink is not implemented
os.unlink()
raises an exception since it’s not secure to delete a local file from the browser environment and the File and Directory Entries API is only a draft proposal.
Brython only supports native Python modules. It doesn’t support Python modules built in C unless they’ve been reimplemented in JavaScript. For example, hashlib
is written in C in CPython and implemented in JavaScript in Brython. You can consult the list of modules in the Brython distribution to compare with the CPython implementation.
You need to include brython_stdlib.js
ou brython_stdlib.min.js
to import modules from the Python standard library.
Brython in Action
At this point, you may be wondering how Brython behaves within a browser that’s only aware of its JavaScript engine. Reusing the previous examples and the tools available in the browser, you’ll learn about the process involved in executing Python code in the browser.
In the section on the CDN server installation, you saw the following example:
1
2<html>
3 <head>
4 <script
5 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.js">
6 </script>
7 </head>
8 <body onload="brython()">
9 <script taper="text/python">
dix import le navigateur
11 le navigateur.alert("Hello Real Python!")
12 </script>
13 </body>
14</html>
Upon loading and parsing the HTML page, brython()
takes the following steps:
- Reads the Python code contained in the element
- Compiles the Python code to equivalent JavaScript
- Evaluates the resulting JavaScript code with
eval()
In the example above, the Python code is embedded in the HTML file:
<script taper="text/python">
import le navigateur
le navigateur.alert("Hello Real Python!")
</script>
Another option is to download the Python code from a separate file:
<head>
<script src="https://www.example.com/main.py"
taper="text/python"></script>
</head>
In this case, the Python file would look like this:
import le navigateur
le navigateur.alert("Hello Real Python!")
Separating the Python code from the HTML code is a cleaner approach and allows you to take advantage of the benefits and functionalities of code editors. Most editors have support for embedded JavaScript in HTML, but they don’t support inline Python in HTML.
Brython’s Internals
This section provides a deeper dive into the process of transforming Python code to JavaScript. If you’re not interested in these details, then feel free to skip this section, as it’s not required for understanding the rest of the tutorial. To illustrate this process and have a peek into the internals of Brython, take the following steps:
- Open the Brython home page.
- Open the web console with Cmd+Alt+je on Mac or Ctrl+Shift+je on Windows and Linux.
In the browser JavaScript REPL, type and execute the following code:
> eval(__BRYTHON__.python_to_js("import browser; browser.console.log('Hello Brython!')"));
python_to_js()
parses and compiles the provided Python code to JavaScript and then executes the JavaScript in the web browser. You should get the following result:

Applying eval()
to Brython code prints "Hello Brython!"
in the browser console. The JavaScript function returns undefined
, which is the default return value for a function in JavaScript.
When you build a Brython application, you shouldn’t need to explicitly call a function in the __BRYTHON__
JavaScript module. This example is provided only to demonstrate how Brython operates behind the scenes. Being aware of __BRYTHON__
can help you read Brython code and even contribute to the project as you gain more experience. It will also help you better understand exceptions that may be displayed in the browser console.
The JavaScript __BRYTHON__
object is available in the JavaScript global scope, and you can access it with the browser JavaScript console.
Using Brython in the Browser
At this point, you have enough of an understanding of Brython to work with more detailed examples. In this section, you’re going to implement a Base64 calculator to experiment in the browser with the DOM API and other functionalities that are usually only available from JavaScript.
You can download the source code for the examples in this tutorial by clicking the link below:
You’ll start by learning how to manipulate the DOM using Python and HTML.
The DOM API in Brython
To experiment with the DOM manipulations available in Brython, you’ll build a form to encode a string to Base64. The finished form will look like this:

Create the following HTML file and name it index.html
:
1
2
3<html>
4 <head>
5 <meta charset="utf-8"/>
6 <link rel="stylesheet"
7 href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.css" />
8 <script
9 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js">
dix </script>
11 <script
12 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.min.js">
13 </script>
14 <script src="main.py" taper="text/python" defer></script>
15 <style>body padding: 30px; </style>
16 </head>
17 <body onload="brython()">
18 <form class="pure-form" onsubmit="return false;">
19 <fieldset>
20 <legend>Base64 Calculator</legend>
21 <input taper="text" id="text-src" placeholder="Text to Encode" />
22 <button
23 taper="submit" id="submit"
24 class="pure-button pure-button-primary"
25 autocomplete="off">D'accord</button>
26 <button id="clear-btn" class="pure-button">Clear</button>
27 </fieldset>
28 </form>
29 <div id="b64-display"></div>
30 </body>
31</html>
The HTML above loads the static resources, defines the UI layout, and initiates the Python compilation:
-
Line 7 loads the PureCSS style sheet to improve on the default HTML style. This isn’t necessary for Brython to work.
-
Line 9 loads the minimized version of the Brython engine.
-
Line 12 loads the minimized version of the Brython standard library.
-
Line 14 loads
main.py
, which handles the dynamic logic of this static HTML page. Note the use ofdefer
. It helps synchronize the loading and evaluation of resources and is sometimes needed to make sure that Brython and any Python scripts are fully loaded before executingbrython()
. -
Line 21 describes an
input
field. This field takes the string to encode as an argument. -
Lines 22 to 25 define the default
button
that triggers the main logic of the page. You can see this logic implemented inmain.py
en dessous de. -
Line 26 defines a
button
to clear up data and elements on the page. This is implemented inmain.py
en dessous de. -
Line 29 declares a
div
intended to be a placeholder for a table.
The associated Python code, main.py
, is as follows:
1from le navigateur import document, prompt, html, alert
2import base64
3
4b64_map =
5
6def base64_compute(_):
7 value = document[[[["text-src"].value
8 if not value:
9 alert("You need to enter a value")
dix return
11 if value dans b64_map:
12 alert(f"'The base64 value of 'value' already exists: 'b64_map[[[[value]'")
13 return
14 b64data = base64.b64encode(value.encode()).decode()
15 b64_map[[[[value] = b64data
16 display_map()
17
18def clear_map(_) -> None:
19 b64_map.clear()
20 document[[[["b64-display"].clear()
21
22def display_map() -> None:
23 table = html.TABLE(Class="pure-table")
24 table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
25 table <= (html.TR(html.TD(key) + html.TD(b64_map[[[[key])) pour key dans b64_map)
26 base64_display = document[[[["b64-display"]
27 base64_display.clear()
28 base64_display <= table
29 document[[[["text-src"].value = ""
30
31document[[[["submit"].bind("click", base64_compute)
32document[[[["clear-btn"].bind("click", clear_map)
The Python code shows the definition of callback functions and the mechanism to manipulate the DOM:
-
Line 1 imports the modules that you use to interact with the DOM and the Browser API code in
brython.min.js
. -
Line 2 imports
base64
, which is available in the Brython standard library,brython_stdlib.min.js
. -
Line 4 declares a dictionary that you’ll use to store data during the life of the HTML page.
-
Line 6 defines the event handler
base64_compute()
, which encodes the Base64 value of the text entered in the input field with IDtext-src
. This is a callback function that takes an event as an argument. This argument isn’t used in the function but is required in Brython and is optional in JavaScript. As a convention, you can use_
as a dummy placeholder. An example of this usage is described in the Google Python Style Guide. -
Line 7 retrieves the value of the DOM element identified with
text-src
. -
Line 18 defines the event handler
clear_map()
, which clears the data and presentation of the data on this page. -
Line 22 defines
display_map()
, which takes the data contained in theb64_map
and displays it under the form on the page. -
Line 26 retrieves the DOM element with the ID
text-src
. -
Line 29 clears the value of the DOM element with the ID
text-src
. -
Line 31 binds the
onclick
event of thesubmit
button tobase64_compute()
. -
Line 32 binds the
onclick
event of theclear-btn
button toclear_map()
.
To manipulate the DOM, Brython uses two operators:
-
<=
is a new operator, specific to Brython, that adds a child to a node. You can see a few examples of this usage indisplay_map()
, defined on line 22. -
+
is a substitute forElement.insertAdjacentHTML('afterend')
and adds sibling nodes.
You can see both operators in the following statement taken from display_map()
:
table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
You can read the above code as “add to the table element a table head element containing a table row element composed of two adjacent table data cell elements. It’s rendered in the browser as the following HTML code:
<table>
<thead><tr><e>Text</e><e>Base64</e></tr></thead>
</table>
The HTML code shows a nested structure for the header row of a table element. Here’s a more readable format of the same code:
<table>
<thead>
<tr>
<e>Text</e>
<e>Base64</e>
</tr>
</thead>
</table>
To observe the result in the Brython console, you can enter the following code block:
>>> from le navigateur import html
>>> table = html.TABLE()
>>> table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
>>> table.outerHTML
'Text Base64
'
To execute the full code, you need to start a web server. As before, you start the built-in Python web server in the same directory as the two files index.html
and main.py
:
$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
After starting the web server, point your browser to http://localhost:8000
. The page looks like this:

You’ll extend this example in the section Browser Web API by allowing the data to be stored between page reloads.
Import in Brython
You can use import
to access Python modules or Brython modules compiled to JavaScript.
Python modules are files with a .py
extension in the root folder of your project or, for a Python package, in a subfolder containing an __init__.py
file. To import Python modules in your Brython code, you need to start a web server. For more on the Python modules, check out Python Modules and Packages – An Introduction.
To explore how to import Python modules into your Brython code, follow the instructions described in the section on installing with PyPI, create and activate a Python virtual environment, install Brython, and modify index.html
as follows:
<html>
<head>
<meta charset="utf-8">
<script taper="text/javascript" src="brython.js"></script>
<script taper="text/javascript" src="brython_stdlib.js"></script>
</head>
<body onload="brython()">
<script taper="text/python">
from le navigateur import document, html, window
import sys
import functional
selection = functional.take(dix, range(10000))
numbers = ', '.join([[[[str(X) pour X dans selection])
document <= html.P(f"sys.version=")
document <= html.P(f"numbers=")
</script>
</body>
</html>
The HTML file above exposes modules imported from the core engine (le navigateur
), from the standard library (sys
), and from a local Python module (functional
). Here’s the content of functional.py
:
import itertools
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(itertools.islice(iterable, n))
This module implements take()
, one of the itertools
recipes. take()
returns the first n elements of a given iterable. It relies on itertools.slice()
.
If you try to open index.html
from the file system with your browser, then you’ll get the following error in the browser console:
Traceback (most recent call last):
File file:///Users/andre/brython/code/import/index.html/__main__
line 3, in
import functional
ModuleNotFoundError: functional
Importing a Python module requires starting a local web server. Start a local web server and point your browser to http://localhost:8000
. You should see the following HTML page:

With a running web server, the browser was able to fetch the module functional.py
when import functional
was executed. The results of both values, sys.version
and numbers
, are inserted in the HTML file by the last two lines of the embedded Python script and rendered by the browser.
Reduce Import Size
In the project directory of the previous example, to reduce the size of the imported JavaScript modules and to precompile Python modules to JavaScript, you can use brython-cli
with the option --modules
:
$ brython-cli --modules
Create brython_modules.js with all the modules used by the application
searching brython_stdlib.js...
finding packages...
script in html index.html
This will generate brython_modules.js
, and you can modify the head
element of index.html
as follows:
1<head>
2<meta charset="utf-8">
3<script taper="text/javascript" src="brython.js"></script>
4<script taper="text/javascript" src="brython_modules.js"></script>
5</head>
Line 4 changes the original script source from brython_stdlib.js
to brython_modules.js
.
Opening index.html
with your browser or pointing the browser to the local server renders the same HTML page. Notice the following points:
- You can render the HTML page in your browser, without running a web server.
- You don’t need to distribute
functional.py
since the code has been converted to JavaScript and bundled inbrython_modules.js
. - You don’t need to load
brython_stdlib.js
.
The command-line tool brython-cli --modules
provides a solution to remove unnecessary code from the standard libraries and compiles your python module to JavaScript code. This helps to package your application and results in a smaller resources download.
Note: Similarly to importing a Python module, loading a Python module with the HTML script
element requires you to start a web server. Consider the following HTML script
element:
<script src="main.py" taper="text/python"></script>
When the Brython function is executed and loads a script
content pointing to a Python file, it attempts to execute an Ajax call that can only be done when a web server is running. If you try to open the file from the file system, then an error similar to the following is displayed in the browser JavaScript console:
IOError: can't load external script at file:///project/main.py
(Ajax calls not supported with protocol file:///)
Security protection prevents you from loading main.py
from the local file system. You can resolve this issue by running a local file server. For more information about this behavior, see the Brython documentation.
Interacting With JavaScript
Brython allows Python code to interact with JavaScript code. The most common pattern is to access JavaScript from Brython. The reverse, although possible, isn’t common. You’ll see an example of JavaScript invoking a Python function in the section JavaScript Unit Tests.
JavaScript
Up to this point, you’ve experienced a few scenarios where Python code interacted with JavaScript code. In particular, you’ve been able to display a message box by invoking browser.alert()
.
You can see alert
in action in the following three examples running in the Brython console, not in the standard CPython interpreter shell:
>>> import le navigateur
>>> le navigateur.alert("Real Python")
Or you can use window
:
>>> from le navigateur import window
>>> window.alert("Real Python")
Or you can use this
:
>>> from javascript import this
>>> this().alert("Real Python")
Due to the new layer exposed by Brython and the global nature of both alert()
and window
, you can invoke alert
on browser.window
or even on javascript.this
.
Here are the main Brython modules allowing access to JavaScript functions:
Modules | Context | Examples |
---|---|---|
le navigateur |
Contains the built-in names and modules | browser.alert() |
browser.document |
Accesses the DOM | document.getElementById("element-id") document["element-id"] |
browser.html |
Creates HTML elements | html.H1("This is the title") |
browser.window |
Accesses La fenêtre functions and objects |
window.navigator window.frames |
javascript |
Accesses objects defined in JavaScript | javascript.this() javascript.JSON.parse() |
In addition to JavaScript functions and APIs available in the browser, you can also access to JavaScript functions that you wrote. The following example demonstrates how to access a custom JavaScript function from Brython:
1
2<html>
3 <head>
4 <meta charset="utf-8">
5 <script
6 src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.js">
7 </script>
8 <script taper="text/javascript">
9 function myMessageBox(name)
dix window.alert(`Hello $name!`);
11
12 </script>
13 </head>
14 <body onload="brython()">
15 <script taper="text/python">
16 from le navigateur import window
17 window.myMessageBox("Jon")
18 </script>
19 </body>
20</html>
Here’s how it works:
- Line 9 defines the custom function
myMessageBox()
in a JavaScript block. - Line 17 invokes
myMessageBox()
.
You can use the same feature to access JavaScript libraries. You’ll see how in the section Web UI Framework, where you’ll interact with Vue.js, a popular web UI framework.
Browser Web API
Browsers expose web APIs that you can access from JavaScript, and Brython has access to the same APIs. In this section, you’ll extend the Base64 calculator to store the data between browser page reloads.
The web API allowing this feature is the Web Storage API. It includes two mechanisms:
sessionStorage
localStorage
You’ll use localStorage
in the upcoming example.
As you learned earlier, the Base64 calculator creates a dictionary containing the input string mapped to the Base64-encoded value of this string. The data persists in memory after the page is loaded but is purged when you reload the page. Saving the data to localStorage
will preserve the dictionary between page reloads. Le localStorage
is a key-value store.
To access localStorage
, you need to import espace de rangement
. To stay close to the initial implementation, you’ll load and save the dictionary data to localStorage
in the JSON format. The key to save and fetch the data will be b64data
. The modified code includes new imports and a load_data()
function:
from browser.local_storage import espace de rangement
import json, base64
def load_data():
data = espace de rangement.get("b64data")
if data:
return json.loads(data)
else:
espace de rangement[[[["b64data"] = json.dumps()
return
load_data()
is executed when the Python code is loaded. It fetches the JSON data from localStorage
and populates a Python dictionary that will be used to hold the data in memory during the life of the page. If it doesn’t find b64data
dans localStorage
, then it creates an empty dictionary for key b64data
dans localStorage
and returns an empty dictionary.
You can view the full Python code incorporating load_data()
by expanding the box below. It shows how to use the localStorage
web API as persistent storage rather than relying on ephemeral in-memory storage, like in the previous implementation of this example.
The following code shows how to manage data using the browser localStorage
:
1from le navigateur import document, prompt, html, alert
2from browser.local_storage import espace de rangement
3import json, base64
4
5def load_data():
6 data = espace de rangement.get("b64data")
7 if data:
8 return json.loads(data)
9 else:
dix espace de rangement[[[["b64data"] = json.dumps()
11 return
12
13def base64_compute(evt):
14 value = document[[[["text-src"].value
15 if not value:
16 alert("You need to enter a value")
17 return
18 if value dans b64_map:
19 alert(f"'value' already exists: 'b64_map[[[[value]'")
20 return
21 b64data = base64.b64encode(value.encode()).decode()
22 b64_map[[[[value] = b64data
23 espace de rangement[[[["b64data"] = json.dumps(b64_map)
24 display_map()
25
26def clear_map(evt):
27 b64_map.clear()
28 espace de rangement[[[["b64data"] = json.dumps()
29 document[[[["b64-display"].clear()
30
31def display_map():
32 if not b64_map:
33 return
34 table = html.TABLE(Class="pure-table")
35 table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
36 table <= (html.TR(html.TD(key) + html.TD(b64_map[[[[key])) pour key dans b64_map)
37 base64_display = document[[[["b64-display"]
38 base64_display.clear()
39 base64_display <= table
40 document[[[["text-src"].value = ""
41
42b64_map = load_data()
43display_map()
44document[[[["submit"].bind("click", base64_compute)
45document[[[["clear-btn"].bind("click", clear_map)
The new lines are highlighted. The global dictionary b64_map
is populated by load_data()
when the file is loaded and processed at the invocation of brython()
. When the page is reloaded, the data is fetched from the localStorage
.
Each time a new Base64 value is calculated, the content of b64_map
is converted to JSON and stored in the local storage. The key to the storage is b64data
.
You can access all the web API functions from le navigateur
and other submodules. High-level documentation on accessing the web API is available in the Brython documentation. For more details, you can consult the web API documentation and use the Brython console to experiment with the web APIs.
In some situations, you may have to choose between familiar Python functions and functions from the web APIs. For example, in the code above, you use the Python Base64 encoding, base64.b64encode()
, but you could have used JavaScript’s btoa()
:
>>> from le navigateur import window
>>> window.btoa("Real Python")
'UmVhbCBQeXRob24='
You can test both variations in the online console. Utilisant window.btoa()
would work only in the Brython context, whereas base64.b64encode()
can be executed with a regular Python implementation like CPython. Note that in the CPython version, base64.b64encode()
takes a bytearray
as the argument type, whereas the JavaScript window.btoa()
takes a string.
If performance is a concern, then consider using the JavaScript version.
Web UI Framework
Popular JavaScript UI frameworks like Angular, React, Vue.js or Svelte have become an important part of the front-end developer’s tool kit, and Brython integrates seamlessly with some of these frameworks. In this section, you’ll build an application using Vue.js version 3 and Brython.
The application you’ll build is a form that calculates the hash of a string. Here’s a screenshot of the running HTML page:

Le body
of the HTML page defines the bindings and templates declaratively:
<html>
<head>
<meta charset="utf-8"/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.2/vue.global.prod.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.min.js"></script>
<script src="main.py" taper="text/python"></script>
<style>
body padding: 30px;
[[[[v-cloak] visibility: hidden;
</style>
</head>
<body onload="brython(1)">
<div id="app">
<form class="pure-form" onsubmit="return false;">
<fieldset>
<legend>Hash Calculator</legend>
<input taper="text" v-model.trim="input_text"
placeholder="Text to Encode" autocomplete="off"/>
<select v-model="algo" v-cloak>
<option v-for="name in algos" v-bind:value="name">
</option>
</select>
<button @click="compute_hash" taper="submit"
class="pure-button pure-button-primary">D'accord</button>
</fieldset>
</form>
<p v-cloak></p>
</div>
</body>
If you’re not familiar with Vue, then you’ll cover a few things quickly below, but feel free to consult the official documentation for more information:
- Vue.js directives are special attribute values, prefixed with
v-
, that provide dynamic behavior and data mapping between values of the DOM and Vue.js components:v-model.trim="input_text"
binds the input value to the Vue modelinput_text
and trims the value.v-model="algo"
binds the value of the dropdown toalgo
.v-for="name in algos"
binds the option value toname
.
- Vue templates are denoted with variables surrounded by double curly braces. Vue.js substitutes the corresponding placeholders with the corresponding value in the Vue component:
- Event handlers are identified with an at symbol (
@
) like in@click="compute_hash"
.
The corresponding Python code describes the Vue and attached business logic:
1from le navigateur import alert, window
2from javascript import this
3import hashlib
4
5hashes =
6 "sha-1": hashlib.sha1,
7 "sha-256": hashlib.sha256,
8 "sha-512": hashlib.sha512,
9
dix
11Vue = window.Vue
12
13def compute_hash(evt):
14 value = this().input_text
15 if not value:
16 alert("You need to enter a value")
17 return
18 hash_object = hashes[[[[this().algo]()
19 hash_object.update(value.encode())
20 hex_value = hash_object.hexdigest()
21 this().hash_value = hex_value
22
23def created():
24 pour name dans hashes:
25 this().algos.append(name)
26 this().algo = next(iter(hashes))
27
28app = Vue.createApp(
29
30 "el": "#app",
31 "created": created,
32 "data": lambda _: "hash_value": "", "algos": [], "algo": "", "input_text": "",
33 "methods": "compute_hash": compute_hash,
34
35)
36
37app.monter("#app")
The declarative nature of Vue.js is displayed in the HTML file with the Vue directives and templates. It’s also demonstrated in the Python code with the declaration of the Vue component on line 11 and lines 28 to 35. This declarative technique wires the node values of the DOM with the Vue data, allowing the reactive behavior of the framework.
This eliminates some boilerplate code that you had to write in the previous example. For instance, notice that you didn’t have to select elements from the DOM with an expression like document["some_id"]
. Creating the Vue app and invoking app.mount()
handles the mapping of the Vue component to the corresponding DOM elements and the binding of the JavaScript functions.
In Python, accessing the Vue object fields requires you to refer to the Vue object with javascript.this()
:
- Line 14 fetches the value of the component field
this().input_text
. - Line 21 updates the data component
this().hash_value
. - Line 25 adds an algorithm to the list
this().algos
. - Line 26 instantiates
this().algo
with the first key ofhashes
.
If this introduction of Vue combined with Brython has spurred your interest, then you may want to check out the vuepy project, which provides full Python bindings for Vue.js and uses Brython to run Python in the browser.
WebAssembly
In some situations, you can use WebAssembly to improve the performance of Brython or even JavaScript. WebAssembly, or Wasm, is binary code that is supported by all major browsers. It can provide a performance improvement over JavaScript in the browser and is a compilation target for languages like C, C++, and Rust. If you’re not using Rust or Wasm, then you can skip this section.
In the following example that demonstrates a way to use WebAssembly, you’ll implement a function in Rust and will invoke it from Python.
This isn’t intended to be a thorough Rust tutorial. It only scratches the surface. For more details about Rust, check out the Rust documentation.
Start by installing Rust using rustup
. To compile Wasm files, you also need to add the wasm32
target:
$ rustup target add wasm32-unknown-unknown
Create a project using cargo
, which is installed during the Rust installation:
The command above creates a skeleton project in a folder named op
. In this folder, you’ll find Cargo.toml
, the Rust build configuration file, which you need to modify to indicate that you want to create a dynamic library. You can do this by adding the highlighted section:
[package]
name = "op"
version = "0.1.0"
authors = ["John["John["John["John"]
edition = "2018"
[lib]
crate-type=["cdylib"]
[dependencies]
Modify src/lib.rs
by replacing its content with the following:
#[no_mangle]
pub extern fn double_first_and_add(X: u32, y: u32) -> u32
(2 * X) + y
In the root of the project, where Cargo.toml
is, compile your project:
$ cargo build --target wasm32-unknown-unknown
Next, create a web
directory with the following index.html
:
1
2
3<html>
4<head>
5 <script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js"></script>
6 <script src="main.py" taper="text/python"></script>
7</head>
8<body onload="brython()">
9
dix<form class="pure-form" onsubmit="return false;">
11 <h2>Custom Operation using Wasm + Brython</h2>
12 <fieldset>
13 <legend>Multiply first number by 2 and add result to second number</legend>
14 <input taper="number" value="0" id="number-1" placeholder="1st number"
15 autocomplete="off" required/>
16 <input taper="number" value="0" id="number-2" placeholder="2nd number"
17 autocomplete="off" required/>
18 <button taper="submit" id="submit" class="pure-button pure-button-primary">
19 Execute
20 </button>
21 </fieldset>
22</form>
23
24<br/>
25<div id="result"></div>
26</body>
27</html>
Line 6 above loads the following main.py
from the same directory:
1from le navigateur import document, window
2
3double_first_and_add = None
4
5def add_rust_fn(module):
6 global double_first_and_add
7 double_first_and_add = module.instance.exports.double_first_and_add
8
9def add_numbers(evt):
dix nb1 = document[[[["number-1"].value ou 0
11 nb2 = document[[[["number-2"].value ou 0
12 res = double_first_and_add(nb1, nb2)
13 document[[[["result"].innerHTML = f"Result: (nb1 * 2) + nb2 = res"
14
15document[[[["submit"].bind("click", add_numbers)
16window.WebAssembly.instantiateStreaming(window.fetch("op.wasm")).then(add_rust_fn)
The highlighted lines are the glue allowing Brython to access the Rust function double_first_and_add()
:
- Line 16 reads
op.wasm
usingWebAssembly
and then invokesadd_rust_fn()
when the Wasm file is downloaded. - Line 5 implements
add_rust_fn()
, which takes the Wasm module as an argument. - Line 7 assigns
double_first_and_add()
to the localdouble_first_and_add
name to make it available to Python.
In the same web
directory, copy op.wasm
from target/wasm32-unknown-unknown/debug/op.wasm
:
$ cp target/wasm32-unknown-unknown/debug/op.wasm web
The project folder layout look like this:
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
├── target
│ ...
└── web
├── index.html
├── main.py
└── op.wasm
This shows the folder structure of the Rust project created with cargo new
. For clarity, target
is partially omitted.
Now start a server in web
:
$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
Finally, point your Internet browser to http://localhost:8000
. Your browser should render a page like the following:

This project shows how to create a WebAssembly that you can use from JavaScript or Brython. Due to the significant overhead resulting from building a Wasm file, this shouldn’t be your first approach for tackling a particular problem.
If JavaScript doesn’t meet your performance requirements, then Rust might be an option. This is mostly useful if you already have Wasm code to interact with, either code that you built or existing Wasm libraries.
Another possible benefit of using Rust to generate a WebAssembly is its access to libraries that don’t exist in Python or JavaScript. It can also be useful if you want to use a Python library that is written in C and that can’t be used with Brython. If such a library exists in Rust, then you might consider building a Wasm file to use it with Brython.
Applying Asynchronous Development in Brython
Synchronous programming is the computation behavior that you may be the most familiar with. For example, when executing three statements, A, B, and C, a program first executes A, then B, and finally C. Each statement blocks the flow of the program before passing it on to the next one.
Imagine a technique such that A would be executed first, B would be invoked but not executed immediately, and then C would be executed. You can think of B as a promise of being executed in the future. Since B is nonblocking, it’s considered asynchronous. For additional background on asynchronus programming, you can check out Getting Started With Async Features in Python.
JavaScript is single threaded and relies on asynchronous processing in particular when network communications are involved. For example, fetching the result of an API doesn’t require blocking the execution of other JavaScript functions.
With Brython, you have access to asynchronous features through a number of components:
As JavaScript has evolved, callbacks have been progressively replaced with promises or async functions. In this tutorial, you’ll learn how to use promises from Brython and how to use the browser.ajax
and browser.aio
modules, which leverage the asynchronous nature of JavaScript.
Le asyncio
module from the CPython library can’t be used in the browser context and is replaced in Brython by browser.aio
.
JavaScript Promises in Brython
In JavaScript, a promise is an object that may produce a result sometime in the future. The value produced upon completion will be either a value or the reason for an error.
Here’s an example that illustrates how to use the JavaScript Promise
object from Brython. You can work with this example in the online console:
1>>> from le navigateur import minuteur, window
2>>> def message_in_future(success, error):
3... minuteur.set_timeout(lambda: success("Message in the future"), 3000)
4...
5>>> def show_message(msg):
6... window.alert(msg)
7...
8>>> window.Promise.new(message_in_future).then(show_message)
9
In the web console, you can get immediate feedback about the execution of the Python code:
- Line 1 imports
minuteur
to set a timeout andwindow
to access thePromise
object. - Line 2 defines an executor,
message_in_future()
, that returns a message when the promise is successful, at the end of the timeout. - Line 5 defines a function,
show_message()
, that displays an alert. - Line 8 creates a promise with the executor, chained with a
then
block, allowing access to the result of the promise.
In the example above, the timeout artificially simulates a long-running function. Real uses of a promise could involve a network call. After 3
seconds, the promise completes successfully with the value "Message in the future"
.
If the executor function, message_in_future()
, detects an error, then it could invoke error()
with the reason for the error as an argument. You can implement this with a new chained method, .catch()
, on the Promise
object, as follows:
>>> window.Promise.new(message_in_future).then(show_message).catch(show_message)
You can see the behavior of the successful completion of the promise in the following image:

When you run the code in the console, you can see that the Promise
object is created first, and then, after the timeout, the message box is displayed.
Ajax in Brython
Asynchronous functions are particularly useful when functions are qualified as I/O bound. This is in contrast to CPU-bound functions. An I/O-bound function is a function that mostly spends time waiting for input or output to finish, whereas a CPU-bound function is computing. Invoking an API over the network or querying a database is an I/O-bound execution, whereas calculating a sequence of prime numbers is CPU bound.
Brython’s browser.ajax
exposes HTTP functions like get()
and post()
that are, by default, asynchronous. These functions take a blocking
parameter that can be set to True
to render the same function synchronous.
To invoke HTTP GET
asynchronously, invoke ajax.get()
as follows:
ajax.get(url, oncomplete=on_complete)
To fetch an API in a blocking mode, set the blocking
parameter to True
:
ajax.get(url, blocking=True, oncomplete=on_complete)
The following code shows the difference between making a blocking Ajax call and a nonblocking Ajax call:
1from le navigateur import ajax, document
2import javascript
3
4def show_text(req):
5 if req.status == 200:
6 log(f"Text received: 'req.text'")
7 else:
8 log(f"Error: req.status - req.text")
9
dixdef log(message):
11 document[[[["log"].value += f"message n"
12
13def ajax_get(evt):
14 log("Before async get")
15 ajax.get("/api.txt", oncomplete=show_text)
16 log("After async get")
17
18def ajax_get_blocking(evt):
19 log("Before blocking get")
20 try:
21 ajax.get("/api.txt", blocking=True, oncomplete=show_text)
22 except Exception as exc:
23 log(f"Error: exc.__name__ - Did you start a local web server?")
24 else:
25 log("After blocking get")
26
27document[[[["get-btn"].bind("click", ajax_get)
28document[[[["get-blocking-btn"].bind("click", ajax_get_blocking)
The code above illustrates both behaviors, synchronous and asynchronous:
-
Line 13 defines
ajax_get()
, which fetches text from a remote file usingajax.get()
. The default behavior ofajax.get()
is asynchronous.ajax_get()
returns, andshow_text()
assigned to the parameteroncomplete
is called back after receiving the remote file/api.txt
. -
Line 18 defines
ajax_get_blocking()
, which demonstrates how to useajax.get()
with the blocking behavior. In this scenario,show_text()
is called beforeajax_get_blocking()
returns.
When you run the full example and click Async Get and Blocking Get, you’ll see the following screen:

You can see that in the first scenario, ajax_get()
is fully executed, and the result of the API call happens asynchronously. In the second situation, the result of the API call is displayed before returning from ajax_get_blocking()
.
Async IO in Brython
With asyncio
, Python 3.4 started to expose new asynchronous capabilities. In Python 3.5, asynchronous support has been enriched with the async
/await
syntax. Due to incompatibility with the browser event loop, Brython implements browser.aio
as a substitute for the standard asyncio
.
The Brython module browser.aio
and the Python module asyncio
both support using the async
and await
keywords and share common functions, like run()
and sleep()
. Both modules implement other distinct functions that pertain to their respective contexts of execution, the CPython context environment for asyncio
and the browser environment for browser.aio
.
Coroutines
You can use run()
and sleep()
to create coroutines. To illustrate the behavior of coroutines implemented in Brython, you’ll implement a variant of a coroutine example available in the CPython documentation:
1from le navigateur import aio as asyncio
2import time
3
4async def say_after(retard, what):
5 await asyncio.sleep(retard)
6 impression(what)
7
8async def main():
9 impression(f"started at time.strftime('%X')")
dix
11 await say_after(1, 'hello')
12 await say_after(2, 'world')
13
14 impression(f"finished at time.strftime('%X')")
15
16asyncio.run(main())
Except for the first import
line, the code is the same as you found in the CPython documentation. It demonstrates the use of the keywords async
and await
and shows run()
and sleep()
in action:
- Line 1 uses
asyncio
as an alias forbrowser.aio
. Although it shadowsaio
, it keeps the code close to the Python documentation example to facilitate the comparison. - Line 4 declares the coroutine
say_after()
. Note the use ofasync
. - Line 5 invokes
asyncio.sleep()
withawait
so that the current function will cede control to another function untilsleep()
completes. - Line 8 declares another coroutine that will itself call the coroutine
say_after()
twice. - Line 9 invokes
run()
, a nonblocking function that takes a coroutine—main()
in this example—as an argument.
Note that in the context of the browser, aio.run()
leverages the internal JavaScript event loop. This differs from the related function asyncio.run()
in CPython, which fully manages the event loop.
To execute this code, paste it into the online Brython editor and click Run. You should get an output similar to the following screenshot:

First the script is executed, then "hello"
is displayed, and finally "world"
is displayed.
For additional details about coroutines in Python, you can check out Async IO in Python: A Complete Walkthrough.
The generic concepts of asynchronous I/O apply to all platforms embracing this pattern. In JavaScript, the event loop is intrinsically part of the environment, whereas in CPython this is something that is managed using functions exposed by asyncio
.
The example above was an intentional exercise to keep the code exactly as shown in the Python documentation example. While coding in the browser with Brython, it’s recommended to explicitly use browser.aio
, as you’ll see in the following section.
Web Specific Functions
To issue an asynchronous call to an API, like in the previous section, you can write a function like the following:
async def process_get(url):
req = await aio.get(url)
Note the use of the keywords async
and await
. The function needs to be defined as async
to use a call with await
. During the execution of this function, when reaching the call to await aio.get(url)
, the function gives control back to the main event loop while waiting for the network call, aio.get()
, to complete. The rest of the program execution is not blocked.
Here’s an example of how to invoke process_get()
:
aio.run(process_get("/some_api"))
The function aio.run()
executes the coroutine process_get()
. It’s nonblocking.
A more complete code example shows how to use the keywords async
and await
and how aio.run()
and aio.get()
are complementary:
1from le navigateur import aio, document
2import javascript
3
4def log(message):
5 document[[[["log"].value += f"message n"
6
7async def process_get(url):
8 log("Before await aio.get")
9 req = await aio.get(url)
dix log(f"Retrieved data: 'req.data'")
11
12def aio_get(evt):
13 log("Before aio.run")
14 aio.run(process_get("/api.txt"))
15 log("After aio.run")
16
17document[[[["get-btn"].bind("click", aio_get)
As in the most recent versions of Python 3, you can use the async
and await
keywords:
- Line 7 defines
process_get()
with the keywordasync
. - Line 9 invokes
aio.get()
with the keywordawait
. Utilisantawait
requires the enclosing function to be defined withasync
. - Line 14 shows how to use
aio.run()
, which takes as an argument theasync
function to be called.
To run the full example, you need to start a web server. You can start the Python development web server with python3 -m http.server
. It starts a local web server on port 8000 and the default page index.html
:

The screenshot shows the sequence of steps executed after clicking Async Get. The combination of using the aio
module and the keywords async
and await
shows how you can embrace the asynchronous programming model that JavaScript promotes.
Distributing and Packaging a Brython Project
The method you use to install Brython may affect how and where you can deploy your Brython project. In particular, to deploy to PyPI, the best option is to first install Brython from PyPI and then create your project with brython-cli
. But a typical web deployment to a private server or to a cloud provider can leverage any installation method you choose.
You have several deployment options:
- Manual and automatic deployments
- Deployment to PyPI
- Deployment to a CDN
You’ll explore each of these in the following sections.
Manual and Automatic Web Deployments
Your application contains all the static dependencies, CSS, JavaScript, Python, and image files that you need for your website. Brython is part of your JavaScript files. All the files can be deployed as-is on the provider of your choice. You can consult the Web Development Tutorials and Automating Django Deployments with Fabric and Ansible for details on deploying your Brython applications.
If you decide to use brython-cli --modules
to precompile your Python code, then the files you deploy won’t have any Python source code, only brython.js
and brython_modules.js
. You also won’t include brython_stdlib.js
since the required modules will be included in brython_modules.js
already.
Deploying to PyPI
When you install Brython from PyPI, you can use brython-cli
to create a package that can be deployed to PyPI. The goals of creating such a package are to extend the default Brython template as a base for your custom projects and to make Brython websites available from PyPI.
After following the instructions in the section on installing from PyPI, execute the following command in your new web
project:
$ brython-cli --make_dist
You’ll be prompted to answer a few questions intended to create brython_setup.json
, which you can modify later. After completion of the command, you’ll have a directory called __dist__
containing the files you need to create an installable package.
You can test the installation of this new package locally as follows:
$ pip install -e __dist__
Subsequently, you can also confirm that the new command deployed locally with the web
package by executing the following command:
$ python -m web --help
usage: web.py [-h] [--install]
optional arguments:
-h, --help show this help message and exit
--install Install web in an empty directory
Notice that the web
command behaves exactly as Brython does after an initial install. You’ve just created a custom installable Brython package that can be deployed to PyPI. For a thorough description of how to deploy your package to PyPI, check out How to Publish an Open-Source Python Package to PyPI.
Once deployed to PyPI, you can install your Brython package with pip
in a Python virtual environment. You’ll be able to create your new customized application with the new command you created:
$ python -m --install
To summarize, here are the steps for deploying to PyPI:
- Install Brython from PyPI.
- Create a project with
brython-cli --install
. - Create an installable package from your project with
brython-cli --make-dist
. - Deploy this package to PyPI.
The other installation methods—CDN, GitHub, and npm—don’t include brython-cli
and therefore aren’t well suited to preparing a PyPI package.
Deploying to a CDN
Just as brython.js
and brython_stdlibs.js
are available on CDN servers, you can also deploy your static assets, images, styles, and JavaScript files, including your Python files or brython_modules.js
, to a CDN. Examples of CDNs include:
If your application is open source, then you can get free CDN support. Examples include CDNJS and jsDelivr.
Creating Google Chrome Extensions
Chrome extensions are components built with web technologies and incorporated into Chrome to customize your browsing environment. Typically, the icons of these extensions are visible at the top of the Chrome window, to the right of the address bar.
Public extensions are available on the Chrome web store. To learn, you’ll install Google Chrome extensions from local files:

Before undertaking the implementation of a Google Chrome extension in Brython, you’ll first implement a JavaScript version and then translate it into Brython.
Hello World Extension in JS
As a starter, you’ll implement an extension that will perform the following actions:
- Open a popup window when you click on the extension icon
- Open a prompt message when you click on the popup window button
- Append the message you entered at the bottom of the initial popup window
The following screenshot illustrates this behavior:

In an empty folder, create the file manifest.json
to configure the extension:
1// manjefest.json
2
3 "name": "JS Hello World",
4 "version": "1.0",
5 "description": "Hello World Chrome Extension in JavaScript",
6 "manifest_version": 2,
7 "browser_action":
8 "default_popup": "popup.html"
9 ,
dix "permissions": [[[["declarativeContent", "storage", "activeTab"]
11
The important field for this example is the default popup file, popup.html
, which you’ll also have to create. For information on the other fields and more, you can consult the Manifest file format documentation.
In the same folder, create the popup.html
file used to define the user interface of the extension:
1
2
3<html>
4 <head>
5 <script src="popup.js" defer></script>
6 </head>
7 <body>
8 <button id="hello-btn">Hello JS</button>
9 <div id="hello"></div>
dix </body>
11</html>
The HTML file includes a link to the JavaScript business logic of the extension and describes its user interface:
- Line 5 refers to
popup.js
, which contains the logic of the extension. - Line 8 defines a
button
that will be bound to a handler inpopup.js
. - Line 9 declares a field to be used by the JavaScript code to display some text.
You also need to create popup.js
:
1// popup.js
2'use strict';
3
4let helloButton = document.getElementById("hello-btn");
5
6helloButton.onclick = function (element)
7 const defaultName = "Real JavaScript";
8 let name = prompt("Enter your name:", defaultName);
9 if (!name)
dix name = defaultName;
11
12 document.getElementById("hello").innerHTML = `Hello, $name!`;
13;
The main logic of the JavaScript code consists of declaring an onclick
handler bound to the field hello-btn
of the HTML container:
- Line 2 invokes the script mode that enables more stringent validation in JavaScript to reveal JavaScript mistakes.
- Line 4 selects the field identified by
hello-btn
danspopup.html
and assigns it to a variable. - Line 6 defines the handler that will process the event when a user clicks the button. This event handler prompts the user for their name, then changes the contents of the identified with
Bonjour
to the provided name.Before installing this extension, take the following steps:
- Open the Google Chrome menu on the right-hand side of the screen.
- Open the submenu More Tools.
- Cliquez sur Extensions.
A screen will display your currently installed extensions, if any. It may look like this:
To install your new extension, you’ll need to take the following steps:
- Ensure that the Developer mode is enabled on the top right-hand side of the screen.
- Cliquez sur Load unpacked.
- Select the folder containing all the files you just created.
If no error occurred during the installation, then you should now see a new icon with a J on the right-hand side of your browser’s address bar. To test your extension, click the J icon of the toolbar displayed below:
If any errors occur during installation or execution, then you should see a red error button to the right of the extension card’s Remove button:
You can click Errors to display the error and identify the root cause. After correction, reload the extension by clicking the circular arrow at the bottom right of the extension card, then repeat the process until it works as you expect.
To test your newly installed extension, you can click the J icon displayed on the right-hand side of the browser toolbar. If the icon isn’t displayed, then click Extensions to list the installed extensions and select the pushpin button aligned with the JS Hello World extension you just installed.
Hello World Extension in Python
If you’ve reached this point, then you’ve already completed the most difficult steps, mostly to get familiar with the process of creating a Chrome extension and installing it. The steps will be similar with Brython, with a couple of differences that you’ll learn in this section.
The manifest file will be distinct, with a different extension name and, for good measure, a different description:
1// manjefest.json 2 3 "name": "Py Hello World", 4 "version": "1.0", 5 "description": "Hello World Chrome Extension in Python", 6 "manifest_version": 2, 7 "browser_action": 8 "default_popup": "popup.html" 9 , dix "content_security_policy": "script-src 'self' 'unsafe-eval';object-src 'self'", 11 "permissions": [[[["declarativeContent", "storage", "activeTab"] 12
Note that you also have to include a new property,
content_security_policy
. This is needed so that the policy againsteval()
can be relaxed in the chrome extension system. Remember that Brython useseval()
.This isn’t something that you introduced and that you can control in Brython. You’ll need to enable using
eval()
if you want to use Brython as the language of your browser extension. If you don’t addunsafe-eval
to thecontent_security_policy
, then you’ll see the following error:Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' blob: filesystem:".
The HTML file will also have a few updates, as follows:
1 2 3<html> 4 <head> 5 <script src="brython.min.js" defer></script> 6 <script src="init_brython.js" defer></script> 7 <script src="popup.py" taper="text/python" defer></script> 8 </head> 9 <body> dix <button id="hello-btn">Hello Py</button> 11 <div id="hello"></div> 12 </body> 13</html>
The HTML code is very similar to the one you used to create a Chrome extension in JavaScript. A few details are worth noting:
- Line 5 loads
brython.min.js
from a local package. For security reasons, only local scripts are loaded and you can’t load from an external source like a CDN. - Line 6 loads
init_brython.js
, which invokesbrython()
. - Line 7 loads
popup.py
. - Line 9 declares
body
without the usualonload="brython()"
.
Another security constraint prevents you from calling
brython()
in theonload
event of thebody
tag. The workaround is to add a listener to the document and to indicate to the browser to executebrython()
after the content of the document is loaded:// init_brython.js document.addEventListener('DOMContentLoaded', function () brython(); );
Finally, you can see the main logic of this application in the following Python code:
# popup.py from le navigateur import document, prompt def Bonjour(evt): default = "Real Python" name = prompt("Enter your name:", default) if not name: name = default document[[[["hello"].innerHTML = f"Hello, name!" document[[[["hello-btn"].bind("click", Bonjour)
With that, you’re ready to proceed with the installation and testing as you did for the JavaScript chrome extension.
Testing and Debugging Brython
There are currently no convenient libraries for unit testing Brython code. As Brython evolves, you’ll see more options to test and debug Python code in the browser. It’s possible to take advantage of the Python unit test framework for a standalone Python module that can be used outside the browser. In the browser, Selenium with browser drivers is a good option. Debugging is also limited but possible.
Python Unit Tests
The Python unit test frameworks, like the built-in
unittest
andpytest
, don’t work in the browser. You can use these frameworks for Python modules that could also be executed in the context of CPython. Any Brython-specific modules likele navigateur
can’t be tested with such tools at the command line. For more information about Python unit testing, check out Getting Started With Testing in Python.Selenium
Selenium is a framework for automating browsers. It’s agnostic to the language used in the browser, whether it’s JavaScript, Elm, Wasm, or Brython, because it uses the WebDriver concept to behave like a user interacting with the browser. You can check out Modern Web Automation With Python and Selenium for more information about this framework.
JavaScript Unit Tests
There are many JavaScript-focused testing frameworks, like Mocha, Jasmine, and QUnit, that perform well in the full JavaScript ecosystem. But they’re not necessarily well suited to unit test Python code running in the browser. One option requires globally exposing the Brython functions to JavaScript, which goes against best practices.
To illustrate the option of exposing a Brython function to JavaScript, you’ll use QUnit, a JavaScript unit test suite that can run self-contained in an HTML file:
1 2 3<html> 4 5<head> 6 <meta charset="utf-8"> 7 <meta name="viewport" content="width=device-width"> 8 <Titre>Test Suite</Titre> 9 <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.13.0.css"> dix <script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js"></script> 11 <script src="https://code.jquery.com/qunit/qunit-2.13.0.js"></script> 12</head> 13 14<body onload="brython()"> 15<div id="qunit"></div> 16<div id="qunit-fixture"></div> 17<script taper="text/python"> 18from le navigateur import window 19 20def python_add(une, b): 21 return une + b 22 23window.py_add = python_add 24</script> 25 26<script> 27const js_add = (une, b) => une + b; 28QUnit.module('js_add_test', function() 29 QUnit.test('should add two numbers', function(assert) 30 assert.equal(js_add(1, 1), 2, '1 + 1 = 2 (javascript'); 31 ); 32); 33 34QUnit.module('py_add_test', function() 35 QUnit.test('should add two numbers in Brython', function(assert) 36 assert.equal(py_add(2, 3), 5, '2 + 3 = 5 (python)'); 37 ); 38); 39 40QUnit.module('py_add_failed_test', function() 41 QUnit.test('should add two numbers in Brython (failure)', function(assert) 42 assert.equal(py_add(2, 3), 6, '2 + 3 != 6 (python)'); 43 ); 44); 45</script> 46 47</body> 48</html>
In one HTML file, you’ve written Python code, JavaScript code, and JavaScript tests to validate functions from both languages executed in the browser:
- Line 11 imports the QUnit framework.
- Line 23 exposes
python_add()
to JavaScript. - Line 28 defines
js_add_test
to test the JavaScript functionjs_add()
. - Line 34 defines
py_add_test
to test the Python functionpython_add()
. - Line 40 defines
py_add_failed_test
to test the Python functionpython_add()
with an error.
You don’t need to start a web server to execute the unit test. Open
index.html
in a browser, and you should see the following:The page shows two successful tests,
js_add_test()
andpy_add_test()
, and one failed test,py_add_failed_test()
.Exposing a Python function to JavaScript shows how you can use a JavaScript unit test framework to execute Python in the browser. Although possible for testing, it’s not recommended in general because it may conflict with existing JavaScript names.
Debugging in Brython
As of this writing, there were no user-friendly tools to debug your Brython application. You weren’t able to generate a source map file that would allow you to debug step by step in the browser development tools.
This shouldn’t discourage you from using Brython. Here are a few tips to help with debugging and troubleshooting your Brython code:
- Use
print()
oubrowser.console.log()
to print variable values in the browser’s developer tools console. - Use f-string debugging as described in Cool New Features in Python 3.8.
- Clear the browser’s IndexedDB once in a while by using the developer tools.
- Disable the browser cache during development by checking the Disable cache checkbox in the Network tab of the browser’s developer tools.
- Add options to
brython()
to enable additional debug information to be displayed in the JavaScript console. - Copy
brython.js
andbrython_stdlib.min.js
locally to speed up reloading during development. - Start a local server when you
import
Python code. - Open the inspector from the extension when troubleshooting a Chrome extension.
One of the niceties of Python is the REPL (read-eval-print loop). The online Brython console offers a platform to experiment with, test, and debug the behavior of some code snippets.
Exploring Alternatives to Brython
Brython isn’t the only option for writing Python code in the browser. A few alternatives are available:
Each implementation approaches the problem from a different angle. Brython attempts to be a replacement for JavaScript by providing access to the same web API and DOM manipulation as JavaScript, but with the appeal of the Python syntax and idioms. It’s packaged as a small download in comparison to some alternatives that may have different goals.
How do these frameworks compare?
Skulpt
Skulpt compiles Python code to JavaScript in the browser. The compilation takes place after the page is loaded, whereas in Brython the compilation takes place during page loading.
Although it doesn’t have built-in functions to manipulate the DOM, Skulpt is very close to Brython in its applications. This includes educational uses and full-blown Python applications, as demonstrated by Anvil.
Skulpt is a maintained project moving toward Python 3. Brython is mostly on par with CPython 3.9 for modules compatible with an execution in the browser.
Transcrypt
Transcrypt includes a command-line tool to compile Python code to JavaScript code. The compilation is said to be ahead of time (AOT). The resulting code can then be loaded into the browser. Transcrypt has a small footprint, about 100KB. It’s fast and supports DOM manipulation.
The difference between Skulpt and Brython is that Transcrypt is compiled to JavaScript with the Transcrypt compiler before being downloaded and used in the browser. This enables speed and small size. However, it prevents Transcrypt from being used as a platform for education like the other platforms.
Pyodide
Pyodide is a WebAssembly compilation of the CPython interpreter. It interprets Python code in the browser. There’s no JavaScript compilation phase. Although Pyodide, like PyPy.js, requires you to download a significant amount of data, it comes loaded with scientific libraries like NumPy, Pandas, Matplotlib, and more.
You can see Pyodide as a Jupyter Notebook environment running entirely in the browser rather than served by a back-end server. You can experiment with Pyodide using a live example.
PyPy.js
PyPy.js uses the PyPy Python interpreter compiled to JavaScript with emscripten, making it compatible for running in a browser.
In addition to the project’s current dormant status, PyPy.js is a large package, about 10 MB, that is prohibitive for typical web applications. You can still use PyPy.js as a platform for learning Python in a browser by opening the PyPy.js home page.
PyPy.js is compiled to JavaScript with emscripten. Pyodide takes it one step further, leveraging emscripten and Wasm in particular to compile Python C extensions like NumPy to WebAssembly.
As of this writing, PyPy.js did not appear to be maintained. For something in the same vein regarding the compilation process, consider Pyodide.
Conclusion
In this tutorial, you’ve taken a deep dive into several facets of writing Python code in the browser. This may have given you some interest in trying Python for front-end development.
In this tutorial, you’ve learned how to:
- Install and use Brython in a local environment
- Replace JavaScript with Python in your front-end web applications
- Manipulate the DOM
- Interact with JavaScript
- Create browser extensions
- Compare alternatives to Brython
In addition to accessing features usually reserved for JavaScript, one of the best uses of Brython is as a learning and teaching tool. You can access a Python editor and console that run in your browser to start exploring the many uses of Brython today.
To review the examples you saw in this tutorial, you can download the source code by clicking the link below:
[ad_2]