main.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. '''
  2. Python 3.7+
  3. @author: olivier.massot, sept 2018
  4. '''
  5. from dataclasses import dataclass
  6. from datetime import datetime
  7. import logging
  8. import sys
  9. from path import Path
  10. import shapefile
  11. import yaml
  12. from core import logconf
  13. from core.constants import MAIN
  14. logger = logging.getLogger("netgeo_checker")
  15. logconf.start("netgeo_checker", logging.INFO)
  16. ETUDE, IN_DIR = False, MAIN / "work" / "SCOPELEC_CAP_097AP0_REC_180829_OK"
  17. # ETUDE, IN_DIR = True, MAIN / "rsc" / "data_in" / "SCOPELEC_101BP0_APD_180725"
  18. subject = MAIN / "work" / "SCOPELEC_CAP_097AP0_REC_180829_OK"
  19. checker = MAIN / "resources" / "netgeo_v2-2_doe.yaml"
  20. # prendre une archive en entrée
  21. # contrôler la presence des 6 fichiers shp
  22. # Pour chaque couche, vérifier le type de géometrie, la presence de données, la projection, l'inclusion du bounding rect dans le departement
  23. # Charger les modèles
  24. # Vérifier enregistrement par enregistrement la validité des données
  25. def check(subject, checker):
  26. """ prends un dossier ou une archive en entier et vérifie son contenu selon les règles données par le fichier de config """
  27. archive, checker = Path(subject), Path(checker)
  28. if archive.isfile():
  29. # extraire vers un dossier temp
  30. # dirname = tempdir
  31. pass
  32. elif archive.isdir():
  33. dirname = subject
  34. else:
  35. raise IOError(f"Impossible de trouver le fichier ou répertoire: {subject}")
  36. logging.info("***** Traitement de '%s' *****", subject.name)
  37. logging.info("> Controlleur: '%s'", checker.name)
  38. with open(checker, "r") as cf:
  39. config = yaml.load(cf)
  40. for filename, model in config["files"].items():
  41. path_ = dirname / filename
  42. logging.info("* Traitement de %s", path_.name)
  43. try:
  44. sf = shapefile.Reader(path_)
  45. except shapefile.ShapefileException:
  46. logger.error("Fichier SHAPE illisible")
  47. continue
  48. shape_names = {1:"Point", 3:"Polyligne", 5:"Polygone"}
  49. if sf.shapeType != model["shape_type"]:
  50. logger.error("Le fichier shapefile n'est pas de type %s", shape_names[model["shape_type"]])
  51. del sf
  52. continue
  53. records = sf.shapeRecords()
  54. if not records:
  55. if not model["can_be_empty"]:
  56. logger.error("Le fichier shapefile ne contient aucune donnees")
  57. del sf, records
  58. continue
  59. else:
  60. logger.warning("Le fichier shapefile ne contient aucune donnees")
  61. if not "fields" in model:
  62. continue
  63. fields = [f[0] for f in sf.fields if f[0] != 'DeletionFlag']
  64. # controle d'éventuels champs inconnus
  65. for f in fields:
  66. if f not in model["fields"]:
  67. logger.warning("Champs inconnu: %s", f)
  68. # parcours et controle des enregistrements
  69. for i, record in enumerate(records):
  70. logging.info("\n> Enregistrement n°%s\n", i)
  71. record_data = {field: record.record[i] for i, field in enumerate(fields)}
  72. for fieldname, fieldmodel in model["fields"].items():
  73. try:
  74. val = record_data[fieldname]
  75. except KeyError:
  76. if fieldmodel.get("required", True):
  77. logger.error("%s - Champs manquant", fieldname)
  78. continue
  79. type_ = fieldmodel.get("type", "str")
  80. if type_ == "float":
  81. try:
  82. _ = float(val)
  83. except (TypeError, ValueError):
  84. logger.error("%s - Valeur invalide, un flottant est attendu ('%s')", fieldname, val)
  85. continue
  86. elif type_ == "datetime":
  87. try:
  88. _ = datetime.strptime(val, fieldmodel.get("date_format", "%d/%m/%Y"))
  89. except ValueError:
  90. logger.error("%s - Valeur invalide, une date est attendu ('%s')", fieldname, val)
  91. continue
  92. else:
  93. if not fieldmodel.get("allow_empty", False) and not val:
  94. logger.error("%s - Champs vide", fieldname)
  95. continue
  96. try:
  97. if not val in fieldmodel["in_list"]:
  98. logger.error("%s - Valeur invalide, pas dans la liste ('%s')", fieldname, val)
  99. continue
  100. except KeyError:
  101. pass
  102. del sf, records
  103. if __name__ == "__main__":
  104. check(subject, checker)
  105. logger.info("-- Fin --")