From 4545d91929f2cdea2eb8d555bde7377f8c61a4af Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 21 Aug 2018 01:28:13 +0200 Subject: [PATCH 01/10] Ignore some errors that are happening when the Python process ends and its subprocesses are cleaned up --- jedi/evaluate/compiled/subprocess/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/jedi/evaluate/compiled/subprocess/__init__.py b/jedi/evaluate/compiled/subprocess/__init__.py index 420e048f..cf21b51b 100644 --- a/jedi/evaluate/compiled/subprocess/__init__.py +++ b/jedi/evaluate/compiled/subprocess/__init__.py @@ -203,13 +203,14 @@ class CompiledSubprocess(object): def _kill(self): self.is_crashed = True - if subprocess.signal is None: - # If the Python process is terminating, sometimes it will remove - # the signal module before a lot of other things, so check for it - # and don't do anything, because the process is killed anyways. - return - self._process.kill() - self._process.wait() + try: + self._process.kill() + self._process.wait() + except (AttributeError, TypeError): + # If the Python process is terminating, it will remove some modules + # earlier than others and in general it's unclear how to deal with + # that so we just ignore the exceptions here. + pass def __del__(self): if not self.is_crashed: From 6a2a2a9fa1d4fbbebf413a9f34da5320a8ad0c7f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 30 Sep 2018 13:26:54 +0200 Subject: [PATCH 02/10] Fix an issue with f-strings, fixes #1224 --- jedi/api/helpers.py | 11 +++++++---- test/completion/fstring.py | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/jedi/api/helpers.py b/jedi/api/helpers.py index fda8d1c2..2489cd9b 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/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' From e1f9624bd43ed600e8e552a1bdc78b966097599d Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 30 Sep 2018 13:36:05 +0200 Subject: [PATCH 03/10] Document that using the REPL autocompletion is only available on Linux/Mac, fixes #1184 --- jedi/api/replstartup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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)" From f9cbc65f2d114d6252a1b42f9deb958d54ab7b95 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 30 Sep 2018 14:07:37 +0200 Subject: [PATCH 04/10] Return SameEnvironment as a default, fixes #1226, #1196 --- jedi/api/environment.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 38c546b9..7aa16dc8 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -184,10 +184,7 @@ 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() From 862f61182941a451c8e158091a328d63cb4ef43b Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 30 Sep 2018 19:06:40 +0200 Subject: [PATCH 05/10] If the VIRTUAL_ENV variable changes, need to reload the default environment, fixes #1201, #1200 --- jedi/api/environment.py | 10 +++++++++- jedi/cache.py | 1 + test/test_api/test_environment.py | 9 ++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 7aa16dc8..2bf6f68a 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -189,8 +189,16 @@ def get_default_environment(): 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/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/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 From c24eb4bd677baf5f3edeee28bee1a626d984b855 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 2 Oct 2018 00:51:51 +0200 Subject: [PATCH 06/10] Fix tensorflow issues with a few hacks (temporary), fixes #1195 --- jedi/api/__init__.py | 13 +++++++++++++ jedi/evaluate/__init__.py | 6 ++++++ jedi/evaluate/compiled/__init__.py | 8 ++++++-- jedi/evaluate/imports.py | 3 +-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index afceea84..c652b368 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -177,6 +177,19 @@ class Script(object): self._pos, self.call_signatures ) completions = completion.completions() + + import_completions_count = len([ + c for c in completions + if not c._name.tree_name + or c._name.tree_name.get_definition().type in ('import_name', 'import_from') + ]) + if import_completions_count > 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 = True + debug.speed('completions end') return completions diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index d316785f..48339439 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -105,6 +105,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 @@ -123,6 +126,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 357d26cc..757aec52 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -32,8 +32,12 @@ def get_string_context_set(evaluator): return builtin_from_name(evaluator, u'str').execute_evaluated() -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 99791dc9..3b1df31a 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -21,7 +21,6 @@ from jedi._compatibility import (FileNotFoundError, ImplicitNSInfo, force_unicode, unicode) from jedi import debug from jedi import settings -from jedi.common.utils import traverse_parents from jedi.parser_utils import get_cached_code_lines from jedi.evaluate import sys_path from jedi.evaluate import helpers @@ -279,7 +278,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 return self._do_import(self.import_path, self.sys_path_with_modifications()) From 96b57f46cbfab28a718847a898525af622aa5f7f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 2 Oct 2018 01:14:28 +0200 Subject: [PATCH 07/10] Release notes for 0.13.0 --- CHANGELOG.rst | 5 ++++- jedi/__init__.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bdc503a2..76536946 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,11 +3,14 @@ Changelog --------- -0.13.0 () +0.13.0 (2018-01-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..ea8ae128 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.0' from jedi.api import Script, Interpreter, set_debug_function, \ preload_module, names From 075577d50c09e2702f9542b64df96c828d468395 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 2 Oct 2018 15:25:31 +0200 Subject: [PATCH 08/10] The changelog date was wrong --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 76536946..0b36b998 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,7 +3,7 @@ Changelog --------- -0.13.0 (2018-01-02) +0.13.0 (2018-10-02) +++++++++++++++++++ - A small release. Some bug fixes. From 23b3327b1daf6fa5260cf1184e5b8d90645323a3 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 2 Oct 2018 15:28:28 +0200 Subject: [PATCH 09/10] Fixed completions of global vars and tensorflow slowness, fixes #1228, #1116 --- jedi/api/__init__.py | 19 ++++++++++++------- test/completion/basic.py | 4 ++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index c652b368..9e568cf8 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -178,17 +178,22 @@ class Script(object): ) completions = completion.completions() - import_completions_count = len([ - c for c in completions - if not c._name.tree_name - or c._name.tree_name.get_definition().type in ('import_name', 'import_from') - ]) - if import_completions_count > 10: + 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 = True + self._evaluator.infer_enabled = False debug.speed('completions end') return completions diff --git a/test/completion/basic.py b/test/completion/basic.py index ae2e3128..c51197e3 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 # ----------------- From bd1010bbd2693f189ff780eb21fc4294071cb280 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 2 Oct 2018 19:05:10 +0200 Subject: [PATCH 10/10] Create a new 0.13.1 release --- CHANGELOG.rst | 5 +++++ jedi/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0b36b998..f74658f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,11 @@ Changelog --------- +0.13.1 (2018-10-02) ++++++++++++++++++++ + +- Bugfixes, because tensorflow completions were still slow. + 0.13.0 (2018-10-02) +++++++++++++++++++ diff --git a/jedi/__init__.py b/jedi/__init__.py index ea8ae128..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.13.0' +__version__ = '0.13.1' from jedi.api import Script, Interpreter, set_debug_function, \ preload_module, names