[Python-checkins] cpython (3.4): Issue #25663: Make rlcompleter avoid duplicate global names

martin.panter python-checkins at python.org
Mon Nov 23 19:40:30 EST 2015


https://hg.python.org/cpython/rev/4799615f4f26
changeset:   99316:4799615f4f26
branch:      3.4
parent:      99313:a33d76465a18
user:        Martin Panter <vadmium+py at gmail.com>
date:        Mon Nov 23 23:50:26 2015 +0000
summary:
  Issue #25663: Make rlcompleter avoid duplicate global names

files:
  Lib/rlcompleter.py           |   7 +++++--
  Lib/test/test_rlcompleter.py |  21 +++++++++++++++++++++
  Misc/NEWS                    |   3 +++
  3 files changed, 29 insertions(+), 2 deletions(-)


diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py
--- a/Lib/rlcompleter.py
+++ b/Lib/rlcompleter.py
@@ -103,13 +103,16 @@
         """
         import keyword
         matches = []
+        seen = {"__builtins__"}
         n = len(text)
         for word in keyword.kwlist:
             if word[:n] == text:
+                seen.add(word)
                 matches.append(word)
-        for nspace in [builtins.__dict__, self.namespace]:
+        for nspace in [self.namespace, builtins.__dict__]:
             for word, val in nspace.items():
-                if word[:n] == text and word != "__builtins__":
+                if word[:n] == text and word not in seen:
+                    seen.add(word)
                     matches.append(self._callable_postfix(val, word))
         return matches
 
diff --git a/Lib/test/test_rlcompleter.py b/Lib/test/test_rlcompleter.py
--- a/Lib/test/test_rlcompleter.py
+++ b/Lib/test/test_rlcompleter.py
@@ -85,6 +85,27 @@
         self.assertEqual(completer.complete('as', 2), 'assert')
         self.assertEqual(completer.complete('an', 0), 'and')
 
+    def test_duplicate_globals(self):
+        namespace = {
+            'False': None,  # Keyword vs builtin vs namespace
+            'assert': None,  # Keyword vs namespace
+            'try': lambda: None,  # Keyword vs callable
+            'memoryview': None,  # Callable builtin vs non-callable
+            'Ellipsis': lambda: None,  # Non-callable builtin vs callable
+        }
+        completer = rlcompleter.Completer(namespace)
+        self.assertEqual(completer.complete('False', 0), 'False')
+        self.assertIsNone(completer.complete('False', 1))  # No duplicates
+        self.assertEqual(completer.complete('assert', 0), 'assert')
+        self.assertIsNone(completer.complete('assert', 1))
+        self.assertEqual(completer.complete('try', 0), 'try')
+        self.assertIsNone(completer.complete('try', 1))
+        # No opening bracket "(" because we overrode the built-in class
+        self.assertEqual(completer.complete('memoryview', 0), 'memoryview')
+        self.assertIsNone(completer.complete('memoryview', 1))
+        self.assertEqual(completer.complete('Ellipsis', 0), 'Ellipsis(')
+        self.assertIsNone(completer.complete('Ellipsis', 1))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -106,6 +106,9 @@
 Library
 -------
 
+- Issue #25663: In the Readline completer, avoid listing duplicate global
+  names, and search the global namespace before searching builtins.
+
 - Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error.
 
 - Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list