Module demo_api.reports
Module de génération de rapports pour demo_api
Ce module contient tous les générateurs de rapports : - JSON : Rapports structurés pour l'API - HTML : Rapports web interactifs - Markdown : Documentation et rapports texte - CSV : Données tabulaires
Sub-modules
demo_api.reports.base-
Classe de base pour tous les générateurs de rapports
demo_api.reports.html_reports-
Générateur de rapports HTML pour demo_api
demo_api.reports.json_reports-
Générateur de rapports JSON pour demo_api
demo_api.reports.markdown_reports-
Générateur de rapports Markdown pour demo_api
Classes
class HTMLReportGenerator (output_directory: str = 'outputs')-
Expand source code
class HTMLReportGenerator(BaseReportGenerator): """Générateur de rapports au format HTML avec templates Jinja2""" def __init__(self, output_directory: str = "outputs"): """ Initialise le générateur de rapports HTML Args: output_directory: Dossier de sortie pour les rapports HTML """ super().__init__(output_directory) self.html_directory = os.path.join(output_directory, "html") self._ensure_html_directory() # Configuration de Jinja2 template_dir = os.path.join( os.path.dirname(__file__), "..", "templates", "html" ) self.jinja_env = Environment( loader=FileSystemLoader(template_dir), autoescape=select_autoescape(["html", "xml"]), trim_blocks=True, lstrip_blocks=True, ) # Ajout de filtres personnalisés self.jinja_env.filters["pad"] = self._pad_filter def _ensure_html_directory(self) -> None: """Crée le dossier HTML s'il n'existe pas""" if not os.path.exists(self.html_directory): os.makedirs(self.html_directory, exist_ok=True) logger.info(f"Dossier HTML créé: {self.html_directory}") def _pad_filter(self, text: str, width: int) -> str: """Filtre Jinja2 pour padding de texte""" return text.ljust(width) def get_extension(self) -> str: """Retourne l'extension des fichiers HTML""" return "html" def generate( self, data: Any, filename: Optional[str] = None, template_name: str = "default.html.j2", ) -> str: """ Génère un rapport HTML Args: data: Données à inclure dans le rapport HTML filename: Nom de fichier personnalisé (optionnel) template_name: Nom du template Jinja2 à utiliser Returns: str: Chemin vers le fichier HTML généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.html_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier HTML try: template = self.jinja_env.get_template(template_name) content = template.render(**report_data) with open(filename, "w", encoding="utf-8") as f: f.write(content) logger.info( "Rapport HTML généré avec succès", filename=filename, template=template_name, ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport HTML", filename=filename, error=str(e), ) raise def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.html" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs HTML", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename, "users_vms_report.html.j2") def generate_status_report( self, status_data: Dict[str, Any], filename: str = "vm_status_report.html" ) -> str: """ Génère un rapport de statut des VMs Args: status_data: Données de statut des VMs filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de statut HTML", filename=filename) return self.generate(status_data, filename, "vm_status_report.html.j2") def _calculate_users_vms_stats(self, users: List[Dict[str, Any]]) -> Dict[str, Any]: """Calcule les statistiques des utilisateurs et VMs""" total_vms: int = 0 vms_by_status: Dict[str, int] = {} users_with_vms: int = 0 users_without_vms: int = 0 for user in users: user_vms = user.get("vms", []) if user_vms: users_with_vms += 1 total_vms += len(user_vms) # Compter les VMs par statut for vm in user_vms: status = vm.get("status", "unknown") vms_by_status[status] = vms_by_status.get(status, 0) + 1 else: users_without_vms += 1 return { "total_vms": total_vms, "vms_by_status": vms_by_status, "users_with_vms": users_with_vms, "users_without_vms": users_without_vms, }Générateur de rapports au format HTML avec templates Jinja2
Initialise le générateur de rapports HTML
Args
output_directory- Dossier de sortie pour les rapports HTML
Ancestors
- BaseReportGenerator
- abc.ABC
Methods
def generate(self,
data: Any,
filename: str | None = None,
template_name: str = 'default.html.j2') ‑> str-
Expand source code
def generate( self, data: Any, filename: Optional[str] = None, template_name: str = "default.html.j2", ) -> str: """ Génère un rapport HTML Args: data: Données à inclure dans le rapport HTML filename: Nom de fichier personnalisé (optionnel) template_name: Nom du template Jinja2 à utiliser Returns: str: Chemin vers le fichier HTML généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.html_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier HTML try: template = self.jinja_env.get_template(template_name) content = template.render(**report_data) with open(filename, "w", encoding="utf-8") as f: f.write(content) logger.info( "Rapport HTML généré avec succès", filename=filename, template=template_name, ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport HTML", filename=filename, error=str(e), ) raiseGénère un rapport HTML
Args
data- Données à inclure dans le rapport HTML
filename- Nom de fichier personnalisé (optionnel)
template_name- Nom du template Jinja2 à utiliser
Returns
str- Chemin vers le fichier HTML généré
def generate_status_report(self, status_data: Dict[str, Any], filename: str = 'vm_status_report.html') ‑> str-
Expand source code
def generate_status_report( self, status_data: Dict[str, Any], filename: str = "vm_status_report.html" ) -> str: """ Génère un rapport de statut des VMs Args: status_data: Données de statut des VMs filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de statut HTML", filename=filename) return self.generate(status_data, filename, "vm_status_report.html.j2")Génère un rapport de statut des VMs
Args
status_data- Données de statut des VMs
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def generate_users_vms_report(self, users: List[Dict[str, Any]], filename: str = 'vm_users.html') ‑> str-
Expand source code
def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.html" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs HTML", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename, "users_vms_report.html.j2")Génère un rapport spécifique pour les utilisateurs et VMs
Args
users- Liste des utilisateurs avec leurs VMs associées
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def get_extension(self) ‑> str-
Expand source code
def get_extension(self) -> str: """Retourne l'extension des fichiers HTML""" return "html"Retourne l'extension des fichiers HTML
class JSONReportGenerator (output_directory: str = 'outputs')-
Expand source code
class JSONReportGenerator(BaseReportGenerator): """Générateur de rapports au format JSON""" def __init__(self, output_directory: str = "outputs"): """ Initialise le générateur de rapports JSON Args: output_directory: Dossier de sortie pour les rapports JSON """ super().__init__(output_directory) self.json_directory = os.path.join(output_directory, "json") self._ensure_json_directory() def _ensure_json_directory(self) -> None: """Crée le dossier JSON s'il n'existe pas""" if not os.path.exists(self.json_directory): os.makedirs(self.json_directory, exist_ok=True) logger.info(f"Dossier JSON créé: {self.json_directory}") def get_extension(self) -> str: """Retourne l'extension des fichiers JSON""" return "json" def generate(self, data: Any, filename: Optional[str] = None) -> str: """ Génère un rapport JSON Args: data: Données à inclure dans le rapport JSON filename: Nom de fichier personnalisé (optionnel) Returns: str: Chemin vers le fichier JSON généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.json_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier JSON try: with open(filename, "w", encoding="utf-8") as f: json.dump( report_data, f, indent=4, sort_keys=True, default=str, ensure_ascii=False, ) logger.info( "Rapport JSON généré avec succès", filename=filename, data_size=len(str(data)), ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport JSON", filename=filename, error=str(e), ) raise def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.json" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename) def _calculate_users_vms_stats(self, users: List[Dict[str, Any]]) -> Dict[str, Any]: """Calcule les statistiques des utilisateurs et VMs""" total_vms: int = 0 vms_by_status: Dict[str, int] = {} users_with_vms: int = 0 users_without_vms: int = 0 for user in users: user_vms = user.get("vms", []) if user_vms: users_with_vms += 1 total_vms += len(user_vms) # Compter les VMs par statut for vm in user_vms: status = vm.get("status", "unknown") vms_by_status[status] = vms_by_status.get(status, 0) + 1 else: users_without_vms += 1 return { "total_vms": total_vms, "vms_by_status": vms_by_status, "users_with_vms": users_with_vms, "users_without_vms": users_without_vms, } def generate_api_summary_report( self, api_data: Dict[str, Any], filename: str = "api_summary.json" ) -> str: """ Génère un rapport de résumé de l'API Args: api_data: Données de l'API (utilisateurs, VMs, etc.) filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de résumé API", filename=filename) summary_data = { "api_info": { "base_url": api_data.get("base_url", "unknown"), "timestamp": api_data.get("timestamp", "unknown"), "status": "success", }, "counts": { "users": len(api_data.get("users", [])), "vms": len(api_data.get("vms", [])), }, "raw_data": api_data, } return self.generate(summary_data, filename)Générateur de rapports au format JSON
Initialise le générateur de rapports JSON
Args
output_directory- Dossier de sortie pour les rapports JSON
Ancestors
- BaseReportGenerator
- abc.ABC
Methods
def generate(self, data: Any, filename: str | None = None) ‑> str-
Expand source code
def generate(self, data: Any, filename: Optional[str] = None) -> str: """ Génère un rapport JSON Args: data: Données à inclure dans le rapport JSON filename: Nom de fichier personnalisé (optionnel) Returns: str: Chemin vers le fichier JSON généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.json_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier JSON try: with open(filename, "w", encoding="utf-8") as f: json.dump( report_data, f, indent=4, sort_keys=True, default=str, ensure_ascii=False, ) logger.info( "Rapport JSON généré avec succès", filename=filename, data_size=len(str(data)), ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport JSON", filename=filename, error=str(e), ) raiseGénère un rapport JSON
Args
data- Données à inclure dans le rapport JSON
filename- Nom de fichier personnalisé (optionnel)
Returns
str- Chemin vers le fichier JSON généré
def generate_api_summary_report(self, api_data: Dict[str, Any], filename: str = 'api_summary.json') ‑> str-
Expand source code
def generate_api_summary_report( self, api_data: Dict[str, Any], filename: str = "api_summary.json" ) -> str: """ Génère un rapport de résumé de l'API Args: api_data: Données de l'API (utilisateurs, VMs, etc.) filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de résumé API", filename=filename) summary_data = { "api_info": { "base_url": api_data.get("base_url", "unknown"), "timestamp": api_data.get("timestamp", "unknown"), "status": "success", }, "counts": { "users": len(api_data.get("users", [])), "vms": len(api_data.get("vms", [])), }, "raw_data": api_data, } return self.generate(summary_data, filename)Génère un rapport de résumé de l'API
Args
api_data- Données de l'API (utilisateurs, VMs, etc.)
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def generate_users_vms_report(self, users: List[Dict[str, Any]], filename: str = 'vm_users.json') ‑> str-
Expand source code
def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.json" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename)Génère un rapport spécifique pour les utilisateurs et VMs
Args
users- Liste des utilisateurs avec leurs VMs associées
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def get_extension(self) ‑> str-
Expand source code
def get_extension(self) -> str: """Retourne l'extension des fichiers JSON""" return "json"Retourne l'extension des fichiers JSON
class MarkdownReportGenerator (output_directory: str = 'outputs')-
Expand source code
class MarkdownReportGenerator(BaseReportGenerator): """Générateur de rapports au format Markdown avec templates Jinja2""" def __init__(self, output_directory: str = "outputs"): """ Initialise le générateur de rapports Markdown Args: output_directory: Dossier de sortie pour les rapports Markdown """ super().__init__(output_directory) self.markdown_directory = os.path.join(output_directory, "markdown") self._ensure_markdown_directory() # Configuration de Jinja2 template_dir = os.path.join( os.path.dirname(__file__), "..", "templates", "markdown" ) self.jinja_env = Environment( loader=FileSystemLoader(template_dir), autoescape=select_autoescape(["html", "xml"]), trim_blocks=True, lstrip_blocks=True, ) # Ajout de filtres personnalisés self.jinja_env.filters["pad"] = self._pad_filter def _ensure_markdown_directory(self) -> None: """Crée le dossier Markdown s'il n'existe pas""" if not os.path.exists(self.markdown_directory): os.makedirs(self.markdown_directory, exist_ok=True) logger.info(f"Dossier Markdown créé: {self.markdown_directory}") def _pad_filter(self, text: str, width: int) -> str: """Filtre Jinja2 pour padding de texte""" return text.ljust(width) def get_extension(self) -> str: """Retourne l'extension des fichiers Markdown""" return "md" def generate( self, data: Any, filename: Optional[str] = None, template_name: str = "default.md.j2", ) -> str: """ Génère un rapport Markdown Args: data: Données à inclure dans le rapport Markdown filename: Nom de fichier personnalisé (optionnel) template_name: Nom du template Jinja2 à utiliser Returns: str: Chemin vers le fichier Markdown généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.markdown_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier Markdown try: template = self.jinja_env.get_template(template_name) content = template.render(**report_data) with open(filename, "w", encoding="utf-8") as f: f.write(content) logger.info( "Rapport Markdown généré avec succès", filename=filename, template=template_name, ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport Markdown", filename=filename, error=str(e), ) raise def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.md" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs Markdown", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename, "users_vms_report.md.j2") def generate_status_report( self, status_data: Dict[str, Any], filename: str = "vm_status_report.md" ) -> str: """ Génère un rapport de statut des VMs Args: status_data: Données de statut des VMs filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de statut Markdown", filename=filename) return self.generate(status_data, filename, "vm_status_report.md.j2") def _calculate_users_vms_stats(self, users: List[Dict[str, Any]]) -> Dict[str, Any]: """Calcule les statistiques des utilisateurs et VMs""" total_vms: int = 0 vms_by_status: Dict[str, int] = {} users_with_vms: int = 0 users_without_vms: int = 0 for user in users: user_vms = user.get("vms", []) if user_vms: users_with_vms += 1 total_vms += len(user_vms) # Compter les VMs par statut for vm in user_vms: status = vm.get("status", "unknown") vms_by_status[status] = vms_by_status.get(status, 0) + 1 else: users_without_vms += 1 return { "total_vms": total_vms, "vms_by_status": vms_by_status, "users_with_vms": users_with_vms, "users_without_vms": users_without_vms, }Générateur de rapports au format Markdown avec templates Jinja2
Initialise le générateur de rapports Markdown
Args
output_directory- Dossier de sortie pour les rapports Markdown
Ancestors
- BaseReportGenerator
- abc.ABC
Methods
def generate(self,
data: Any,
filename: str | None = None,
template_name: str = 'default.md.j2') ‑> str-
Expand source code
def generate( self, data: Any, filename: Optional[str] = None, template_name: str = "default.md.j2", ) -> str: """ Génère un rapport Markdown Args: data: Données à inclure dans le rapport Markdown filename: Nom de fichier personnalisé (optionnel) template_name: Nom du template Jinja2 à utiliser Returns: str: Chemin vers le fichier Markdown généré """ if filename is None: filename = self._generate_filename("report", self.get_extension()) else: # S'assurer que le fichier a la bonne extension if not filename.endswith(f".{self.get_extension()}"): filename = f"{filename}.{self.get_extension()}" filename = os.path.join(self.markdown_directory, filename) # Préparer les données avec métadonnées report_data = {"metadata": self._get_metadata(), "data": data} # Générer le fichier Markdown try: template = self.jinja_env.get_template(template_name) content = template.render(**report_data) with open(filename, "w", encoding="utf-8") as f: f.write(content) logger.info( "Rapport Markdown généré avec succès", filename=filename, template=template_name, ) return filename except Exception as e: logger.error( "Erreur lors de la génération du rapport Markdown", filename=filename, error=str(e), ) raiseGénère un rapport Markdown
Args
data- Données à inclure dans le rapport Markdown
filename- Nom de fichier personnalisé (optionnel)
template_name- Nom du template Jinja2 à utiliser
Returns
str- Chemin vers le fichier Markdown généré
def generate_status_report(self, status_data: Dict[str, Any], filename: str = 'vm_status_report.md') ‑> str-
Expand source code
def generate_status_report( self, status_data: Dict[str, Any], filename: str = "vm_status_report.md" ) -> str: """ Génère un rapport de statut des VMs Args: status_data: Données de statut des VMs filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info("Génération du rapport de statut Markdown", filename=filename) return self.generate(status_data, filename, "vm_status_report.md.j2")Génère un rapport de statut des VMs
Args
status_data- Données de statut des VMs
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def generate_users_vms_report(self, users: List[Dict[str, Any]], filename: str = 'vm_users.md') ‑> str-
Expand source code
def generate_users_vms_report( self, users: List[Dict[str, Any]], filename: str = "vm_users.md" ) -> str: """ Génère un rapport spécifique pour les utilisateurs et VMs Args: users: Liste des utilisateurs avec leurs VMs associées filename: Nom du fichier de sortie Returns: str: Chemin vers le fichier généré """ logger.info( "Génération du rapport utilisateurs/VMs Markdown", users_count=len(users), filename=filename, ) # Statistiques supplémentaires stats = self._calculate_users_vms_stats(users) report_data = { "summary": { "total_users": len(users), "total_vms": stats["total_vms"], "vms_by_status": stats["vms_by_status"], "users_with_vms": stats["users_with_vms"], "users_without_vms": stats["users_without_vms"], }, "users": users, } return self.generate(report_data, filename, "users_vms_report.md.j2")Génère un rapport spécifique pour les utilisateurs et VMs
Args
users- Liste des utilisateurs avec leurs VMs associées
filename- Nom du fichier de sortie
Returns
str- Chemin vers le fichier généré
def get_extension(self) ‑> str-
Expand source code
def get_extension(self) -> str: """Retourne l'extension des fichiers Markdown""" return "md"Retourne l'extension des fichiers Markdown