AssistantEric/APIsManager.py

changeset 39
7b6ca9397ecc
parent 32
68ef15fe34c3
child 40
f22c4a330026
--- a/AssistantEric/APIsManager.py	Fri Sep 30 18:19:21 2011 +0200
+++ b/AssistantEric/APIsManager.py	Sat Oct 01 16:21:09 2011 +0200
@@ -40,6 +40,13 @@
     populate_del_api_stmt = """
         DELETE FROM api WHERE fileId = :fileId
     """
+    populate_bases_stmt = """
+        INSERT INTO bases (class, baseClasses, fileId)
+        VALUES (:class, :baseClasses, :fileId)
+    """
+    populate_del_bases_stmt = """
+        DELETE FROM bases WHERE fileId = :fileId
+    """
     populate_file_stmt = """
         INSERT INTO file (file) VALUES (:file)
     """
@@ -128,6 +135,11 @@
             modTime = QFileInfo(os.path.join(self.__projectPath, apiFile)).lastModified()
         else:
             modTime = QFileInfo(apiFile).lastModified()
+            basesFile = os.path.splitext(apiFile)[0] + ".bas"
+            if os.path.exists(basesFile):
+                modTimeBases = QFileInfo(basesFile).lastModified()
+                if modTimeBases > modTime:
+                    modTime = modTimeBases
         if loadTime < modTime:
             self.__loadApiFile(apiFile)
     
@@ -137,6 +149,9 @@
         
         @param apiFile filename of the raw API file (string)
         """
+        apis = []
+        bases = []
+        
         if self.__language == ApisNameProject:
             try:
                 module = Utilities.ModuleParser.readModule(
@@ -147,25 +162,35 @@
                 if language:
                     apiGenerator = APIGenerator(module)
                     apis = apiGenerator.genAPI(True, "", True)
-                else:
-                    apis = []
+                    basesDict = apiGenerator.genBases(True)
+                    for baseEntry in basesDict:
+                        if basesDict[baseEntry]:
+                            bases.append("{0} {1}\n".format(
+                                baseEntry, " ".join(sorted(basesDict[baseEntry]))))
             except (IOError, ImportError):
-                apis = []
+                pass
         else:
             try:
                 apis = Utilities.readEncodedFile(apiFile)[0].splitlines(True)
             except (IOError, UnicodeError):
-                apis = []
+                pass
+            try:
+                basesFile = os.path.splitext(apiFile)[0] + ".bas"
+                if os.path.exists(basesFile):
+                    bases = Utilities.readEncodedFile(basesFile)[0].splitlines(True)
+            except (IOError, UnicodeError):
+                pass
             language = None
         
         if len(apis) > 0:
-            self.__storeApis(apis, apiFile, language)
+            self.__storeApis(apis, bases, apiFile, language)
     
-    def __storeApis(self, apis, apiFile, language):
+    def __storeApis(self, apis, bases, apiFile, language):
         """
         Private method to put the API entries into the database.
         
         @param apis list of api entries (list of strings)
+        @param bases list of base class entries (list of strings)
         @param apiFile filename of the file read to get the APIs (string)
         @param language programming language of the file of the APIs (string)
         """
@@ -195,7 +220,11 @@
             query.bindValue(":fileId", id)
             query.exec_()
             
-            # step 3: load the given api file
+            query.prepare(self.populate_del_bases_stmt)
+            query.bindValue(":fileId", id)
+            query.exec_()
+            
+            # step 3: load the given API info
             query.prepare(self.populate_api_stmt)
             for api in apis:
                 if self.__aborted:
@@ -258,6 +287,22 @@
                     
                     sig = ""
             
+            # step 4: load the given base classes info
+            query.prepare(self.populate_bases_stmt)
+            for base in bases:
+                if self.__aborted:
+                    break
+                
+                base = base.strip()
+                if len(base) == 0:
+                    continue
+                
+                class_, baseClasses = base.split(" ", 1)
+                query.bindValue(":class", class_)
+                query.bindValue(":baseClasses", baseClasses)
+                query.bindValue(":fileId", id)
+                query.exec_()
+            
             if not self.__aborted:
                 # step 4: update the file entry
                 query.prepare(self.update_file_stmt)
@@ -289,12 +334,17 @@
             query.next()
             id = int(query.value(0))
             
-            # step 2: delete all api entries belonging to this file
+            # step 2: delete all API entries belonging to this file
             query.prepare(self.populate_del_api_stmt)
             query.bindValue(":fileId", id)
             query.exec_()
             
-            # step 3: delete the file entry
+            # step 3: delete all base classes entries belonging to this file
+            query.prepare(self.populate_del_bases_stmt)
+            query.bindValue(":fileId", id)
+            query.exec_()
+            
+            # step 4: delete the file entry
             query.prepare(self.file_delete_id_stmt)
             query.bindValue(":id", id)
             query.exec_()
@@ -341,7 +391,7 @@
     apiPreparationStarted = pyqtSignal()
     apiPreparationCancelled = pyqtSignal()
     
-    DB_VERSION = 3
+    DB_VERSION = 4
     
     create_mgmt_stmt = """
         CREATE TABLE mgmt
@@ -362,6 +412,15 @@
     """
     drop_api_stmt = """DROP TABLE IF EXISTS api"""
     
+    create_bases_stmt = """
+        CREATE TABLE bases
+        (class TEXT UNIQUE ON CONFLICT IGNORE,
+         baseClasses TEXT,
+         fileId INTEGER
+        )
+    """
+    drop_bases_stmt = """DROP TABLE IF EXISTS bases"""
+    
     create_file_stmt = """
         CREATE TABLE file
         (id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -380,6 +439,9 @@
     create_fullContext_idx = """CREATE INDEX fullContext_idx on api (fullContext)"""
     drop_fullContext_idx = """DROP INDEX IF EXISTS fullContext_idx"""
     
+    create_bases_idx = """CREATE INDEX base_idx on bases (class)"""
+    drop_bases_idx = """DROP INDEX IF EXISTS base_idx"""
+    
     create_file_idx = """CREATE INDEX file_idx on file (file)"""
     drop_file_idx = """DROP INDEX IF EXISTS file_idx"""
 
@@ -402,6 +464,10 @@
         WHERE acWord GLOB :acWord AND context = :context
         ORDER BY acWord
     """
+    bases_stmt = """
+        SELECT baseClasses from bases
+        WHERE class = :class
+    """
     ct_stmt = """
         SELECT DISTINCT acWord, signature, fullContext FROM api
         WHERE acWord = :acWord
@@ -462,6 +528,7 @@
         """
         if self.__language in ["Python", "Python2", "Python3"]:
             self.__discardFirst = "self"
+            # TODO: discard first can be 'cls' as well
         else:
             self.__discardFirst = ""
         self.__lexer = QScintilla.Lexers.getLexer(self.__language)
@@ -525,14 +592,17 @@
             # step 1: drop old tables
             query.exec_(self.drop_mgmt_stmt)
             query.exec_(self.drop_api_stmt)
+            query.exec_(self.drop_bases_stmt)
             query.exec_(self.drop_file_stmt)
             # step 2: drop old indices
             query.exec_(self.drop_acWord_idx)
             query.exec_(self.drop_context_idx)
             query.exec_(self.drop_fullContext_idx)
+            query.exec_(self.drop_bases_idx)
             query.exec_(self.drop_file_idx)
             # step 3: create tables
             query.exec_(self.create_api_stmt)
+            query.exec_(self.create_bases_stmt)
             query.exec_(self.create_file_stmt)
             query.exec_(self.create_mgmt_stmt)
             query.exec_(self.mgmt_insert_stmt)
@@ -540,6 +610,7 @@
             query.exec_(self.create_acWord_idx)
             query.exec_(self.create_context_idx)
             query.exec_(self.create_fullContext_idx)
+            query.exec_(self.create_bases_idx)
             query.exec_(self.create_file_idx)
         finally:
             del query
@@ -590,7 +661,7 @@
                 db.commit()
         return prepared
     
-    def getCompletions(self, start=None, context=None):
+    def getCompletions(self, start=None, context=None, followHierarchy=False):
         """
         Public method to determine the possible completions.
         
@@ -598,6 +669,8 @@
             completed (string)
         @keyparam context string giving the context (e.g. classname)
             to be completed (string)
+        @keyparam followHierarchy flag indicating to follow the hierarchy of
+            base classes (boolean)
         @return list of dictionaries with possible completions (key 'completion'
             contains the completion (string), key 'context'
             contains the context (string) and key 'pictureId'
@@ -634,11 +707,24 @@
                     del query
             finally:
                 db.commit()
+            
+            if followHierarchy:
+                query = QSqlQuery(db)
+                query.prepare(self.bases_stmt)
+                query.bindValue(":class", context)
+                query.exec_()
+                if query.next():
+                    bases = query.value(0).split()
+                else:
+                    bases = []
+                for base in bases:
+                    completions.extend(self.getCompletions(start, base,
+                                       followHierarchy=True))
         
         return completions
     
     def getCalltips(self, acWord, commas, context=None, fullContext=None,
-                    showContext=True):
+                    showContext=True, followHierarchy=False):
         """
         Public method to determine the calltips.
         
@@ -647,6 +733,8 @@
         @param context string giving the context (e.g. classname) (string)
         @param fullContext string giving the full context (string)
         @param showContext flag indicating to show the calltip context (boolean)
+        @keyparam followHierarchy flag indicating to follow the hierarchy of
+            base classes (boolean)
         @return list of calltips (list of string)
         """
         calltips = []
@@ -689,7 +777,21 @@
             finally:
                 db.commit()
             
-            if context and len(calltips) == 0:
+            if followHierarchy:
+                query = QSqlQuery(db)
+                query.prepare(self.bases_stmt)
+                query.bindValue(":class", context)
+                query.exec_()
+                if query.next():
+                    bases = query.value(0).split()
+                else:
+                    bases = []
+                for base in bases:
+                    calltips.extend(self.getCalltips(acWord, commas, context=base,
+                                                     showContext=showContext,
+                                                     followHierarchy=True))
+            
+            if context and len(calltips) == 0 and not followHierarchy:
                 # nothing found, try without a context
                 calltips = self.getCalltips(acWord, commas, showContext=showContext)
         

eric ide

mercurial