Mon, 22 Feb 2016 22:26:21 +0100
Improved shell completer for local variables and behavior of Python versions equaled.
--- a/DebugClients/Python/DebugClientBase.py Wed Feb 17 22:11:12 2016 +0100 +++ b/DebugClients/Python/DebugClientBase.py Mon Feb 22 22:26:21 2016 +0100 @@ -1887,8 +1887,7 @@ """ completerDelims = ' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>/?' - completions = [] - state = 0 + completions = set() # find position of last delim character pos = -1 while pos >= -len(text): @@ -1900,20 +1899,38 @@ break pos -= 1 + # Get local and global completions try: - comp = self.complete(text, state) + localdict = self.currentThread.getFrameLocals(self.framenr) + localCompleter = Completer(localdict).complete + self.__getCompletionList(text, localCompleter, completions) + except AttributeError: + pass + self.__getCompletionList(text, self.complete, completions) + + self.write("%s%s||%s\n" % (DebugProtocol.ResponseCompletion, + unicode(list(completions)), text)) + + def __getCompletionList(self, text, completer, completions): + """ + Private method to create a completions list. + + @param text text to complete (string) + @param completer completer methode + @param completions set where to add new completions strings (set) + """ + state = 0 + try: + comp = completer(text, state) except Exception: comp = None while comp is not None: - completions.append(comp) + completions.add(comp) state += 1 try: - comp = self.complete(text, state) + comp = completer(text, state) except Exception: comp = None - - self.write("%s%s||%s\n" % (DebugProtocol.ResponseCompletion, - unicode(completions), text)) def startDebugger(self, filename=None, host=None, port=None, enableTrace=1, exceptions=1, tracePython=0, redirect=1):
--- a/DebugClients/Python/FlexCompleter.py Wed Feb 17 22:11:12 2016 +0100 +++ b/DebugClients/Python/FlexCompleter.py Mon Feb 22 22:26:21 2016 +0100 @@ -162,6 +162,18 @@ except IndexError: return None + def _callable_postfix(self, val, word): + """ + Protected method to check for a callable. + + @param val value to check (object) + @param word word to ammend (string) + @return ammended word (string) + """ + if hasattr(val, '__call__'): + word = word + "(" + return word + def global_matches(self, text): """ Public method to compute matches when text is a simple name. @@ -173,14 +185,13 @@ import keyword matches = [] n = len(text) - for list in [keyword.kwlist, - __builtin__.__dict__.keys(), - self.namespace.keys()]: - for word in list: - if word[:n] == text and \ - word != "__builtins__" and \ - word not in matches: - matches.append(word) + for word in keyword.kwlist: + if word[:n] == text: + matches.append(word) + for nspace in [__builtin__.__dict__, self.namespace]: + for word, val in nspace.items(): + if word[:n] == text and word != "__builtins__": + matches.append(self._callable_postfix(val, word)) return matches def attr_matches(self, text): @@ -212,8 +223,16 @@ if not m: return expr, attr = m.group(1, 3) - object = eval(expr, self.namespace) - words = dir(object) + try: + thisobject = eval(expr, self.namespace) + except Exception: + return [] + + # get the content of the object, except __builtins__ + words = dir(thisobject) + if "__builtins__" in words: + words.remove("__builtins__") + if hasattr(object, '__class__'): words.append('__class__') words = words + get_class_members(object.__class__) @@ -221,10 +240,11 @@ n = len(attr) for word in words: try: - if word[:n] == attr and word != "__builtins__": - match = "%s.%s" % (expr, word) - if match not in matches: - matches.append(match) + if word[:n] == attr and hasattr(thisobject, word): + val = getattr(thisobject, word) + word = self._callable_postfix( + val, "%s.%s" % (expr, word)) + matches.append(word) except Exception: # some badly behaved objects pollute dir() with non-strings, # which cause the completion to fail. This way we skip the
--- a/DebugClients/Python3/DebugClientBase.py Wed Feb 17 22:11:12 2016 +0100 +++ b/DebugClients/Python3/DebugClientBase.py Mon Feb 22 22:26:21 2016 +0100 @@ -1937,8 +1937,7 @@ """ completerDelims = ' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>/?' - completions = [] - state = 0 + completions = set() # find position of last delim character pos = -1 while pos >= -len(text): @@ -1950,20 +1949,38 @@ break pos -= 1 + # Get local and global completions try: - comp = self.complete(text, state) + localdict = self.currentThread.getFrameLocals(self.framenr) + localCompleter = Completer(localdict).complete + self.__getCompletionList(text, localCompleter, completions) + except AttributeError: + pass + self.__getCompletionList(text, self.complete, completions) + + self.write("{0}{1}||{2}\n".format(DebugProtocol.ResponseCompletion, + str(list(completions)), text)) + + def __getCompletionList(self, text, completer, completions): + """ + Private method to create a completions list. + + @param text text to complete (string) + @param completer completer methode + @param completions set where to add new completions strings (set) + """ + state = 0 + try: + comp = completer(text, state) except Exception: comp = None while comp is not None: - completions.append(comp) + completions.add(comp) state += 1 try: - comp = self.complete(text, state) + comp = completer(text, state) except Exception: comp = None - - self.write("{0}{1}||{2}\n".format(DebugProtocol.ResponseCompletion, - str(completions), text)) def startDebugger(self, filename=None, host=None, port=None, enableTrace=True, exceptions=True, tracePython=False,