mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Update rlcompleter from 3.13.5 (#5990)
This commit is contained in:
1 parent
559a7a56e5
commit
80a9e0ed54
2 files changed
+90
-26
No files matched your search
Vendored
+31
-15
@@ -31,7 +31,11 @@ Notes:
|
||||
|
||||
import atexit
|
||||
import builtins
|
||||
import inspect
|
||||
import keyword
|
||||
import re
|
||||
import __main__
|
||||
import warnings
|
||||
|
||||
__all__ = ["Completer"]
|
||||
|
||||
@@ -85,10 +89,11 @@ class Completer:
|
||||
return None
|
||||
|
||||
if state == 0:
|
||||
if "." in text:
|
||||
self.matches = self.attr_matches(text)
|
||||
else:
|
||||
self.matches = self.global_matches(text)
|
||||
with warnings.catch_warnings(action="ignore"):
|
||||
if "." in text:
|
||||
self.matches = self.attr_matches(text)
|
||||
else:
|
||||
self.matches = self.global_matches(text)
|
||||
try:
|
||||
return self.matches[state]
|
||||
except IndexError:
|
||||
@@ -96,7 +101,13 @@ class Completer:
|
||||
|
||||
def _callable_postfix(self, val, word):
|
||||
if callable(val):
|
||||
word = word + "("
|
||||
word += "("
|
||||
try:
|
||||
if not inspect.signature(val).parameters:
|
||||
word += ")"
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return word
|
||||
|
||||
def global_matches(self, text):
|
||||
@@ -106,18 +117,17 @@ class Completer:
|
||||
defined in self.namespace that match.
|
||||
|
||||
"""
|
||||
import keyword
|
||||
matches = []
|
||||
seen = {"__builtins__"}
|
||||
n = len(text)
|
||||
for word in keyword.kwlist:
|
||||
for word in keyword.kwlist + keyword.softkwlist:
|
||||
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'}:
|
||||
'else', '_'}:
|
||||
word = word + ' '
|
||||
matches.append(word)
|
||||
for nspace in [self.namespace, builtins.__dict__]:
|
||||
@@ -139,7 +149,6 @@ class Completer:
|
||||
with a __getattr__ hook is evaluated.
|
||||
|
||||
"""
|
||||
import re
|
||||
m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
|
||||
if not m:
|
||||
return []
|
||||
@@ -169,13 +178,20 @@ class Completer:
|
||||
if (word[:n] == attr and
|
||||
not (noprefix and word[:n+1] == noprefix)):
|
||||
match = "%s.%s" % (expr, word)
|
||||
try:
|
||||
val = getattr(thisobject, word)
|
||||
except Exception:
|
||||
pass # Include even if attribute not set
|
||||
if isinstance(getattr(type(thisobject), word, None),
|
||||
property):
|
||||
# bpo-44752: thisobject.word is a method decorated by
|
||||
# `@property`. What follows applies a postfix if
|
||||
# thisobject.word is callable, but know we know that
|
||||
# this is not callable (because it is a property).
|
||||
# Also, getattr(thisobject, word) will evaluate the
|
||||
# property method, which is not desirable.
|
||||
matches.append(match)
|
||||
continue
|
||||
if (value := getattr(thisobject, word, None)) is not None:
|
||||
matches.append(self._callable_postfix(value, match))
|
||||
else:
|
||||
match = self._callable_postfix(val, match)
|
||||
matches.append(match)
|
||||
matches.append(match)
|
||||
if matches or not noprefix:
|
||||
break
|
||||
if noprefix == '_':
|
||||
|
||||
Vendored
+59
-11
@@ -2,6 +2,7 @@ import unittest
|
||||
from unittest.mock import patch
|
||||
import builtins
|
||||
import rlcompleter
|
||||
from test.support import MISSING_C_DOCSTRINGS
|
||||
|
||||
class CompleteMe:
|
||||
""" Trivial class used in testing rlcompleter.Completer. """
|
||||
@@ -40,21 +41,41 @@ class TestRlcompleter(unittest.TestCase):
|
||||
|
||||
# test with a customized namespace
|
||||
self.assertEqual(self.completer.global_matches('CompleteM'),
|
||||
['CompleteMe('])
|
||||
['CompleteMe(' if MISSING_C_DOCSTRINGS else 'CompleteMe()'])
|
||||
self.assertEqual(self.completer.global_matches('eg'),
|
||||
['egg('])
|
||||
# XXX: see issue5256
|
||||
self.assertEqual(self.completer.global_matches('CompleteM'),
|
||||
['CompleteMe('])
|
||||
['CompleteMe(' if MISSING_C_DOCSTRINGS else 'CompleteMe()'])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_attr_matches(self):
|
||||
# test with builtins namespace
|
||||
self.assertEqual(self.stdcompleter.attr_matches('str.s'),
|
||||
['str.{}('.format(x) for x in dir(str)
|
||||
if x.startswith('s')])
|
||||
self.assertEqual(self.stdcompleter.attr_matches('tuple.foospamegg'), [])
|
||||
expected = sorted({'None.%s%s' % (x, '(' if x != '__doc__' else '')
|
||||
for x in dir(None)})
|
||||
|
||||
def create_expected_for_none():
|
||||
if not MISSING_C_DOCSTRINGS:
|
||||
parentheses = ('__init_subclass__', '__class__')
|
||||
else:
|
||||
# When `--without-doc-strings` is used, `__class__`
|
||||
# won't have a known signature.
|
||||
parentheses = ('__init_subclass__',)
|
||||
|
||||
items = set()
|
||||
for x in dir(None):
|
||||
if x in parentheses:
|
||||
items.add(f'None.{x}()')
|
||||
elif x == '__doc__':
|
||||
items.add(f'None.{x}')
|
||||
else:
|
||||
items.add(f'None.{x}(')
|
||||
return sorted(items)
|
||||
|
||||
expected = create_expected_for_none()
|
||||
self.assertEqual(self.stdcompleter.attr_matches('None.'), expected)
|
||||
self.assertEqual(self.stdcompleter.attr_matches('None._'), expected)
|
||||
self.assertEqual(self.stdcompleter.attr_matches('None.__'), expected)
|
||||
@@ -64,7 +85,7 @@ class TestRlcompleter(unittest.TestCase):
|
||||
['CompleteMe.spam'])
|
||||
self.assertEqual(self.completer.attr_matches('Completeme.egg'), [])
|
||||
self.assertEqual(self.completer.attr_matches('CompleteMe.'),
|
||||
['CompleteMe.mro(', 'CompleteMe.spam'])
|
||||
['CompleteMe.mro()', 'CompleteMe.spam'])
|
||||
self.assertEqual(self.completer.attr_matches('CompleteMe._'),
|
||||
['CompleteMe._ham'])
|
||||
matches = self.completer.attr_matches('CompleteMe.__')
|
||||
@@ -81,18 +102,42 @@ class TestRlcompleter(unittest.TestCase):
|
||||
if x.startswith('s')])
|
||||
|
||||
def test_excessive_getattr(self):
|
||||
# Ensure getattr() is invoked no more than once per attribute
|
||||
"""Ensure getattr() is invoked no more than once per attribute"""
|
||||
|
||||
# note the special case for @property methods below; that is why
|
||||
# we use __dir__ and __getattr__ in class Foo to create a "magic"
|
||||
# class attribute 'bar'. This forces `getattr` to call __getattr__
|
||||
# (which is doesn't necessarily do).
|
||||
class Foo:
|
||||
calls = 0
|
||||
@property
|
||||
def bar(self):
|
||||
self.calls += 1
|
||||
return None
|
||||
bar = ''
|
||||
def __getattribute__(self, name):
|
||||
if name == 'bar':
|
||||
self.calls += 1
|
||||
return None
|
||||
return super().__getattribute__(name)
|
||||
|
||||
f = Foo()
|
||||
completer = rlcompleter.Completer(dict(f=f))
|
||||
self.assertEqual(completer.complete('f.b', 0), 'f.bar')
|
||||
self.assertEqual(f.calls, 1)
|
||||
|
||||
def test_property_method_not_called(self):
|
||||
class Foo:
|
||||
_bar = 0
|
||||
property_called = False
|
||||
|
||||
@property
|
||||
def bar(self):
|
||||
self.property_called = True
|
||||
return self._bar
|
||||
|
||||
f = Foo()
|
||||
completer = rlcompleter.Completer(dict(f=f))
|
||||
self.assertEqual(completer.complete('f.b', 0), 'f.bar')
|
||||
self.assertFalse(f.property_called)
|
||||
|
||||
|
||||
def test_uncreated_attr(self):
|
||||
# Attributes like properties and slots should be completed even when
|
||||
# they haven't been created on an instance
|
||||
@@ -114,6 +159,9 @@ class TestRlcompleter(unittest.TestCase):
|
||||
self.assertEqual(completer.complete('el', 0), 'elif ')
|
||||
self.assertEqual(completer.complete('el', 1), 'else')
|
||||
self.assertEqual(completer.complete('tr', 0), 'try:')
|
||||
self.assertEqual(completer.complete('_', 0), '_')
|
||||
self.assertEqual(completer.complete('match', 0), 'match ')
|
||||
self.assertEqual(completer.complete('case', 0), 'case ')
|
||||
|
||||
def test_duplicate_globals(self):
|
||||
namespace = {
|
||||
@@ -134,7 +182,7 @@ class TestRlcompleter(unittest.TestCase):
|
||||
# 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.assertEqual(completer.complete('Ellipsis', 0), 'Ellipsis()')
|
||||
self.assertIsNone(completer.complete('Ellipsis', 1))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in new issue
Block a user