소스 검색

Ajouts: accepte les zip, controle les coordonnées

olivier.massot 7 년 전
부모
커밋
9fed13afab
4개의 변경된 파일60개의 추가작업 그리고 38개의 파일을 삭제
  1. 1 1
      logging.yaml
  2. 51 34
      main.py
  3. 1 1
      requirements.txt
  4. 7 2
      resources/netgeo_v2-2_doe.yaml

+ 1 - 1
logging.yaml

@@ -35,7 +35,7 @@ handlers:
         capacity: 100000000
 
 loggers:
-    netgeo_checker:
+    datachecker:
         level: DEBUG
         handlers: [console]
         propagate: no

+ 51 - 34
main.py

@@ -3,12 +3,11 @@ Python 3.7+
 
 @author: olivier.massot, sept 2018
 '''
-from dataclasses import dataclass
 from datetime import datetime
 import logging
-import sys
+import zipfile
 
-from path import Path
+from path import Path, TempDir
 import shapefile
 import yaml
 
@@ -16,38 +15,32 @@ from core import logconf
 from core.constants import MAIN
 
 
-logger = logging.getLogger("netgeo_checker")
-logconf.start("netgeo_checker", logging.INFO)
-
-ETUDE, IN_DIR = False, MAIN / "work" / "SCOPELEC_CAP_097AP0_REC_180829_OK"
-# ETUDE, IN_DIR = True, MAIN / "rsc" / "data_in" / "SCOPELEC_101BP0_APD_180725"
-
-
-subject = MAIN / "work" / "SCOPELEC_CAP_097AP0_REC_180829_OK"
-checker = MAIN / "resources" / "netgeo_v2-2_doe.yaml"
-
-# prendre une archive en entrée
-# contrôler la presence des 6 fichiers shp
-# 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
-# Charger les modèles
-# Vérifier enregistrement par enregistrement la validité des données
-
+logger = logging.getLogger("datachecker")
+logconf.start("datachecker", logging.INFO)
 
+# TODO Vérifier la projection (besoin de GDAL/OGR)
 
 def check(subject, checker):    
     """ prends un dossier ou une archive en entier et vérifie son contenu selon les règles données par le fichier de config """
-    archive, checker = Path(subject), Path(checker)
+    subject, checker = Path(subject), Path(checker)
     
-    if archive.isfile():
-        # extraire vers un dossier temp
-        # dirname = tempdir
-        pass
-    elif archive.isdir():
-        dirname = subject
+    if subject.isfile():
+        with TempDir() as dirname:
+            zip_ref = zipfile.ZipFile(subject, 'r')
+            zip_ref.extractall(dirname)
+            zip_ref.close()
+            print()
+            if Path(dirname / subject.stem).isdir(): # cas où l'archive contient un dossier qui lui-même contient les fichiers
+                dirname /= subject.stem
+            check_folder(dirname, checker)
+        
+    elif subject.isdir():
+        check_folder(subject, checker)
     else:
         raise IOError(f"Impossible de trouver le fichier ou répertoire: {subject}")
-    
-    logging.info("*****   Traitement de '%s'   *****", subject.name)
+
+def check_folder(folder, checker):
+    logging.info("*****   Traitement de '%s'   *****", folder.name)
     
     logging.info("> Controlleur: '%s'", checker.name)
     
@@ -55,20 +48,34 @@ def check(subject, checker):
         config = yaml.load(cf)
     
     for filename, model in config["files"].items():
-        path_ = dirname / filename
+        path_ = folder / filename
         logging.info("* Traitement de %s", path_.name)
         
+        if not path_.isfile():
+            logger.error("Fichier introuvable")
+            continue
+        
         try:
             sf = shapefile.Reader(path_)
         except shapefile.ShapefileException:
             logger.error("Fichier SHAPE illisible")
             continue
         
-        shape_names = {1:"Point", 3:"Polyligne", 5:"Polygone"}
-        if sf.shapeType != model["shape_type"]:
-            logger.error("Le fichier shapefile n'est pas de type %s", shape_names[model["shape_type"]])
-            del sf
-            continue
+        if "srid" in config:
+            pass
+
+        xmin, xmax, ymin, ymax = (int(config.get("xmin", 0)), 
+                                  int(config.get("xmax", float("inf"))), 
+                                  int(config.get("ymin", 0)), 
+                                  int(config.get("ymax", float("inf")))
+                                  )
+            
+        if "shape_type" in model:
+            shape_names = {1:"Point", 3:"Polyligne", 5:"Polygone"}
+            if sf.shapeType != model["shape_type"]:
+                logger.error("Le fichier shapefile n'est pas de type %s", shape_names[model["shape_type"]])
+                del sf
+                continue
 
         records = sf.shapeRecords()
         if not records:
@@ -95,6 +102,11 @@ def check(subject, checker):
             logging.info("\n> Enregistrement n°%s\n", i)
             record_data = {field: record.record[i] for i, field in enumerate(fields)}
             
+            x1, y1, x2, y2 = sf.shapes()[i].bbox
+            if not xmin <= x1 <= xmax or not xmin <= x2 <= xmax or \
+               not ymin <= y1 <= ymax or not ymin <= y2 <= ymax:
+                logger.error("L'élément est situé hors de la zone autorisée")
+            
             for fieldname, fieldmodel in model["fields"].items():
                 
                 try:
@@ -133,5 +145,10 @@ def check(subject, checker):
 
 
 if __name__ == "__main__":
+    
+    subject = MAIN / "work" / "SCOPELEC_CAP_097AP0_REC_180829_OK.zip"
+    checker = MAIN / "resources" / "netgeo_v2-2_doe.yaml"
+    
     check(subject, checker)
+    
     logger.info("-- Fin --")

+ 1 - 1
requirements.txt

@@ -1,5 +1,5 @@
 pypyodbc
-path.py
+path.py>=11.1.0
 lxml
 python-dateutil
 pyyaml

+ 7 - 2
resources/netgeo_v2-2_doe.yaml

@@ -1,3 +1,9 @@
+xmin: 1341999.9443451899569482
+xmax: 1429750.0912875002250075
+ymin: 8147750.0839389534667134
+ymax: 8294000.0620922148227692
+srid: 3949
+
 files:
   "artere_geo.shp":
     shape_type: 3
@@ -17,7 +23,6 @@ files:
   "tranchee_geo.shp":
     shape_type: 3
     can_be_empty: False
-    srid: 3949
     fields:
       TR_CODE:
         type: str
@@ -78,4 +83,4 @@ files:
         type: str
         in_list: ["EN ETUDE", "EN REALISATION", "EN SERVICE", "HORS SERVICE"]
   "zapbo_geo.shp":
-    shape_type: 5
+    shape_type: 5