Code/app/plan_d_action/utils/data/pda_interface.py
Stéphan Peccini 6d2e877341
feat(audit): audit qualité complet — 907→0 erreurs ruff + fix multiselect labels
- Correction des 907 erreurs ruff (pathlib, imports, nommage, simplifications, docstrings)
- Fix déduplication labels dans multiselect nœuds d'arrivée (analyse)
- Expansion 1→N label→IDs pour le Sankey (Pays d'opération)
- Ajout CLAUDE.md et document de design de l'audit
- Mise à jour .gitignore (artefacts tests exploratoires)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:52:01 +01:00

265 lines
9.3 KiB
Python

import streamlit as st
def afficher_bloc_ihh_isg(titre, _ihh, _isg, details_content="", ui = True) -> str|None:
"""Affiche un bloc detaille IHH/ISG avec vulnerabilite, tableaux et graphique."""
contenu_bloc = ""
if ui:
st.markdown(f"### {titre}")
else:
contenu_bloc = f"### {titre}\n"
if not details_content:
st.markdown("Données non disponibles")
return None
lines = details_content.split('\n')
# 1. Afficher vulnérabilité combinée en premier
if "#### Vulnérabilité combinée IHH-ISG" in details_content:
contenu_md = "#### Vulnérabilité combinée IHH-ISG\n"
contenu_md += afficher_section_texte(lines, "#### Vulnérabilité combinée IHH-ISG", "###")
contenu_md += "\n"
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 2. Afficher ISG des pays impliqués
if "##### ISG des pays impliqués" in details_content:
# Afficher le résumé ISG combiné
for line in lines:
if "**ISG combiné:" in line:
st.markdown(line)
break
contenu_md = "#### ISG des pays impliqués\n"
contenu_md += afficher_section_avec_tableau(lines, "##### ISG des pays impliqués")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 3. Afficher la section IHH complète
if "#### Indice de Herfindahl-Hirschmann" in details_content:
contenu_md = "#### Indice de Herfindahl-Hirschmann\n"
# Tableau de résumé IHH
contenu_md += afficher_section_avec_tableau(lines, "#### Indice de Herfindahl-Hirschmann")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# IHH par entreprise
if "##### IHH par entreprise (acteurs)" in details_content:
contenu_md = "##### IHH par entreprise (acteurs)\n"
contenu_md += afficher_section_texte(lines, "##### IHH par entreprise (acteurs)", "##### IHH par pays")
st.markdown(contenu_md)
# IHH par pays
if "##### IHH par pays" in details_content:
contenu_md = "##### IHH par pays\n"
contenu_md += afficher_section_texte(lines, "##### IHH par pays", "##### En résumé")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# En résumé
if "##### En résumé" in details_content:
contenu_md = "##### En résumé\n"
contenu_md += afficher_section_texte(lines, "##### En résumé", "####")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
if not ui:
return contenu_bloc
return None
def afficher_section_avec_tableau(lines, section_start, section_end=None):
"""Affiche une section contenant un tableau."""
in_section = False
table_lines = []
for line in lines:
if section_start in line:
in_section = True
continue
if in_section and section_end and section_end in line or in_section and line.startswith('#') and section_start not in line:
break
if in_section:
if line.strip().startswith('|'):
table_lines.append(line)
elif table_lines and not line.strip().startswith('|'):
# Fin du tableau
break
if table_lines:
return '\n'.join(table_lines)
return None
def afficher_section_texte(lines, section_start, section_end_marker=None):
"""Affiche le texte d'une section sans les tableaux."""
in_section = False
contenu_md = []
for line in lines:
if section_start in line:
in_section = True
continue
if in_section and section_end_marker and line.startswith(section_end_marker) or in_section and line.startswith('#') and section_start not in line:
break
if in_section and line.strip() and not line.strip().startswith('|'):
contenu_md.append(line + '\n')
return '\n'.join(contenu_md)
def afficher_description(titre, description, ui = True) -> str|None:
"""Affiche ou retourne la description d'un element du plan d'action.
Extrait et affiche le premier paragraphe descriptif avant les sections detaillees
(tableaux, titres, etc.). Supporte mode UI (affichage Streamlit) ou mode texte
(retour string pour export).
Args:
titre: Titre de la section de description.
description: Contenu markdown complet incluant la description.
ui: Si True, affiche dans Streamlit. Si False, retourne le contenu. Defaut: True.
Returns:
str | None: Contenu markdown si ui=False, None sinon.
"""
contenu_bloc = ""
if ui:
st.markdown(f"### {titre}")
else:
contenu_bloc = f"### {titre}\n"
if description:
lines = description.split('\n')
description_lines = []
# Extraire le premier paragraphe descriptif
for line in lines:
line = line.strip()
if not line:
if description_lines: # Si on a déjà du contenu, une ligne vide termine le paragraphe
break
continue
# Arrêter aux titres de sections ou tableaux
if line.startswith(('####', '|', '**Unité')):
break
description_lines.append(line)
contenu_md = ' '.join(description_lines) if description_lines else "Description non disponible"
else:
contenu_md = "Description non disponible"
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
return None
contenu_bloc += contenu_md
return contenu_bloc
def afficher_caracteristiques_minerai(_minerai, _mineraux_data, details_content="", ui = True) -> str|None:
"""Affiche les caracteristiques generales d'un minerai avec indices ICS et IVC.
Presente la vulnerabilite combinee ICS-IVC, puis les sections detaillees ICS
(avec tableaux par composant) et IVC. Supporte mode UI (Streamlit) ou mode
texte (retour string pour export).
Args:
minerai: Nom du minerai a afficher.
mineraux_data: Dictionnaire contenant les donnees du minerai.
details_content: Contenu markdown complet des caracteristiques. Defaut: "".
ui: Si True, affiche dans Streamlit. Si False, retourne le contenu. Defaut: True.
Returns:
str | None: Contenu markdown si ui=False, None sinon.
"""
contenu_bloc = ""
if ui:
st.markdown("### Caractéristiques générales")
else:
contenu_bloc = "### Caractéristiques générales\n"
if not details_content:
if ui:
st.markdown("Données non disponibles")
else:
contenu_bloc += "Données non disponibles\n"
return None
lines = details_content.split('\n')
# 3. Afficher la vulnérabilité combinée ICS-IVC en dernier
if "#### Vulnérabilité combinée ICS-IVC" in details_content:
contenu_md = "#### Vulnérabilité combinée ICS-IVC\n"
contenu_md += afficher_section_texte(lines, "#### Vulnérabilité combinée ICS-IVC", "####")
contenu_md += "\n"
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 1. Afficher la section ICS complète
if "#### ICS" in details_content:
contenu_md = "#### ICS\n"
# Afficher le premier tableau ICS (avec toutes les colonnes)
contenu_md += afficher_section_avec_tableau(lines, "#### ICS", "##### Valeurs d'ICS par composant concerné")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# Afficher la sous-section "Valeurs d'ICS par composant"
if "##### Valeurs d'ICS par composant concerné" in details_content:
contenu_md = "##### Valeurs d'ICS par composant concerné\n"
# Afficher le résumé ICS moyen
for line in lines:
if "**ICS moyen" in line:
contenu_md += line
break
contenu_md += "\n"
contenu_md += afficher_section_avec_tableau(lines, "##### Valeurs d'ICS par composant concerné", "**ICS moyen")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 2. Afficher la section IVC complète
if "#### IVC" in details_content:
contenu_md = "#### IVC\n"
# Afficher tous les détails de la section IVC
contenu_md += afficher_section_texte(lines, "#### IVC", "#### Vulnérabilité combinée ICS-IVC")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
return None
contenu_bloc += contenu_md
return contenu_bloc
if not ui:
return contenu_bloc
return None