forked from VimPlug/jedi
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bf8a69024 | ||
|
|
9bb8f335c9 | ||
|
|
8d313e014f | ||
|
|
a79d386eba | ||
|
|
48b137a7f5 | ||
|
|
b4a4dacebd | ||
|
|
efd8861d62 | ||
|
|
2f86f549f5 | ||
|
|
cc0c4cc308 | ||
|
|
9617d4527d | ||
|
|
86ae11eb43 | ||
|
|
078595f8d7 | ||
|
|
76417cc3c1 | ||
|
|
70800a6dc2 | ||
|
|
4711b85b50 | ||
|
|
368bf7e58a | ||
|
|
3bdb941daa | ||
|
|
bd1010bbd2 | ||
|
|
23b3327b1d | ||
|
|
075577d50c |
@@ -3,7 +3,22 @@
|
|||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
|
||||||
0.13.0 (2018-01-02)
|
0.13.3 (2019-02-24)
|
||||||
|
+++++++++++++++++++
|
||||||
|
|
||||||
|
- Fixed an issue with embedded Pytho, see https://github.com/davidhalter/jedi-vim/issues/870
|
||||||
|
|
||||||
|
0.13.2 (2018-12-15)
|
||||||
|
+++++++++++++++++++
|
||||||
|
|
||||||
|
- Fixed a bug that led to Jedi spawning a lot of subprocesses.
|
||||||
|
|
||||||
|
0.13.1 (2018-10-02)
|
||||||
|
+++++++++++++++++++
|
||||||
|
|
||||||
|
- Bugfixes, because tensorflow completions were still slow.
|
||||||
|
|
||||||
|
0.13.0 (2018-10-02)
|
||||||
+++++++++++++++++++
|
+++++++++++++++++++
|
||||||
|
|
||||||
- A small release. Some bug fixes.
|
- A small release. Some bug fixes.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ As you see Jedi is pretty simple and allows you to concentrate on writing a
|
|||||||
good text editor, while still having very good IDE features for Python.
|
good text editor, while still having very good IDE features for Python.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '0.13.0'
|
__version__ = '0.13.3'
|
||||||
|
|
||||||
from jedi.api import Script, Interpreter, set_debug_function, \
|
from jedi.api import Script, Interpreter, set_debug_function, \
|
||||||
preload_module, names
|
preload_module, names
|
||||||
|
|||||||
@@ -348,6 +348,11 @@ try:
|
|||||||
except NameError:
|
except NameError:
|
||||||
NotADirectoryError = IOError
|
NotADirectoryError = IOError
|
||||||
|
|
||||||
|
try:
|
||||||
|
PermissionError = PermissionError
|
||||||
|
except NameError:
|
||||||
|
PermissionError = IOError
|
||||||
|
|
||||||
|
|
||||||
def no_unicode_pprint(dct):
|
def no_unicode_pprint(dct):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -178,17 +178,22 @@ class Script(object):
|
|||||||
)
|
)
|
||||||
completions = completion.completions()
|
completions = completion.completions()
|
||||||
|
|
||||||
import_completions_count = len([
|
def iter_import_completions():
|
||||||
c for c in completions
|
for c in completions:
|
||||||
if not c._name.tree_name
|
tree_name = c._name.tree_name
|
||||||
or c._name.tree_name.get_definition().type in ('import_name', 'import_from')
|
if tree_name is None:
|
||||||
])
|
continue
|
||||||
if import_completions_count > 10:
|
definition = tree_name.get_definition()
|
||||||
|
if definition is not None \
|
||||||
|
and definition.type in ('import_name', 'import_from'):
|
||||||
|
yield c
|
||||||
|
|
||||||
|
if len(list(iter_import_completions())) > 10:
|
||||||
# For now disable completions if there's a lot of imports that
|
# For now disable completions if there's a lot of imports that
|
||||||
# might potentially be resolved. This is the case for tensorflow
|
# might potentially be resolved. This is the case for tensorflow
|
||||||
# and has been fixed for it. This is obviously temporary until we
|
# and has been fixed for it. This is obviously temporary until we
|
||||||
# have a better solution.
|
# have a better solution.
|
||||||
self._evaluator.infer_enabled = True
|
self._evaluator.infer_enabled = False
|
||||||
|
|
||||||
debug.speed('completions end')
|
debug.speed('completions end')
|
||||||
return completions
|
return completions
|
||||||
|
|||||||
@@ -153,9 +153,9 @@ def _get_virtual_env_from_var():
|
|||||||
variable is considered to be safe / controlled by the user solely.
|
variable is considered to be safe / controlled by the user solely.
|
||||||
"""
|
"""
|
||||||
var = os.environ.get('VIRTUAL_ENV')
|
var = os.environ.get('VIRTUAL_ENV')
|
||||||
if var is not None:
|
if var:
|
||||||
if var == sys.prefix:
|
if var == sys.prefix:
|
||||||
return SameEnvironment()
|
return _try_get_same_env()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return create_environment(var, safe=False)
|
return create_environment(var, safe=False)
|
||||||
@@ -184,14 +184,53 @@ def get_default_environment():
|
|||||||
if virtual_env is not None:
|
if virtual_env is not None:
|
||||||
return virtual_env
|
return virtual_env
|
||||||
|
|
||||||
# If no VirtualEnv is found, use the environment we're already
|
return _try_get_same_env()
|
||||||
|
|
||||||
|
|
||||||
|
def _try_get_same_env():
|
||||||
|
env = SameEnvironment()
|
||||||
|
if not os.path.basename(env.executable).lower().startswith('python'):
|
||||||
|
# This tries to counter issues with embedding. In some cases (e.g.
|
||||||
|
# VIM's Python Mac/Windows, sys.executable is /foo/bar/vim. This
|
||||||
|
# happens, because for Mac a function called `_NSGetExecutablePath` is
|
||||||
|
# used and for Windows `GetModuleFileNameW`. These are both platform
|
||||||
|
# specific functions. For all other systems sys.executable should be
|
||||||
|
# alright. However here we try to generalize:
|
||||||
|
#
|
||||||
|
# 1. Check if the executable looks like python (heuristic)
|
||||||
|
# 2. In case it's not try to find the executable
|
||||||
|
# 3. In case we don't find it use an interpreter environment.
|
||||||
|
#
|
||||||
|
# The last option will always work, but leads to potential crashes of
|
||||||
|
# Jedi - which is ok, because it happens very rarely and even less,
|
||||||
|
# because the code below should work for most cases.
|
||||||
|
if os.name == 'nt':
|
||||||
|
# The first case would be a virtualenv and the second a normal
|
||||||
|
# Python installation.
|
||||||
|
checks = (r'Scripts\python.exe', 'python.exe')
|
||||||
|
else:
|
||||||
|
# For unix it looks like Python is always in a bin folder.
|
||||||
|
checks = (
|
||||||
|
'bin/python%s.%s' % (sys.version_info[0], sys.version[1]),
|
||||||
|
'bin/python%s' % (sys.version_info[0]),
|
||||||
|
'bin/python',
|
||||||
|
)
|
||||||
|
for check in checks:
|
||||||
|
guess = os.path.join(sys.exec_prefix, check)
|
||||||
|
if os.path.isfile(guess):
|
||||||
|
# Bingo - We think we have our Python.
|
||||||
|
return Environment(guess)
|
||||||
|
# It looks like there is no reasonable Python to be found.
|
||||||
|
return InterpreterEnvironment()
|
||||||
|
# If no virtualenv is found, use the environment we're already
|
||||||
# using.
|
# using.
|
||||||
return SameEnvironment()
|
return env
|
||||||
|
|
||||||
|
|
||||||
def get_cached_default_environment():
|
def get_cached_default_environment():
|
||||||
|
var = os.environ.get('VIRTUAL_ENV')
|
||||||
environment = _get_cached_default_environment()
|
environment = _get_cached_default_environment()
|
||||||
if environment.path != os.environ.get('VIRTUAL_ENV'):
|
if var and var != environment.path:
|
||||||
_get_cached_default_environment.clear_cache()
|
_get_cached_default_environment.clear_cache()
|
||||||
return _get_cached_default_environment()
|
return _get_cached_default_environment()
|
||||||
return environment
|
return environment
|
||||||
|
|||||||
@@ -130,7 +130,10 @@ def get_stack_at_position(grammar, code_lines, module_node, pos):
|
|||||||
p.parse(tokens=tokenize_without_endmarker(code))
|
p.parse(tokens=tokenize_without_endmarker(code))
|
||||||
except EndMarkerReached:
|
except EndMarkerReached:
|
||||||
return p.stack
|
return p.stack
|
||||||
raise SystemError("This really shouldn't happen. There's a bug in Jedi.")
|
raise SystemError(
|
||||||
|
"This really shouldn't happen. There's a bug in Jedi:\n%s"
|
||||||
|
% list(tokenize_without_endmarker(code))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def evaluate_goto_definition(evaluator, context, leaf):
|
def evaluate_goto_definition(evaluator, context, leaf):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError, NotADirectoryError
|
from jedi._compatibility import FileNotFoundError, NotADirectoryError, PermissionError
|
||||||
from jedi.api.environment import SameEnvironment, \
|
from jedi.api.environment import SameEnvironment, \
|
||||||
get_cached_default_environment
|
get_cached_default_environment
|
||||||
from jedi.api.exceptions import WrongVersion
|
from jedi.api.exceptions import WrongVersion
|
||||||
@@ -151,7 +151,7 @@ def _is_django_path(directory):
|
|||||||
try:
|
try:
|
||||||
with open(os.path.join(directory, 'manage.py'), 'rb') as f:
|
with open(os.path.join(directory, 'manage.py'), 'rb') as f:
|
||||||
return b"DJANGO_SETTINGS_MODULE" in f.read()
|
return b"DJANGO_SETTINGS_MODULE" in f.read()
|
||||||
except (FileNotFoundError, NotADirectoryError):
|
except (FileNotFoundError, NotADirectoryError, PermissionError):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -167,7 +167,7 @@ def get_default_project(path=None):
|
|||||||
for dir in traverse_parents(check, include_current=True):
|
for dir in traverse_parents(check, include_current=True):
|
||||||
try:
|
try:
|
||||||
return Project.load(dir)
|
return Project.load(dir)
|
||||||
except (FileNotFoundError, NotADirectoryError):
|
except (FileNotFoundError, NotADirectoryError, PermissionError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if first_no_init_file is None:
|
if first_no_init_file is None:
|
||||||
|
|||||||
@@ -267,6 +267,11 @@ class DictComprehension(ComprehensionMixin, Sequence):
|
|||||||
|
|
||||||
return ContextSet(FakeSequence(self.evaluator, u'list', lazy_contexts))
|
return ContextSet(FakeSequence(self.evaluator, u'list', lazy_contexts))
|
||||||
|
|
||||||
|
def exact_key_items(self):
|
||||||
|
# NOTE: A smarter thing can probably done here to achieve better
|
||||||
|
# completions, but at least like this jedi doesn't crash
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
class GeneratorComprehension(ComprehensionMixin, GeneratorBase):
|
class GeneratorComprehension(ComprehensionMixin, GeneratorBase):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
import textwrap
|
import textwrap
|
||||||
from inspect import cleandoc
|
from inspect import cleandoc
|
||||||
|
|
||||||
@@ -158,6 +159,7 @@ def get_call_signature(funcdef, width=72, call_string=None):
|
|||||||
p = '(' + ''.join(param.get_code() for param in funcdef.get_params()).strip() + ')'
|
p = '(' + ''.join(param.get_code() for param in funcdef.get_params()).strip() + ')'
|
||||||
else:
|
else:
|
||||||
p = funcdef.children[2].get_code()
|
p = funcdef.children[2].get_code()
|
||||||
|
p = re.sub(r'\s+', ' ', p)
|
||||||
if funcdef.annotation:
|
if funcdef.annotation:
|
||||||
rtype = " ->" + funcdef.annotation.get_code()
|
rtype = " ->" + funcdef.annotation.get_code()
|
||||||
else:
|
else:
|
||||||
@@ -183,6 +185,8 @@ def get_doc_with_call_signature(scope_node):
|
|||||||
doc = clean_scope_docstring(scope_node)
|
doc = clean_scope_docstring(scope_node)
|
||||||
if call_signature is None:
|
if call_signature is None:
|
||||||
return doc
|
return doc
|
||||||
|
if not doc:
|
||||||
|
return call_signature
|
||||||
return '%s\n\n%s' % (call_signature, doc)
|
return '%s\n\n%s' % (call_signature, doc)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -10,7 +10,7 @@ __AUTHOR_EMAIL__ = 'davidhalter88@gmail.com'
|
|||||||
# Get the version from within jedi. It's defined in exactly one place now.
|
# Get the version from within jedi. It's defined in exactly one place now.
|
||||||
with open('jedi/__init__.py') as f:
|
with open('jedi/__init__.py') as f:
|
||||||
tree = ast.parse(f.read())
|
tree = ast.parse(f.read())
|
||||||
version = tree.body[1].value.s
|
version = tree.body[int(not hasattr(tree, 'docstring'))].value.s
|
||||||
|
|
||||||
readme = open('README.rst').read() + '\n\n' + open('CHANGELOG.rst').read()
|
readme = open('README.rst').read() + '\n\n' + open('CHANGELOG.rst').read()
|
||||||
with open('requirements.txt') as f:
|
with open('requirements.txt') as f:
|
||||||
@@ -33,7 +33,7 @@ setup(name='jedi',
|
|||||||
install_requires=install_requires,
|
install_requires=install_requires,
|
||||||
extras_require={
|
extras_require={
|
||||||
'testing': [
|
'testing': [
|
||||||
'pytest>=2.3.5',
|
'pytest>=3.1.0',
|
||||||
# docopt for sith doctests
|
# docopt for sith doctests
|
||||||
'docopt',
|
'docopt',
|
||||||
# coloroma for colored debug output
|
# coloroma for colored debug output
|
||||||
|
|||||||
@@ -154,6 +154,9 @@ def global_define():
|
|||||||
#? int()
|
#? int()
|
||||||
global_var_in_func
|
global_var_in_func
|
||||||
|
|
||||||
|
#? ['global_var_in_func']
|
||||||
|
global_var_in_f
|
||||||
|
|
||||||
|
|
||||||
def funct1():
|
def funct1():
|
||||||
# From issue #610
|
# From issue #610
|
||||||
@@ -175,6 +178,7 @@ def init_global_var_predefined():
|
|||||||
#? int() None
|
#? int() None
|
||||||
global_var_predefined
|
global_var_predefined
|
||||||
|
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# within docstrs
|
# within docstrs
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ exe['c']
|
|||||||
a = 'a'
|
a = 'a'
|
||||||
exe2 = kwargs_func(**{a:3,
|
exe2 = kwargs_func(**{a:3,
|
||||||
'b':4.0})
|
'b':4.0})
|
||||||
|
|
||||||
#? int()
|
#? int()
|
||||||
exe2['a']
|
exe2['a']
|
||||||
#? float()
|
#? float()
|
||||||
@@ -326,6 +327,19 @@ exe2['b']
|
|||||||
#? int() float()
|
#? int() float()
|
||||||
exe2['c']
|
exe2['c']
|
||||||
|
|
||||||
|
exe3 = kwargs_func(**{k: v for k, v in [(a, 3), ('b', 4.0)]})
|
||||||
|
|
||||||
|
# Should resolve to the same as 2 but jedi is not smart enough yet
|
||||||
|
# Here to make sure it doesn't result in crash though
|
||||||
|
#?
|
||||||
|
exe3['a']
|
||||||
|
|
||||||
|
#?
|
||||||
|
exe3['b']
|
||||||
|
|
||||||
|
#?
|
||||||
|
exe3['c']
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# *args / ** kwargs
|
# *args / ** kwargs
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
@@ -138,18 +138,30 @@ set_t2.c
|
|||||||
# python >= 3.5
|
# python >= 3.5
|
||||||
|
|
||||||
d = {'a': 3}
|
d = {'a': 3}
|
||||||
|
dc = {v: 3 for v in ['a']}
|
||||||
|
|
||||||
#? dict()
|
#? dict()
|
||||||
{**d}
|
{**d}
|
||||||
|
|
||||||
|
#? dict()
|
||||||
|
{**dc}
|
||||||
|
|
||||||
#? str()
|
#? str()
|
||||||
{**d, "b": "b"}["b"]
|
{**d, "b": "b"}["b"]
|
||||||
|
|
||||||
|
#? str()
|
||||||
|
{**dc, "b": "b"}["b"]
|
||||||
|
|
||||||
# Should resolve to int() but jedi is not smart enough yet
|
# Should resolve to int() but jedi is not smart enough yet
|
||||||
# Here to make sure it doesn't result in crash though
|
# Here to make sure it doesn't result in crash though
|
||||||
#?
|
#?
|
||||||
{**d}["a"]
|
{**d}["a"]
|
||||||
|
|
||||||
|
# Should resolve to int() but jedi is not smart enough yet
|
||||||
|
# Here to make sure it doesn't result in crash though
|
||||||
|
#?
|
||||||
|
{**dc}["a"]
|
||||||
|
|
||||||
s = {1, 2, 3}
|
s = {1, 2, 3}
|
||||||
|
|
||||||
#? set()
|
#? set()
|
||||||
|
|||||||
@@ -131,6 +131,17 @@ def test_get_default_environment_from_env_does_not_use_safe(tmpdir, monkeypatch)
|
|||||||
assert env.path == 'fake'
|
assert env.path == 'fake'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('virtualenv', ['', 'fufuuuuu', sys.prefix])
|
||||||
|
def test_get_default_environment_when_embedded(monkeypatch, virtualenv):
|
||||||
|
# When using Python embedded, sometimes the executable is not a Python
|
||||||
|
# executable.
|
||||||
|
executable_name = 'RANDOM_EXE'
|
||||||
|
monkeypatch.setattr(sys, 'executable', executable_name)
|
||||||
|
monkeypatch.setenv('VIRTUAL_ENV', virtualenv)
|
||||||
|
env = get_default_environment()
|
||||||
|
assert env.executable != executable_name
|
||||||
|
|
||||||
|
|
||||||
def test_changing_venv(venv_path, monkeypatch):
|
def test_changing_venv(venv_path, monkeypatch):
|
||||||
monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', venv_path)
|
monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', venv_path)
|
||||||
get_cached_default_environment()
|
get_cached_default_environment()
|
||||||
|
|||||||
@@ -142,6 +142,16 @@ def test_docstring_keyword(Script):
|
|||||||
assert 'assert' in completions[0].docstring()
|
assert 'assert' in completions[0].docstring()
|
||||||
|
|
||||||
|
|
||||||
|
def test_docstring_params_formatting(Script):
|
||||||
|
defs = Script("""
|
||||||
|
def func(param1,
|
||||||
|
param2,
|
||||||
|
param3):
|
||||||
|
pass
|
||||||
|
func""").goto_definitions()
|
||||||
|
assert defs[0].docstring() == 'func(param1, param2, param3)'
|
||||||
|
|
||||||
|
|
||||||
# ---- Numpy Style Tests ---
|
# ---- Numpy Style Tests ---
|
||||||
|
|
||||||
@pytest.mark.skipif(numpydoc_unavailable,
|
@pytest.mark.skipif(numpydoc_unavailable,
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ def test_import_not_in_sys_path(Script):
|
|||||||
("from flask.ext.", "bar"),
|
("from flask.ext.", "bar"),
|
||||||
("from flask.ext.", "baz"),
|
("from flask.ext.", "baz"),
|
||||||
("from flask.ext.", "moo"),
|
("from flask.ext.", "moo"),
|
||||||
pytest.mark.xfail(("import flask.ext.foo; flask.ext.foo.", "Foo")),
|
pytest.param("import flask.ext.foo; flask.ext.foo.", "Foo", marks=pytest.mark.xfail),
|
||||||
pytest.mark.xfail(("import flask.ext.bar; flask.ext.bar.", "Foo")),
|
pytest.param("import flask.ext.bar; flask.ext.bar.", "Foo", marks=pytest.mark.xfail),
|
||||||
pytest.mark.xfail(("import flask.ext.baz; flask.ext.baz.", "Foo")),
|
pytest.param("import flask.ext.baz; flask.ext.baz.", "Foo", marks=pytest.mark.xfail),
|
||||||
pytest.mark.xfail(("import flask.ext.moo; flask.ext.moo.", "Foo")),
|
pytest.param("import flask.ext.moo; flask.ext.moo.", "Foo", marks=pytest.mark.xfail),
|
||||||
])
|
])
|
||||||
def test_flask_ext(Script, code, name):
|
def test_flask_ext(Script, code, name):
|
||||||
"""flask.ext.foo is really imported from flaskext.foo or flask_foo.
|
"""flask.ext.foo is really imported from flaskext.foo or flask_foo.
|
||||||
|
|||||||
@@ -85,4 +85,4 @@ def test_get_call_signature(code, call_signature):
|
|||||||
node = node.children[0]
|
node = node.children[0]
|
||||||
assert parser_utils.get_call_signature(node) == call_signature
|
assert parser_utils.get_call_signature(node) == call_signature
|
||||||
|
|
||||||
assert parser_utils.get_doc_with_call_signature(node) == (call_signature + '\n\n')
|
assert parser_utils.get_doc_with_call_signature(node) == call_signature
|
||||||
|
|||||||
Reference in New Issue
Block a user