• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2from unittest.mock import patch
3import builtins
4import rlcompleter
5
6class CompleteMe:
7    """ Trivial class used in testing rlcompleter.Completer. """
8    spam = 1
9    _ham = 2
10
11
12class TestRlcompleter(unittest.TestCase):
13    def setUp(self):
14        self.stdcompleter = rlcompleter.Completer()
15        self.completer = rlcompleter.Completer(dict(spam=int,
16                                                    egg=str,
17                                                    CompleteMe=CompleteMe))
18
19        # forces stdcompleter to bind builtins namespace
20        self.stdcompleter.complete('', 0)
21
22    def test_namespace(self):
23        class A(dict):
24            pass
25        class B(list):
26            pass
27
28        self.assertTrue(self.stdcompleter.use_main_ns)
29        self.assertFalse(self.completer.use_main_ns)
30        self.assertFalse(rlcompleter.Completer(A()).use_main_ns)
31        self.assertRaises(TypeError, rlcompleter.Completer, B((1,)))
32
33    def test_global_matches(self):
34        # test with builtins namespace
35        self.assertEqual(sorted(self.stdcompleter.global_matches('di')),
36                         [x+'(' for x in dir(builtins) if x.startswith('di')])
37        self.assertEqual(sorted(self.stdcompleter.global_matches('st')),
38                         [x+'(' for x in dir(builtins) if x.startswith('st')])
39        self.assertEqual(self.stdcompleter.global_matches('akaksajadhak'), [])
40
41        # test with a customized namespace
42        self.assertEqual(self.completer.global_matches('CompleteM'),
43                         ['CompleteMe()'])
44        self.assertEqual(self.completer.global_matches('eg'),
45                         ['egg('])
46        # XXX: see issue5256
47        self.assertEqual(self.completer.global_matches('CompleteM'),
48                         ['CompleteMe()'])
49
50    def test_attr_matches(self):
51        # test with builtins namespace
52        self.assertEqual(self.stdcompleter.attr_matches('str.s'),
53                         ['str.{}('.format(x) for x in dir(str)
54                          if x.startswith('s')])
55        self.assertEqual(self.stdcompleter.attr_matches('tuple.foospamegg'), [])
56        expected = sorted({'None.%s%s' % (x, '(' if x != '__doc__' else '')
57                           for x in dir(None)})
58        self.assertEqual(self.stdcompleter.attr_matches('None.'), expected)
59        self.assertEqual(self.stdcompleter.attr_matches('None._'), expected)
60        self.assertEqual(self.stdcompleter.attr_matches('None.__'), expected)
61
62        # test with a customized namespace
63        self.assertEqual(self.completer.attr_matches('CompleteMe.sp'),
64                         ['CompleteMe.spam'])
65        self.assertEqual(self.completer.attr_matches('Completeme.egg'), [])
66        self.assertEqual(self.completer.attr_matches('CompleteMe.'),
67                         ['CompleteMe.mro()', 'CompleteMe.spam'])
68        self.assertEqual(self.completer.attr_matches('CompleteMe._'),
69                         ['CompleteMe._ham'])
70        matches = self.completer.attr_matches('CompleteMe.__')
71        for x in matches:
72            self.assertTrue(x.startswith('CompleteMe.__'), x)
73        self.assertIn('CompleteMe.__name__', matches)
74        self.assertIn('CompleteMe.__new__(', matches)
75
76        with patch.object(CompleteMe, "me", CompleteMe, create=True):
77            self.assertEqual(self.completer.attr_matches('CompleteMe.me.me.sp'),
78                             ['CompleteMe.me.me.spam'])
79            self.assertEqual(self.completer.attr_matches('egg.s'),
80                             ['egg.{}('.format(x) for x in dir(str)
81                              if x.startswith('s')])
82
83    def test_excessive_getattr(self):
84        """Ensure getattr() is invoked no more than once per attribute"""
85
86        # note the special case for @property methods below; that is why
87        # we use __dir__ and __getattr__ in class Foo to create a "magic"
88        # class attribute 'bar'. This forces `getattr` to call __getattr__
89        # (which is doesn't necessarily do).
90        class Foo:
91            calls = 0
92            bar = ''
93            def __getattribute__(self, name):
94                if name == 'bar':
95                    self.calls += 1
96                    return None
97                return super().__getattribute__(name)
98
99        f = Foo()
100        completer = rlcompleter.Completer(dict(f=f))
101        self.assertEqual(completer.complete('f.b', 0), 'f.bar')
102        self.assertEqual(f.calls, 1)
103
104    def test_property_method_not_called(self):
105        class Foo:
106            _bar = 0
107            property_called = False
108
109            @property
110            def bar(self):
111                self.property_called = True
112                return self._bar
113
114        f = Foo()
115        completer = rlcompleter.Completer(dict(f=f))
116        self.assertEqual(completer.complete('f.b', 0), 'f.bar')
117        self.assertFalse(f.property_called)
118
119
120    def test_uncreated_attr(self):
121        # Attributes like properties and slots should be completed even when
122        # they haven't been created on an instance
123        class Foo:
124            __slots__ = ("bar",)
125        completer = rlcompleter.Completer(dict(f=Foo()))
126        self.assertEqual(completer.complete('f.', 0), 'f.bar')
127
128    @unittest.mock.patch('rlcompleter._readline_available', False)
129    def test_complete(self):
130        completer = rlcompleter.Completer()
131        self.assertEqual(completer.complete('', 0), '\t')
132        self.assertEqual(completer.complete('a', 0), 'and ')
133        self.assertEqual(completer.complete('a', 1), 'as ')
134        self.assertEqual(completer.complete('as', 2), 'assert ')
135        self.assertEqual(completer.complete('an', 0), 'and ')
136        self.assertEqual(completer.complete('pa', 0), 'pass')
137        self.assertEqual(completer.complete('Fa', 0), 'False')
138        self.assertEqual(completer.complete('el', 0), 'elif ')
139        self.assertEqual(completer.complete('el', 1), 'else')
140        self.assertEqual(completer.complete('tr', 0), 'try:')
141
142    def test_duplicate_globals(self):
143        namespace = {
144            'False': None,  # Keyword vs builtin vs namespace
145            'assert': None,  # Keyword vs namespace
146            'try': lambda: None,  # Keyword vs callable
147            'memoryview': None,  # Callable builtin vs non-callable
148            'Ellipsis': lambda: None,  # Non-callable builtin vs callable
149        }
150        completer = rlcompleter.Completer(namespace)
151        self.assertEqual(completer.complete('False', 0), 'False')
152        self.assertIsNone(completer.complete('False', 1))  # No duplicates
153        # Space or colon added due to being a reserved keyword
154        self.assertEqual(completer.complete('assert', 0), 'assert ')
155        self.assertIsNone(completer.complete('assert', 1))
156        self.assertEqual(completer.complete('try', 0), 'try:')
157        self.assertIsNone(completer.complete('try', 1))
158        # No opening bracket "(" because we overrode the built-in class
159        self.assertEqual(completer.complete('memoryview', 0), 'memoryview')
160        self.assertIsNone(completer.complete('memoryview', 1))
161        self.assertEqual(completer.complete('Ellipsis', 0), 'Ellipsis()')
162        self.assertIsNone(completer.complete('Ellipsis', 1))
163
164if __name__ == '__main__':
165    unittest.main()
166