Use of dataclass

See also

  • python_typing

  • dataclasses

  1 """Calcul des statistiques journalière d'utilisation des programmes.
  2
  3
  4 Exemples d'appel
  5 =================
  6
  7 ::
  8
  9     python manage_dev.py update_stats_day
 10
 11
 12 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:59] update_stats_day()
 13 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:85] stat_product_name.product_name='XXXXXXXXXXXXXXXXXX' stat_product_name.nb_total_logs=7
 14 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.9.7' version.nb_logs=3 (42.86%)
 15 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.7.0' version.nb_logs=2 (28.57%)
 16 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.6.1' version.nb_logs=2 (28.57%)
 17 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:85] stat_product_name.product_name='YYYYYYYYYYYYYYYYYY' stat_product_name.nb_total_logs=2
 18 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.9.7' version.nb_logs=1 (50.00%)
 19 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.7.0' version.nb_logs=1 (50.00%)
 20 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:85] stat_product_name.product_name='ZZZZZZZZZZZZZZZZ' stat_product_name.nb_total_logs=1
 21 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.7.2' version.nb_logs=1 (100.00%)
 22 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:85] stat_product_name.product_name='AAAAAAAAAAAAAAAAa' stat_product_name.nb_total_logs=1
 23 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='2.0.0' version.nb_logs=1 (100.00%)
 24 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:85] stat_product_name.product_name='BBBBBBBBBBBBBBBBBBB' stat_product_name.nb_total_logs=1
 25 [10/Feb/2020 14:14:23] INFO [logs.management.commands.update_stats_day:88]     - version.version='1.3.38' version.nb_logs=1 (100.00%)
 26
 27
 28 """
 29
 30
 31 import logging
 32 import pendulum
 33 from typing import List, Dict
 34
 35 from django.core.management.base import BaseCommand
 36
 37 from programs.models import Program
 38 from logs.models import LogHardwareId
 39
 40 logger = logging.getLogger(__name__)
 41
 42 from dataclasses import dataclass, field
 43
 44
 45 @dataclass
 46 class StatsProductNameVersion:
 47     product_name: str
 48     version: str = ""
 49     nb_logs: int = 0
 50     stats_product_name: "StatsProductName" = None
 51
 52     @property
 53     def percent_logs(self):
 54         percent = ""
 55         p = self.nb_logs / self.stats_product_name.nb_total_logs
 56         percent = f"({p:.2%})"
 57         return percent
 58
 59 @dataclass
 60 class StatsProductName:
 61     product_name: str
 62     nb_total_logs: int = 0
 63     versions: List[StatsProductNameVersion] = field(default_factory=list)
 64
 65 logger = logging.getLogger(__name__)
 66
 67
 68 class Command(BaseCommand):
 69     """Calcul des statistiques journalières d'utilisation des programmes."""
 70
 71     def add_arguments(self, parser):
 72         """
 73         - https://docs.python.org/3/library/argparse.html
 74         """
 75
 76     def handle(self, *args, **options):
 77         logger.info("update_stats_day()")
 78         now = pendulum.now()
 79         list_stats_product_name = []
 80         for product_name in Program.objects.filter(version_is_ready=True).values_list("product_name", flat=True).distinct():
 81             stats_product_name = StatsProductName(product_name=product_name)
 82             logs_hardware = LogHardwareId.objects.filter(
 83                 date_connexion__year=now.year,
 84                 date_connexion__month=now.month,
 85                 date_connexion__day=now.day,
 86                 product_name=product_name,
 87             ).order_by("product_name", "-version")
 88             if logs_hardware.exists():
 89                 # il existe des logs hardware pour ce programme (product_name)
 90                 list_stats_product_name.append(stats_product_name)
 91                 stats_product_name.nb_total_logs = len(logs_hardware)
 92                 current_version = None
 93                 for log in logs_hardware:
 94                     if current_version is None or current_version != log.version:
 95                         # nouvelle version ou changement de version
 96                         product_name_version = StatsProductNameVersion(product_name=product_name, version=log.version, stats_product_name=stats_product_name)
 97                         current_version = log.version
 98                         stats_product_name.versions.append(product_name_version)
 99
100                     product_name_version.nb_logs = product_name_version.nb_logs + 1
101
102         for stat_product_name in list_stats_product_name:
103             logger.info(f"{stat_product_name.product_name=} {stat_product_name.nb_total_logs=}")
104             for version in stat_product_name.versions:
105
106                 logger.info(f"    - {version.version=} {version.nb_logs=} {version.percent_logs}")