فهرست منبع

integration moteur datacheck ok

omassot 7 سال پیش
والد
کامیت
97aba191da
8فایلهای تغییر یافته به همراه132 افزوده شده و 76 حذف شده
  1. 0 19
      core/constants.py
  2. 2 1
      core/logging.yaml
  3. 57 0
      core/model.py
  4. 3 3
      core/validation_errors.py
  5. 20 34
      core/validator.py
  6. 6 9
      schemas/mn1_rec.py
  7. 6 6
      schemas/mn2_rec.py
  8. 38 4
      ui/dlg_main.py

+ 0 - 19
core/constants.py

@@ -12,22 +12,3 @@ LOGDIR = Path("%appdata%").expandvars() / "mncheck"
 LOGDIR.mkdir_p()
 
 LOGCONF = MAIN / "core" / "logging.yaml"
-
-
-
-GEOM_UNKNOWN = 0
-GEOM_POINT = 1
-GEOM_LINE = 2
-GEOM_POLYGON = 3
-GEOM_MULTIPOINT = 4
-GEOM_MULTILINE = 5
-GEOM_MULTIPOLYGON = 6
-
-GEOM_NAMES = {0: "(AUCUN)", 
-               1: "POINT", 
-               2: "LIGNE", 
-               3: "POLYGONE", 
-               4: "MULTI-POINT", 
-               5:"MULTI-LIGNE", 
-               6:"MULTI-POLYGONE",
-               }

+ 2 - 1
core/logging.yaml

@@ -15,6 +15,7 @@ handlers:
         class: core.QHandler.QHandler
         level: DEBUG
         formatter: message_only
+        
     file:
         class: logging.handlers.RotatingFileHandler
         level: DEBUG
@@ -32,5 +33,5 @@ loggers:
 
 root:
     level: DEBUG
-    handlers: [file]
+    handlers: []
     propagate: yes

+ 57 - 0
core/model.py

@@ -0,0 +1,57 @@
+'''
+
+@author: olivier.massot, 2018
+'''
+
+import logging
+from qgis.core import QgsWkbTypes
+
+from PyQt5.QtCore import QVariant
+
+
+logger = logging.getLogger("mncheck")
+
+class QgsModel():
+    
+    GEOM_UNKNOWN = 0
+    GEOM_POINT = 1
+    GEOM_LINE = 2
+    GEOM_POLYGON = 3
+    GEOM_MULTIPOINT = 4
+    GEOM_MULTILINE = 5
+    GEOM_MULTIPOLYGON = 6
+    
+    GEOM_NAMES = {0: "(AUCUN)", 1: "POINT", 2: "LIGNE", 3: "POLYGONE", 
+                  4: "MULTI-POINT", 5:"MULTI-LIGNE", 6:"MULTI-POLYGONE"}
+    
+    layername = ""
+    pk = ""
+    geom_type = 0
+    bounding_box = (0,0,1,1)
+    schema = {}
+
+    def __init__(self, qgs_feature):
+        
+        self._feature = qgs_feature
+        
+        attributes = dict(zip([f.name() for f in qgs_feature.fields()], qgs_feature.attributes()))
+        
+        for attr, value in attributes.items():
+            if isinstance(value, QVariant):
+                value = value.value() if not value.isNull() else ""
+            setattr(self, attr, value)
+        
+        self.geom = qgs_feature.geometry()
+        
+    def is_geometry_valid(self):
+        return self._feature.geometry().isGeosValid()
+        
+    def get_geom_type(self):
+        return QgsWkbTypes.singleType(self._feature.geometry().wkbType())
+        
+    def get_bounding_box(self):
+        bb = self._feature.geometry().boundingBox()
+        return (bb.xMinimum(), bb.yMinimum(), bb.xMaximum(), bb.yMaximum())
+    
+        
+        

+ 3 - 3
core/validation_errors.py

@@ -14,13 +14,13 @@ class BaseValidationError():
     name = "Erreur"
     level = ERROR
     help = ""
-    def __init__(self, message, filename="", field=""):
+    def __init__(self, message, layername="", field=""):
         self.message = message
-        self.filename = filename
+        self.layername = layername
         self.field = field
         
     def __repr__(self):
-        return " - ".join(filter(None, [self.name, self.filename, self.field, self.message]))
+        return " - ".join(filter(None, [self.name, self.layername, self.field, self.message]))
 
 # Erreurs dans le chargement des couches
 class InputError(BaseValidationError):

+ 20 - 34
core/validator.py

@@ -3,14 +3,18 @@
 
     @author: olivier.massot, sept. 2018
 '''
-from qgis.core import QgsProject #@UnresolvedImport
+import logging
+from qgis.core import QgsProject
 
-from core import constants
 from core.cerberus_extend import CerberusErrorHandler, \
     _translate_messages, ExtendedValidator
+from core.model import QgsModel
 from core.validation_errors import CRITICAL, DataError, GeomTypeError, BoundingBoxError, \
     MissingLayer, WrongSrid
 
+
+logger = logging.getLogger("mncheck")
+
 class ValidatorInterruption(BaseException): 
     pass
 
@@ -19,28 +23,6 @@ class Checkpoint():
         self.name = name
         self.valid = valid
 
-
-###########    MODELES    ################
-
-class BaseModel():
-    filename = ""
-    pk = ""
-    schema = {}
-    def __init__(self, **kwargs):
-        self.__dict__.update(kwargs)
-        
-class QgsModel():
-    layername = ""
-    pk = ""
-    geom_type = 0
-    bounding_box = (0,0,1,1)
-    schema = {}
-    
-    def __init__(self, qgs_feature):
-        self.__dict__.update(qgs_feature.__dict__)
-
-###########    VALIDATION    ################
-
 class BaseValidator():
     schema_name = ""
     models = {}
@@ -88,7 +70,7 @@ class BaseValidator():
         # Controle la structure des données (champs, formats et types)
         self._structure_validation()
         self.checkpoint("Contrôle de la structure des données")
-        
+         
         # Validation technique
         try:
             self._technical_validation()
@@ -128,30 +110,34 @@ class BaseValidator():
             
             for item in self.dataset[model]:
 
+                # geom valid
+                if not item.is_geometry_valid():
+                    self.log_error(GeomTypeError("La géométrie de l'objet est invalide".format(), layername=model.layername, field="geom"))
+
                 # geom type
-                if item.geom_type != model.geom_type:
-                    self.log_error(GeomTypeError("Type de géométrie invalide: {} (attendu: {})".format(item.geom_name, constants.GEOM_NAMES[model.geom_type]), filename=model.filename, field="geom"))
+                if item.get_geom_type() != model.geom_type:
+                    self.log_error(GeomTypeError("Type de géométrie invalide: {} (attendu: {})".format(item.geom_name, QgsModel.GEOM_NAMES[model.geom_type]), layername=model.layername, field="geom"))
 
                 # bounding box
-                x1, y1, x2, y2 = item.bounding_box
+                x1, y1, x2, y2 = item.get_bounding_box()
                 if any(x < xmin or x > xmax for x in (x1, x2)) or \
                    any(y < ymin or y > ymax for y in (y1, y2)):
-                    self.log_error(BoundingBoxError("Situé hors de l'emprise autorisée", filename=model.filename, field="geom"))
+                    self.log_error(BoundingBoxError("Situé hors de l'emprise autorisée", layername=model.layername, field="geom"))
 
                 v.validate(item.__dict__)
-               
+                
                 for field, verrors in v.errors.items():
                     for err in verrors:
-                        self.log_error(DataError(_translate_messages(err), filename=model.filename, field=field))
+                        self.log_error(DataError(_translate_messages(err), layername=model.layername, field=field))
     
     @classmethod
     def _technical_validation(cls):
         raise NotImplementedError()
     
-    def build_report(self, schema, filename):
+    def build_report(self, schema, layername):
         report = {}
         report["schema"] = schema
-        report["filename"] = filename
+        report["reportname"] = ""
         report["checkpoints"] = [{"name": chk.name, "valid": chk.valid} for chk in self.checkpoints]
         
         report["errors"] = {}
@@ -160,7 +146,7 @@ class BaseValidator():
             if not err.name in report["errors"]:
                 report["errors"][err.name] = {"help": err.help, "order_": err.order_, "list": []}
             
-            err_report = {"filename": err.filename or "-",
+            err_report = {"layername": err.layername or "-",
                           "field": err.field or "-",
                           "message": err.message}
             if err_report not in report["errors"][err.name]["list"]:

+ 6 - 9
schemas/mn1_rec.py

@@ -15,7 +15,7 @@ from schemas._common import XMIN, YMIN, XMAX, YMAX, TOLERANCE, CRS
 
 class Artere(QgsModel):
     layername = "artere_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'AR_ID_INSE': {'type': 'string', 'empty': False, 'regex': r'50\d{3}'}, 
@@ -46,7 +46,7 @@ class Artere(QgsModel):
 
 class Cable(QgsModel):
     layername = "cable_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'CA_NUMERO': {'type': 'string', 'maxlength': 17}, 
@@ -72,7 +72,7 @@ class Cable(QgsModel):
     
 class Equipement(QgsModel):
     layername = "equipement_passif"
-    geom_type = constants.GEOM_POINT
+    geom_type = QgsModel.GEOM_POINT
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'EQ_NOM': {'type': 'string', 'maxlength': 10, 'contains_any_of': ['PBO', 'BPE', 'BAI']}, 
@@ -94,7 +94,7 @@ class Equipement(QgsModel):
 
 class Noeud(QgsModel):
     layername = "noeud_geo"
-    geom_type = constants.GEOM_POINT
+    geom_type = QgsModel.GEOM_POINT
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'NO_NOM': {'type': 'string', 'maxlength': 30}, 
@@ -127,7 +127,7 @@ class Noeud(QgsModel):
     
 class Tranchee(QgsModel):
     layername = "tranchee_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'TR_ID_INSE': {'type': 'string', 'empty': False, 'regex': r'50\d{3}'}, 
@@ -156,7 +156,7 @@ class Tranchee(QgsModel):
     
 class Zapbo(QgsModel):
     layername = "zapbo_geo"
-    geom_type = constants.GEOM_POLYGON
+    geom_type = QgsModel.GEOM_POLYGON
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'ID_ZAPBO': {'type': 'string', 'maxlength': 30, 'contains_any_of': ['PBO', 'BPE']}, 
@@ -168,9 +168,6 @@ class Zapbo(QgsModel):
     
     
     
-    
-    
-    
 ####### Validateur
     
     

+ 6 - 6
schemas/mn2_rec.py

@@ -21,7 +21,7 @@ STATUTS = ['EN ETUDE', 'EN REALISATION', 'EN SERVICE', 'HORS SERVICE']
 
 class Artere(QgsModel):
     layername = "artere_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'AR_CODE': {'type': 'string', 'maxlength': 26},
@@ -60,7 +60,7 @@ class Artere(QgsModel):
 
 class Cable(QgsModel):
     layername = "cable_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'CA_CODE': {'type': 'string', 'maxlength': 18}, 
@@ -93,7 +93,7 @@ class Cable(QgsModel):
     
 class Equipement(QgsModel):
     layername = "equipement_passif"
-    geom_type = constants.GEOM_POINT
+    geom_type = QgsModel.GEOM_POINT
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'EQ_CODE': {'type': 'string', 'maxlength': 18}, 
@@ -125,7 +125,7 @@ class Equipement(QgsModel):
 
 class Noeud(QgsModel):
     layername = "noeud_geo"
-    geom_type = constants.GEOM_POINT
+    geom_type = QgsModel.GEOM_POINT
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'NO_CODE': {'type': 'string', 'maxlength': 18}, 
@@ -161,7 +161,7 @@ class Noeud(QgsModel):
     
 class Tranchee(QgsModel):
     layername = "tranchee_geo"
-    geom_type = constants.GEOM_LINE
+    geom_type = QgsModel.GEOM_LINE
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'TR_CODE': {'type': 'string', 'maxlength': 23}, 
@@ -193,7 +193,7 @@ class Tranchee(QgsModel):
     
 class Zapbo(QgsModel):
     layername = "zapbo_geo"
-    geom_type = constants.GEOM_POLYGON
+    geom_type = QgsModel.GEOM_POLYGON
     crs = CRS
     bounding_box = (XMIN,YMIN,XMAX,YMAX)
     schema = {'ID_ZAPBO': {'type': 'string', 'maxlength': 30, 'contains_any_of': ['PBO', 'BPE']}, 

+ 38 - 4
ui/dlg_main.py

@@ -2,17 +2,16 @@
 """
 import importlib
 import logging
-
-from qgis.core import QgsProject #@UnresolvedImport
+from qgis.core import QgsProject  # @UnresolvedImport
 
 from PyQt5 import QtWidgets
 from PyQt5 import uic
 from PyQt5.Qt import QIcon, QPixmap, Qt, QTableWidgetItem, QHeaderView
+from PyQt5.QtWidgets import QApplication
 
 from core.constants import MAIN, RSCDIR
 
 
-
 logger = logging.getLogger("mncheck")
 
 Ui_Main, _ = uic.loadUiType(MAIN / 'ui'/ 'dlg_main.ui')
@@ -105,6 +104,9 @@ class DlgMain(QtWidgets.QDialog):
 
     def run(self):
         
+        QApplication.setOverrideCursor(Qt.WaitCursor)
+        self.clear_layers_table()
+        
         validator = self.selected_validator()
         
         if not validator:
@@ -113,7 +115,39 @@ class DlgMain(QtWidgets.QDialog):
         
         report = validator.submit(self.iface)
         
-        logger.info(report)
+        logger.debug(report)
+        
+        for chk in report["checkpoints"]:
+            cur_row = self.ui.tbl_layers.rowCount()
+            self.ui.tbl_layers.insertRow(cur_row)
+            
+            lbl_icon, lbl_checkpoint = QTableWidgetItem(), QTableWidgetItem()
+            
+            lbl_checkpoint.setText(chk["name"])
+            lbl_icon.setIcon(QIcon(QPixmap(RSCDIR / ("ok_16.png" if chk["valid"] else "error_16.png"))))
+            
+            self.ui.tbl_layers.setItem(cur_row, 0, lbl_icon)
+            self.ui.tbl_layers.setItem(cur_row, 1, lbl_checkpoint)
+            if not chk["valid"]:
+                self.ui.tbl_layers.setItem(cur_row, 2, QTableWidgetItem("Des erreurs ont été trouvées"))
+
+        
+        for type_err in report["errors"]:
+            for err in report["errors"][type_err]["list"]:
+                cur_row = self.ui.tbl_layers.rowCount()
+                self.ui.tbl_layers.insertRow(cur_row)
+                
+                lbl_icon, lbl_field, lbl_err = QTableWidgetItem(), QTableWidgetItem(), QTableWidgetItem()
+                
+                lbl_field.setText(f"{err['layername']}.{err['field']}")
+                lbl_err.setText(f"{type_err}: {err['message']}")
+#                 lbl_icon.setIcon(QIcon(QPixmap(RSCDIR / "error_16.png")))
+                
+#                 self.ui.tbl_layers.setItem(cur_row, 0, lbl_icon)
+                self.ui.tbl_layers.setItem(cur_row, 1, lbl_field)
+                self.ui.tbl_layers.setItem(cur_row, 2, lbl_err)
+    
+        QApplication.restoreOverrideCursor()
     
     def show_help(self):
         pass