Ver código fonte

Add 'build_trees' function

olivier.massot 7 anos atrás
pai
commit
aadf34c79e
3 arquivos alterados com 77 adições e 94 exclusões
  1. 2 12
      Viewer.py
  2. 74 30
      core.py
  3. 1 52
      qt_viewer.ui

+ 2 - 12
Viewer.py

@@ -356,24 +356,14 @@ class Viewer(QMainWindow):
         self.ui.txtPanel.clear()
         self.ui.treeWidget.clear()
 
-#         if self.ui.radioRefsOnly.isChecked():
-#             mode = core.REFS_ONLY
-#         elif self.ui.radioDepsOnly.isChecked():
-#             mode = core.DEPS_ONLY
-#         else:
-#             mode = core.DEPS_AND_REFS
-#         print(mode)
-
         QApplication.setOverrideCursor(Qt.WaitCursor)
 
         core.Analyse.run(source_dir)
 
         QApplication.restoreOverrideCursor()
 
-        if core.Analyse.duplicated_names:
-            QMessageBox.warning(self, "Risque d'instabilités", "Attention! Des doublons ont été trouvés dans les noms des objets suivants:\n{}".format(", ".join(core.Analyse.duplicated_names)))
-
-#         QMessageBox.information(self, "test", "{} objets chargés".format(len(core.Analyse.objects)))
+        if core.Analyse.duplicates():
+            QMessageBox.warning(self, "Risque d'instabilités", "Attention! Des doublons ont été trouvés dans les noms des objets")
 
         self.ui.progressBar.setVisible(False)
         self.ui.stackedWidget.setCurrentIndex(1)

+ 74 - 30
core.py

@@ -28,11 +28,11 @@ class InvalidFileExt(IOError):
     pass
 
 class Mention():
-    def __init__(self, line, objname, quote):
+    def __init__(self, line, objname, quote, obj):
         self.line = line
         self.objname = objname
         self.quote = quote
-        self.obj = None
+        self.obj = obj
 
 class AccessObject():
     type_ = "<unknown>"
@@ -45,7 +45,8 @@ class AccessObject():
         self._sourcecode = ""
 
         self.mentions = []
-        self.deps = {}
+        self.deps = []
+        self.refs = []
 
     def __repr__(self):
         return "<{}: {}>".format(self.type_, self.name_)
@@ -107,7 +108,7 @@ class RelationObject(AccessObject):
 
 class Analyse():
     objects = []
-    duplicated_names = []
+    index = {}
 
     @classmethod
     def report(cls, current, total, msg=""):
@@ -138,22 +139,31 @@ class Analyse():
             for file in Path(source_dir / dirname).files():
                 try:
                     obj = accobj.from_file(file)
-                    if obj.name_ in [other.name_ for other in cls.objects] and not obj.name_ in cls.duplicated_names:
-                        cls.duplicated_names.append(obj.name_)
+
                     cls.objects.append(obj)
+
+                    if type(obj) is not ModuleObject:
+                        if not obj.name_ in cls.index:
+                            cls.index[obj.name_] = []
+                        cls.index[obj.name_].append(obj)
+                    else:
+                        for fname in obj.functions:
+                            if not fname in cls.index:
+                                cls.index[fname] = []
+                            cls.index[fname].append(obj)
+
                 except InvalidFileExt:
                     print("Ignored unrecognized file: {}".format(file))
 
     @classmethod
-    def find_deps(cls, subject):
+    def parse_source(cls, subject):
 
         # On cherche le nom de chaque autre objet, ainsi que le nom des fonctions issues des modules
-        look_for = [obj.name_ for obj in cls.objects if obj is not subject] + sum([obj.functions for obj in cls.objects if obj is not subject])
+        look_for = [obj.name_ for obj in cls.objects if obj is not subject] + list(sum([obj.functions for obj in cls.objects if obj is not subject], []))
 
         names = "|".join(list(set(look_for)))
 
         rx = re.compile("""(.*(?:^|\t| |\[|\]|&|\(|\)|\.|!|"|')({})(?:$|\t| |\[|\]|&|\(|\)|\.|!|"|').*)""".format(names), MULTILINE)
-        mentions = []
 
         # Indexe la position des lignes
         line_ends = [m.end() for m in re.finditer('.*\n', subject.sourcecode)]
@@ -162,36 +172,65 @@ class Analyse():
             line = next(i for i in range(len(line_ends)) if line_ends[i] > match.start(1)) + 1
             quote = match.group(1).strip()
             objname = match.group(2)
-            mentions.append(Mention(line, objname, quote))
-        subject.mentions = mentions
 
-#             if mentions:
-#                 subject.deps[candidate] = mentions
+            if len(cls.index[objname]) == 1:
+                obj = cls.index[objname][0]
+            else:
+                print("!!! Duplicate")
+
+            subject.mentions.append(Mention(line, objname, quote, obj))
+
 
     @classmethod
-    def analyse_all(cls):
+    def parse_all(cls):
         # Mise à jour des dépendances:
         # # parcourt les objets, et recherche dans le code source de chacun des mentions du nom des autres objets.
+        for index, subject in enumerate(cls.objects):
+            cls.report(index, len(cls.objects), "* {}: {}".format(subject.type_, subject.name_))
+            cls.parse_source(subject)
+
+    @classmethod
+    def build_trees(cls):
         total = len(cls.objects)
         for index, subject in enumerate(cls.objects):
-            cls.report(index, total, "* {}: {}".format(subject.type_, subject.name_))
-            cls.find_deps(subject)
+            cls.report(index, total * 2)
+
+            for mention in subject.mentions:
+                if not mention.obj in subject.deps:
+                    subject.deps.append(mention.obj)
+
+        for index, subject in enumerate(cls.objects):
+            cls.report(total + index, total * 2)
+
+            for obj in cls.objects:
+                if obj is subject:
+                    continue
+                if subject in obj.deps:
+                    subject.refs.append(obj)
 
     @classmethod
     def run(cls, source_dir):
         # Liste les objets à partir de l'arborescence du repertoire des sources
-        cls.report(0, 100, "Analyse du répertoire")
+        cls.report(0, 100, "Chargement des données")
         cls.load_objects(source_dir)
 
         cls.report(0, 100, "> {} objets trouvés".format(len(cls.objects)))
+        cls.report(0, 100, "Analyse du code source".format(len(cls.objects)))
+        cls.parse_all()
 
-        cls.analyse_all()
+        cls.report(0, 100, "Construction de l'arbre des dépendances".format(len(cls.objects)))
+        cls.build_trees()
 
         cls.report(100, 100, "Analyse terminée")
         cls.ended()
 
         return cls.objects
 
+    @classmethod
+    def duplicates(cls):
+        return {k: v for k, v in cls.items() if len(v) > 1}
+
+
 if __name__ == "__main__":
 
     here = Path(__file__).parent.abspath()
@@ -199,24 +238,29 @@ if __name__ == "__main__":
     resultfile = here / r"test\analyse.txt"
     resultfile.remove_p()
 
-    def print_(i, total, msg):
-        print("({}/{}) {}".format(i, total, msg))
+    def print_(i, total, msg=""):
+        if msg:
+            print("({}/{}) {}".format(i, total, msg))
 
     Analyse.report = print_
 
     Analyse.run(source_dir)
 
-    with open(resultfile, "w+") as f:
+    with open(resultfile, "w+", encoding='utf-8') as f:
         for obj in Analyse.objects:
-            msg = "# L'objet [{}] '{}' mentionne dans son code-source:".format(obj.type_, obj.name_)
-            for mention in obj.mentions:
-                msg += "\n\t\t'{}'\t\tLine: {}\t>>\t{}".format(mention.objname, mention.line, mention.quote)
-#             for dep, mentions in obj.deps.items():
-#                 msg += "\n\t* [{}] '{}'".format(dep.type_, dep.name_)
-#                 for mention in mentions:
-#                     msg += "\n\t\tLine: {} >> {}".format(mention.line, mention.quote)
-#             if not obj.deps:
-#                 msg += "\n\t (pas de dépendances)"
+            msg = "# '{}' [{}]".format(obj.name_, obj.type_)
+            if obj.deps:
+                msg += "\n\tMentionne: {}".format(", ".join(["'{}' [{}]".format(dep.name_, dep.type_) for dep in obj.deps]))
+            else:
+                msg += "\n\t (ne mentionne aucun autre objet)"
+            if obj.refs:
+                msg += "\n\tEst mentionné par: {}".format(", ".join(["'{}' [{}]".format(ref.name_, ref.type_) for ref in obj.refs]))
+            else:
+                msg += "\n\t (n'est mentionné nul part ailleurs)"
+            if obj.mentions:
+                msg += "\n\t Détail:"
+                for mention in obj.mentions:
+                    msg += "\n\t\t'{}'\t\tLine: {}\t>>\t{}".format(mention.objname, mention.line, mention.quote)
 
             msg += "\n"
             f.write(msg)

+ 1 - 52
qt_viewer.ui

@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>886</width>
-    <height>658</height>
+    <height>657</height>
    </rect>
   </property>
   <property name="font">
@@ -409,57 +409,6 @@
           </property>
          </spacer>
         </item>
-        <item>
-         <widget class="QGroupBox" name="groupBox">
-          <property name="minimumSize">
-           <size>
-            <width>200</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="title">
-           <string/>
-          </property>
-          <layout class="QHBoxLayout" name="horizontalLayout_3">
-           <property name="leftMargin">
-            <number>3</number>
-           </property>
-           <property name="topMargin">
-            <number>3</number>
-           </property>
-           <property name="rightMargin">
-            <number>3</number>
-           </property>
-           <property name="bottomMargin">
-            <number>3</number>
-           </property>
-           <item>
-            <widget class="QRadioButton" name="radioDepsAndRefs">
-             <property name="text">
-              <string>Standard</string>
-             </property>
-             <property name="checked">
-              <bool>true</bool>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QRadioButton" name="radioDepsOnly">
-             <property name="text">
-              <string>Dépendances slt.</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QRadioButton" name="radioRefsOnly">
-             <property name="text">
-              <string>Références slt.</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
         <item>
          <widget class="QPushButton" name="btn_test">
           <property name="text">