def getImportedNameDefinitionLine( path, name, info = None ): """ Searches for the given name in the given file and provides its line number. -1 if not found. Only top level names are searched through. """ if info is None: mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetForFileName( os.path.realpath( path ) ) if widget is None: # The file is not opened now info = getBriefModuleInfoFromFile( path ) else: editor = widget.getEditor() info = getBriefModuleInfoFromMemory( editor.text() ) # Check the object names for classObj in info.classes: if classObj.name == name: return classObj.line for funcObj in info.functions: if funcObj.name == name: return funcObj.line for globalObj in info.globals: if globalObj.name == name: return globalObj.line return -1
def getImportsList( fileContent ): " Parses a python file and provides a list imports in it " result = [] info = getBriefModuleInfoFromMemory( str( fileContent ) ) for importObj in info.imports: if importObj.name not in result: result.append( importObj.name ) return result
def getCurrentBufferInfo( self ): " Provides the current buffer parsed info " if self.__currentUUID is None: return None widget = self.__editorsManager.getWidgetByUUID( self.__currentUUID ) if widget is None: return None editor = widget.getEditor() info = getBriefModuleInfoFromMemory( editor.text() ) return info
def __extractDocstring(self, content): " Extracts a docstring and sets it as a tooltip if needed " if self.tooltip != "": return if self.fileName.endswith( '.py' ) or \ self.fileName.endswith( '.py3' ) or \ self.fileName.endswith( '.pyw' ): info = getBriefModuleInfoFromMemory("\n".join(content)) self.tooltip = "" if info.docstring is not None: self.tooltip = info.docstring.text return
def __extractDocstring( self, content ): " Extracts a docstring and sets it as a tooltip if needed " if self.tooltip != "": return if self.fileName.endswith( '.py' ) or \ self.fileName.endswith( '.py3' ) or \ self.fileName.endswith( '.pyw' ): info = getBriefModuleInfoFromMemory( "\n".join( content ) ) self.tooltip = "" if info.docstring is not None: self.tooltip = info.docstring.text return
def test_lone_import( self ): " Test for lone import keyword " pythonFile = self.dir + "loneimport.py" info = cdmbriefparser.getBriefModuleInfoFromFile( pythonFile ) self.failUnless( info.isOK != True ) f = open( pythonFile ) content = f.read() f.close() info = cdmbriefparser.getBriefModuleInfoFromMemory( content ) self.failUnless( info.isOK != True ) return
def test_lone_import(self): " Test for lone import keyword " pythonFile = self.dir + "loneimport.py" info = cdmbriefparser.getBriefModuleInfoFromFile(pythonFile) self.failUnless(info.isOK != True) f = open(pythonFile) content = f.read() f.close() info = cdmbriefparser.getBriefModuleInfoFromMemory(content) self.failUnless(info.isOK != True) return
def getImportsInLine( fileContent, lineNumber ): " Provides a list of imports in in the given import line " imports = [] importsWhat = [] info = getBriefModuleInfoFromMemory( str( fileContent ) ) for importObj in info.imports: if importObj.line == lineNumber: if importObj.name not in imports: imports.append( importObj.name ) for whatObj in importObj.what: if whatObj.name not in importsWhat: importsWhat.append( whatObj.name ) return imports, importsWhat
def __populateFromProject( self ): " Populates find name dialog from the project files " mainWindow = GlobalData().mainWindow for fname in GlobalData().project.filesList: if detectFileType( fname ) in [ PythonFileType, Python3FileType ]: widget = mainWindow.getWidgetForFileName( fname ) if widget is None: info = GlobalData().briefModinfoCache.get( fname ) else: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) self.__populateInfo( info, fname ) return
def main(): " main function for the netschedule multi test " parser = OptionParser( """ %prog <file name> """ ) parser.add_option( "-m", "--use-memory-buffer", action="store_true", dest="memory", default=False, help="Read the whole file first and " \ "then parse it (default: False)" ) # parse the command line options options, args = parser.parse_args() if len( args ) != 1: return parserError( parser, "One argument is expected" ) fileName = os.path.abspath( args[ 0 ] ) if not os.path.exists( fileName ): raise Exception( "Cannot find file to parse. Expected here: " + \ fileName ) info = None if options.memory: content = file( fileName ).read() info = getBriefModuleInfoFromMemory( content ) else: info = getBriefModuleInfoFromFile( fileName ) print info.niceStringify() if info.isOK: print "No errors found" else: print "Errors found" if len( info.lexerErrors ) > 0: print "Lexer errors:" print "\n".join( info.lexerErrors ) else: print "No lexer errors" if len( info.errors ) > 0: print "Parser errors:" print "\n".join( info.errors ) else: print "No parser errors" return 0
def __populateFromOpened( self ): " Populates the name dialog from the opened files " mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager for record in editorsManager.getTextEditors(): # uuid = record[ 0 ] fname = record[ 1 ] widget = record[ 2 ] if fname.endswith( '.py' ) or \ fname.endswith( '.py3' ) or \ fname.endswith( '.pyw' ): content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) self.__populateInfo( info, fname ) return
def __showParserError( self ): " Shows the parser errors window " if self.__currentUUID is None: return try: fName = self.__outlineBrowsers[ self.__currentUUID ].shortFileName widget = self.__editorsManager.getWidgetByUUID( self.__currentUUID ) if widget is None: return editor = widget.getEditor() info = getBriefModuleInfoFromMemory( editor.text() ) dialog = ParserErrorsDialog( fName, info ) dialog.exec_() except Exception, ex: logging.error( str( ex ) )
def _isSystemImportOrAlias( obj, text, info ): " Checks if the obj is a system wide import name (possibly alias) " buildSystemWideModulesList() if obj in __systemwideModules: return True, obj # Check aliases if info is None: info = getBriefModuleInfoFromMemory( text ) for item in info.imports: if item.alias == obj: if item.name in __systemwideModules: # That's an alias for a system module return True, item.name # That's an alias for something else, so stop search for a system # module alias return False, obj return False, obj
def _isSystemImportOrAlias(obj, text, info): " Checks if the obj is a system wide import name (possibly alias) " buildSystemWideModulesList() if obj in __systemwideModules: return True, obj # Check aliases if info is None: info = getBriefModuleInfoFromMemory(text) for item in info.imports: if item.alias == obj: if item.name in __systemwideModules: # That's an alias for a system module return True, item.name # That's an alias for something else, so stop search for a system # module alias return False, obj return False, obj
def meat(self, pythonFile, errorMsg): " The test process meat " info = cdmbriefparser.getBriefModuleInfoFromFile(pythonFile) self.failUnless(info.isOK == True) f = open(pythonFile) content = f.read() f.close() info = cdmbriefparser.getBriefModuleInfoFromMemory(content) self.failUnless(info.isOK == True) outFileName = pythonFile.replace(".py", ".out") outFile = open(outFileName, "w") outFile.write(info.niceStringify()) outFile.close() okFileName = pythonFile.replace(".py", ".ok") self.failUnless(files_equal(outFileName, okFileName), errorMsg) return
def __populateFromOpened(self): " Populates the name dialog from the opened files " mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager showTooltips = Settings().findFileTooltips for record in editorsManager.getTextEditors(): # uuid = record[ 0 ] fname = record[1] widget = record[2] fileType = detectFileType(fname) tooltip = "" if showTooltips and fileType in [PythonFileType, Python3FileType]: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory(content) if info.docstring is not None: tooltip = info.docstring.text newItem = FileItem(self.rootItem, getFileIcon(fileType), fname, tooltip) self.rootItem.appendChild(newItem) self.count += 1 return
def meat( self, pythonFile, errorMsg ): " The test process meat " info = cdmbriefparser.getBriefModuleInfoFromFile( pythonFile ) self.failUnless( info.isOK == True ) f = open( pythonFile ) content = f.read() f.close() info = cdmbriefparser.getBriefModuleInfoFromMemory( content ) self.failUnless( info.isOK == True ) outFileName = pythonFile.replace( ".py", ".out" ) outFile = open( outFileName, "w" ) outFile.write( info.niceStringify() ) outFile.close() okFileName = pythonFile.replace( ".py", ".ok" ) self.failUnless( files_equal( outFileName, okFileName ), errorMsg ) return
def __populateFromOpened( self ): " Populates the name dialog from the opened files " mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager showTooltips = Settings().findFileTooltips for record in editorsManager.getTextEditors(): # uuid = record[ 0 ] fname = record[ 1 ] widget = record[ 2 ] fileType = detectFileType( fname ) tooltip = "" if showTooltips and fileType in [ PythonFileType, Python3FileType ]: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) if info.docstring is not None: tooltip = info.docstring.text newItem = FileItem( self.rootItem, getFileIcon( fileType ), fname, tooltip ) self.rootItem.appendChild( newItem ) self.count += 1 return
def __populateFromProject(self): " Populates find name dialog from the project files " mainWindow = GlobalData().mainWindow showTooltips = Settings().findFileTooltips for fname in GlobalData().project.filesList: if fname.endswith(os.path.sep): continue fileType = detectFileType(fname) tooltip = "" if showTooltips and fileType in [PythonFileType, Python3FileType]: widget = mainWindow.getWidgetForFileName(fname) if widget is None: info = GlobalData().briefModinfoCache.get(fname) else: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory(content) if info.docstring is not None: tooltip = info.docstring.text newItem = FileItem(self.rootItem, getFileIcon(fileType), fname, tooltip) self.rootItem.appendChild(newItem) self.count += 1 return
def __populateFromProject( self ): " Populates find name dialog from the project files " mainWindow = GlobalData().mainWindow showTooltips = Settings().findFileTooltips for fname in GlobalData().project.filesList: if fname.endswith( os.path.sep ): continue fileType = detectFileType( fname ) tooltip = "" if showTooltips and fileType in [ PythonFileType, Python3FileType ]: widget = mainWindow.getWidgetForFileName( fname ) if widget is None: info = GlobalData().briefModinfoCache.get( fname ) else: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) if info.docstring is not None: tooltip = info.docstring.text newItem = FileItem( self.rootItem, getFileIcon( fileType ), fname, tooltip ) self.rootItem.appendChild( newItem ) self.count += 1 return
def __onTabChanged( self, index ): " Triggered when another tab becomes active " # If the timer is still active that means the tab was switched before # the handler had a chance to work. Therefore update the previous tab # first if so. if self.__updateTimer.isActive(): self.__updateTimer.stop() self.__updateView() # Now, switch the outline browser to the new tab if index == -1: widget = self.__editorsManager.currentWidget() else: widget = self.__editorsManager.getWidgetByIndex( index ) if widget is None: if self.__currentUUID is not None: self.__outlineBrowsers[ self.__currentUUID ].browser.hide() self.__currentUUID = None self.__noneLabel.show() self.showParsingErrorsButton.setEnabled( False ) return if widget.getType() not in [ MainWindowTabWidgetBase.PlainTextEditor, MainWindowTabWidgetBase.VCSAnnotateViewer ]: if self.__currentUUID is not None: self.__outlineBrowsers[ self.__currentUUID ].browser.hide() self.__currentUUID = None self.__noneLabel.show() self.showParsingErrorsButton.setEnabled( False ) return # This is text editor, detect the file type if widget.getFileType() not in [ PythonFileType, Python3FileType ]: if self.__currentUUID is not None: self.__outlineBrowsers[ self.__currentUUID ].browser.hide() self.__currentUUID = None self.__noneLabel.show() self.showParsingErrorsButton.setEnabled( False ) return # This is a python file, check if we already have the parsed info in # the cache uuid = widget.getUUID() if uuid in self.__outlineBrowsers: # We have it, hide the current and show the existed if self.__currentUUID is not None: self.__outlineBrowsers[ self.__currentUUID ].browser.hide() self.__currentUUID = None else: self.__noneLabel.hide() self.__currentUUID = uuid self.__outlineBrowsers[ self.__currentUUID ].browser.show() info = self.__outlineBrowsers[ self.__currentUUID ].info self.showParsingErrorsButton.setEnabled( info.isOK != True ) return # It is first time we are here, create a new editor = widget.getEditor() editor.SCEN_CHANGE.connect( self.__onBufferChanged ) editor.cursorPositionChanged.connect( self.__cursorPositionChanged ) info = getBriefModuleInfoFromMemory( editor.text() ) self.showParsingErrorsButton.setEnabled( info.isOK != True ) shortFileName = widget.getShortName() browser = OutlineBrowser( uuid, shortFileName, info, self ) browser.setHeaderHighlight( info.isOK != True ) self.__connectOutlineBrowser( browser ) self.__layout.addWidget( browser ) if self.__currentUUID is not None: self.__outlineBrowsers[ self.__currentUUID ].browser.hide() self.__currentUUID = None else: self.__noneLabel.hide() self.__currentUUID = uuid attributes = OutlineAttributes() attributes.browser = browser attributes.contextItem = None attributes.info = info attributes.shortFileName = shortFileName attributes.changed = False self.__outlineBrowsers[ self.__currentUUID ] = attributes self.__outlineBrowsers[ self.__currentUUID ].browser.show() return
def getContext(editor, info=None, skipBlankLinesBack=False, skipDef=True): """ Detects the context at the text cursor position. skipBlankLinesBack == False => current cursor position is used skipBlankLinesBack == True => skip blank lines back and use the first non-blank line as the cursor position. skipDef == True => treat a definition as belonging to an upper level context (not included into the context stack) skipDef == False => treat a definition as starting a context level (included into the context stack as the last one) """ # It is expected that this is a python editor. # If non-python editor is given, then a global context is provided context = TextCursorContext() lexer = editor.lexer() if lexer is None or not isinstance(lexer, QsciLexerPython): return context # It's not the first position, so the parsed module info is required if info is None: info = getBriefModuleInfoFromMemory(editor.text()) line, pos = editor.getCursorPosition() if skipBlankLinesBack == True: while line >= 0: text = editor.text(line) trimmedText = text.strip() if trimmedText != "": pos = len(text.rstrip()) break line -= 1 if line < 0: line = 0 pos = 0 _IdentifyScope(info, context, line + 1, pos, skipDef) if not skipDef: if _getDefinitionObject(info, line + 1, pos) is not None: return context if context.length == 0: return context continueLine = False currentLine = context.getLastScopeLine() + 1 for currentLine in xrange(context.getLastScopeLine(), editor.lines()): if currentLine == line: break text = editor.text(currentLine) trimmedText = text.strip() if continueLine == False: if trimmedText == "" or trimmedText.startswith("#"): continue # Here: there must be characters in the line nonSpacePos = _getFirstNonSpacePos(text) context.stripLevels(nonSpacePos) if context.length == 0: return context if trimmedText.endswith( "," ) or trimmedText.endswith( '\\' ) or \ _endsWithTripleQuotedString( editor, currentLine, len( text ) - 1 ): continueLine = True else: continueLine = False if continueLine: context.stripLevels(nonSpacePos) else: nonSpacePos = _getFirstNonSpacePos(editor.text(line)) if nonSpacePos == -1: context.stripLevels(pos) else: context.stripLevels(min(pos, nonSpacePos)) return context
def __onMcCabeObject( self, objName, fileName ): " Called when the user activated McCabe item " info = None mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: if fileName == "": logging.error( "The unsaved buffer has been closed" ) return # No widget, but we know the file name info = getBriefModuleInfoFromFile( fileName ) else: # The widget was found editor = widget.getEditor() # The editor content has been modified, so re-parse the buffer info = getBriefModuleInfoFromMemory( editor.text() ) parts = objName.split( '.' ) currentIndex = 0 functionsContainer = info.functions classesContainer = info.classes line = -1 if objName == "__main__" and len( parts ) == 1: # Special case - global file scope line = 1 currentIndex = 1 while currentIndex < len( parts ): found = False for func in functionsContainer: if func.name == parts[ currentIndex ]: if currentIndex == len( parts ) - 1: # Found, jump to the line line = func.line break functionsContainer = func.functions classesContainer = func.classes found = True break if line != -1: break if found: currentIndex += 1 continue for klass in classesContainer: if klass.name == parts[ currentIndex ]: if currentIndex == len( parts ) - 1: # Found, jump to the line line = klass.line break functionsContainer = klass.functions classesContainer = klass.classes found = True if line != -1: break if found: currentIndex += 1 continue # Not found logging.error( "Cannot find the " + objName ) return # Here we have the line number if widget is None: GlobalData().mainWindow.openFile( fileName, line ) else: editor = widget.getEditor() editor.gotoLine( line ) editor.setFocus() return
def getContext( editor, info = None, skipBlankLinesBack = False, skipDef = True ): """ Detects the context at the text cursor position. skipBlankLinesBack == False => current cursor position is used skipBlankLinesBack == True => skip blank lines back and use the first non-blank line as the cursor position. skipDef == True => treat a definition as belonging to an upper level context (not included into the context stack) skipDef == False => treat a definition as starting a context level (included into the context stack as the last one) """ # It is expected that this is a python editor. # If non-python editor is given, then a global context is provided context = TextCursorContext() lexer = editor.lexer() if lexer is None or not isinstance( lexer, QsciLexerPython ): return context # It's not the first position, so the parsed module info is required if info is None: info = getBriefModuleInfoFromMemory( editor.text() ) line, pos = editor.getCursorPosition() if skipBlankLinesBack == True: while line >= 0: text = editor.text( line ) trimmedText = text.strip() if trimmedText != "": pos = len( text.rstrip() ) break line -= 1 if line < 0: line = 0 pos = 0 _IdentifyScope( info, context, line + 1, pos, skipDef ) if not skipDef: if _getDefinitionObject( info, line + 1, pos ) is not None: return context if context.length == 0: return context continueLine = False currentLine = context.getLastScopeLine() + 1 for currentLine in xrange( context.getLastScopeLine(), editor.lines() ): if currentLine == line: break text = editor.text( currentLine ) trimmedText = text.strip() if continueLine == False: if trimmedText == "" or trimmedText.startswith( "#" ): continue # Here: there must be characters in the line nonSpacePos = _getFirstNonSpacePos( text ) context.stripLevels( nonSpacePos ) if context.length == 0: return context if trimmedText.endswith( "," ) or trimmedText.endswith( '\\' ) or \ _endsWithTripleQuotedString( editor, currentLine, len( text ) - 1 ): continueLine = True else: continueLine = False if continueLine: context.stripLevels( nonSpacePos ) else: nonSpacePos = _getFirstNonSpacePos( editor.text( line ) ) if nonSpacePos == -1: context.stripLevels( pos ) else: context.stripLevels( min( pos, nonSpacePos ) ) return context
def __getImportedObjects(moduleName, fileName): " Provides a list of objects to be imported from " buildSystemWideModulesList() modulePath = None moduleName = str(moduleName) if moduleName in __systemwideModules: modulePath = __systemwideModules[moduleName] if modulePath is None or moduleName in Settings().dirSafeModules: # it could be a built-in module return getImportNames(moduleName) else: # Not a system wide, try search in the project # or current directories if moduleName.startswith("."): # That's a relative import if not fileName: # File name must be known for a relative import return set() dotCount = 0 while moduleName.startswith("."): dotCount += 1 moduleName = moduleName[1:] # Strip as many paths as dots instruct baseDir = os.path.dirname(fileName) while dotCount > 1: baseDir = os.path.dirname(baseDir) dotCount -= 1 specificModules = getProjectSpecificModules(baseDir, True) else: specificModules = getProjectSpecificModules(fileName) if moduleName in specificModules: modulePath = specificModules[moduleName] if modulePath is None: return set() binarySuffix = __isBinaryModule(modulePath) if binarySuffix is not None: try: modName = os.path.basename(modulePath) modObj = imp.load_module(modName, None, modulePath, binarySuffix) return set(dir(modObj)) except: # Failed to load a binary module return set() # It's not a binary module, so parse it and make a list of objects. # Check first if the module is loaded into the editor mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager widget = editorsManager.getWidgetForFileName(modulePath) if widget is None: # Not loaded, so parse it from a file info = getBriefModuleInfoFromFile(modulePath) else: # Parse it from memory because it could be changed editor = widget.getEditor() info = getBriefModuleInfoFromMemory(editor.text()) return __getParsedModuleNames(info)
def __process( self ): " Accumulation process " # Intermediate working data self.__participantFiles = [] self.__projectImportDirs = [] self.__projectImportsCache = {} self.dataModel.clear() self.__inProgress = True try: self.infoLabel.setText( 'Building the list of files to analyze...' ) QApplication.processEvents() # Build the list of participating python files self.__buildParticipants() self.__projectImportDirs = \ GlobalData().project.getImportDirsAsAbsolutePaths() QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.close() return self.progressBar.setRange( 0, len( self.__participantFiles ) ) index = 1 # Now, parse the files and build the diagram data model if self.__what == ImportsDiagramDialog.SingleBuffer: info = getBriefModuleInfoFromMemory( str( self.__buf ) ) self.__addSingleFileToDataModel( info, self.__path ) else: infoSrc = GlobalData().briefModinfoCache for fName in self.__participantFiles: self.progressBar.setValue( index ) self.infoLabel.setText( 'Analyzing ' + fName + "..." ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return info = infoSrc.get( fName ) self.__addSingleFileToDataModel( info, fName ) index += 1 # The import caches and other working data are not needed anymore self.__participantFiles = None self.__projectImportDirs = None self.__projectImportsCache = None # Generating the graphviz layout self.infoLabel.setText( 'Generating layout using graphviz...' ) QApplication.processEvents() graph = getGraphFromDescriptionData( self.dataModel.toGraphviz() ) graph.normalize( self.physicalDpiX(), self.physicalDpiY() ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return # Generate graphics scene self.infoLabel.setText( 'Generating graphics scene...' ) QApplication.processEvents() self.__buildGraphicsScene( graph ) # Clear the data model self.dataModel = None except Exception, exc: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) self.__inProgress = False self.__onClose() return
def __onMcCabeObject(self, objName, fileName): " Called when the user activated McCabe item " info = None mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: if fileName == "": logging.error("The unsaved buffer has been closed") return # No widget, but we know the file name info = getBriefModuleInfoFromFile(fileName) else: # The widget was found editor = widget.getEditor() # The editor content has been modified, so re-parse the buffer info = getBriefModuleInfoFromMemory(editor.text()) parts = objName.split('.') currentIndex = 0 functionsContainer = info.functions classesContainer = info.classes line = -1 if objName == "__main__" and len(parts) == 1: # Special case - global file scope line = 1 currentIndex = 1 while currentIndex < len(parts): found = False for func in functionsContainer: if func.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = func.line break functionsContainer = func.functions classesContainer = func.classes found = True break if line != -1: break if found: currentIndex += 1 continue for klass in classesContainer: if klass.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = klass.line break functionsContainer = klass.functions classesContainer = klass.classes found = True if line != -1: break if found: currentIndex += 1 continue # Not found logging.error("Cannot find the " + objName) return # Here we have the line number if widget is None: GlobalData().mainWindow.openFile(fileName, line) else: editor = widget.getEditor() editor.gotoLine(line) editor.setFocus() return
def getCompletionList(fileName, scope, obj, prefix, editor, text, info=None): """ High level function. It provides a list of suggestions for autocompletion depending on the text cursor scope and the object the user wants completion for """ onImportModule, needToComplete, moduleName = isOnSomeImport(editor) if onImportModule: if not needToComplete: # No need to complete return [], False if moduleName != "": return list(__getImportedObjects(moduleName, fileName)), False # Need to complete a module name return list(__getModuleNames(fileName)), True if isRemarkLine(editor): return list(getEditorTags(editor, prefix, True)), False if isStringLiteral(editor): return list(getEditorTags(editor, prefix, True)), False if obj == "" and prefix == "": return list(getEditorTags(editor, prefix, True)), False # Check a popular case self. and then something if scope.getScope() == scope.ClassMethodScope: infoObj = scope.getInfoObj() if not infoObj.isStaticMethod() and infoObj.arguments: firstArgName = infoObj.arguments[0] if firstArgName == obj: # The user completes the class member proposals, isOK = _getRopeCompletion(fileName, text, editor, prefix) if isOK == False: return list(getEditorTags(editor, prefix, True)), False # The rope proposals include private members and built-ins # which are inaccessible/not needed in most case. # Exclude everything private and built-in result = _excludePrivateAndBuiltins(proposals) # By some reasons rope sometimes inserts the current # word with '=' at the end. Let's just discard it. currentWord = str(editor.getCurrentWord()).strip() result.discard(currentWord + "=") # Add private members of the class itself if info is None: info = getBriefModuleInfoFromMemory(text) _addClassPrivateNames(scope.levels[scope.length - 2][0], result) return list(result), False # Rope does not offer anything for system modules, let's handle it here # if so if obj != "": isSystemImport, realImportName = _isSystemImportOrAlias( obj, text, info) if isSystemImport: # Yes, that is a reference to something from a system module return list(__getImportedObjects(realImportName, "")), False # Try rope completion proposals, isOK = _getRopeCompletion(fileName, text, editor, prefix) if isOK == False: return list(getEditorTags(editor, prefix, True)), False result = _excludePrivateAndBuiltins(proposals) # By some reasons rope sometimes inserts the current word with '=' at the # end. Let's just discard it. currentWord = str(editor.getCurrentWord()).strip() result.discard(currentWord + "=") if not result: return list(getEditorTags(editor, prefix, True)), False if obj == "": # Inject the editor tags as it might be good to have # words from another scope result.update(getEditorTags(editor, prefix, True)) return list(result), False
def __getImportedObjects( moduleName, fileName ): " Provides a list of objects to be imported from " buildSystemWideModulesList() modulePath = None moduleName = str( moduleName ) if moduleName in __systemwideModules: modulePath = __systemwideModules[ moduleName ] if modulePath is None or moduleName in Settings().dirSafeModules: # it could be a built-in module return getImportNames( moduleName ) else: # Not a system wide, try search in the project # or current directories if moduleName.startswith( "." ): # That's a relative import if not fileName: # File name must be known for a relative import return set() dotCount = 0 while moduleName.startswith( "." ): dotCount += 1 moduleName = moduleName[ 1: ] # Strip as many paths as dots instruct baseDir = os.path.dirname( fileName ) while dotCount > 1: baseDir = os.path.dirname( baseDir ) dotCount -= 1 specificModules = getProjectSpecificModules( baseDir, True ) else: specificModules = getProjectSpecificModules( fileName ) if moduleName in specificModules: modulePath = specificModules[ moduleName ] if modulePath is None: return set() binarySuffix = __isBinaryModule( modulePath ) if binarySuffix is not None: try: modName = os.path.basename( modulePath ) modObj = imp.load_module( modName, None, modulePath, binarySuffix ) return set( dir( modObj ) ) except: # Failed to load a binary module return set() # It's not a binary module, so parse it and make a list of objects. # Check first if the module is loaded into the editor mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager widget = editorsManager.getWidgetForFileName( modulePath ) if widget is None: # Not loaded, so parse it from a file info = getBriefModuleInfoFromFile( modulePath ) else: # Parse it from memory because it could be changed editor = widget.getEditor() info = getBriefModuleInfoFromMemory( editor.text() ) return __getParsedModuleNames( info )
def getCompletionList( fileName, scope, obj, prefix, editor, text, info = None ): """ High level function. It provides a list of suggestions for autocompletion depending on the text cursor scope and the object the user wants completion for """ onImportModule, needToComplete, moduleName = isOnSomeImport( editor ) if onImportModule: if not needToComplete: # No need to complete return [], False if moduleName != "": return list( __getImportedObjects( moduleName, fileName ) ), False # Need to complete a module name return list( __getModuleNames( fileName ) ), True if isRemarkLine( editor ): return list( getEditorTags( editor, prefix, True ) ), False if isStringLiteral( editor ): return list( getEditorTags( editor, prefix, True ) ), False if obj == "" and prefix == "": return list( getEditorTags( editor, prefix, True ) ), False # Check a popular case self. and then something if scope.getScope() == scope.ClassMethodScope: infoObj = scope.getInfoObj() if not infoObj.isStaticMethod() and infoObj.arguments: firstArgName = infoObj.arguments[ 0 ] if firstArgName == obj: # The user completes the class member proposals, isOK = _getRopeCompletion( fileName, text, editor, prefix ) if isOK == False: return list( getEditorTags( editor, prefix, True ) ), False # The rope proposals include private members and built-ins # which are inaccessible/not needed in most case. # Exclude everything private and built-in result = _excludePrivateAndBuiltins( proposals ) # By some reasons rope sometimes inserts the current # word with '=' at the end. Let's just discard it. currentWord = str( editor.getCurrentWord() ).strip() result.discard( currentWord + "=" ) # Add private members of the class itself if info is None: info = getBriefModuleInfoFromMemory( text ) _addClassPrivateNames( scope.levels[ scope.length - 2 ][ 0 ], result ) return list( result ), False # Rope does not offer anything for system modules, let's handle it here # if so if obj != "": isSystemImport, realImportName = _isSystemImportOrAlias( obj, text, info ) if isSystemImport: # Yes, that is a reference to something from a system module return list( __getImportedObjects( realImportName, "" ) ), False # Try rope completion proposals, isOK = _getRopeCompletion( fileName, text, editor, prefix ) if isOK == False: return list( getEditorTags( editor, prefix, True ) ), False result = _excludePrivateAndBuiltins( proposals ) # By some reasons rope sometimes inserts the current word with '=' at the # end. Let's just discard it. currentWord = str( editor.getCurrentWord() ).strip() result.discard( currentWord + "=" ) if not result: return list( getEditorTags( editor, prefix, True ) ), False if obj == "": # Inject the editor tags as it might be good to have # words from another scope result.update( getEditorTags( editor, prefix, True ) ) return list( result ), False
def updateBar( self ): " Triggered when the timer is fired " self.__updateTimer.stop() # just in case if self.parent().getFileType() not in [ Python3FileType, PythonFileType ]: return if not self.__connected: self.__connectEditorSignals() # Parse the buffer content self.__currentInfo = getBriefModuleInfoFromMemory( self.__editor.text() ) # Decide what icon to use if self.__currentInfo.isOK: self.__updateInfoIcon( self.STATE_OK_UTD ) else: self.__updateInfoIcon( self.STATE_BROKEN_UTD ) # Calc the cursor context context = getContext( self.__editor, self.__currentInfo, True, False ) # Display the context self.__populateGlobalScope() if context.length == 0: self.__globalScopeCombo.setCurrentIndex( -1 ) else: index = self.__globalScopeCombo.findData( context.levels[ 0 ][ 0 ].line ) self.__globalScopeCombo.setCurrentIndex( index ) usedFromStore = 0 index = 1 while index < context.length: if len( self.__path ) < index: newPathItem = PathElement( self ) self.__path.append( newPathItem ) self.__layout.addWidget( newPathItem.icon ) self.__layout.addWidget( newPathItem.combo ) combo = newPathItem.combo combo.pathIndex = len( self.__path ) - 1 combo.jumpToLine.connect( self.__onJumpToLine ) else: self.__path[ index - 1 ].icon.setVisible( True ) self.__path[ index - 1 ].combo.setVisible( True ) combo = self.__path[ index - 1 ].combo combo.clear() # Populate the combo box self.__populateClassesAndFunctions( context.levels[ index - 1 ][ 0 ], combo ) combo.setCurrentIndex( combo.findData( context.levels[ index ][ 0 ].line ) ) index += 1 usedFromStore += 1 # it might need to have one more level with nothing selected if context.length > 0: if len( context.levels[ context.length - 1 ][ 0 ].functions ) > 0 or \ len( context.levels[ context.length - 1 ][ 0 ].classes ) > 0: # Need to add a combo if len( self.__path ) <= usedFromStore: newPathItem = PathElement( self ) self.__path.append( newPathItem ) self.__layout.addWidget( newPathItem.icon ) self.__layout.addWidget( newPathItem.combo ) combo = newPathItem.combo combo.pathIndex = len( self.__path ) - 1 combo.jumpToLine.connect( self.__onJumpToLine ) else: self.__path[ index - 1 ].icon.setVisible( True ) self.__path[ index - 1 ].combo.setVisible( True ) combo = self.__path[ index - 1 ].combo combo.clear() self.__populateClassesAndFunctions( context.levels[ context.length - 1 ][ 0 ], combo ) combo.setCurrentIndex( -1 ) usedFromStore += 1 # Hide extra components if so index = usedFromStore while index < len( self.__path ): self.__path[ index ].icon.setVisible( False ) self.__path[ index ].combo.setVisible( False ) index += 1 # Make sure the spacer is the last item self.__layout.removeWidget( self.__spacer ) self.__layout.addWidget( self.__spacer ) return