Skip to content

Commit 30abd71

Browse files
committed
WIP: copy&adapt some tests from the original fancycompleter. They don't work because they need to be ported from pytest to unittest
1 parent 6ddfa61 commit 30abd71

2 files changed

Lines changed: 210 additions & 6 deletions

File tree

Lib/_pyrepl/fancycompleter.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@
55
"""
66
Colorful TAB completion for Python prompt
77
"""
8-
from __future__ import with_statement
9-
from __future__ import print_function
10-
118
from _pyrepl import readline
129
from _colorize import ANSIColors
1310
import rlcompleter
14-
import sys
1511
import types
16-
import os.path
1712
from itertools import count
1813

1914

@@ -124,7 +119,7 @@ def global_matches(self, text):
124119
except Exception as exc:
125120
values.append(exc)
126121
if self.config.use_colors and names:
127-
return self.color_matches(names, values)
122+
return self.colorize_matches(names, values)
128123
return names
129124

130125
def attr_matches(self, text):
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import unittest
2+
import sys
3+
4+
import _pyrepl.readline
5+
from _pyrepl.fancycompleter import Completer, DefaultConfig, commonprefix
6+
7+
8+
class ConfigForTest(DefaultConfig):
9+
use_colors = False
10+
11+
class ColorConfig(DefaultConfig):
12+
use_colors = True
13+
14+
class FancyCompleterTests(unittest.TestCase):
15+
16+
def test_commonprefix(self):
17+
assert commonprefix(['isalpha', 'isdigit', 'foo']) == ''
18+
assert commonprefix(['isalpha', 'isdigit']) == 'is'
19+
assert commonprefix(['isalpha', 'isdigit', 'foo'], base='i') == 'is'
20+
assert commonprefix([]) == ''
21+
assert commonprefix(['aaa', 'bbb'], base='x') == ''
22+
23+
24+
def test_complete_attribute(self):
25+
compl = Completer({'a': None}, ConfigForTest)
26+
assert compl.attr_matches('a.') == ['a.__']
27+
matches = compl.attr_matches('a.__')
28+
assert 'a.__class__' not in matches
29+
assert '__class__' in matches
30+
assert compl.attr_matches('a.__class') == ['a.__class__']
31+
32+
33+
def test_complete_attribute_prefix(self):
34+
class C(object):
35+
attr = 1
36+
_attr = 2
37+
__attr__attr = 3
38+
compl = Completer({'a': C}, ConfigForTest)
39+
assert compl.attr_matches('a.') == ['attr', 'mro']
40+
assert compl.attr_matches('a._') == ['_C__attr__attr', '_attr', ' ']
41+
matches = compl.attr_matches('a.__')
42+
assert 'a.__class__' not in matches
43+
assert '__class__' in matches
44+
assert compl.attr_matches('a.__class') == ['a.__class__']
45+
46+
compl = Completer({'a': None}, ConfigForTest)
47+
assert compl.attr_matches('a._') == ['a.__']
48+
49+
50+
def test_complete_attribute_colored(self):
51+
compl = Completer({'a': 42}, ColorConfig)
52+
matches = compl.attr_matches('a.__')
53+
assert len(matches) > 2
54+
expected_color = compl.config.color_by_type.get(type(compl.__class__))
55+
assert expected_color == '35;01'
56+
expected_part = Color.set(expected_color, '__class__')
57+
for match in matches:
58+
if expected_part in match:
59+
break
60+
else:
61+
assert False, matches
62+
assert ' ' in matches
63+
64+
65+
def test_complete_colored_single_match(self):
66+
"""No coloring, via commonprefix."""
67+
compl = Completer({'foobar': 42}, ColorConfig)
68+
matches = compl.global_matches('foob')
69+
assert matches == ['foobar']
70+
71+
72+
def test_does_not_color_single_match(self):
73+
class obj:
74+
msgs = []
75+
76+
compl = Completer({'obj': obj}, ColorConfig)
77+
matches = compl.attr_matches('obj.msgs')
78+
assert matches == ['obj.msgs']
79+
80+
81+
def test_complete_global(self):
82+
compl = Completer({'foobar': 1, 'foobazzz': 2}, ConfigForTest)
83+
assert compl.global_matches('foo') == ['fooba']
84+
matches = compl.global_matches('fooba')
85+
assert set(matches) == set(['foobar', 'foobazzz'])
86+
assert compl.global_matches('foobaz') == ['foobazzz']
87+
assert compl.global_matches('nothing') == []
88+
89+
90+
def test_complete_global_colored(self):
91+
compl = Completer({'foobar': 1, 'foobazzz': 2}, ColorConfig)
92+
assert compl.global_matches('foo') == ['fooba']
93+
matches = compl.global_matches('fooba')
94+
assert set(matches) == {
95+
' ',
96+
'\x1b[001;00m\x1b[33;01mfoobazzz\x1b[00m',
97+
'\x1b[000;00m\x1b[33;01mfoobar\x1b[00m',
98+
}
99+
assert compl.global_matches('foobaz') == ['foobazzz']
100+
assert compl.global_matches('nothing') == []
101+
102+
103+
def test_complete_global_colored_exception(self):
104+
compl = Completer({'tryme': ValueError()}, ColorConfig)
105+
if sys.version_info >= (3, 6):
106+
assert compl.global_matches('try') == [
107+
'\x1b[000;00m\x1b[37mtry:\x1b[00m',
108+
'\x1b[001;00m\x1b[31;01mtryme\x1b[00m',
109+
' '
110+
]
111+
else:
112+
assert compl.global_matches('try') == [
113+
'\x1b[000;00m\x1b[37mtry\x1b[00m',
114+
'\x1b[001;00m\x1b[31;01mtryme\x1b[00m',
115+
' '
116+
]
117+
118+
119+
def test_complete_global_exception(monkeypatchself):
120+
import rlcompleter
121+
122+
def rlcompleter_global_matches(self, text):
123+
return ['trigger_exception!', 'nameerror', 'valid']
124+
125+
monkeypatch.setattr(rlcompleter.Completer, 'global_matches',
126+
rlcompleter_global_matches)
127+
128+
compl = Completer({'valid': 42}, ColorConfig)
129+
assert compl.global_matches("") == [
130+
"\x1b[000;00m\x1b[31;01mnameerror\x1b[00m",
131+
"\x1b[001;00m\x1b[31;01mtrigger_exception!\x1b[00m",
132+
"\x1b[002;00m\x1b[33;01mvalid\x1b[00m",
133+
" ",
134+
]
135+
136+
137+
def test_color_for_obj(monkeypatchself):
138+
class Config(ColorConfig):
139+
color_by_type = {}
140+
141+
compl = Completer({}, Config)
142+
assert compl.color_for_obj(1, "foo", "bar") == "\x1b[001;00m\x1b[00mfoo\x1b[00m"
143+
144+
145+
def test_complete_with_indexer(self):
146+
compl = Completer({'lst': [None, 2, 3]}, ConfigForTest)
147+
assert compl.attr_matches('lst[0].') == ['lst[0].__']
148+
matches = compl.attr_matches('lst[0].__')
149+
assert 'lst[0].__class__' not in matches
150+
assert '__class__' in matches
151+
assert compl.attr_matches('lst[0].__class') == ['lst[0].__class__']
152+
153+
154+
def test_autocomplete(self):
155+
class A:
156+
aaa = None
157+
abc_1 = None
158+
abc_2 = None
159+
abc_3 = None
160+
bbb = None
161+
compl = Completer({'A': A}, ConfigForTest)
162+
#
163+
# in this case, we want to display all attributes which start with
164+
# 'a'. MOREOVER, we also include a space to prevent readline to
165+
# automatically insert the common prefix (which will the the ANSI escape
166+
# sequence if we use colors)
167+
matches = compl.attr_matches('A.a')
168+
assert sorted(matches) == [' ', 'aaa', 'abc_1', 'abc_2', 'abc_3']
169+
#
170+
# IF there is an actual common prefix, we return just it, so that readline
171+
# will insert it into place
172+
matches = compl.attr_matches('A.ab')
173+
assert matches == ['A.abc_']
174+
#
175+
# finally, at the next TAB, we display again all the completions available
176+
# for this common prefix. Agai, we insert a spurious space to prevent the
177+
# automatic completion of ANSI sequences
178+
matches = compl.attr_matches('A.abc_')
179+
assert sorted(matches) == [' ', 'abc_1', 'abc_2', 'abc_3']
180+
181+
182+
def test_complete_exception(self):
183+
compl = Completer({}, ConfigForTest)
184+
assert compl.attr_matches('xxx.') == []
185+
186+
187+
def test_complete_invalid_attr(self):
188+
compl = Completer({'str': str}, ConfigForTest)
189+
assert compl.attr_matches('str.xx') == []
190+
191+
192+
def test_complete_function_skipped(self):
193+
compl = Completer({'str': str}, ConfigForTest)
194+
assert compl.attr_matches('str.split().') == []
195+
196+
197+
def test_unicode_in___dir__(self):
198+
class Foo(object):
199+
def __dir__(self):
200+
return [u'hello', 'world']
201+
202+
compl = Completer({'a': Foo()}, ConfigForTest)
203+
matches = compl.attr_matches('a.')
204+
assert matches == ['hello', 'world']
205+
assert type(matches[0]) is str
206+
207+
208+
if __name__ == "__main__":
209+
unittest.main()

0 commit comments

Comments
 (0)