Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad7e3e5b1f | |||
| b8af6a17a1 | |||
| 0c9666204b | |||
| cd468a837c | |||
| 8a2f7f620c | |||
| 3a73cdf4b9 | |||
| 6fdec32b29 |
+5
-4
@@ -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=
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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"] },
|
||||||
|
|||||||
Reference in New Issue
Block a user