Compare commits

...

7 Commits

Author SHA1 Message Date
Colin Maudry ad7e3e5b1f Récupération de schéma plus robuste et changelog 2026-05-18 12:17:59 +02:00
Colin Maudry b8af6a17a1 Merge branch 'release/2.7.7' 2026-05-11 10:35:29 +02:00
Colin Maudry 0c9666204b Autorisation du HTML dans les annonces 2026-05-11 10:34:06 +02:00
Colin Maudry cd468a837c Changelog v2.7.7 2026-05-11 10:31:18 +02:00
Colin Maudry 8a2f7f620c Suppression des mentions sur les profils d'acheteurs qui ne publient pas de données
Omnikles publie via l'API DUME de l'AIFE, ne reste que Klekoon. Mais bon, ça fait des mauvaises vibes sur la page de le préciser :)
2026-05-11 10:26:16 +02:00
Colin Maudry 3a73cdf4b9 P dans les announcements plus compacts 2026-05-05 15:43:08 +02:00
Colin Maudry 6fdec32b29 Merge tag 'v2.7.6' into dev
- Correction du problème de filtre par date dans les tableaux
- Retour des cartes dans les pages acheteur et titulaire
- Possibilité de chercher un SIRET/SIREN avec des espaces dans les champs `SIRET acheteur` et `Identifiant titulaire`
2026-05-05 15:06:32 +02:00
8 changed files with 47 additions and 24 deletions
+5 -4
View File
@@ -9,16 +9,17 @@ ANNOUNCEMENTS=
# Chemin vers le schéma de données # Chemin vers le schéma de données
DATA_SCHEMA_PATH=https://www.data.gouv.fr/api/1/datasets/r/9a4144c0-ee44-4dec-bee5-bbef38191d9a DATA_SCHEMA_PATH=https://www.data.gouv.fr/api/1/datasets/r/9a4144c0-ee44-4dec-bee5-bbef38191d9a
DATA_SCHEMA_PATH_LOCAL=../schema.json
# Colonnes masquées par défaut # Colonnes masquées par défaut
DISPLAYED_COLUMNS="uid, acheteur_id, acheteur_nom, montant, objet, titulaire_nom, titulaire_id, dateNotification, dureeMois, acheteur_departement_code, sourceDataset" DISPLAYED_COLUMNS="uid, acheteur_id, acheteur_nom, montant, objet, titulaire_nom, titulaire_id, dateNotification, dureeMois, acheteur_departement_code, sourceDataset"
# Formulaire de contact # Formulaire de contact
SENDER_SERVER_DOMAIN="mail.example.com" # serveur SMTP SENDER_SERVER_DOMAIN="mail.example.com" # serveur SMTP
LOGIN_PASSWORD="" # mot de passe du serveur LOGIN_PASSWORD="" # mot de passe du serveur
LOGIN_EMAIL="connect@example.fr" # adresse utilisée pour se connecter au serveur SMTP LOGIN_EMAIL="connect@example.fr" # adresse utilisée pour se connecter au serveur SMTP
FROM_EMAIL="from@example.com" # adresse d'envoi des emails (From) FROM_EMAIL="from@example.com" # adresse d'envoi des emails (From)
TO_EMAIL="to@example.com" # adresse de destination des emails (To) TO_EMAIL="to@example.com" # adresse de destination des emails (To)
# Matomo # Matomo
MATOMO_ID_SITE= MATOMO_ID_SITE=
+8
View File
@@ -1,3 +1,11 @@
##### 2.7.8 (18 mai 2026)
- Récupération du schéma de données plus robuste, ne pas dépendre de data.gouv.fr
##### 2.7.7 (11 mai 2026)
- Suppression des mentions sur les profils d'acheteur. Omnikles/Safetender publie via l'API DUME et Klekoon ne publie pas, mais c'est peut-être pas le seul, donc je préfère supprimer et refaire un tour.
##### 2.7.6 (5 mai 2026) ##### 2.7.6 (5 mai 2026)
- Correction du problème de filtre par date dans les tableaux - Correction du problème de filtre par date dans les tableaux
+1 -1
View File
@@ -1,7 +1,7 @@
[project] [project]
name = "decp.info" name = "decp.info"
description = "Interface d'exploration et d'analyse des marchés publics français." description = "Interface d'exploration et d'analyse des marchés publics français."
version = "2.7.6" version = "2.7.8"
requires-python = ">= 3.10" requires-python = ">= 3.10"
authors = [{ name = "Colin Maudry", email = "colin@colmo.tech" }] authors = [{ name = "Colin Maudry", email = "colin@colmo.tech" }]
dependencies = [ dependencies = [
+7 -1
View File
@@ -145,7 +145,13 @@ navbar = dbc.Navbar(
style={"minWidth": "230px"}, style={"minWidth": "230px"},
), ),
dbc.Nav( dbc.Nav(
children=[dcc.Markdown(os.getenv("ANNOUNCEMENTS"), id="announcements")], children=[
dcc.Markdown(
os.getenv("ANNOUNCEMENTS"),
id="announcements",
dangerously_allow_html=True,
),
],
style={ style={
"maxWidth": "1200px", "maxWidth": "1200px",
"display": "inline-block", "display": "inline-block",
+4
View File
@@ -144,6 +144,10 @@ p.version > a {
max-width: 900px; max-width: 900px;
} }
#announcements p {
margin-bottom: 0.2rem;
}
.seeBorder { .seeBorder {
border: dotted 1px green; border: dotted 1px green;
} }
+1 -8
View File
@@ -87,14 +87,7 @@ Vous pouvez consommer les données qui alimentent decp.info
dcc.Markdown( dcc.Markdown(
"""Les données visibles sur ce site proviennent exclusivement de la publication de données ouvertes par les acheteurs publics ou en leur nom, régie par [l'arrêté du 22 décembre 2022](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000046850496). Leur qualité est donc principalement liée à la qualité de leur saisie par les agents publics, parfois peu aidé·es par la qualité des outils à leur disposition. Je pense que l'analyse de marchés individuels et le comptage de marchés sur des critères autres que financiers sont plutôt fiables. En revanche, certains montants de marché estimés à des valeurs farfelues ([1 euro](https://decp.info/marches/432766947000192025S01301), [1 milliard](https://decp.info/marches/2459004280001320210000000271)) faussent les calculs par aggrégation (sommes, moyennes, médianes) et donc la production de statistiques financières fiables. Acheteurs, acheteuses : s'il vous plaît, essayez d'estimer les montants des marchés publics attribués de manière plus précise. """Les données visibles sur ce site proviennent exclusivement de la publication de données ouvertes par les acheteurs publics ou en leur nom, régie par [l'arrêté du 22 décembre 2022](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000046850496). Leur qualité est donc principalement liée à la qualité de leur saisie par les agents publics, parfois peu aidé·es par la qualité des outils à leur disposition. Je pense que l'analyse de marchés individuels et le comptage de marchés sur des critères autres que financiers sont plutôt fiables. En revanche, certains montants de marché estimés à des valeurs farfelues ([1 euro](https://decp.info/marches/432766947000192025S01301), [1 milliard](https://decp.info/marches/2459004280001320210000000271)) faussent les calculs par aggrégation (sommes, moyennes, médianes) et donc la production de statistiques financières fiables. Acheteurs, acheteuses : s'il vous plaît, essayez d'estimer les montants des marchés publics attribués de manière plus précise.
Quant à l'exhaustivité, je consolide toutes les sources de données exploitables que j'ai pu identifier (voir [ci-dessous](/a-propos#sources). Certains profils d'acheteurs ne publient pas leurs données malgré l'obligation réglementaire : Quant à l'exhaustivité, je consolide toutes les sources de données exploitables que j'ai pu identifier (voir [ci-dessous](/bin.usr-is-merged/)). Je tiens à souligner la belle continuité de la publication par la DGFiP des données des marchés publics remontées via le [protocole PES](https://www.collectivites-locales.gouv.fr/finances-locales/le-protocole-dechange-standard-pes). Merci à leurs équipes."""
- klekoon.fr (ils y travaillent)
- safetender.com (Omnikles)
**marches-publics.info** (AWS) publie ses données de manière assez sporadique depuis début 2023. Compte tenu de son poids dans le secteur, c'est assez dommageable pour la transparence des marchés publics.
Au milieu de ces mauvaises nouvelles, je tiens à souligner la belle continuité de la publication par la DGFiP des données des marchés publics remontées via le [protocole PES](https://www.collectivites-locales.gouv.fr/finances-locales/le-protocole-dechange-standard-pes). Merci à leurs équipes."""
), ),
html.H4("Sources de données ", id="sources"), html.H4("Sources de données ", id="sources"),
get_sources_tables(os.getenv("SOURCE_STATS_CSV_PATH")), get_sources_tables(os.getenv("SOURCE_STATS_CSV_PATH")),
+20 -9
View File
@@ -2,7 +2,9 @@ import json
import logging import logging
import os import os
from collections import OrderedDict from collections import OrderedDict
from pathlib import Path
import httpx
import polars as pl import polars as pl
from httpx import HTTPError, get from httpx import HTTPError, get
@@ -63,16 +65,25 @@ def get_departement_region(code_postal):
def get_data_schema() -> dict: def get_data_schema() -> dict:
# Récupération du schéma des données tabulaires # Récupération du schéma des données tabulaires
path = os.getenv("DATA_SCHEMA_PATH") url = os.getenv("DATA_SCHEMA_PATH")
if path.startswith("http"): local_path = Path(os.getenv("DATA_SCHEMA_LOCAL", ""))
original_schema: dict = get(
os.getenv("DATA_SCHEMA_PATH"), follow_redirects=True original_schema = {}
).json() if url:
elif os.path.exists(path): try:
with open(path) as f: original_schema: dict = get(url, follow_redirects=True).json()
except (
httpx.ReadTimeout,
httpx.ReadError,
httpx.ConnectError,
httpx.ConnectTimeout,
):
logger.error(f"Erreur HTTP lors de la récupération du schéma ({url})")
if os.path.exists(local_path) and original_schema == {}:
with open(local_path) as f:
original_schema: dict = json.load(f) original_schema: dict = json.load(f)
else: logger.info(f"Utilisation du schéma local ({local_path})")
raise Exception(f"Chemin vers le schéma invalide: {path}")
new_schema = OrderedDict() new_schema = OrderedDict()
Generated
+1 -1
View File
@@ -760,7 +760,7 @@ wheels = [
[[package]] [[package]]
name = "decp-info" name = "decp-info"
version = "2.7.6" version = "2.7.7"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "dash", extra = ["compress"] }, { name = "dash", extra = ["compress"] },