1
0
forked from VimPlug/jedi

Merge branch 'dev' of git://github.com/davidhalter/jedi

This commit is contained in:
Laurens Van Houtven
2013-06-23 22:50:00 +02:00
28 changed files with 1124 additions and 201 deletions

View File

@@ -42,8 +42,8 @@ import sys
# imports and circular imports... Just avoid it:
sys.path.insert(0, __path__[0])
from .api import Script, NotFoundError, set_debug_function, _quick_complete, \
preload_module
from .api import Script, Interpreter, NotFoundError, set_debug_function, \
preload_module, defined_names
from . import settings
sys.path.pop(0)

2
jedi/__main__.py Normal file
View File

@@ -0,0 +1,2 @@
from os import path
print(path.join(path.dirname(path.abspath(__file__)), 'replstartup.py'))

View File

@@ -20,6 +20,7 @@ from jedi import helpers
from jedi import common
from jedi import cache
from jedi import modules
from jedi import interpret
from jedi._compatibility import next, unicode
import evaluate
import keywords
@@ -53,14 +54,18 @@ class Script(object):
``unicode`` object (default ``'utf-8'``).
:type source_encoding: str
"""
def __init__(self, source, line, column, source_path,
source_encoding='utf-8'):
def __init__(self, source, line=None, column=None, source_path=None,
source_encoding='utf-8'):
lines = source.splitlines()
line = len(lines) if line is None else line
column = len(lines[-1]) if column is None else column
api_classes._clear_caches()
debug.reset_time()
self.source = modules.source_to_unicode(source, source_encoding)
self.pos = line, column
self._module = modules.ModuleWithCursor(source_path,
source=self.source, position=self.pos)
self._module = modules.ModuleWithCursor(
source_path, source=self.source, position=self.pos)
self._source_path = source_path
self.source_path = None if source_path is None \
else os.path.abspath(source_path)
@@ -337,7 +342,8 @@ class Script(object):
:rtype: list of :class:`api_classes.Definition`
"""
d = [api_classes.Definition(d) for d in set(self._goto()[0])]
d = [api_classes.Definition(d) for d in set(self._goto()[0])
if not isinstance(d, imports.ImportPath._GlobalNamespace)]
return self._sorted_defs(d)
def _goto(self, add_import_name=False):
@@ -385,7 +391,9 @@ class Script(object):
defs, search_name = evaluate.goto(stmt)
definitions = follow_inexistent_imports(defs)
if isinstance(user_stmt, pr.Statement):
if user_stmt.get_commands()[0].start_pos > self.pos:
call = user_stmt.get_commands()[0]
if not isinstance(call, (str, unicode)) and \
call.start_pos > self.pos:
# The cursor must be after the start, otherwise the
# statement is just an assignee.
definitions = [user_stmt]
@@ -503,6 +511,45 @@ class Script(object):
return sorted(d, key=lambda x: (x.module_path or '', x.start_pos))
class Interpreter(Script):
"""
Jedi API for Python REPLs.
In addition to completion of simple attribute access, Jedi
supports code completion based on static code analysis.
Jedi can complete attributes of object which is not initialized
yet.
>>> from os.path import join
>>> namespace = locals()
>>> script = Interpreter('join().up', [namespace])
>>> print(script.complete()[0].word)
upper
"""
def __init__(self, source, namespaces=[], **kwds):
"""
Parse `source` and mixin interpreted Python objects from `namespaces`.
:type source: str
:arg source: Code to parse.
:type namespaces: list of dict
:arg namespaces: a list of namespace dictionaries such as the one
returned by :func:`locals`.
Other optional arguments are same as the ones for :class:`Script`.
If `line` and `column` are None, they are assumed be at the end of
`source`.
"""
super(Interpreter, self).__init__(source, **kwds)
importer = interpret.ObjectImporter(self._parser.user_scope)
for ns in namespaces:
importer.import_raw_namespace(ns)
def defined_names(source, source_path=None, source_encoding='utf-8'):
"""
Get all definitions in `source` sorted by its position.
@@ -519,7 +566,7 @@ def defined_names(source, source_path=None, source_encoding='utf-8'):
modules.source_to_unicode(source, source_encoding),
module_path=source_path,
)
return api_classes._defined_names(parser.scope)
return api_classes._defined_names(parser.module)
def preload_module(*modules):
@@ -545,25 +592,3 @@ def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
debug.enable_warning = warnings
debug.enable_notice = notices
debug.enable_speed = speed
def _quick_complete(source):
"""
Convenience function to complete a source string at the end.
Example:
>>> _quick_complete('''
... import datetime
... datetime.da''') #doctest: +ELLIPSIS
[<Completion: date>, <Completion: datetime>, ...]
:param source: The source code to be completed.
:type source: string
:return: Completion objects as returned by :meth:`complete`.
:rtype: list of :class:`api_classes.Completion`
"""
lines = re.sub(r'[\n\r\s]*$', '', source).splitlines()
pos = len(lines), len(lines[-1])
script = Script(source, pos[0], pos[1], '')
return script.completions()

View File

@@ -142,9 +142,19 @@ class BaseDefinition(object):
def path(self):
"""The module path."""
path = []
def insert_nonnone(x):
if x:
path.insert(0, x)
if not isinstance(self._definition, keywords.Keyword):
par = self._definition
while par is not None:
if isinstance(par, pr.Import):
insert_nonnone(par.namespace)
insert_nonnone(par.from_ns)
if par.relative_count == 0:
break
with common.ignored(AttributeError):
path.insert(0, par.name)
par = par.parent

View File

@@ -318,7 +318,9 @@ def find_name(scope, name_str, position=None, search_global=False,
exc = pr.Class, pr.Function
until = lambda: par.parent.parent.get_parent_until(exc)
if par.isinstance(pr.Flow):
if par is None:
pass
elif par.isinstance(pr.Flow):
if par.command == 'for':
result += handle_for_loops(par)
else:
@@ -554,16 +556,33 @@ def assign_tuples(tup, results, seek_name):
else:
r = eval_results(i)
# are there still tuples or is it just a Call.
if isinstance(command, pr.Array):
# These are "sub"-tuples.
result += assign_tuples(command, r, seek_name)
else:
if command.name.names[-1] == seek_name:
result += r
# LHS of tuples can be nested, so resolve it recursively
result += find_assignments(command, r, seek_name)
return result
def find_assignments(lhs, results, seek_name):
"""
Check if `seek_name` is in the left hand side `lhs` of assignment.
`lhs` can simply be a variable (`pr.Call`) or a tuple/list (`pr.Array`)
representing the following cases::
a = 1 # lhs is pr.Call
(a, b) = 2 # lhs is pr.Array
:type lhs: pr.Call
:type results: list
:type seek_name: str
"""
if isinstance(lhs, pr.Array):
return assign_tuples(lhs, results, seek_name)
elif lhs.name.names[-1] == seek_name:
return results
else:
return []
@recursion.RecursionDecorator
@cache.memoize_default(default=())
def follow_statement(stmt, seek_name=None):
@@ -587,7 +606,7 @@ def follow_statement(stmt, seek_name=None):
if len(stmt.get_set_vars()) > 1 and seek_name and stmt.assignment_details:
new_result = []
for ass_commands, op in stmt.assignment_details:
new_result += assign_tuples(ass_commands[0], result, seek_name)
new_result += find_assignments(ass_commands[0], result, seek_name)
result = new_result
return set(result)
@@ -775,7 +794,10 @@ def goto(stmt, call_path=None):
commands = stmt.get_commands()
assert len(commands) == 1
call = commands[0]
call_path = list(call.generate_call_path())
if isinstance(call, (str, unicode)):
call_path = [call]
else:
call_path = list(call.generate_call_path())
scope = stmt.get_parent_until(pr.IsScope)
pos = stmt.start_pos

View File

@@ -162,9 +162,9 @@ class ImportPath(pr.Base):
# If you edit e.g. gunicorn, there will be imports like this:
# `from gunicorn import something`. But gunicorn is not in the
# sys.path. Therefore look if gunicorn is a parent directory, #56.
parts = self.file_path.split(os.path.sep)
in_path = []
if self.import_path:
parts = self.file_path.split(os.path.sep)
for i, p in enumerate(parts):
if p == self.import_path[0]:
new = os.path.sep.join(parts[:i])

171
jedi/interpret.py Normal file
View File

@@ -0,0 +1,171 @@
"""
Module to handle interpreted Python objects.
"""
import itertools
import tokenize
from jedi import parsing_representation as pr
class ObjectImporter(object):
"""
Import objects in "raw" namespace such as :func:`locals`.
"""
def __init__(self, scope):
self.scope = scope
count = itertools.count()
self._genname = lambda: '*jedi-%s*' % next(count)
"""
Generate unique variable names to avoid name collision.
To avoid name collision to already defined names, generated
names are invalid as Python identifier.
"""
def import_raw_namespace(self, raw_namespace):
"""
Import interpreted Python objects in a namespace.
Three kinds of objects are treated here.
1. Functions and classes. The objects imported like this::
from os.path import join
2. Modules. The objects imported like this::
import os
3. Instances. The objects created like this::
from datetime import datetime
dt = datetime(2013, 1, 1)
:type raw_namespace: dict
:arg raw_namespace: e.g., the dict given by `locals`
"""
scope = self.scope
for (variable, obj) in raw_namespace.items():
objname = getattr(obj, '__name__', None)
# Import functions and classes
module = getattr(obj, '__module__', None)
if module and objname:
fakeimport = self.make_fakeimport(module, objname, variable)
scope.add_import(fakeimport)
continue
# Import modules
if getattr(obj, '__file__', None) and objname:
fakeimport = self.make_fakeimport(objname)
scope.add_import(fakeimport)
continue
# Import instances
objclass = getattr(obj, '__class__', None)
module = getattr(objclass, '__module__', None)
if objclass and module:
alias = self._genname()
fakeimport = self.make_fakeimport(module, objclass.__name__,
alias)
fakestmt = self.make_fakestatement(variable, alias, call=True)
scope.add_import(fakeimport)
scope.add_statement(fakestmt)
continue
def make_fakeimport(self, module, variable=None, alias=None):
"""
Make a fake import object.
The following statements are created depending on what parameters
are given:
- only `module`: ``import <module>``
- `module` and `variable`: ``from <module> import <variable>``
- all: ``from <module> import <variable> as <alias>``
:type module: str
:arg module: ``<module>`` part in ``from <module> import ...``
:type variable: str
:arg variable: ``<variable>`` part in ``from ... import <variable>``
:type alias: str
:arg alias: ``<alias>`` part in ``... import ... as <alias>``.
:rtype: :class:`parsing_representation.Import`
"""
submodule = self.scope._sub_module
if variable:
varname = pr.Name(
module=submodule,
names=[(variable, (-1, 0))],
start_pos=(-1, 0),
end_pos=(None, None))
else:
varname = None
modname = pr.Name(
module=submodule,
names=[(module, (-1, 0))],
start_pos=(-1, 0),
end_pos=(None, None))
if alias:
aliasname = pr.Name(
module=submodule,
names=[(alias, (-1, 0))],
start_pos=(-1, 0),
end_pos=(None, None))
else:
aliasname = None
if varname:
fakeimport = pr.Import(
module=submodule,
namespace=varname,
from_ns=modname,
alias=aliasname,
start_pos=(-1, 0),
end_pos=(None, None))
else:
fakeimport = pr.Import(
module=submodule,
namespace=modname,
alias=aliasname,
start_pos=(-1, 0),
end_pos=(None, None))
return fakeimport
def make_fakestatement(self, lhs, rhs, call=False):
"""
Make a fake statement object that represents ``lhs = rhs``.
:type call: bool
:arg call: When `call` is true, make a fake statement that represents
``lhs = rhs()``.
:rtype: :class:`parsing_representation.Statement`
"""
submodule = self.scope._sub_module
lhsname = pr.Name(
module=submodule,
names=[(lhs, (0, 0))],
start_pos=(0, 0),
end_pos=(None, None))
rhsname = pr.Name(
module=submodule,
names=[(rhs, (0, 0))],
start_pos=(0, 0),
end_pos=(None, None))
token_list = [lhsname, (tokenize.OP, '=', (0, 0)), rhsname]
if call:
token_list.extend([
(tokenize.OP, '(', (0, 0)),
(tokenize.OP, ')', (0, 0)),
])
return pr.Statement(
module=submodule,
set_vars=[lhsname],
used_vars=[rhsname],
token_list=token_list,
start_pos=(0, 0),
end_pos=(None, None))

View File

@@ -141,6 +141,7 @@ class ModuleWithCursor(Module):
last_line = self.get_line(self._line_temp)
if last_line and last_line[-1] == '\\':
line = last_line[:-1] + ' ' + line
self._line_length = len(last_line)
else:
break
return line[::-1]
@@ -187,6 +188,7 @@ class ModuleWithCursor(Module):
elif token_type == tokenize.NUMBER:
pass
else:
self._column_temp = self._line_length - end[1]
break
self._column_temp = self._line_length - end[1]

View File

@@ -56,7 +56,7 @@ class Parser(object):
self.start_pos = self.end_pos = 1 + offset[0], offset[1]
# initialize global Scope
self.module = pr.SubModule(module_path, self.start_pos, top_module)
self.scope = self.module
self._scope = self.module
self.current = (None, None)
source = source + '\n' # end with \n, because the parser needs it
@@ -390,7 +390,7 @@ class Parser(object):
#print 'new_stat', set_vars, used_vars
if self.freshscope and not self.no_docstr and len(tok_list) == 1 \
and self.last_token[0] == tokenize.STRING:
self.scope.add_docstr(self.last_token[1])
self._scope.add_docstr(self.last_token[1])
return None, tok
else:
stmt = stmt_class(self.module, set_vars, used_vars, tok_list,
@@ -408,7 +408,7 @@ class Parser(object):
and len(stmt.token_list) == 1
and first_tok[0] == tokenize.STRING):
# ... then set it as a docstring
self.scope.statements[-1].add_docstr(first_tok[1])
self._scope.statements[-1].add_docstr(first_tok[1])
if tok in always_break + not_first_break:
self._gen.push_last_back()
@@ -429,7 +429,7 @@ class Parser(object):
self.start_pos, self.end_pos = start_pos, end_pos
except (StopIteration, common.MultiLevelStopIteration):
# on finish, set end_pos correctly
s = self.scope
s = self._scope
while s is not None:
if isinstance(s, pr.Module) \
and not isinstance(s, pr.SubModule):
@@ -443,8 +443,8 @@ class Parser(object):
or self.user_scope is None
and self.start_pos[0] >= self.user_position[0]):
debug.dbg('user scope found [%s] = %s' %
(self.parserline.replace('\n', ''), repr(self.scope)))
self.user_scope = self.scope
(self.parserline.replace('\n', ''), repr(self._scope)))
self.user_scope = self._scope
self.last_token = self.current
self.current = (typ, tok)
return self.current
@@ -472,29 +472,29 @@ class Parser(object):
#debug.dbg('main: tok=[%s] type=[%s] indent=[%s]'\
# % (tok, tokenize.tok_name[token_type], start_position[0]))
while token_type == tokenize.DEDENT and self.scope != self.module:
while token_type == tokenize.DEDENT and self._scope != self.module:
token_type, tok = self.next()
if self.start_pos[1] <= self.scope.start_pos[1]:
self.scope.end_pos = self.start_pos
self.scope = self.scope.parent
if isinstance(self.scope, pr.Module) \
and not isinstance(self.scope, pr.SubModule):
self.scope = self.module
if self.start_pos[1] <= self._scope.start_pos[1]:
self._scope.end_pos = self.start_pos
self._scope = self._scope.parent
if isinstance(self._scope, pr.Module) \
and not isinstance(self._scope, pr.SubModule):
self._scope = self.module
# check again for unindented stuff. this is true for syntax
# errors. only check for names, because thats relevant here. If
# some docstrings are not indented, I don't care.
while self.start_pos[1] <= self.scope.start_pos[1] \
while self.start_pos[1] <= self._scope.start_pos[1] \
and (token_type == tokenize.NAME or tok in ['(', '['])\
and self.scope != self.module:
self.scope.end_pos = self.start_pos
self.scope = self.scope.parent
if isinstance(self.scope, pr.Module) \
and not isinstance(self.scope, pr.SubModule):
self.scope = self.module
and self._scope != self.module:
self._scope.end_pos = self.start_pos
self._scope = self._scope.parent
if isinstance(self._scope, pr.Module) \
and not isinstance(self._scope, pr.SubModule):
self._scope = self.module
use_as_parent_scope = self.top_module if isinstance(self.scope,
pr.SubModule) else self.scope
use_as_parent_scope = self.top_module if isinstance(self._scope,
pr.SubModule) else self._scope
first_pos = self.start_pos
if tok == 'def':
func = self._parse_function()
@@ -503,7 +503,7 @@ class Parser(object):
self.start_pos[0])
continue
self.freshscope = True
self.scope = self.scope.add_scope(func, self._decorators)
self._scope = self._scope.add_scope(func, self._decorators)
self._decorators = []
elif tok == 'class':
cls = self._parse_class()
@@ -511,7 +511,7 @@ class Parser(object):
debug.warning("class: syntax error@%s" % self.start_pos[0])
continue
self.freshscope = True
self.scope = self.scope.add_scope(cls, self._decorators)
self._scope = self._scope.add_scope(cls, self._decorators)
self._decorators = []
# import stuff
elif tok == 'import':
@@ -522,7 +522,7 @@ class Parser(object):
i = pr.Import(self.module, first_pos, end_pos, m,
alias, defunct=defunct)
self._check_user_stmt(i)
self.scope.add_import(i)
self._scope.add_import(i)
if not imports:
i = pr.Import(self.module, first_pos, self.end_pos, None,
defunct=True)
@@ -559,7 +559,7 @@ class Parser(object):
alias, mod, star, relative_count,
defunct=defunct or defunct2)
self._check_user_stmt(i)
self.scope.add_import(i)
self._scope.add_import(i)
self.freshscope = False
#loops
elif tok == 'for':
@@ -569,7 +569,7 @@ class Parser(object):
if tok == ':':
s = [] if statement is None else [statement]
f = pr.ForFlow(self.module, s, first_pos, set_stmt)
self.scope = self.scope.add_statement(f)
self._scope = self._scope.add_statement(f)
else:
debug.warning('syntax err, for flow started @%s',
self.start_pos[0])
@@ -612,13 +612,13 @@ class Parser(object):
# the flow statement, because a dedent releases the
# main scope, so just take the last statement.
try:
s = self.scope.statements[-1].set_next(f)
s = self._scope.statements[-1].set_next(f)
except (AttributeError, IndexError):
# If set_next doesn't exist, just add it.
s = self.scope.add_statement(f)
s = self._scope.add_statement(f)
else:
s = self.scope.add_statement(f)
self.scope = s
s = self._scope.add_statement(f)
self._scope = s
else:
for i in inputs:
i.parent = use_as_parent_scope
@@ -629,7 +629,7 @@ class Parser(object):
s = self.start_pos
self.freshscope = False
# add returns to the scope
func = self.scope.get_parent_until(pr.Function)
func = self._scope.get_parent_until(pr.Function)
if tok == 'yield':
func.is_generator = True
@@ -646,7 +646,7 @@ class Parser(object):
elif tok == 'global':
stmt, tok = self._parse_statement(self.current)
if stmt:
self.scope.add_statement(stmt)
self._scope.add_statement(stmt)
for name in stmt.used_vars:
# add the global to the top, because there it is
# important.
@@ -659,8 +659,9 @@ class Parser(object):
continue
elif tok == 'assert':
stmt, tok = self._parse_statement()
stmt.parent = use_as_parent_scope
self.scope.asserts.append(stmt)
if stmt is not None:
stmt.parent = use_as_parent_scope
self._scope.asserts.append(stmt)
# default
elif token_type in [tokenize.NAME, tokenize.STRING,
tokenize.NUMBER] \
@@ -670,7 +671,7 @@ class Parser(object):
# by the statement parser.
stmt, tok = self._parse_statement(self.current)
if stmt:
self.scope.add_statement(stmt)
self._scope.add_statement(stmt)
self.freshscope = False
else:
if token_type not in [tokenize.COMMENT, tokenize.INDENT,

View File

@@ -16,11 +16,11 @@ is the easiest way to write a parser. The same behaviour applies to ``Param``,
which is being used in a function definition.
The easiest way to play with this module is to use :class:`parsing.Parser`.
:attr:`parsing.Parser.scope` holds an instance of :class:`SubModule`:
:attr:`parsing.Parser.module` holds an instance of :class:`SubModule`:
>>> from jedi.parsing import Parser
>>> parser = Parser('import os', 'example.py')
>>> submodule = parser.scope
>>> submodule = parser.module
>>> submodule
<SubModule: example.py@1-1>
@@ -248,14 +248,14 @@ class Scope(Simple, IsScope):
... b = y
... b.c = z
... ''')
>>> parser.scope.get_defined_names()
>>> parser.module.get_defined_names()
[<Name: a@2,0>, <Name: b@3,0>]
Note that unlike :meth:`get_set_vars`, assignment to object
attribute does not change the result because it does not change
the defined names in this scope.
>>> parser.scope.get_set_vars()
>>> parser.module.get_set_vars()
[<Name: a@2,0>, <Name: b@3,0>, <Name: b.c@4,0>]
"""

25
jedi/replstartup.py Normal file
View File

@@ -0,0 +1,25 @@
"""
``PYTHONSTARTUP`` to use Jedi in your Python interpreter.
To use Jedi completion in Python interpreter, add the following in your shell
setup (e.g., ``.bashrc``)::
export PYTHONSTARTUP="$(python -m jedi)"
Then you will be able to use Jedi completer in your Python interpreter::
$ python
Python 2.7.2+ (default, Jul 20 2012, 22:15:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path.join().split().in<TAB> # doctest: +SKIP
os.path.join().split().index os.path.join().split().insert
"""
import jedi.utils
jedi.utils.setup_readline()
del jedi
# Note: try not to do many things here, as it will contaminate global
# namespace of the interpreter.

View File

@@ -127,8 +127,10 @@ cache_directory = os.path.expanduser(_cache_directory)
"""
The path where all the caches can be found.
On Linux, this defaults to ``~/.cache/jedi/``, on OS X to ``~/.jedi/`` and on
Windows to ``%APPDATA%\\Jedi\\Jedi\\``.
On Linux, this defaults to ``~/.cache/jedi/``, on OS X to
``~/Library/Caches/Jedi/`` and on Windows to ``%APPDATA%\\Jedi\\Jedi\\``.
On Linux, if environment variable ``$XDG_CACHE_HOME`` is set,
``$XDG_CACHE_HOME/jedi`` is used instead of the default one.
"""
# ----------------

110
jedi/utils.py Normal file
View File

@@ -0,0 +1,110 @@
"""
Utilities for end-users.
"""
from rlcompleter import Completer
from jedi import Interpreter
_NON_DELIMS = ' \t\n()'
"""
:class:`rcompleter.Completer` assumes these characters to be delimiter
(i.e., :meth:`rcompleter.Completer.complete` does not expect these
characters) but :class:`JediRLCompleter` can handle them.
"""
try:
import readline
except ImportError:
pass
else:
_READLINE_DEFAULT_DELIMS = readline.get_completer_delims()
_READLINE_JEDI_DELIMS = ''.join(
set(_READLINE_DEFAULT_DELIMS) - set(_NON_DELIMS))
class JediRLCompleter(Completer):
"""
:class:`rlcompleter.Completer` enhanced by Jedi.
This class tries matchers defined in :class:`.Completer` first.
If they fail, :class:`jedi.Interpreter` is used.
>>> import os
>>> completer = JediRLCompleter(locals())
>>> completer.complete('os.path.joi', 0) # completion w/o Jedi
'os.path.join('
>>> completer.complete('os.path.join().s', 0) # completion with Jedi
'os.path.join().split'
"""
def _jedi_matches(self, text):
completions = Interpreter(text, [self.namespace]).completions()
return [text + c.complete for c in completions]
@staticmethod
def _split_for_default_matcher(text, delims=_NON_DELIMS):
"""
Split `text` before passing it to :meth:`Completer.attr_matches` etc.
>>> JediRLCompleter._split_for_default_matcher('f(')
('f(', '')
>>> JediRLCompleter._split_for_default_matcher('f().g')
('f()', '.g')
"""
import re
m = re.match(r"(.*[{0}])([^{0}]*)".format(re.escape(delims)), text)
if not m:
return ('', text)
return m.groups()
def _find_matches(self, default_matcher, text):
"""
Common part for :meth:`attr_matches` and :meth:`global_matches`.
Try `default_matcher` first and return what it returns if
it is not empty. Otherwise, try :meth:`_jedi_matches`.
:arg default_matcher: :meth:`.Completer.attr_matches` or
:meth:`.Completer.global_matches`.
:arg str text: code to complete
"""
(pre, body) = self._split_for_default_matcher(text)
matches = default_matcher(self, body)
if matches:
return [pre + m for m in matches]
return self._jedi_matches(text)
def attr_matches(self, text):
# NOTE: Completer is old type class so `super` cannot be used here
return self._find_matches(Completer.attr_matches, text)
def global_matches(self, text):
# NOTE: Completer is old type class so `super` cannot be used here
return self._find_matches(Completer.global_matches, text)
def setup_readline():
"""
Install Jedi completer to :mod:`readline`.
This function setups :mod:`readline` to use Jedi in Python interactive
shell. If you want to use custom ``PYTHONSTARTUP`` file, you can call
this function like this:
>>> from jedi.utils import setup_readline
>>> setup_readline()
"""
try:
import readline
except ImportError:
print("Module readline not available.")
else:
readline.set_completer(JediRLCompleter().complete)
readline.parse_and_bind("tab: complete")
readline.set_completer_delims(_READLINE_JEDI_DELIMS)