<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fh="http://purl.org/syndication/history/1.0"><channel><title>Basile Marchand | Articles et notes</title><description>Calcul scientifique, simulation numérique, HPC et ressources pédagogiques de Basile Marchand.</description><link>https://bmarchand.fr/</link><language>fr</language><fh:complete/><atom:link rel="self" href="https://bmarchand.fr/blog/rss.xml"/><item><title>Du pixel art avec Octave : des matrices, des couleurs et un peu de tramage</title><link>https://bmarchand.fr/blog/pixel-art-octave/</link><guid isPermaLink="true">https://bmarchand.fr/blog/pixel-art-octave/</guid><description>Transformer une photo en pixel art avec GNU Octave : moyennes par blocs, palette K-means et diffusion d’erreur inspirée de Floyd–Steinberg.</description><pubDate>Sat, 14 Nov 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pour me refaire un peu la main sur Octave, je me suis amusé à transformer une photo en pixel art. Le principe est assez simple : faire de gros pixels et réduire le nombre de couleurs. Et comme on est dans Octave, autant faire ça avec quelques produits de matrices 😎.&lt;/p&gt;
&lt;p&gt;Voilà le genre de résultat que ça donne :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_15_16.webp&quot; alt=&quot;Vue urbaine transformée en pixel art avec des blocs de 15 pixels et une palette de 16 couleurs.&quot;&gt;&lt;/p&gt;
&lt;p&gt;L’ensemble du code est disponible sur &lt;a href=&quot;https://github.com/basileMarchand/octave-pixel-art&quot;&gt;GitHub&lt;/a&gt;. Ici je vais surtout vous expliquer les quelques opérations derrière.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;on-commence-par-faire-de-gros-pixels&quot;&gt;On commence par faire de gros pixels&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Voici la photo de départ :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/original.webp&quot; alt=&quot;Photo de départ : des immeubles sous un ciel bleu.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Une image RGB, c’est un tableau avec trois canaux : rouge, vert et bleu. On peut donc travailler sur chaque canal comme sur une matrice. Je commence par convertir l’image avec &lt;code dir=&quot;auto&quot;&gt;im2double&lt;/code&gt;, pour avoir des valeurs entre 0 et 1.&lt;/p&gt;
&lt;p&gt;Ensuite, l’idée est de prendre des blocs de pixels et de remplacer chaque bloc par sa couleur moyenne. Si je prends des blocs de 15 × 15, mes 225 pixels deviennent un seul pixel. On perd les petits détails et on garde les grandes zones de couleur.&lt;/p&gt;
&lt;p&gt;Pour faire ça, j’ai construit deux projecteurs avec un produit de Kronecker :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;width_r = floor(width &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; ratio);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;height_r = floor(height &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; ratio);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;im_crop = im(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;:height_r*ratio, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;:width_r*ratio, :);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;projector_left = kron(speye(height_r), ones(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, ratio) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; ratio);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;projector_right = kron(speye(width_r), ones(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, ratio) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; ratio);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; c = &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;:channels&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;im_r(:,:,c) = projector_left &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; im_crop(:,:,c) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; projector_right&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;endfor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Alors si &lt;code dir=&quot;auto&quot;&gt;kron&lt;/code&gt; ne vous parle pas, ici il sert à répéter le même petit bloc de moyenne le long de la matrice. &lt;code dir=&quot;auto&quot;&gt;speye&lt;/code&gt; nous donne une matrice identité creuse, et &lt;code dir=&quot;auto&quot;&gt;ones(1, ratio) / ratio&lt;/code&gt; fait la moyenne de &lt;code dir=&quot;auto&quot;&gt;ratio&lt;/code&gt; valeurs.&lt;/p&gt;
&lt;p&gt;Le projecteur de gauche regroupe les lignes, celui de droite les colonnes. Avec les deux multiplications, on a donc notre moyenne sur chaque carré. On recadre juste l’image au début pour avoir un nombre entier de blocs.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;maintenant-on-réduit-les-couleurs&quot;&gt;Maintenant on réduit les couleurs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;À ce stade on a une petite image, mais encore beaucoup de couleurs différentes. Pour obtenir une palette de 8, 16 ou 32 couleurs, j’utilise K-means.&lt;/p&gt;
&lt;p&gt;On range les pixels dans une matrice où chaque ligne contient les trois valeurs RGB d’un pixel, puis on demande à K-means de les répartir en &lt;code dir=&quot;auto&quot;&gt;ncolors&lt;/code&gt; groupes :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;X = reshape(im_r, [], &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[idx, palette] = kmeans(X, ncolors, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Start&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;plus&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Replicates&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Les centres des groupes nous donnent les couleurs de la palette. Donc pas besoin de choisir à la main les couleurs qui vont bien avec la photo, c’est le calcul qui s’en charge.&lt;/p&gt;
&lt;p&gt;Pour voir ce que ça change, voilà le résultat avec des blocs de 15 × 15 :&lt;/p&gt;















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;2 couleurs&lt;/th&gt;&lt;th&gt;8 couleurs&lt;/th&gt;&lt;th&gt;32 couleurs&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_15_2.webp&quot; alt=&quot;Résultat avec une palette de 2 couleurs.&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_15_8.webp&quot; alt=&quot;Résultat avec une palette de 8 couleurs.&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_15_32.webp&quot; alt=&quot;Résultat avec une palette de 32 couleurs.&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Avec deux couleurs on est assez radical ! En augmentant la palette on retrouve progressivement les nuances du ciel et des bâtiments.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;un-peu-de-tramage&quot;&gt;Un peu de tramage&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Une fois la palette calculée, on pourrait simplement remplacer chaque pixel par la couleur la plus proche. Mais dans les dégradés, notamment le ciel ici, on se retrouve vite avec de grandes bandes de couleur.&lt;/p&gt;
&lt;p&gt;J’ai donc ajouté un tramage inspiré de Floyd–Steinberg. Le principe : quand on remplace un pixel par une couleur de la palette, on calcule l’écart et on en transmet une partie aux pixels voisins. Ils vont en tenir compte au moment de choisir leur propre couleur.&lt;/p&gt;
&lt;p&gt;Pour choisir la couleur, on fait tout simplement une recherche du plus proche voisin dans notre palette RGB :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;distances = sum((palette &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; pixel).^2, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[~, k] = min(distances);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;color = palette(k,:);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;error = &lt;/span&gt;&lt;span&gt;0.3&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; (pixel &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; color);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Dans cette version je diffuse 30 % de l’erreur, répartis entre le pixel de droite et les trois voisins de la ligne suivante :&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;À gauche&lt;/th&gt;&lt;th&gt;Même colonne&lt;/th&gt;&lt;th&gt;À droite&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;Pixel courant&lt;/td&gt;&lt;td&gt;7/16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3/16&lt;/td&gt;&lt;td&gt;5/16&lt;/td&gt;&lt;td&gt;1/16&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;On parcourt l’image de gauche à droite et de haut en bas. L’erreur est donc toujours envoyée à des pixels que l’on n’a pas encore traités. C’est ce qui donne les petits motifs visibles dans les transitions entre deux couleurs.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;et-on-remet-tout-ça-à-la-bonne-taille&quot;&gt;Et on remet tout ça à la bonne taille&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Il reste à agrandir notre petite image. Ici on utilise le plus proche voisin pour garder des blocs bien nets :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;im_pix = imresize(im_d, ratio, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;nearest&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Chaque pixel redevient un carré de &lt;code dir=&quot;auto&quot;&gt;ratio × ratio&lt;/code&gt; pixels, avec la couleur choisie à l’étape précédente. Le tramage a été fait sur la petite image, donc ses motifs sont agrandis eux aussi.&lt;/p&gt;
&lt;p&gt;Avec 16 couleurs, voilà ce que donne le changement de taille des blocs :&lt;/p&gt;















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Blocs de 5 × 5&lt;/th&gt;&lt;th&gt;Blocs de 15 × 15&lt;/th&gt;&lt;th&gt;Blocs de 30 × 30&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_5_16.webp&quot; alt=&quot;Résultat avec des blocs de 5 pixels.&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_15_16.webp&quot; alt=&quot;Résultat avec des blocs de 15 pixels.&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img src=&quot;https://bmarchand.fr/media/octave-pixel-art/image_30_16.webp&quot; alt=&quot;Résultat avec des blocs de 30 pixels.&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;&lt;h2 id=&quot;pour-jouer-avec-le-code&quot;&gt;Pour jouer avec le code&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Il vous faudra Octave et les paquets &lt;code dir=&quot;auto&quot;&gt;image&lt;/code&gt; et &lt;code dir=&quot;auto&quot;&gt;statistics&lt;/code&gt;. Le script &lt;code dir=&quot;auto&quot;&gt;main.m&lt;/code&gt; lit une photo RGB nommée &lt;code dir=&quot;auto&quot;&gt;image.jpg&lt;/code&gt; et génère les variantes dans &lt;code dir=&quot;auto&quot;&gt;outputs/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les deux boucles permettent de faire varier le nombre de couleurs et la taille des blocs :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; color = [&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; ratio = [&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;im_pixel = pixel_art(im_int, ratio, color);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;output_filepath = fullfile(folder, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sprintf(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;image_%d_%d.jpg&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, ratio, color));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;imwrite(im_pixel, output_filepath);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;endfor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;endfor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ça fait 30 variantes pour regarder tranquillement ce qui vous plaît. Vous pouvez aussi jouer avec le coefficient &lt;code dir=&quot;auto&quot;&gt;0.3&lt;/code&gt; dans &lt;code dir=&quot;auto&quot;&gt;floyd_steinberg.m&lt;/code&gt; pour changer la quantité d’erreur diffusée.&lt;/p&gt;
&lt;p&gt;Le &lt;a href=&quot;https://github.com/basileMarchand/octave-pixel-art&quot;&gt;dépôt&lt;/a&gt; contient les images et les deux fonctions si vous voulez essayer avec vos propres photos 🤗.&lt;/p&gt;</content:encoded><category>octave</category><category>traitement-image</category><category>algebre-lineaire</category></item><item><title>Rendre un code scientifique reproductible : Git, tests et CI/CD</title><link>https://bmarchand.fr/blog/industrialisation-recherche-numerique/</link><guid isPermaLink="true">https://bmarchand.fr/blog/industrialisation-recherche-numerique/</guid><description>Six étapes pour structurer un code de recherche, versionner les expériences, ajouter des tests et automatiser les calculs avec Git et la CI/CD.</description><pubDate>Sat, 23 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Le 23 mai 2026, j’ai eu le plaisir d’animer une session pour les jeunes chercheurs (doctorants, postdocs) lors du colloque &lt;strong&gt;CSMA Junior 2026&lt;/strong&gt; à Giens (Var). L’objectif de cette rencontre était de parler ouvertement d’un sujet parfois tabou mais pourtant si universel : l’organisation – ou plutôt le chaos – logiciel dans la recherche en calcul scientifique et mécanique numérique.&lt;/p&gt;
&lt;p&gt;L’exposé original s’intitulait &lt;em&gt;« De simulation_finale_v2_matin.zip à une industrialisation de ta recherche »&lt;/em&gt;. Ce titre, c’est un clin d’œil à nos pires travers en thèse ou en postdoc. On a tous un jour perdu une journée entière (voir beaucoup plus) à se demander : &lt;em&gt;« Comment j’ai généré cette courbe dans mon papier de l’an dernier ? »&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pourtant, sortir de ce chaos ne demande pas de se transformer en ingénieur système ou en gourou du DevOps du jour au lendemain. C’est une démarche progressive, pragmatique, qui tient en une échelle de maturité de six niveaux.&lt;/p&gt;
&lt;p&gt;L’industrialisation logicielle d’un workflow scientifique n’est pas une corvée d’ingénieur ennuyeuse. C’est &lt;strong&gt;une part intrinsèque du métier de chercheur&lt;/strong&gt; dès lors qu’un prototype produit des résultats que l’on veut conserver, partager, refaire ou publier.&lt;/p&gt;
&lt;p&gt;Car en réalité : &lt;strong&gt;Ce n’est pas le ZIP. C’est ce qu’il cache.&lt;/strong&gt;&lt;/p&gt;
&lt;aside aria-label=&quot;Dépôt de démonstration&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Dépôt de démonstration&lt;/p&gt;&lt;div&gt;&lt;p&gt;Pour illustrer cette transition, j’ai mis à disposition un dépôt complet montrant le passage d’un code de recherche classique et brouillon à un projet structuré, testé et automatisé :&lt;/p&gt;&lt;github-repo data-url=&quot;https://github.com/basileMarchand/csma_junior_2026&quot;&gt;&lt;article aria-label=&quot;Dépôt csma_junior_2026&quot;&gt;&lt;a href=&quot;https://github.com/basileMarchand/csma_junior_2026&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;strong&gt;csma_junior_2026&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;Material for practical session at CSMA Junior 2026&lt;/p&gt;&lt;div&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;span data-language-name=&quot;&quot;&gt;Python&lt;/span&gt;&lt;/span&gt;&lt;span data-forks=&quot;&quot; aria-label=&quot;0 forks&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;🍴 &lt;/span&gt;&lt;span data-forks-count=&quot;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p role=&quot;status&quot;&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; hidden&gt;Réessayer&lt;/button&gt;&lt;/article&gt;&lt;/github-repo&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;hr&gt;
&lt;div&gt;&lt;h2 id=&quot;les-conséquences-du-research-chaos&quot;&gt;Les conséquences du “Research Chaos”&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Lorsqu’on développe dans l’urgence d’une publication ou d’un rendu de projet, la désorganisation s’installe vite. Ce désordre a deux types de conséquences symétriques :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scientifiques&lt;/strong&gt; : Perte de temps à refaire ce qui tournait déjà, perte de connaissance au départ d’un membre de l’équipe, manque de capitalisation et figures impossibles à régénérer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Humaines&lt;/strong&gt; : Frustration, colère devant le terminal qui renvoie des erreurs cryptiques, déprime de voir son travail s’évaporer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ranger son code et son workflow, ce n’est pas uniquement pour la rigueur scientifique de l’éditeur ou des relecteurs, c’est avant tout &lt;strong&gt;pour soi&lt;/strong&gt; et pour son propre confort de recherche. Chaque pipeline propre construit aujourd’hui devient un actif précieux pour demain.&lt;/p&gt;
&lt;hr&gt;
&lt;div&gt;&lt;h2 id=&quot;les-6-niveaux-de-maturité-logicielle-en-recherche&quot;&gt;Les 6 niveaux de maturité logicielle en recherche&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour progresser sans se décourager, voici une grille de lecture réaliste. Identifiez où vous vous situez actuellement, et visez simplement le niveau supérieur.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-1--ne-pas-perdre-lhistorique-git-et-commits-propres&quot;&gt;Niveau 1 : Ne pas perdre l’historique (Git et commits propres)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Le premier symptôme du chaos, c’est le dossier encombré de fichiers du type &lt;code dir=&quot;auto&quot;&gt;run_v1.py&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;run_v2_modifs.py&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;run_final.py&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;simulation_finale_v2_matin.zip&lt;/code&gt;. Le problème de cette méthode, c’est qu’elle n’offre aucun historique fiable ni repère temporel.&lt;/p&gt;
&lt;p&gt;Adopter &lt;strong&gt;Git&lt;/strong&gt; est la première étape indispensable. Non pas comme un outil complexe de gestion de versions, mais comme un véritable &lt;strong&gt;assistant à la réflexion scientifique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Considérez chaque commit comme une note dans votre journal de bord de recherche. Un bon commit documente un changement d’hypothèse physique, une correction de formule ou un nouveau paramètre. Par exemple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;feat: Ajout de la loi de comportement hyperélastique pour la poutre&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;fix: Correction du facteur de conversion d&apos;unités (Pa vers MPa)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;test: Ajout du cas de comparaison analytique&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ces messages précis traduisent l’évolution de votre démarche scientifique et vous libèrent de la charge mentale d’avoir à vous souvenir de chaque ligne modifiée.&lt;/p&gt;
&lt;aside aria-label=&quot;Astuce : Versionner aussi ses publications !&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Astuce : Versionner aussi ses publications !&lt;/p&gt;&lt;div&gt;&lt;p&gt;Si vous rédigez vos articles, rapports ou votre manuscrit de thèse en &lt;strong&gt;LaTeX&lt;/strong&gt;, &lt;strong&gt;Markdown&lt;/strong&gt; ou tout autre format textuel, Git est également votre meilleur allié. Fini les fichiers &lt;code dir=&quot;auto&quot;&gt;these_version_directeur_v3_corrige.docx&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;En versionnant vos fichiers de rédaction, vous suivez l’évolution de vos textes ligne par ligne, pouvez travailler sereinement sur des branches séparées avec vos co-auteurs, et identifier instantanément les modifications apportées entre deux cycles de relecture.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-2--pouvoir-relancer-readme-et-commandes-claires&quot;&gt;Niveau 2 : Pouvoir relancer (README et commandes claires)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Le signal d’alarme de ce niveau est simple : devoir expliquer de vive voix à un collègue (ou à soi-même six mois plus tard) les huit commandes manuelles à exécuter dans le bon ordre pour lancer le script de post-traitement.&lt;/p&gt;
&lt;p&gt;Le remède ? &lt;strong&gt;Rendre explicite ce qui est dans votre tête.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Un fichier &lt;code dir=&quot;auto&quot;&gt;README.md&lt;/code&gt; minimal mais rigoureux à la racine de votre projet doit faire office de carte au trésor. Il doit décrire sans ambiguïté :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comment installer rapidement le projet.&lt;/li&gt;
&lt;li&gt;La commande exacte pour lancer un calcul de test.&lt;/li&gt;
&lt;li&gt;La méthode pas à pas pour régénérer la figure principale de votre article.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-3--reproduire-lenvironnement-gestion-des-dépendances&quot;&gt;Niveau 3 : Reproduire l’environnement (Gestion des dépendances)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;La douleur associée ici est le fameux : &lt;em&gt;« Ça marche uniquement sur ma machine »&lt;/em&gt;. En calcul scientifique, on dépend d’un écosystème fragile : versions de Python, de bibliothèques (NumPy, SciPy), de compilateurs (gfortran, GCC), de solveurs externes (comme code_aster) ou de modules installés sur un cluster HPC.&lt;/p&gt;
&lt;p&gt;Il n’y a pas d’outil magique unique, mais plutôt une collection de solutions adaptées à chaque contexte :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;En pur Python&lt;/strong&gt; : Privilégiez des outils ultra-rapides et modernes comme &lt;code dir=&quot;auto&quot;&gt;uv&lt;/code&gt; (par Astral), combiné à un fichier standardisé &lt;code dir=&quot;auto&quot;&gt;pyproject.toml&lt;/code&gt; pour verrouiller vos versions de bibliothèques.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;En Fortran/C++ scientifique&lt;/strong&gt; : Tournez-vous vers &lt;code dir=&quot;auto&quot;&gt;Conda&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Pixi&lt;/code&gt; ou &lt;code dir=&quot;auto&quot;&gt;Spack&lt;/code&gt; qui gèrent très bien les dépendances de bas niveau et les variantes de compilation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sur cluster ou pour diffusion&lt;/strong&gt; : Les conteneurs comme &lt;code dir=&quot;auto&quot;&gt;Docker&lt;/code&gt; (pour votre machine) ou &lt;code dir=&quot;auto&quot;&gt;Apptainer&lt;/code&gt; / &lt;code dir=&quot;auto&quot;&gt;Singularity&lt;/code&gt; (très populaires en HPC pour s’affranchir des privilèges root) permettent d’embarquer tout votre système avec vous.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-4--vérifier-les-tests-comme-filet-de-sécurité&quot;&gt;Niveau 4 : Vérifier (Les tests comme filet de sécurité)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;C’est la peur de modifier le code de peur de « casser » un résultat obtenu il y a trois mois. Pour s’affranchir de cette angoisse, il faut poser des filets de sécurité automatique : les tests.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;« On ne teste pas du code pour le plaisir de coder. On teste pour acheter de la confiance dans les résultats scientifiques. »&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En calcul numérique, ces tests peuvent prendre des formes très élégantes et concrètes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;La solution analytique&lt;/strong&gt; : Comparer votre sortie numérique à une solution exacte connue (par exemple sur un cas simple de poutre en traction élastique).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;La non-régression&lt;/strong&gt; : Sauvegarder les résultats d’une simulation stable dans un fichier de référence (&lt;code dir=&quot;auto&quot;&gt;reference.ref.csv&lt;/code&gt;). Votre test exécute le code, génère un nouveau CSV et compare les valeurs avec une tolérance numérique rigoureuse via &lt;code dir=&quot;auto&quot;&gt;np.testing.assert_allclose&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Les invariants physiques&lt;/strong&gt; : Vérifier des ordres de grandeur ou des principes de conservation (conservation de la masse, énergie positive, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h4 id=&quot;️-vérification--validation&quot;&gt;⚠️ Vérification ≠ Validation&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;C’est une distinction conceptuelle fondamentale en calcul scientifique :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;La Vérification&lt;/strong&gt; répond à la question : &lt;em&gt;« Résout-on correctement les équations mathématiques ? »&lt;/em&gt;. C’est une affaire de bugs, d’implémentation et de convergence numérique. C’est l’objectif de vos tests unitaires et de non-régression.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;La Validation&lt;/strong&gt; répond à la question : &lt;em&gt;« Le modèle mathématique choisi représente-t-il fidèlement la physique ? »&lt;/em&gt;. C’est une confrontation aux données expérimentales et aux domaines de validité.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour avancer sereinement, l’automatisation de la &lt;strong&gt;vérification&lt;/strong&gt; est un prérequis non négociable. Des frameworks comme &lt;code dir=&quot;auto&quot;&gt;pytest&lt;/code&gt; se chargent de découvrir et d’exécuter ces vérifications de manière totalement transparente.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-5--orchestrer-lautomatisation-avec-des-workflows&quot;&gt;Niveau 5 : Orchestrer (L’automatisation avec des workflows)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;À ce stade, vous commencez à réaliser des études paramétriques ou des étapes successives de pré-traitement, calcul et post-traitement. Lancer chaque étape à la main devient fastidieux et source d’erreurs d’inattention.&lt;/p&gt;
&lt;p&gt;La solution consiste à utiliser un outil d’orchestration de tâches qui va matérialiser votre pipeline sous forme de &lt;strong&gt;DAG (Graphe Orienté Acyclique)&lt;/strong&gt;.
Un outil comme &lt;strong&gt;Snakemake&lt;/strong&gt; (très implanté en science) ou de simples fichiers &lt;strong&gt;GNU Make&lt;/strong&gt; vous permettent de décrire les relations de cause à effet : &lt;em&gt;« Pour produire cette figure, j’ai besoin de ce CSV d’agrégation, qui lui-même nécessite d’avoir lancé 10 simulations RVE avec différentes tailles de mailles »&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Grâce à un système intelligent de vérification des dates de modification des fichiers (timestamps), l’orchestrateur ne recalcule que ce qui a changé. Si vous modifiez uniquement le script de tracé, Snakemake ne relancera pas les 10 heures de calcul sous-jacentes, il régénérera instantanément la figure finale.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;niveau-6--sassurer-que-ça-dure-lintégration-continue-cicd&quot;&gt;Niveau 6 : S’assurer que ça dure (L’intégration continue CI/CD)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Le niveau ultime consiste à déléguer complètement la surveillance à un serveur tiers. Grâce aux plateformes comme &lt;strong&gt;GitHub Actions&lt;/strong&gt; ou &lt;strong&gt;GitLab CI&lt;/strong&gt;, chaque fois que vous poussez votre code (&lt;code dir=&quot;auto&quot;&gt;git push&lt;/code&gt;), une machine virtuelle neutre s’initialise à la volée.&lt;/p&gt;
&lt;p&gt;Elle installe votre environnement propre (&lt;code dir=&quot;auto&quot;&gt;uv sync&lt;/code&gt;), exécute l’intégralité de vos tests (&lt;code dir=&quot;auto&quot;&gt;pytest&lt;/code&gt;), et valide que vos pipelines de calcul (&lt;code dir=&quot;auto&quot;&gt;Snakemake&lt;/code&gt;) tournent sans erreur. Si vous avez introduit une régression par inadvertance, vous recevez immédiatement une alerte par mail.&lt;/p&gt;
&lt;hr&gt;
&lt;div&gt;&lt;h2 id=&quot;conclusion--une-marche-après-lautre&quot;&gt;Conclusion : Une marche après l’autre&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;L’industrialisation de votre recherche n’est pas un objectif où tout doit être parfait immédiatement. C’est un voyage progressif.&lt;/p&gt;
&lt;p&gt;Si vous appliquez aujourd’hui de manière systématique Git (Niveau 1) et un README clair (Niveau 2), vous aurez déjà accompli 80% du chemin pour vous épargner des maux de tête et garantir la pérennité de vos travaux. Les outils modernes comme &lt;code dir=&quot;auto&quot;&gt;uv&lt;/code&gt; ou &lt;code dir=&quot;auto&quot;&gt;Snakemake&lt;/code&gt; sont là pour vous aider à automatiser le reste, libérant ainsi votre esprit pour ce qui compte vraiment : &lt;strong&gt;les idées&lt;/strong&gt;.&lt;/p&gt;</content:encoded><category>python</category><category>git</category><category>ci-cd</category><category>reproductibilite</category></item><item><title>Observable : un notebook interactif pour visualiser un sondage LinkedIn</title><link>https://bmarchand.fr/blog/observable/</link><guid isPermaLink="true">https://bmarchand.fr/blog/observable/</guid><description>Découverte du notebook Observable à travers la visualisation interactive d&apos;un sondage LinkedIn.</description><pubDate>Thu, 24 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;aside aria-label=&quot;Contexte&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Contexte&lt;/p&gt;&lt;div&gt;&lt;p&gt;Je vous mets ici le &lt;a href=&quot;https://observablehq.com/@basilemarchand/survey&quot;&gt;lien&lt;/a&gt; et dessous le rendu d’un notebook fait dans &lt;a href=&quot;https://observablehq.com/&quot;&gt;observable&lt;/a&gt;. Le contenu était surtout un prétexte pour faire un peu joujou avec observable.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;iframe frameborder=&quot;0&quot; allowfullscreen title=&quot;Notebook Observable : visualisation d’un sondage LinkedIn&quot; loading=&quot;lazy&quot; src=&quot;https://observablehq.com/embed/@basilemarchand/survey@341?cell=*&quot;&gt;&lt;/iframe&gt;</content:encoded><category>javascript</category><category>observable</category><category>visualisation</category></item><item><title>Python 3.14 sans GIL : benchmarks du multithreading</title><link>https://bmarchand.fr/blog/python_314_nogil/</link><guid isPermaLink="true">https://bmarchand.fr/blog/python_314_nogil/</guid><description>Benchmarks de Python 3.14b2 avec et sans GIL : comparaison du multithreading sur plusieurs charges de calcul et limites des mesures.</description><pubDate>Wed, 11 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Périmètre des mesures :&lt;/strong&gt; ces benchmarks ont été réalisés avec Python &lt;strong&gt;3.14b2&lt;/strong&gt; en juin 2025. Les résultats décrivent cette version bêta et les cas testés ; ils ne constituent pas une mesure des versions stables ultérieures. Le Dockerfile et les scripts sont accessibles dans le dépôt associé.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;h2 id=&quot;-un-peu-de-contexte--le-gil-pourquoi-et-pour-quoi-faire-&quot;&gt;🧠 Un peu de contexte : le GIL, pourquoi et pour quoi faire ?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Le GIL (&lt;em&gt;Global Interpreter Lock&lt;/em&gt;) est un mécanisme présent dans l’implémentation CPython depuis toujours. Il garantit qu’un seul et unique thread peut exécuter du bytecode Python à la fois. Ce mécanisme permet historiquement de grandement simplifier la gestion de la mémoire interne de l’interpréteur.&lt;/p&gt;
&lt;p&gt;Néanmoins, ce verrou global a un effet de bord majeur : &lt;strong&gt;les programmes multi-threads ne scalent pas sur plusieurs cœurs&lt;/strong&gt; pour des workloads &lt;em&gt;CPU-bound&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;➡️ En pratique, &lt;code dir=&quot;auto&quot;&gt;threading.Thread&lt;/code&gt; est donc surtout utilisé pour des I/O.&lt;/p&gt;
&lt;p&gt;Depuis des années, la suppression du GIL était un sujet récurrent dans la communauté Python. Depuis Python 3.13, ça se concrétise !&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;-python-313-introduit-un-mode-expérimental----disable-gil&quot;&gt;🧪 Python 3.13 introduit un mode expérimental : &lt;code dir=&quot;auto&quot;&gt;--disable-gil&lt;/code&gt;&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;C’est l’objet de la &lt;a href=&quot;https://peps.python.org/pep-0703/&quot;&gt;PEP 703 – Making the Global Interpreter Lock Optional&lt;/a&gt; proposée par Sam Gross, qui a fait beaucoup parler d’elle. Depuis Python 3.13, il est possible de permettre la désactivation du GIL — pour cela, il faut que l’interpréteur Python soit compilé avec l’option &lt;code dir=&quot;auto&quot;&gt;--disable-gil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Avec ce mode activé à la compilation, le GIL est pilotable via la variable d’environnement &lt;code dir=&quot;auto&quot;&gt;PYTHON_GIL=0|1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Par exemple, pour lancer un script en mode &lt;code dir=&quot;auto&quot;&gt;nogil&lt;/code&gt;, il suffit de faire :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;PYTHON_GIL&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;python3&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;my_script.py&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Quelques benchmarks existent en ligne, par exemple &lt;a href=&quot;https://medium.com/@r_bilan/python-3-13-without-the-gil-a-game-changer-for-concurrency-5e035500f0da&quot;&gt;celui-ci&lt;/a&gt;. Mais j’ai voulu approfondir un peu le sujet et évaluer l’apport potentiel de cette révolution !&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;-setup-pour-les-tests&quot;&gt;🔧 Setup pour les tests&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour faire mes tests, j’ai mis en place une image Docker qui compile Python 3.14b2 avec l’option &lt;code dir=&quot;auto&quot;&gt;--disable-gil&lt;/code&gt;. Le Dockerfile et l’ensemble des cas de test sont disponibles&lt;/p&gt;
&lt;github-repo data-url=&quot;https://github.com/basileMarchand/benchmark_python3.14_nogil&quot;&gt;&lt;article aria-label=&quot;Dépôt benchmark_python3.14_nogil&quot;&gt;&lt;a href=&quot;https://github.com/basileMarchand/benchmark_python3.14_nogil&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;strong&gt;benchmark_python3.14_nogil&lt;/strong&gt;&lt;/a&gt;&lt;p hidden&gt;&lt;/p&gt;&lt;div&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;span data-language-name=&quot;&quot;&gt;Python&lt;/span&gt;&lt;/span&gt;&lt;span data-forks=&quot;&quot; aria-label=&quot;0 forks&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;🍴 &lt;/span&gt;&lt;span data-forks-count=&quot;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p role=&quot;status&quot;&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; hidden&gt;Réessayer&lt;/button&gt;&lt;/article&gt;&lt;/github-repo&gt;
&lt;p&gt;Pour construire le Docker :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ docker build . -f Dockerfile-nogil -t python:nogil_3.14b2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;️-benchmark-1--factorielle-lourde-en-multi-thread&quot;&gt;⚙️ Benchmark #1 : Factorielle lourde en multi-thread&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour le premier test, on fait tout bêtement un gros calcul de factorielle dans plusieurs threads.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; threading&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; math&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test_function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_thread&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;thread_start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;math.&lt;/span&gt;&lt;span&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;250000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;thread_execution_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; thread_start_time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;threads &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; num_thread &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;thread &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;test_function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;(num_thread,)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;thread.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;thread&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; thread &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; threads:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;thread.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;execution_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;     Elapsed time: &lt;/span&gt;&lt;span&gt;{execution_time&lt;/span&gt;&lt;span&gt;:.2f&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; seconds&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;-résultats&quot;&gt;🧾 Résultats&lt;/h3&gt;&lt;/div&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Temps total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GIL ON&lt;/td&gt;&lt;td&gt;1.97 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GIL OFF&lt;/td&gt;&lt;td&gt;0.56 s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;✅ &lt;strong&gt;Gain ×3~4&lt;/strong&gt; : ici, &lt;code dir=&quot;auto&quot;&gt;--disable-gil&lt;/code&gt; permet une vraie parallélisation du calcul lourd avec un très bon scaling.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;️-benchmark-2--calculs-mathématiques-modérés&quot;&gt;⚙️ Benchmark #2 : Calculs mathématiques modérés&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Même idée que précédemment, mais avec une charge mathématique un peu plus variée.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; threading&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; math&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; random&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stress_function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;thread_id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;complexity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; complexity&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;log1p&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;exp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# borné pour ne pas exploser la RAM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run_threads&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads=&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;complexity=&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Launching &lt;/span&gt;&lt;span&gt;{num_threads}&lt;/span&gt;&lt;span&gt; threads with complexity &lt;/span&gt;&lt;span&gt;{complexity}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;stress_function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;(i, complexity)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; t &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; threads:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;total_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;   Elapsed time &lt;/span&gt;&lt;span&gt;{total_time&lt;/span&gt;&lt;span&gt;:.2f&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; seconds&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; __name__ &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;__main__&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;run_threads&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;complexity&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;20_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;-résultats-1&quot;&gt;🧾 Résultats&lt;/h3&gt;&lt;/div&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Temps total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GIL ON&lt;/td&gt;&lt;td&gt;1.36 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GIL OFF&lt;/td&gt;&lt;td&gt;0.41 s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;✅ &lt;strong&gt;Gain ×3~4 à nouveau&lt;/strong&gt;, scaling constant.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;️-benchmark-3--accès-concurrent-partagé&quot;&gt;⚙️ Benchmark #3 : Accès concurrent partagé&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;On ajoute ici des écritures dans une variable partagée (une liste Python). Chaque thread écrit dans une case distincte.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stress_function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;thread_id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;complexity&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;shared_data&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; complexity&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;log1p&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;exp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; math.&lt;/span&gt;&lt;span&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_result &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_data[thread_id] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; local_result&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run_threads&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads=&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;complexity=&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_data &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; num_threads&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lock &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Lock&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;stress_function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;(i, complexity, shared_data, lock)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; t &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; threads:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;total_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;total_sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sum&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;shared_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;     Elapsed time: &lt;/span&gt;&lt;span&gt;{total_time&lt;/span&gt;&lt;span&gt;:.2f&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; seconds&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;        -&gt; Global result: &lt;/span&gt;&lt;span&gt;{total_sum &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;:.2f&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;-résultats-2&quot;&gt;🧾 Résultats&lt;/h3&gt;&lt;/div&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Temps total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GIL ON&lt;/td&gt;&lt;td&gt;1.32 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GIL OFF&lt;/td&gt;&lt;td&gt;0.43 s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;🔒 Grâce à un découpage propre 😎 (pas de collision entre threads), &lt;code dir=&quot;auto&quot;&gt;nogil&lt;/code&gt; reste très efficace ici.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;️-benchmark-4--recherche-du-plus-proche-voisin-sur-10m-points&quot;&gt;⚠️ Benchmark #4 : Recherche du plus proche voisin sur 10M points&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Test plus réaliste : 10M de points 3D aléatoires, recherche du plus proche voisin en multithreading avec dictionnaire partagé.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; threading&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; random&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; math &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; sqrt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;distance2&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; (a[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;b[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (a[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;b[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (a[&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;b[&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;find_closest_worker&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;points&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;query_point&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;shared_result&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;tid&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_min_dist &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;inf&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_min_idx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;d &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;distance2&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;points&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; query_point&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; local_min_dist:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_min_dist &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;local_min_idx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; lock:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; local_min_dist &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;min_dist&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;]:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;min_dist&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; local_min_dist&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;closest_idx&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; local_min_idx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;owner&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; tid&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threaded_closest_point&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;points&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;query_point&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;num_threads=&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;len&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;points&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;chunk_size &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;//&lt;/span&gt;&lt;span&gt; num_threads&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shared_result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;min_dist&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;inf&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;closest_idx&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;owner&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lock &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Lock&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; tid &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;num_threads&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;start &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; tid &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; chunk_size&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;end &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (tid &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; chunk_size &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; tid &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; num_threads &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threading.&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;find_closest_worker&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                             &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;(points, query_point, start, end, shared_result, lock, tid)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;threads.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; t &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; threads:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;closest_idx&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;], &lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;shared_result&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;min_dist&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;]), shared_result[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;owner&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; __name__ &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;__main__&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;N &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;10_000_000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;num_threads &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;points &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span&gt;random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; _ &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;query_point &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), random.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Launching threaded NN search with &lt;/span&gt;&lt;span&gt;{num_threads}&lt;/span&gt;&lt;span&gt; threads&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t0 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;idx, dist, owner &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threaded_closest_point&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;points&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; query_point&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; num_threads&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;t1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; time.&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;    Elapsed time: &lt;/span&gt;&lt;span&gt;{t1 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; t0&lt;/span&gt;&lt;span&gt;:.2f&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; seconds&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;-résultats-3&quot;&gt;🧾 Résultats&lt;/h3&gt;&lt;/div&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Temps total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GIL ON&lt;/td&gt;&lt;td&gt;2.38 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GIL OFF&lt;/td&gt;&lt;td&gt;3.61 s ❗&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;❌ Et là, grosse surprise : activer &lt;code dir=&quot;auto&quot;&gt;nogil&lt;/code&gt; rend les choses plus lentes. Je n’ai pas vraiment d’explication certaine. Mais si je devais avancer une théorie je dirais que l’accès concurrent à la grosse liste Python entraine quelques limitations.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;-bonus--version-c-équivalente--nanobind&quot;&gt;🔁 Bonus : version C++ équivalente + &lt;code dir=&quot;auto&quot;&gt;nanobind&lt;/code&gt;&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;J’ai aussi testé ce cas en C++ multithreadé natif, exposé à Python via &lt;a href=&quot;https://github.com/wjakob/nanobind&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;nanobind&lt;/code&gt;&lt;/a&gt;. c’est surtout pour voir si en suivant exactement la même logique mais en changeant juste la stack technique on obtient des résultats différents. Et donc oui :&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Implémentation&lt;/th&gt;&lt;th&gt;Temps total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Python GIL ON&lt;/td&gt;&lt;td&gt;2.38 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Python GIL OFF&lt;/td&gt;&lt;td&gt;3.61 s ❗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++ (threads)&lt;/td&gt;&lt;td&gt;0.88 s ✅&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;En version threads c++ on a bien un gros gain de performance. Donc la logique est bonne, pas trop mauvaise en tout cas, la limitation vient de Python 😿.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;-conclusion&quot;&gt;🔚 Conclusion&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Python progresse — c’est indéniable et enthousiasmant. Mais pour des cas fortement concurrentiels, les implémentations natives (C/C++) gardent un net avantage.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Python 3.14 &lt;code dir=&quot;auto&quot;&gt;--disable-gil&lt;/code&gt; &lt;strong&gt;offre des gains réels&lt;/strong&gt; pour des tâches &lt;em&gt;CPU-bound&lt;/em&gt; multithreadées&lt;/li&gt;
&lt;li&gt;⚠️ Mais les performances &lt;strong&gt;ne sont pas systématiquement meilleures&lt;/strong&gt;, notamment dès qu’il y a de gros volumes de données ou de la contention mémoire&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;-pour-aller-plus-loin&quot;&gt;📚 Pour aller plus loin&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0703/&quot;&gt;PEP 703 — Making the Global Interpreter Lock Optional&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3.14/whatsnew/3.14.html&quot;&gt;Python 3.14 changelog (beta)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wjakob/nanobind&quot;&gt;nanobind GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>python</category><category>performance</category><category>multithreading</category></item><item><title>asyncssh : automatiser SSH et tunnels en Python</title><link>https://bmarchand.fr/blog/asyncssh/</link><guid isPermaLink="true">https://bmarchand.fr/blog/asyncssh/</guid><description>Tutoriel pratique pour automatiser des connexions SSH, exécuter des commandes distantes et créer un tunnel de port-forwarding en Python avec asyncssh.</description><pubDate>Sat, 10 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Dans cet article je vais essayer d’illustrer simplement comment utiliser le module &lt;a href=&quot;https://asyncssh.readthedocs.io/&quot;&gt;asyncssh&lt;/a&gt; de Python pour :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scripter des actions distantes&lt;/li&gt;
&lt;li&gt;Etablir un tunnel ssh permettant de faire du port forwarding&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alors si vous vous êtes déjà confronté à ces problématiques vous avez peut-être déjà croisé la route du module Python paramiko. Alors personellement je ne recommande pas l’usage de paramiko (en gros j’ai perdu un temps monstrueux avec paramiko, c’est peut-être ma faute attention, notamment lorsque je devais faire des portages d’application entre windows 7 / windows 10 et Linux) et du coup depuis ce jour je suis passé à asyncssh et ça fonctionne parfaitement.&lt;/p&gt;
&lt;p&gt;La seule difficulté avec asyncssh vient du async … En effet c’est un module destiné à être utilisé dans un mode de programmation asynchrone avec asyncio il faut donc être un peu à l’aise avec les &lt;code dir=&quot;auto&quot;&gt;async/await&lt;/code&gt; dans Python 🤨 ! Si ce n’est pas le cas je vous invite à aller jeter un oeil sur le mooc &lt;a href=&quot;https://www.fun-mooc.fr/fr/cours/python-3-des-fondamentaux-aux-concepts-avances-du-langage/&quot;&gt;Python 3&lt;/a&gt; en semaine 8 vous avez une magnifique introduction à la programmation asynchrone.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;connection-à-un-serveur&quot;&gt;Connection à un serveur&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;La première étape est bien évidemment la connection au serveur ssh. Pour cela on passe par la fonction &lt;code dir=&quot;auto&quot;&gt;connect&lt;/code&gt; de asyncssh qui prend entre autre arguments :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un nom d’utilisateur &lt;code dir=&quot;auto&quot;&gt;username&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Une authentification avec deux solutions possibles :
&lt;ul&gt;
&lt;li&gt;mot de passe classique dans ce cas il suffit de spécifier l’argument &lt;code dir=&quot;auto&quot;&gt;password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Clé ssh et dans ce cas il faut spécifier l’argument &lt;code dir=&quot;auto&quot;&gt;client_keys&lt;/code&gt; qui est une liste contenant la où les clés ssh ainsi que l’argument &lt;code dir=&quot;auto&quot;&gt;passphrase&lt;/code&gt; qui est donc la passphrase de la clé ssh.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;une-fois-connecté-exécuter-des-commandes-&quot;&gt;Une fois connecté, exécuter des commandes !&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Une fois la connection avec notre serveur établie nous pouvons commencer à faire des choses intéressantes (enfin ça dépend de vous ça). Mais pour commencer la méthode essentielle à connaître est la méthode &lt;a href=&quot;https://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHClientConnection.run&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;run&lt;/code&gt;&lt;/a&gt; qui comme son nom l’indique va nous permettre d’exécuter des commandes à distance. Dans sa version basique la méthode &lt;code dir=&quot;auto&quot;&gt;run&lt;/code&gt; prend une chaîne de caractère par exemple si je veux lancer la commande &lt;code dir=&quot;auto&quot;&gt;ls ~/Documents&lt;/code&gt; et bien c’est ce qu’on fait !&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;out &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; client.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ls ~/Documents&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Alors le &lt;code dir=&quot;auto&quot;&gt;out&lt;/code&gt; que l’on récupère est une instance de &lt;a href=&quot;https://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHCompletedProcess&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;asyncssh.SSHCompletedProcess&lt;/code&gt;&lt;/a&gt; on s’en fout un peu tout ce qu’il faut savoir c’est qu’il y a dans ce truc 3 attributs qui sont utiles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;out.returncode&lt;/code&gt; si différent de &lt;code dir=&quot;auto&quot;&gt;0&lt;/code&gt; y a un truc qui a planté quelque part !&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;out.stdout&lt;/code&gt; la sortie standard&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;out.stderr&lt;/code&gt; la sortie d’erreur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alors juste vous le savez peut-être mais suivant la commande que vous exécutez ne regardez pas que dans le &lt;code dir=&quot;auto&quot;&gt;stderr&lt;/code&gt; si vous avez des erreurs car il existe tout un tas de logiciels qui écrivent les erreurs dans le &lt;code dir=&quot;auto&quot;&gt;stdout&lt;/code&gt; et certain ont même le génie d’ecrire des infos dans le &lt;code dir=&quot;auto&quot;&gt;stderr&lt;/code&gt; …&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;ou-bien-lire-et-écrire-des-fichiers&quot;&gt;Ou bien lire et écrire des fichiers&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;De la même manière il est possible une fois la connection établie de lire et/ou écrire des fichiers via sftp si vous voulez tout savoir. Pour cela il suffit de créer un client sftp à partir du client ssh une fois la connexion établie.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; client.&lt;/span&gt;&lt;span&gt;start_sftp_client&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; sftp:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;## Read, write file, create directory, ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;## all on remote file system&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;pass&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Une fois le client sftp créé nous pouvons utiliser tout une ribambelle (oui j’aime bien ce mot) de méthodes par exemple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;sftp.exists( remote_path )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;sftp.mkdir( remote_path )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;sftp.open( fname, mode)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;sftp.chmod( remote_path, mode )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour la liste complète des méthodes &lt;a href=&quot;https://asyncssh.readthedocs.io/en/latest/api.html#sftpclient&quot;&gt;RTFM&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;et-avec-un-petit-rebond-cest-tout-aussi-simple-&quot;&gt;Et avec un petit rebond c’est tout aussi simple !&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Alors le truc génial 🤩 de la fonction &lt;code dir=&quot;auto&quot;&gt;asyncssh.connect&lt;/code&gt; est qu’elle accepte un argument optionnel &lt;code dir=&quot;auto&quot;&gt;tunnel&lt;/code&gt;. Cet argument permet de spécifier un client ssh déjà connecté. En gros si pour accéder à la machine &lt;code dir=&quot;auto&quot;&gt;machine-C&lt;/code&gt; depuis &lt;code dir=&quot;auto&quot;&gt;machine-A&lt;/code&gt; on doit forcément passer par la machine &lt;code dir=&quot;auto&quot;&gt;machine-B&lt;/code&gt; et bien avec cet argument &lt;code dir=&quot;auto&quot;&gt;tunnel&lt;/code&gt; ce sera super simple il suffira de faire un truc du genre :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;proxy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;machine-B&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;machine-C&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tunnel&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;proxy&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Il existe également une version avec context manager qui prends la forme suivante :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;machine-B&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; proxy:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;machine-C&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tunnel&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;proxy&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; client:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# do something crazy with my ssh client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;port-forwarding-et-tunnel-ssh&quot;&gt;Port forwarding et tunnel ssh&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour finir je vais vous montrer l’autre truc super sympa de &lt;code dir=&quot;auto&quot;&gt;asyncssh&lt;/code&gt; à savoir que l’on peut depuis un boût de Python construire un tunnel ssh qui va nous permettre de faire du port forwarding. Deux trucs sympa :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le même code va fonctionner sous Linux, Mac et Windows donc pas de prise de tête&lt;/li&gt;
&lt;li&gt;On peut comme ça automatiser et surtout cacher plein d’opérations aux end-users. Car je sais pas vous mais moi si je demande aux gens de faire un tunnel ssh à la main avec OpenSSH ma boite mail va exploser avec les “ça marche pas” !!&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; client:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;listener &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; client.&lt;/span&gt;&lt;span&gt;forward_local_port&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; local_port&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_ip&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_port&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; listener.&lt;/span&gt;&lt;span&gt;wait_closed&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Le Python précédent est équivalent à la commande OpenSSH suivante pour les connaisseurs :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;ssh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-L&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;local_port:remote_ip:remote_port&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username@hostname&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Bon alors par contre le code Python précédent est bloquant, c’est-à-dire qu’une fois le tunnel créé on ne peut rien faire d’autre ce qui peut s’avérer génant. Une solution assez simple pour ne pas se retrouver bloqué est simplement de déléguer la création du tunnel à un process séparé de notre process principal. Pour cela un petit coup de &lt;code dir=&quot;auto&quot;&gt;multiprocessing&lt;/code&gt; et ça roule !&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; asyncio&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; multiprocessing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; asyncssh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;standalone_tunnel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;local_port&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;remote_port&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;remote_ip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do_job&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;local_port&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;remote_port&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;remote_ip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt; asyncssh.&lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; client:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;listener &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; client.&lt;/span&gt;&lt;span&gt;forward_local_port&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; local_port&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_ip&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_port&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; listener.&lt;/span&gt;&lt;span&gt;wait_closed&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;asyncio.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;do_job&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; username&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; password&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; local_port&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_port&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; remote_ip&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;except&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Exception&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; e:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Port Forwarding Error : &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Sous Windows et macOS, protéger le démarrage du processus enfant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; __name__ &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;__main__&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; multiprocessing.&lt;/span&gt;&lt;span&gt;Process&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;standalone_tunnel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;(hostname, username, password, local_port, remote_port, remote_ip)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;p.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Je viens de vous montrer en mode express comment le module &lt;code dir=&quot;auto&quot;&gt;asyncssh&lt;/code&gt; de Python peut très facilement nous permettre de scripter des actions nécessitant des connections à des serveurs distants via ssh. Il y a évidemment plein d’applications possibles à cela mais je vais juste vous en présenter deux que j’ai eu à réaliser.&lt;/p&gt;
&lt;p&gt;La première application a été la mise en place d’un outil pour faire de la visualisation distante. En effet à partir de Mars 2020 et une certaine pandémie mondiale il a fallu dans le labo où je suis que les utilisateurs puissent travailler à distance, notamment avec des softs disposant d’interface graphique un peu lourde. Pour cela j’ai développé une solution assez simple où chaque utilisateur lance sur un serveur du labo un serveur VNC et ensuite via un tunnel ssh (qui forward le port VNC de l’utilisateur vers un port local de son portable en faisant un rebond via la passerelle ssh) peut accéder à sa session graphique via le client VNC installé localement. Et bien évidemment si je demande aux utilisateurs de faire tout ça à la main 🤯 donc j’ai packagé tout ça dans une petite application Python à base de asyncssh et PyQt pour le graphique et en deux clics les utilisateurs peuvent se connecter !&lt;/p&gt;
&lt;p&gt;La seconde application que j’ai pu avoir de &lt;code dir=&quot;auto&quot;&gt;asyncssh&lt;/code&gt; est le développement d’un utilitaire Python pour lancer un jupyter notebook sur un noeuds de calcul du cluster et faire le port forwarding qui va bien pour que l’utilisateur puisse ensuite ouvrir son notebook et travailler dans son navigateur en local. Pour cela le process est assez simple :&lt;/p&gt;
&lt;ol role=&quot;list&quot;&gt;
&lt;li&gt;Connexion à la frontal du cluster (besoin de deux rebonds dans mon cas mais facile avec asyncssh 😜)&lt;/li&gt;
&lt;li&gt;Ecriture sur le filesystem du cluster d’un script de soumission pour le gestionnaire de job (slurm)&lt;/li&gt;
&lt;li&gt;Soumission du job slurm&lt;/li&gt;
&lt;li&gt;Une fois le job slurm commencé, ouverture des fichiers de log du job pour récupérer le nom sur lequel le job est parti et le port sur lequel jupyter a démarré&lt;/li&gt;
&lt;li&gt;Connexion ssh au noeud du cluster où mon job tourne&lt;/li&gt;
&lt;li&gt;Création du tunnel ssh pour le port forwarding&lt;/li&gt;
&lt;li&gt;C’est bon il n’y a plus qu’à ouvrir son navigateur 📓&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Pour aller plus loin :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bmarchand.fr/blog/flask_notion/&quot;&gt;Tutoriel : Flask et Notion comme base de données&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bmarchand.fr/blog/python_314_nogil/&quot;&gt;Python 3.14 sans GIL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bmarchand.fr/teaching/informatique/&quot;&gt;Cours Informatique&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>python</category><category>asyncssh</category></item><item><title>Tutoriel : Flask et Notion comme base de données</title><link>https://bmarchand.fr/blog/flask_notion/</link><guid isPermaLink="true">https://bmarchand.fr/blog/flask_notion/</guid><description>Tutoriel pas à pas : construire une application Flask qui utilise Notion comme base de données, déploiement gratuit sur Vercel.</description><pubDate>Fri, 23 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Dans cet article, nous allons parcourir le processus de création d’une application web avec Flask, qui permet aux utilisateurs de saisir des informations via un formulaire et stocke ces données dans une base de données Notion. Nous couvrirons ensuite comment déployer &lt;strong&gt;gratuitement&lt;/strong&gt; cette application sur Vercel !!&lt;/p&gt;
&lt;p&gt;L’intégralité du code est disponible sur &lt;a href=&quot;https://github.com/basileMarchand/flask-notion-demo&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;github-repo data-url=&quot;https://github.com/basileMarchand/flask-notion-demo&quot;&gt;&lt;article aria-label=&quot;Dépôt flask-notion-demo&quot;&gt;&lt;a href=&quot;https://github.com/basileMarchand/flask-notion-demo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;strong&gt;flask-notion-demo&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;Example of Python Flask App with Notion database storage&lt;/p&gt;&lt;div&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;span data-language-name=&quot;&quot;&gt;Python&lt;/span&gt;&lt;/span&gt;&lt;span data-forks=&quot;&quot; aria-label=&quot;0 forks&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;🍴 &lt;/span&gt;&lt;span data-forks-count=&quot;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p role=&quot;status&quot;&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; hidden&gt;Réessayer&lt;/button&gt;&lt;/article&gt;&lt;/github-repo&gt;
&lt;div&gt;&lt;h2 id=&quot;prérequis&quot;&gt;Prérequis&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour suivre ce tutoriel, vous avez besoin des éléments suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connaissance de base en Python&lt;/li&gt;
&lt;li&gt;Notions de base du développement web (HTML)&lt;/li&gt;
&lt;li&gt;Compte Notion avec accès à l’API (si ça vous parle pas, pas de panique on va voir ça ensemble 🤗)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;étape-1️⃣--configuration-de-lenvironnement&quot;&gt;Étape 1️⃣ : Configuration de l’Environnement&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Installez Flask, Flask-WTF, et Requests dans votre environnement Python :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;install requirements&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;pip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Flask&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Flask-WTF&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;requests&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;étape-2️⃣--création-de-lapplication-flask&quot;&gt;Étape 2️⃣ : Création de l’Application Flask&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;structure-de-lapplication&quot;&gt;Structure de l’Application&lt;/h3&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;app.py&lt;/code&gt; : Le fichier principal de l’application Flask.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;templates/&lt;/code&gt; : Un dossier contenant les templates HTML pour le formulaire et l’affichage des données.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h3 id=&quot;définition-du-formulaire&quot;&gt;Définition du Formulaire&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;On commence par définir la structure de notre formulaire en créant une classe qui hérite de FlaskForm. Chaque champ du formulaire est représenté par un objet (par exemple, &lt;code dir=&quot;auto&quot;&gt;StringField&lt;/code&gt; pour du texte, &lt;code dir=&quot;auto&quot;&gt;SelectField&lt;/code&gt; pour une liste déroulante) avec des validateurs pour imposer certaines règles (comme &lt;code dir=&quot;auto&quot;&gt;DataRequired&lt;/code&gt; pour les champs obligatoires, &lt;code dir=&quot;auto&quot;&gt;Email&lt;/code&gt; pour valider les adresses email).&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; flask_wtf &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FlaskForm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; wtforms &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; StringField, SelectField, SubmitField&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; wtforms.validators &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; DataRequired, Email&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UserForm&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;FlaskForm&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;nom &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringField&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Nom&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;validators&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;DataRequired&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;prenom &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringField&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Prénom&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;validators&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;DataRequired&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;mail &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringField&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Email&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;validators&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;DataRequired&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Email&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;humeur &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SelectField&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Humeur&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;happy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Happy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;), (&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;sad&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Sad&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;validators&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;DataRequired&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;submit &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SubmitField&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Envoyer&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Dans cet exemple, &lt;code dir=&quot;auto&quot;&gt;StringField&lt;/code&gt; et &lt;code dir=&quot;auto&quot;&gt;SelectField&lt;/code&gt; sont utilisés pour créer des champs de texte et une liste déroulante, respectivement. La liste des choix pour humeur est définie par un ensemble de tuples, où chaque tuple contient le code interne et l’affichage de l’option.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;intégration-du-formulaire-dans-une-vue-flask&quot;&gt;Intégration du formulaire dans une vue Flask&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Après avoir défini la classe de formulaire, intégrez-la dans une vue Flask. Lorsque la route est sollicitée via &lt;code dir=&quot;auto&quot;&gt;GET&lt;/code&gt;, le formulaire est affiché à l’utilisateur. Si la méthode est POST et que le formulaire est validé, vous pouvez traiter les données.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@app.route&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;methods&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;GET&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;home&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;form &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UserForm&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; form.&lt;/span&gt;&lt;span&gt;validate_on_submit&lt;/span&gt;&lt;span&gt;():&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# Traitement des données du formulaire&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;nom &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; form.nom.data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;prenom &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; form.prenom.data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;mail &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; form.mail.data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;humeur &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; form.humeur.data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# C&apos;est ici qu&apos;on va envoyer  les données à Notion&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# on voit ça un peu plus tard 🔥&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url_for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;home&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;))  &lt;/span&gt;&lt;span&gt;# Redirection après le traitement&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;render_template&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;formulaire.html&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;rendu-du-formulaire-dans-un-template-html&quot;&gt;Rendu du formulaire dans un template HTML&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Dans votre template HTML, utilisez les objets de formulaire passés depuis la vue pour générer le HTML du formulaire. Flask-WTF et WTForms facilitent cette tâche en offrant des méthodes pour rendre chaque champ ainsi que leurs labels et erreurs potentielles.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;action&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.hidden_tag() }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.nom.label }} {{ form.nom() }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.prenom.label }} {{ form.prenom() }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.mail.label }} {{ form.mail() }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.humeur.label }} {{ form.humeur() }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ form.submit() }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;{{ form.hidden_tag() }}&lt;/code&gt; est utilisé pour inclure un token CSRF, qui protège contre les attaques de type Cross-Site Request Forgery. Chaque champ est rendu avec son label (&lt;code dir=&quot;auto&quot;&gt;{{ form.nom.label }}&lt;/code&gt;) et le champ lui-même (&lt;code dir=&quot;auto&quot;&gt;{{ form.nom() }}&lt;/code&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;on-ajoute-une-route-pour-afficher-les-données&quot;&gt;On ajoute une route pour afficher les données&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;On ajoute simplement une route qui permet d’afficher les données stockées dans la base de données Notion.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@app.route&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;/database&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;voir_database&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;donnees &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# On récupère les données de la base de données Notion&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# On voit ça un peu plus tard 🔥&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;render_template&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;database.html&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;donnees&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;donnees&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Le template HTML associé est le suivant :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lang&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;fr&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;meta&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;charset&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;UTF-8&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Visualisation de la Base de Données&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Données de la Base&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;border&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;thead&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;tr&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Nom&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Prénom&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Email&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Humeur&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;th&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;tr&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;thead&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;tbody&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{% for item in donnees %}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;tr&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ item[&apos;Nom&apos;] }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ item[&apos;Prénom&apos;] }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ item[&apos;Email&apos;] }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{ item[&apos;Humeur&apos;] }}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;td&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;tr&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{% endfor %}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;tbody&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;étape-3️⃣--utilisation-de-notion-comme-base-de-données&quot;&gt;Étape 3️⃣ : Utilisation de Notion comme Base de Données&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;configuration-de-lapi-notion&quot;&gt;Configuration de l’API Notion&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Pour interagir avec l’API Notion et automatiser des tâches telles que la création de pages ou la récupération de données depuis une base de données Notion, vous aurez besoin d’un token d’intégration. Ce token agit comme une clé d’API, vous permettant d’authentifier vos requêtes à l’API Notion. Voici comment vous pouvez générer ce token.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;création-dune-intégration&quot;&gt;Création d’une Intégration&lt;/h4&gt;&lt;/div&gt;
&lt;ol role=&quot;list&quot;&gt;
&lt;li&gt;Accédez à votre compte Notion : Connectez-vous à votre compte Notion où vous souhaitez utiliser l’API.&lt;/li&gt;
&lt;li&gt;Ouvrez les paramètres d’intégration : Dans le coin inférieur gauche de l’interface Notion, cliquez sur votre avatar ou initiales, puis sélectionnez “Paramètres &amp;#x26; Membres”. Dans le menu latéral, choisissez l’onglet “Intégrations”.&lt;/li&gt;
&lt;li&gt;Créez une nouvelle intégration : Cliquez sur le bouton “Nouvelle intégration”. Remplissez le formulaire avec les détails de votre intégration :
&lt;ul&gt;
&lt;li&gt;Nom de l’intégration : Donnez un nom à votre intégration. Choisissez quelque chose de descriptif pour vous rappeler à quoi sert cette intégration.&lt;/li&gt;
&lt;li&gt;Capacités d’intégration : Laissez les options par défaut ou ajustez-les selon vos besoins.&lt;/li&gt;
&lt;li&gt;Associez à un espace de travail : Sélectionnez l’espace de travail Notion où vous souhaitez utiliser cette intégration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Soumettez le formulaire : Après avoir rempli les détails, cliquez sur “Soumettre” pour créer l’intégration.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;h4 id=&quot;récupérer-le-token-dintégration&quot;&gt;Récupérer le token d’intégration&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Une fois l’intégration créée, Notion affichera un token d’intégration (aussi appelé “Secret interne”). Copiez ce token et gardez-le en sécurité ; vous en aurez besoin pour authentifier vos requêtes à l’API Notion. Ce token est sensible et doit être traité comme un mot de passe.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;partager-une-base-de-données-avec-lintégration&quot;&gt;Partager une base de données avec l’intégration&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Pour que votre intégration puisse accéder à une base de données Notion spécifique, vous devez partager cette base de données avec l’intégration.&lt;/p&gt;
&lt;ol role=&quot;list&quot;&gt;
&lt;li&gt;Ouvrez la base de données dans Notion que vous souhaitez connecter à votre intégration.&lt;/li&gt;
&lt;li&gt;Cliquez sur “Partager” dans le coin supérieur droit de la page de la base de données.&lt;/li&gt;
&lt;li&gt;Ajoutez votre intégration : Dans le menu de partage, tapez le nom de l’intégration que vous avez créée et sélectionnez-la dans la liste. Cela donnera à l’intégration l’accès à la base de données.&lt;/li&gt;
&lt;li&gt;Ajustez les permissions si nécessaire : Assurez-vous que l’intégration a les permissions adéquates pour réaliser les actions que vous prévoyez (lire, écrire, etc.).&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;h4 id=&quot;stocker-le-token-dintégration-et-lid-de-la-base-de-données&quot;&gt;Stocker le token d’intégration et l’ID de la base de données&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Pour utiliser le token d’intégration et l’ID de la base de données dans votre application Flask, vous pouvez les stocker dans des variables d’environnement. Cela vous permet de garder ces informations sensibles en sécurité et de les utiliser dans votre application sans les exposer directement dans votre code.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;NOTION_API_KEY&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;NOTION_API_KEY&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_ID&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;DATABASE_ID&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Vous pouvez également utiliser un fichier &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; pour stocker ces variables d’environnement. Pour cela, vous pouvez utiliser la bibliothèque &lt;code dir=&quot;auto&quot;&gt;python-dotenv&lt;/code&gt; pour charger ces variables dans votre application Flask.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; dotenv &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; load_dotenv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;load_dotenv&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;⚠️ Pensez à ajouter le fichier &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; à votre fichier &lt;code dir=&quot;auto&quot;&gt;.gitignore&lt;/code&gt; pour éviter de le partager publiquement.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;utilisation-de-lapi-notion&quot;&gt;Utilisation de l’API Notion&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Pour interagir avec l’API Notion, on va utiliser la bibliothèque &lt;code dir=&quot;auto&quot;&gt;requests&lt;/code&gt; pour envoyer des requêtes HTTP à l’API Notion. Pour un usage avancé vous êtes invité à lire la &lt;a href=&quot;https://developers.notion.com/reference/intro&quot;&gt;documentation&lt;/a&gt; officielle de l’API Notion.&lt;/p&gt;
&lt;p&gt;Pour l’exemple que l’on traite ici nous avons besoin de deux fonctions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La première pour créer une nouvelle page dans une base de données Notion correspondant aux données saisies par l’utilisateur.&lt;/li&gt;
&lt;li&gt;La seconde pour récupérer les données de la base de données Notion et les afficher dans la page &lt;code dir=&quot;auto&quot;&gt;database.html&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La première fonction peut donc ressembler à ceci (pour bien comprendre la structure il faut vraiment aller voir la &lt;a href=&quot;https://developers.notion.com/reference/intro&quot;&gt;documentation&lt;/a&gt; de l’API Notion) :&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;push_to_notion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nom&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;prenom&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;mail&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;humeur&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;url &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://api.notion.com/v1/pages&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;token &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;NOTION_API_KEY&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;database_id &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;DATABASE_ID&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;headers &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Authorization&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Bearer &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;token&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Content-Type&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;application/json&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Notion-Version&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2022-06-28&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;data &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;database_id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: database_id},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Nom&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: nom}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Prénom&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;rich_text&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: prenom}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Email&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: mail&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Humeur&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: humeur}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;response &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; requests.&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; response.status_code &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Data sent to Notion&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Fail to sent data : &lt;/span&gt;&lt;span&gt;{response.text}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Pour visualiser les entrées existantes, c’est un peu plus simple. Il suffit d’envoyer une requête POST à l’endpoint &lt;code dir=&quot;auto&quot;&gt;/v1/databases/{database_id}/query&lt;/code&gt; de l’API Notion, en remplaçant &lt;code dir=&quot;auto&quot;&gt;{database_id}&lt;/code&gt; par l’ID de votre base de données. Cette requête ne nécessite pas de corps de requête pour récupérer toutes les entrées, mais peut être personnalisée pour filtrer les résultats si besoin.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pull_from_notion&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;url &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;https://api.notion.com/v1/databases/&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;DATABASE_ID&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/query&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;headers &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Authorization&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Bearer &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;os.environ.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;NOTION_API_KEY&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Notion-Version&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2022-06-28&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;response &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; requests.&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; response.status_code &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;entries &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; response.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;results&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# Traitement des données, extraction et transformation selon les besoins&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&quot;Erreur lors de la récupération des données : &lt;/span&gt;&lt;span&gt;{response.text}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;étape-4️⃣--déploiement-de-lapplication-sur-vercel&quot;&gt;Étape 4️⃣ : Déploiement de l’Application sur Vercel&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Pour finir on va voir comment déployer gratuitement notre application en ligne. On va passer par le service de déploiement Vercel. Il en existe d’autre que vous pouvez utiliser comme Heroku par exemple. Tout d’abord il faut créer un compte sur &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;configuration-de-lenvironnement&quot;&gt;Configuration de l’Environnement&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Pour déployer votre application Flask sur Vercel, vous devez ajouter un fichier &lt;code dir=&quot;auto&quot;&gt;vercel.json&lt;/code&gt; à la racine de votre projet. Ce fichier contient des informations sur votre application, telles que les paramètres de déploiement, les variables d’environnement, etc.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;version&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;builds&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&quot;src&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;app.py&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&quot;use&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;@vercel/python&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;routes&quot;&lt;/span&gt;&lt;span&gt;: [{ &lt;/span&gt;&lt;span&gt;&quot;src&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/.*&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;dest&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;app.py&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; }]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Il faut également spécifier les dépendances de l’application dans un fichier &lt;code dir=&quot;auto&quot;&gt;requirements.txt&lt;/code&gt; à la racine de votre projet. Dans notre cas il s’agit de &lt;code dir=&quot;auto&quot;&gt;Flask&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Flask-WTF&lt;/code&gt;, et &lt;code dir=&quot;auto&quot;&gt;requests&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Flask==2.0.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Flask-WTF==0.15.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;requests==2.26.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;🔑 Pour spécifier à votre application les NOTION_API_KEY et DATABASE_ID il faut que vous passiez par le site de Vercel pour configurer des variables spécifiques à votre déploiement. Cela ne peut-être fait qu’une fois le projet connu de Vercel, ce que l’on voit juste en dessous.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;déploiement-de-lapplication&quot;&gt;Déploiement de l’Application&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Pour déployer votre application sur Vercel, vous pouvez utiliser l’interface en ligne ou l’interface en ligne de commande. Pour l’interface en ligne, il suffit de suivre les étapes suivantes :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connectez-vous à votre compte Vercel.&lt;/li&gt;
&lt;li&gt;Cliquez sur “Nouveau Projet” pour importer votre application.&lt;/li&gt;
&lt;li&gt;Suivez les étapes pour importer votre application depuis un dépôt Git (GitHub, GitLab, Bitbucket, etc.).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pour l’interface en ligne de commande, vous pouvez utiliser la commande &lt;code dir=&quot;auto&quot;&gt;vercel&lt;/code&gt; pour déployer votre application. Assurez-vous d’avoir installé le &lt;a href=&quot;https://vercel.com/download&quot;&gt;CLI Vercel&lt;/a&gt; sur votre machine.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;vercel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Suivez les étapes pour déployer votre application. Vous pouvez également spécifier des variables d’environnement pour votre application lors du déploiement.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Et voilà, vous avez maintenant une application Flask qui stocke les données dans une base de données Notion et qui est déployée gratuitement sur Vercel ! Vous pouvez maintenant partager votre application avec le monde entier 🚀&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour aller plus loin :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bmarchand.fr/blog/asyncssh/&quot;&gt;Asyncssh : automatiser SSH et tunnels en Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bmarchand.fr/teaching/network/&quot;&gt;Réseaux et Web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data=&quot;https://github.com/basileMarchand/flask-notion-demo&quot;&gt;&lt;/div&gt;</content:encoded><category>python</category><category>flask</category><category>notion</category></item></channel></rss>