diff --git a/jedi/utils.py b/jedi/utils.py index af6b8eb3..74ba7ebd 100644 --- a/jedi/utils.py +++ b/jedi/utils.py @@ -10,7 +10,7 @@ from jedi._compatibility import builtins from jedi import Interpreter -def setup_readline(): +def setup_readline(namespace=__main__.__dict__): """ Install Jedi completer to :mod:`readline`. @@ -68,7 +68,6 @@ def setup_readline(): library module. """ if state == 0: - namespace = __main__.__dict__ interpreter = Interpreter(text, [namespace]) # The following part is a bit hackish, because it tries to @@ -76,20 +75,20 @@ def setup_readline(): # use the "default" completion with ``getattr`` if # possible. path, dot, like = interpreter._get_completion_parts() - if re.match('^[\w][\w\d.]*$', path): + if not path or re.match('^[\w][\w\d.]*$', path): paths = path.split('.') if path else [] - namespaces = (namespace, builtins) + namespaces = (namespace, builtins.__dict__) for p in paths: old, namespaces = namespaces, [] for n in old: try: - namespaces.append(getattr(n, p)) - except AttributeError: + namespaces.append(n[p].__dict__) + except (KeyError, AttributeError): pass self.matches = [] for n in namespaces: - for name in dir(n): + for name in n.keys(): if name.lower().startswith(like.lower()): self.matches.append(path + dot + name) else: @@ -101,8 +100,6 @@ def setup_readline(): return None readline.set_completer(JediRL().complete) - j = JediRL() - j.complete('r', 0) readline.parse_and_bind("tab: complete") # No delimiters, Jedi handles that. diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 00000000..1e796452 --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,59 @@ +import readline + +from jedi import utils + + +class TestSetupReadline(): + namespace = dict() + utils.setup_readline(namespace) + + def completions(self, text): + completer = readline.get_completer() + i = 0 + completions = [] + while True: + completion = completer(text, i) + if completion is None: + break + completions.append(completion) + i += 1 + return completions + + def test_simple(self): + assert self.completions('list') == ['list'] + assert self.completions('importerror') == ['ImportError'] + + def test_nested(self): + assert self.completions('list.Insert') == ['list.insert'] + assert self.completions('list().Insert') == ['list().insert'] + + def test_magic_methods(self): + assert self.completions('list.__getitem__') == ['list.__getitem__'] + assert self.completions('list().__getitem__') == ['list().__getitem__'] + + def test_modules(self): + import sys + import os + self.namespace['sys'] = sys + self.namespace['os'] = os + + c = set(['os.' + d for d in dir(os) if d.startswith('ch')]) + assert set(self.completions('os.ch')) == set(c) + assert self.completions('os.chdir') == ['os.chdir'] + assert self.completions('os.path.join') == ['os.path.join'] + assert self.completions('os.path.join().upper') == ['os.path.join().upper'] + + del self.namespace['sys'] + del self.namespace['os'] + + def test_colorama(self): + """Only test it if colorama library is available""" + try: + # if colorama is installed + import colorama + except ImportError: + pass + else: + self.namespace['colorama'] = colorama + assert self.completions('colorama') + del self.namespace['colorama']