Skip to content

Commit b4cee82

Browse files
GlobalCompleter returns unicode matches
1 parent b230413 commit b4cee82

File tree

4 files changed

+32
-16
lines changed

4 files changed

+32
-16
lines changed

bpython/_py3compat.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,13 @@ def prepare_for_exec(arg, encoding=None):
4949
else:
5050
def prepare_for_exec(arg, encoding=None):
5151
return arg.encode(encoding)
52+
53+
54+
def try_decode(s, encoding):
55+
"""Try to decode s which is str names. Return None if not decodable"""
56+
if not py3 and not isinstance(s, unicode):
57+
try:
58+
return s.decode(encoding)
59+
except UnicodeDecodeError:
60+
return None
61+
return s

bpython/autocomplete.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from bpython import inspection
3535
from bpython import importcompletion
3636
from bpython import line as lineparts
37-
from bpython._py3compat import py3
37+
from bpython._py3compat import py3, try_decode
3838
from bpython.lazyre import LazyReCompile
3939

4040

@@ -286,11 +286,17 @@ def matches(self, cursor_offset, line, **kwargs):
286286
n = len(text)
287287
for word in keyword.kwlist:
288288
if method_match(word, n, text):
289-
matches.add(word)
289+
word = try_decode(word, 'ascii') # py2 keywords are all ascii
290+
if word is not None:
291+
matches.add(word)
290292
for nspace in [builtins.__dict__, locals_]:
291293
for word, val in nspace.items():
292294
if (method_match(word, len(text), text) and
293295
word != "__builtins__"):
296+
word = try_decode(word, 'ascii')
297+
# if identifier isn't ascii, don't complete (syntax error)
298+
if word is None:
299+
continue
294300
matches.add(_callable_postfix(val, word))
295301
return matches
296302

bpython/importcompletion.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
# THE SOFTWARE.
2222

23-
from bpython._py3compat import py3
23+
from bpython._py3compat import py3, try_decode
2424
from bpython.line import current_word, current_import, \
2525
current_from_import_from, current_from_import_import
2626

@@ -42,17 +42,6 @@
4242
fully_loaded = False
4343

4444

45-
def try_decode_module(module, encoding):
46-
"""Try to decode module names."""
47-
if not py3 and not isinstance(module, unicode):
48-
try:
49-
return module.decode(encoding)
50-
except UnicodeDecodeError:
51-
# Not importable anyway, ignore it
52-
return None
53-
return module
54-
55-
5645
def module_matches(cw, prefix=''):
5746
"""Modules names to replace cw with"""
5847
full = '%s.%s' % (prefix, cw) if prefix else cw
@@ -83,7 +72,7 @@ def attr_matches(cw, prefix='', only_modules=False):
8372
if module_part:
8473
matches = ('%s.%s' % (module_part, m) for m in matches)
8574

86-
generator = (try_decode_module(match, 'ascii') for match in matches)
75+
generator = (try_decode(match, 'ascii') for match in matches)
8776
return set(filter(lambda x: x is not None, generator))
8877

8978

@@ -184,7 +173,7 @@ def find_all_modules(path=None):
184173
if not p:
185174
p = os.curdir
186175
for module in find_modules(p):
187-
module = try_decode_module(module, sys.getfilesystemencoding())
176+
module = try_decode(module, sys.getfilesystemencoding())
188177
if module is None:
189178
continue
190179
modules.add(module)

bpython/test/test_autocomplete.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# encoding: utf-8
2+
13
from collections import namedtuple
24
import inspect
35
from bpython._py3compat import py3
@@ -273,6 +275,15 @@ def function():
273275
locals_={'function': function}),
274276
set(('function(', )))
275277

278+
def test_completions_are_unicode(self):
279+
for m in self.com.matches(1, 'a', locals_={'abc': 10}):
280+
self.assertIsInstance(m, type(u''))
281+
282+
@unittest.skipIf(py3, "in Python 3 invalid identifiers are passed through")
283+
def test_ignores_nonascii_encodable(self):
284+
self.assertSetEqual(self.com.matches(1, 'abc', locals_={'abcß': 10}),
285+
set())
286+
276287

277288
class TestParameterNameCompletion(unittest.TestCase):
278289
def test_set_of_params_returns_when_matches_found(self):

0 commit comments

Comments
 (0)