diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bdc503a2..f74658f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,11 +3,19 @@ Changelog --------- -0.13.0 () +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. - Remove Python 3.3 support. Python 3.3 support has been dropped by the Python foundation. +- Default environments are now using the same Python version as the Python + process. In 0.12.x, we used to load the latest Python version on the system. - Added ``include_builtins`` as a parameter to usages. - ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that changes the previous behavior slightly. diff --git a/jedi/__init__.py b/jedi/__init__.py index 84ec1782..a90f106b 100644 --- a/jedi/__init__.py +++ b/jedi/__init__.py @@ -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. """ -__version__ = '0.12.1' +__version__ = '0.13.1' from jedi.api import Script, Interpreter, set_debug_function, \ preload_module, names diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 26f388e5..06721810 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -179,6 +179,24 @@ class Script(object): self._pos, self.call_signatures ) completions = completion.completions() + + def iter_import_completions(): + for c in completions: + tree_name = c._name.tree_name + if tree_name is None: + continue + 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 + # might potentially be resolved. This is the case for tensorflow + # and has been fixed for it. This is obviously temporary until we + # have a better solution. + self._evaluator.infer_enabled = False + debug.speed('completions end') return completions diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 38c546b9..2bf6f68a 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -184,16 +184,21 @@ def get_default_environment(): if virtual_env is not None: return virtual_env - for environment in find_system_environments(): - return environment - - # If no Python Environment is found, use the environment we're already + # If no VirtualEnv is found, use the environment we're already # using. return SameEnvironment() -@time_cache(seconds=10 * 60) # 10 Minutes def get_cached_default_environment(): + environment = _get_cached_default_environment() + if environment.path != os.environ.get('VIRTUAL_ENV'): + _get_cached_default_environment.clear_cache() + return _get_cached_default_environment() + return environment + + +@time_cache(seconds=10 * 60) # 10 Minutes +def _get_cached_default_environment(): return get_default_environment() diff --git a/jedi/api/helpers.py b/jedi/api/helpers.py index 9e421dde..2f7af1b1 100644 --- a/jedi/api/helpers.py +++ b/jedi/api/helpers.py @@ -105,14 +105,17 @@ def get_stack_at_position(grammar, code_lines, module_node, pos): # TODO This is for now not an official parso API that exists purely # for Jedi. tokens = grammar._tokenize(code) - for token_ in tokens: - if token_.string == safeword: + for token in tokens: + if token.string == safeword: raise EndMarkerReached() - elif token_.prefix.endswith(safeword): + elif token.prefix.endswith(safeword): # This happens with comments. raise EndMarkerReached() + elif token.string.endswith(safeword): + yield token # Probably an f-string literal that was not finished. + raise EndMarkerReached() else: - yield token_ + yield token # The code might be indedented, just remove it. code = dedent(_get_code_for_stack(code_lines, module_node, pos)) diff --git a/jedi/api/replstartup.py b/jedi/api/replstartup.py index 4c44a626..3ac84708 100644 --- a/jedi/api/replstartup.py +++ b/jedi/api/replstartup.py @@ -1,6 +1,8 @@ """ To use Jedi completion in Python interpreter, add the following in your shell -setup (e.g., ``.bashrc``):: +setup (e.g., ``.bashrc``). This works only on Linux/Mac, because readline is +not available on Windows. If you still want Jedi autocompletion in your REPL, +just use IPython instead:: export PYTHONSTARTUP="$(python -m jedi repl)" diff --git a/jedi/cache.py b/jedi/cache.py index 6c0c2a83..93e2bd7f 100644 --- a/jedi/cache.py +++ b/jedi/cache.py @@ -126,6 +126,7 @@ def time_cache(seconds): wrapper.clear_cache = lambda: cache.clear() return wrapper + return decorator diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 827fbddf..ccd65cae 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -118,6 +118,9 @@ class Evaluator(object): self.is_analysis = False self.project = project self.access_cache = {} + # This setting is only temporary to limit the work we have to do with + # tensorflow and others. + self.infer_enabled = True self.reset_recursion_limitations() self.allow_different_encoding = True @@ -170,6 +173,9 @@ class Evaluator(object): return self.project._get_sys_path(self, environment=self.environment) def eval_element(self, context, element): + if not self.infer_enabled: + return NO_CONTEXTS + if isinstance(context, CompForContext): return eval_node(context, element) diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 42c7ed76..a4904c40 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -54,8 +54,12 @@ def get_string_context_set(evaluator): return execute_evaluated(builtin_from_name(evaluator, u'str')) -def load_module(evaluator, **kwargs): - access_path = evaluator.compiled_subprocess.load_module(**kwargs) +def load_module(evaluator, dotted_name, **kwargs): + # Temporary, some tensorflow builtins cannot be loaded, so it's tried again + # and again and it's really slow. + if dotted_name.startswith('tensorflow.'): + return None + access_path = evaluator.compiled_subprocess.load_module(dotted_name=dotted_name, **kwargs) if access_path is None: return None return create_from_access_path(evaluator, access_path) diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 25dac530..245f7edc 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -276,7 +276,7 @@ class Importer(object): return sys_path_mod def follow(self): - if not self.import_path: + if not self.import_path or not self._evaluator.infer_enabled: return NO_CONTEXTS import_names = tuple( diff --git a/test/completion/basic.py b/test/completion/basic.py index 0cb12e92..b72cc3d6 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -154,6 +154,9 @@ def global_define(): #? int() global_var_in_func +#? ['global_var_in_func'] +global_var_in_f + def funct1(): # From issue #610 @@ -175,6 +178,7 @@ def init_global_var_predefined(): #? int() None global_var_predefined + # ----------------- # within docstrs # ----------------- diff --git a/test/completion/fstring.py b/test/completion/fstring.py index 818ee27f..97cc1cc0 100644 --- a/test/completion/fstring.py +++ b/test/completion/fstring.py @@ -28,3 +28,7 @@ Fr'''sasdf''' + '' #? ['upper'] f'xyz'.uppe + + +#? 3 [] +f'f' diff --git a/test/test_api/test_environment.py b/test/test_api/test_environment.py index 98230e57..6e2cf36b 100644 --- a/test/test_api/test_environment.py +++ b/test/test_api/test_environment.py @@ -7,7 +7,7 @@ import jedi from jedi._compatibility import py_version from jedi.api.environment import get_default_environment, find_virtualenvs, \ InvalidPythonEnvironment, find_system_environments, \ - get_system_environment, create_environment + get_system_environment, create_environment, get_cached_default_environment def test_sys_path(): @@ -129,3 +129,10 @@ def test_get_default_environment_from_env_does_not_use_safe(tmpdir, monkeypatch) monkeypatch.setenv('VIRTUAL_ENV', fake_python) env = get_default_environment() assert env.path == 'fake' + + +def test_changing_venv(venv_path, monkeypatch): + monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', venv_path) + get_cached_default_environment() + monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', sys.executable) + assert get_cached_default_environment().executable == sys.executable