]> granicus.if.org Git - python/commitdiff
Issue #25663: Merge rlcompleter fix from 3.5
authorMartin Panter <vadmium+py@gmail.com>
Tue, 24 Nov 2015 00:19:10 +0000 (00:19 +0000)
committerMartin Panter <vadmium+py@gmail.com>
Tue, 24 Nov 2015 00:19:10 +0000 (00:19 +0000)
1  2 
Lib/rlcompleter.py
Lib/test/test_rlcompleter.py
Misc/NEWS

index 02e1fa50cc4d5388f08abbef12c4a51d9b6466ef,378f5aa647351c3691c4f60553c7e2a06b1dcb7e..319e82627175183b856dfb5a849ebdbb58284299
@@@ -106,16 -107,12 +107,18 @@@ class Completer
          n = len(text)
          for word in keyword.kwlist:
              if word[:n] == text:
+                 seen.add(word)
 +                if word in {'finally', 'try'}:
 +                    word = word + ':'
 +                elif word not in {'False', 'None', 'True',
 +                                  'break', 'continue', 'pass',
 +                                  'else'}:
 +                    word = 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
  
index 8ff75c75c54a7b66de0ce0a4bf41d452ecc3dca0,2d5d9c1f70b5049cce7fe58fc9b459ba3ffd7ff0..34a5eff7f7419b7c1bca69ff96efce8dbfd08929
@@@ -103,15 -80,31 +103,36 @@@ class TestRlcompleter(unittest.TestCase
      def test_complete(self):
          completer = rlcompleter.Completer()
          self.assertEqual(completer.complete('', 0), '\t')
 -        self.assertEqual(completer.complete('a', 0), 'and')
 -        self.assertEqual(completer.complete('a', 1), 'as')
 -        self.assertEqual(completer.complete('as', 2), 'assert')
 -        self.assertEqual(completer.complete('an', 0), 'and')
 +        self.assertEqual(completer.complete('a', 0), 'and ')
 +        self.assertEqual(completer.complete('a', 1), 'as ')
 +        self.assertEqual(completer.complete('as', 2), 'assert ')
 +        self.assertEqual(completer.complete('an', 0), 'and ')
 +        self.assertEqual(completer.complete('pa', 0), 'pass')
 +        self.assertEqual(completer.complete('Fa', 0), 'False')
 +        self.assertEqual(completer.complete('el', 0), 'elif ')
 +        self.assertEqual(completer.complete('el', 1), 'else')
 +        self.assertEqual(completer.complete('tr', 0), 'try:')
  
+     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 --cc Misc/NEWS
index cce8bd87e7999d48a730306af15ef6d5928c4fdd,b4ac09557fe00822391ce9196d7e5a6eb200248c..758a817a6bcc6117b03b2c5eedb18ee4b172c89c
+++ b/Misc/NEWS
@@@ -95,15 -112,6 +95,18 @@@ Core and Builtin
  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.
 +
 +- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
 +
 +- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
 +  entries.  Patch by Dingyuan Wang.
 +
  - Issue #25626: Change three zlib functions to accept sizes that fit in
    Py_ssize_t, but internally cap those sizes to UINT_MAX.  This resolves a
    regression in 3.5 where GzipFile.read() failed to read chunks larger than 2