Nous aurons deux présentations au programme de cette session accueillie chez notre sponsor Liksi (merci) :
Plaidoyer pour un monde sans ORM
SQL avancé (via ORM Django)
1. Plaidoyer pour un monde sans ORM
Jonathan Leger - ingénieur logiciel à Scaleway (profil LinkedIn)
Retours d’expérience sur l’utilisation des ORM SQL en Python dans le domaine de la facturation
2. SQL avancé (via ORM Django)
Anthony Ricaud - lead product engineer, indépendant (profil LinkedIn)
Présentation et retour d’expérience sur l’utilisation de quelques fonctions avancées de SQL. On évoquera colonnes générées, index partiels, index couvrants. En bonus, on verra leur utilisation via l’ORM de Django.
Sponsor
Merci à Liksi d’accueillir cette session au 37 boulevard Solférino, et pour l’apéritif convivial qui suivra. L’inscription est gratuite, elle permet de dimensionner l’apéro ; elle engage donc à venir ou à libérer sa place en cas d’indisponibilité soudaine
L’évènement est ouvert à toute personne intéressée par ces sujets, dans la limite de la jauge de 45 personnes. Une rediffusion sera disponible sur la chaîne YouTube du BreizhCamp quelques jours plus tard.
Mon équipe à la Plateforme de l’inclusion, un groupement d’intérêt public issu de Beta.gouv, recrute un·e développeur·se Django senior.
En résumé : applications publiques (.gouv.fr), code source sur GitHub, équipe très solide et sympa, code de qualité, excellente couverture de test. Poste en freelance ou CDD, temps partiel 4j/semaine ou équivalent. Télétravail total possible (avec bureaux dispos à Paris ou Lyon).
Auberge espagnole : apportez à boire et à manger que vous voudrez bien partager avec les autres participant.e.s.
Localisation : l’entrée du Yack est discrète : avant de venir, prenez soin de consulter la carte ainsi que la photo de l’entrée ci-dessous. Le bâtiment 19 aura un fléchage avec des feuilles A4.
Cher journal, ça fait quelque temps (première tentative de réponse en 2019…) que je me pose ces questions : existe-t-il un déphasage entre le prix des carburants à la pompe et le prix du pétrole brut ? Si oui, quelle est sa durée ? Dépend-il de la hausse ou de la baisse des cours ? En anglais on parle de "rocket and feathers effect" : les prix montent-ils comme une fusée et redescendent-ils comme une plume ?
Niveau recherche bibliographique sur ce sujet, je n'ai rien fait.
Mon analyse se cantonnera au Gazole et SP95, carburants pour lesquels les données disponibles pour la France sont continues depuis 2007.
Avertissement :
je ne suis pas statisticien, encore moins économétricien.
j'ai demandé un coup de main aux modèles d'IA suivants : OpenAI ChatGPT, Google Gemini et Microsoft Copilot. Pour cette étude, le premier est clairement le plus pertinent. Là où tous se valent pour de la syntaxe de base python/dataframe ou pour optimiser un peu la lecture des fichiers XML, j'ai trouvé que ChatGPT apportait vraiment une plus-value critique sur le code, sur l'analyse que je voulais mener et sur des propositions d'améliorations de méthodologie.
C'est parti !
Avant de s'attaquer aux carburants, intéressons-nous à leur origine : le pétrole brut.
Pétroles bruts et carburants raffinés
Il existe plusieurs pétroles bruts, nommés en fonction de leur origine géographique.
Les plus connus sont le Brent de mer du Nord et le WTI américain (West Texas Intermediate). La très grande majorité des bruts échangés sur les marchés financiers ont des prix indexés sur le Brent ou le WTI. À titre d'exemple il existe, entre autres, les bruts suivants : le Arab Light, le Dubai Crude, le Murban ou le Urals.
Comme les choses sont bien faites™, Brent et WTI ont des cours boursiers 'très' proches (sauf à de rares occasions[1]) ce qui permet de faire le raccourci suivant sans trop d'erreur : "LE" prix du brut.
Les cours des bruts sont ainsi une signature (d'une partie) de l'histoire géopolitique.
On observe aussi une forte augmentation de fréquence et d'amplitude du cours des bruts, ça devient vraiment chaotique ! Pas sûr que ça soit rassurant.
Carburants raffinés
Le gouvernement français met à notre disposition des archives des prix des carburants, point de distribution par point de distribution depuis 2007 ! Les données sont disponibles en Open Data : https://www.prix-carburants.gouv.fr/rubrique/opendata/
for i in $(seq 20072026);do wget https://donnees.roulez-eco.fr/opendata/annee/$i -O $i.zip;donefor i in *.zip;do unzip $i;done
Un peu plus de 400 Mo d'archive et 4.3 Go de xml décompressé.
On charge tout ça dans une DataFrame qui a un peu plus de 62 millions de lignes ! (N.B. : prévoyez de la RAM, chez moi ça en a pris ~22 Go pour parser tout ça)
En agrégeant par jour ça devient nettement plus raisonnable : 39000 lignes.
On a ainsi une ligne par jour avec la moyenne, le minimum, le maximum et l'écart-type.
À partir de 2016, on observe que le prix du gazole rejoint celui du sans-plomb. C'est purement un effet fiscal. On le voit d'autant mieux en faisant la différence entre les deux carburants :
Quand vous entendez nos chers commentateurs économistes parler de spread, c'est ça : la différence entre 2 indicateurs (et son évolution au cours du temps).
En comparant deux périodes de 4,5 ans autour de ce changement de fiscalité : on était en moyenne à +20 centimes sur le litre de SP95 sur la première période, contre +10 centimes sur la seconde période.
Mais revenons à nos moutons : y a-t-il des corrélations entre le prix du carburant et celui du brut.
Corrélations
Pour chercher des corrélations, il faut comparer des choux avec des choux. Pour le moment on a vu des cours de bruts en dollars US par baril et des prix de carburants en euros par litre.
La première chose à faire est de passer le prix du brut de US$ par baril en € par L en tenant compte de l'évolution du taux de change € ↔ US$. On lira au passage que le barrel oil utilisé est issu de la normalisation du volume des barils en bois utilisés par l'industrie pétrolière américaine au XIXᵉ siècle. Un baril valait 42 gallons US soit ~159 L. On se retrouve alors à comparer des carburants en €/L avec du brut en €/L. On avance, mais, en France, nos litres de carburants sont taxés !
La seconde chose à faire est de tenir compte de ces taxes (et de leurs évolutions au cours du temps bien sûr) pour deux raisons : elles constituent une part fixe et significative du prix final à la pompe, sans corrélation avec le prix de la matière première et elles évoluent au cours du temps. On est ainsi passé de la TIPP (Taxe Intérieure sur les Produits Pétroliers) introduite en 1976 à la TICPE (Taxe Intérieure de Consommation sur les Produits Énergétiques) en 2011[2], elle-même remplacée par l'"Accise sur les produits énergétiques autres que les gaz naturels et les charbons" (on n'a même plus fait l'effort de trouver un bel acronyme, APEAGNC ?). Ces dernières incluent depuis 2014 la "Taxe Carbone" ("Contribution Climat Énergie"). Enfin nous n'oublierons pas la TVA qui a pour assiette le produit hors taxe et l'APEAGNC! Bien évidemment tout ça dépend du carburant.
Bon là, il faut commencer à faire de l'archéologie parce que trouver des sources fiables sur les évolutions de ces taxes depuis 2007 est compliqué. Outre les changements de noms, il faudrait se palucher toutes les lois de finances et décrets d'applications pour obtenir les valeurs exactes. Tu t'en doutes cher journal, je n'ai pas fait ça. J'ai demandé à mes AmIes de m'en faire un résumé. Elles n'étaient pas trop en désaccord les unes avec les autres (figure) mais ça reste des pincettes à ajouter aux précautions qu'on prendra pour interpréter les résultats de l'analyse.
Par flemme, et parce que je passe déjà bien plus de temps qu'imaginé à explorer tant de subtilités, mon analyse ne retire pas les coûts de raffinage, de transport et les marges des vendeurs finaux (ou tout autre facteur que mon esprit n'imagine même pas).
Vouloir établir des corrélations sur presque 20 ans d'histoire économique, c'est osé.
Corrélation simple
En utilisant un premier modèle, on obtient le graphique suivant :
On y remarque deux choses :
les coefficients de corrélation ne sont pas bien élevés : plus ils sont proches de 1, plus le modèle représente les données avec fidélité. Compte tenu des limites de l'analyse et de tout ce dont le modèle ne tient pas compte, il est quand même intéressant de voir une corrélation statistiquement significative.
les coefficients de corrélation sont différents selon que le brut est à la hausse ou à la baisse. On a là une première indication d'un effet fusée / plume. Lorsque le brut est à la hausse, l'impact sur le prix du gazole est le plus important dès le lendemain. Tandis que pour un brut à la baisse, il faut attendre entre 2 et 3 jours pour voir un effet sur le prix à la pompe.
Ce modèle de corrélation simple ne prend pas en compte différents phénomènes, par exemple le fait que tout s'enchaine : la baisse du brut du jour J a un impact à partir de J+2, mais le cours du brut à J+1 peut aussi affecter les prix à J+2 (quand le Brent à la hausse) etc.
Pour affiner, on peut utiliser une régression linéaire par moindres carrés. Ici je n'invente rien non plus, j'utilise un modèle fourni par StatsModels. Et comme on dépasse déjà les limites de mes connaissances en statistiques et que je ne veux pas raconter trop de conneries, je n'irai guère plus loin.
L'avantage de ce modèle par rapport au précédent est qu'il permet de distinguer les effets de chaque délai. Par exemple : après avoir pris en compte tous les délais jusqu'à 10 jours, est-ce que le délai au jour 2 importe toujours ?
En pratique la différence avec le modèle précédent est très faible :
On a toujours un effet majeur à J+1 en cas de hausse du brut et un effet important seulement à partir de J+2 en cas de baisse.
Un des gros avantages, c'est qu'on a maintenant des intervalles de confiance qui nous indiquent à partir de quand les changements ne sont plus significatifs. Ici on voit que à partir de J+6, la hausse du brut au jour J n'a plus d'influence alors qu'en cas de baisse, il faut attendre J+9 pour que tous les effets soient estompés.
Conclusions
Oui, cette analyse imparfaite met en évidence un effet "fusée/plume" mesurable. Avec ces données et les hypothèses retenues, le prix des carburants à la pompe monte plus rapidement qu'il ne redescend. Mais cet effet n'est pas dramatique ni outrageusement dissymétrique, on parle d'une seule journée de décalage à la hausse contre 2 à 3 jours pour que la majorité d'une baisse du brut soit répercuté en station.
J'ai une quantification temporelle de la réponse à mes questions initiales. J'ai appris des choses et découvert de nouveaux outils.
Je connaissais Jupyter-notebook et les dataframes de pandas, je me suis essayé à utiliser proprement les venv, uv pour installer n'importe quel paquet python en un éclair, ty et ruff pour trouver des bugs dans mon code avant de le lancer (non je n'ai pas d'actions chez AstralOpenAI). J'ai découvert aussi jupytext qui permet d'avoir une version texte en clair d'un jupyter notebook, de travailler dessus, surtout pour le mettre en forme automatiquement avec black par exemple, et pouvoir le réinjecter dans le notebook tout en conservant le résultat de l'exécution de chaque cellule ! Et en facilitant le versionnage.
Il serait intéressant de mener la même étude, soit avec le SP95, soit sur des périodes plus restreintes pour voir si les corrélations y sont plus marquées voire si elles changent. Partir du brut pour aller en station est aussi un grand écart économique pour lequel j'ai fait de nombreux raccourcis, utiliser les "spot prices de Rotterdam" qui intègrent en autres les coûts de raffinage aurait pu être plus judicieux et plus juste mais je les ai découverts en fin d'analyse (et c'est là encore tout un monde avec ses acronymes et ses subtilités).
Une dernière image pour la route :
Oui ça n'a rien à voir mais c'est mon journal !
Dans un autre style vous pouvez tester Hypercube de Nathan Fake, découvert grâce à [DEEP]Search de Laurent Garnier sur FIP.
U.S. Energy Information Administration, Crude Oil Prices: Brent - Europe [DCOILBRENTEU], retrieved from FRED, Federal Reserve Bank of St. Louis;
https://fred.stlouisfed.org/series/DCOILBRENTEU
U.S. Energy Information Administration, Crude Oil Prices: West Texas Intermediate (WTI) - Cushing, Oklahoma [DCOILWTICO], retrieved from FRED, Federal Reserve Bank of St. Louis;
https://fred.stlouisfed.org/series/DCOILWTICO
Trognoncal est un moteur d’agenda culturel participatif dont le développement a débuté en 2023, et dont la première instance a été lancée en septembre 2024 pour le Puy-de-Dôme à l’adresse https://pommesdelune.fr/.
Développé en python/django, il s’appuie sur une pile logicielle intégrant celery et selenium, afin de récupérer chaque nuit les événements publiés sur les sites internet des organisateurs d’événements.
Sous Unix, un fichier Makefile est le moyen classique d’exécuter diverses tâches (en premier lieu des compilations de binaires). Récemment, deux outils (just et task) ont gagné en popularité. Ils ont le même objectif, tout en cherchant à être plus adaptés aux usages de développement actuels.
L’installation des différents outils est simple :
Le binaire make est dans le paquet make (incroyable !) et est probablement déjà installé.
Le binaire just est dans le paquet just (bis).
Debian ne contient pas de paquet task. Un binaire task est bien disponible dans le paquet taskwarrior mais c’est un outil pour décompter le temps passé. Les développeurs de Taskfile fournissent un paquet Debian, déclaré comme incompatible avec taskwarrior à cause du nom identique de l’exécutable. Compiler le binaire soi-même est facile une fois que les outils pour compiler du Go sont déjà présents sur la machine.
A. Formats de fichier
Voici des exemples minimaux pour les trois outils :
1. Makefile
cible:
commande
Les fichiers Makefile utilisent des tabulations. Aujourd’hui, on s’attend plutôt à des espaces. Un éditeur correct sait déjà le gérer donc ça ne devrait pas être vraiment un problème mais peut surprendre un nouvel arrivant.
2. Justfile
cible:
commande
Il n’y a pas de différence visible avec le Makefile précédent car les fichiers Justfile en sont proches. Le format est simple et utilise des espaces plutôt que des tabulations.
C’est un format spécifique que les autres outils ne prennent pas toujours bien en charge (ou pas par défaut). Par exemple, bat (dans le paquet Debian nommé batcat) ou pygments ne savent pas faire de la coloration syntaxique sur ce format. Par contre, il existe des greffons pour Codium ou pour emacs (par exemple, just-mode, son code source et le dépôt Melpa), etc. De même, WordPress ne le prend pas en compte donc tous les codes source de Justfile ne bénéficieront pas de coloration syntaxique dans cet article.
Exemple de fichier Justfile dans Codium
3. Taskfile
version:'3'
tasks:
cible:
cmd: commande
Taskfile réutilise le format YAML. Cela permet d’avoir une syntaxe connue et un outillage déjà prêt (coloration syntaxique et vérification de la syntaxe). Cependant, cela donne aussi des contenus plus verbeux que les Justfiles.
À noter que la ligne version est indispensable aux Taskfile car des versions antérieures du format de fichier sont incompatibles.
B. Exemples équivalents
Voici trois fichiers d’exemple montrant les mêmes commandes basiques pour les Makefile, Justfile et Taskfile :
1. Makefile
BINNAME = hellomake
.PHONY: build clean test
build: ## Compile le binaire
gcc -o $(BINNAME) main.c
./gen_assets.sh
clean: ## Supprime les fichiers générés
rm -f $(BINNAME)
test: ## Exécute les tests
./tests.sh
Historiquement, les Makefile étaient (et sont encore) utilisés pour produire des fichiers. Les cibles peuvent être des fichiers et donc on se retrouve régulièrement à utiliser .PHONY. C’est pratique mais ça ne me semble pas très élégant.
2. Justfile
BINNAME := "hellojust"
# Compile le binaire
build:
gcc -o {{BINNAME}} main.c
./gen_assets.sh
# Supprime les fichiers générés
clean:
rm -f {{BINNAME}}
# Exécute les tests
test:
./tests.sh
La syntaxe reste très proche d’un Makefile. En terme de possibilité, il n’y a pas de dépendances sur les fichiers pour exécuter (ou non) une commande.
3. Taskfile.yml
version:'3'
vars:
BINNAME: hellotask
tasks:
build:
desc: Compile le binaire
cmds:
- gcc -o {{.BINNAME}} main.c
- ./gen_assets.sh
clean:
desc: Supprime les fichiers générés
cmd: rm -f {{.BINNAME}}
test:
desc: Exécute les tests
cmd: ./tests.sh
Le format YAML permet de faire des listes ou de laisser sur une seule ligne s’il n’y a qu’une seule instruction (cf. cmd). L’ensemble des attributs rend le contenu assez explicite. Il n’y a pas de dépendances sur les fichiers (comme just).
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
[...]
$ make staticserver PORT=8888
python3 -m http.server 8888
Serving HTTP on 0.0.0.0 port 8888 (http://0.0.0.0:8888/) ...
2. Justfile
Justfile a des paramètres avec des valeurs par défaut :
staticserver port="8000":
python3 -m http.server {{port}}
Le résultat dans un terminal :
$ just staticserver
python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) …
[...]
$ just staticserver 8888
python3 -m http.server 8888
Serving HTTP on 0.0.0.0 port 8888 (http://0.0.0.0:8888/) …
À noter que just staticserver PORT=8888 provoque une erreur (invalid int value: 'PORT=8888').
3. Taskfile
version:'3'
tasks:
staticserver:
vars:
PORT:'{{default "8000" .PORT}}'
cmds:
- python3 -m http.server {{.PORT}}
Le résultat dans un terminal :
$ task staticserver
task: [staticserver] python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
[...]
$ task staticserver PORT=8888
task: [staticserver] python3 -m http.server 8888
Serving HTTP on 0.0.0.0 port 8888 (http://0.0.0.0:8888/) ...
D. Prise en compte de fichier .env
La prise en charge est plus ou moins directe mais rien d’insurmontable.
1. Makefile
Contrairement à just et task, make ne prend pas nativement les fichiers .env en charge. Il suffit d’ajouter ces lignes en début de fichier pour que le fichier .env soit chargé :
# Chargement du fichier .env
ifneq (,$(wildcard ./.env))
include .env
export
endif
C’est simplement du code valide pour make : ici, la fonction wildcard permet de détecter l’existence du fichier .env. La directive include charge le fichier donc les données du fichier .env deviennent disponibles comme variables dans le Makefile. La directive export passe l’ensemble des variables en tant que variables d’environnement aux commandes exécutées par le Makefile.
C’est plus simple pour just et task car le chargement de fichiers d’environnement est déjà intégré aux outils.
2. Justfile
Il suffit d’activer l’usage de fichier .env puis de récupérer la variable d’environnement souhaitée :
set dotenv-load
port := env("PORT", "8000")
La variable port dans just vaudra ce que contient la variable d’environnement PORT si elle est disponible, sinon elle vaudra 8000.
Cela suppose que l’on a un commentaire qui suit la convention attendue par la cible help :
cible: ## viser le centre
guillaume --tell --vise=pomme
F. Ne pas afficher la commande exécutée
Dans ce cas, seules les sorties standard et d’erreur sont affichées.
make et just utilisent la même astuce : préfixer la commande par @.
task utilise l’attribut silent qui peut être inséré à plusieurs endroits. Une variable d’environnement est aussi disponible.
tasks:
echo:
cmds:
-cmd: echo "Print something"
silent: true
Conclusion
Les trois outils ont des capacités non abordées dans cet article. J’ai l’impression que les cas d’usage entre just et task se recoupent complètement.
make est le choix classique avec la barrière à l’entrée la plus faible pour entrer sur une base de code. Cependant, si just ou task est déjà installé pour développer des services web par exemple, autant le mettre partout.
Entre les deux, j’ai une préférence pour just qui est moins verbeux. La popularité des deux projets est grandissante mais just a l’air de prendre l’avantage :
Un serveur HTTP de fichiers statiques est vraiment fourni avec Python : la commande python3 -m http.server est fonctionnelle. C’est pratique pour du réseau local mais une mauvaise idée en production.