From 1cf5b194caaaef5c61bf83b8ba76d0d9ca29beb2 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 13 Sep 2018 07:05:20 +0200 Subject: [PATCH 1/8] jedi.api.environment._SUPPORTED_PYTHONS: add 3.7 The grammar is available in parso already, and it works in general. --- jedi/api/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 77b0a4be..46a71e7e 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -17,7 +17,7 @@ import parso _VersionInfo = namedtuple('VersionInfo', 'major minor micro') -_SUPPORTED_PYTHONS = ['3.6', '3.5', '3.4', '3.3', '2.7'] +_SUPPORTED_PYTHONS = ['3.7', '3.6', '3.5', '3.4', '3.3', '2.7'] _SAFE_PATHS = ['/usr/bin', '/usr/local/bin'] _CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor) From fc9a55b042b990a2965e573d80b0babfb76d64bd Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Sep 2018 05:44:19 +0200 Subject: [PATCH 2/8] jedi/api/environment.py: minor flake8 fix --- jedi/api/environment.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 46a71e7e..793c7e98 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -318,10 +318,10 @@ def _get_executables_from_windows_registry(version): # TODO: support Python Anaconda. sub_keys = [ - r'SOFTWARE\Python\PythonCore\{version}\InstallPath', - r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath', - r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath', - r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath' + r'SOFTWARE\Python\PythonCore\{version}\InstallPath', + r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath', + r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath', + r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath' ] for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]: for sub_key in sub_keys: From cdb760487b273df5657d5b0669fa755cfca20a0e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Sep 2018 05:35:25 +0200 Subject: [PATCH 3/8] tests: venv_path: use session scope --- test/conftest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 0a5598e3..7291600a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -126,11 +126,12 @@ class StaticAnalysisCase(object): return "<%s: %s>" % (self.__class__.__name__, os.path.basename(self._path)) -@pytest.fixture() -def venv_path(tmpdir, environment): +@pytest.fixture(scope='session') +def venv_path(tmpdir_factory, environment): if environment.version_info.major < 3: pytest.skip("python -m venv does not exist in Python 2") + tmpdir = tmpdir_factory.mktemp('venv_path') dirname = os.path.join(tmpdir.dirname, 'venv') # We cannot use the Python from tox because tox creates virtualenvs and From 56bd7951005778a7c5dd299fdadaa2c372165fd4 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 13 Aug 2018 17:44:19 +0200 Subject: [PATCH 4/8] _get_virtual_env_from_var: use safe=False Without this creating an env from VIRTUAL_ENV will always silently fail if it is not the same/current environment. --- jedi/api/environment.py | 7 ++++++- test/test_api/test_environment.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 793c7e98..38c546b9 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -147,13 +147,18 @@ class InterpreterEnvironment(_BaseEnvironment): def _get_virtual_env_from_var(): + """Get virtualenv environment from VIRTUAL_ENV environment variable. + + It uses `safe=False` with ``create_environment``, because the environment + variable is considered to be safe / controlled by the user solely. + """ var = os.environ.get('VIRTUAL_ENV') if var is not None: if var == sys.prefix: return SameEnvironment() try: - return create_environment(var) + return create_environment(var, safe=False) except InvalidPythonEnvironment: pass diff --git a/test/test_api/test_environment.py b/test/test_api/test_environment.py index a11e4857..98230e57 100644 --- a/test/test_api/test_environment.py +++ b/test/test_api/test_environment.py @@ -110,3 +110,22 @@ def test_create_environment_venv_path(venv_path): def test_create_environment_executable(): environment = create_environment(sys.executable) assert environment.executable == sys.executable + + +def test_get_default_environment_from_env_does_not_use_safe(tmpdir, monkeypatch): + fake_python = os.path.join(str(tmpdir), 'fake_python') + with open(fake_python, 'w') as f: + f.write('') + + def _get_subprocess(self): + if self._start_executable != fake_python: + raise RuntimeError('Should not get called!') + self.executable = fake_python + self.path = 'fake' + + monkeypatch.setattr('jedi.api.environment.Environment._get_subprocess', + _get_subprocess) + + monkeypatch.setenv('VIRTUAL_ENV', fake_python) + env = get_default_environment() + assert env.path == 'fake' From afb2755c272d1a8e9357968acf93ece8ea7e8ce8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Sep 2018 05:36:29 +0200 Subject: [PATCH 5/8] Add extras_require=testing --- setup.py | 10 +++++++++- tox.ini | 21 +++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/setup.py b/setup.py index ebcd4e55..d964d541 100755 --- a/setup.py +++ b/setup.py @@ -31,7 +31,15 @@ setup(name='jedi', packages=find_packages(exclude=['test', 'test.*']), python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', install_requires=install_requires, - extras_require={'dev': ['docopt']}, + extras_require={ + 'testing': [ + 'pytest>=2.3.5', + # docopt for sith doctests + 'docopt', + # coloroma for colored debug output + 'colorama', + ], + }, package_data={'jedi': ['evaluate/compiled/fake/*.pym']}, platforms=['any'], classifiers=[ diff --git a/tox.ini b/tox.ini index f450b735..92d61f87 100644 --- a/tox.ini +++ b/tox.ini @@ -1,16 +1,10 @@ [tox] envlist = py27, py34, py35, py36 [testenv] -deps = - pytest>=2.3.5 - pytest-cache -# docopt for sith doctests - docopt -# coloroma for colored debug output - colorama +extras = testing # Overwrite the parso version (only used sometimes). -# git+https://github.com/davidhalter/parso.git - -rrequirements.txt +# deps = +# git+https://github.com/davidhalter/parso.git passenv = JEDI_TEST_ENVIRONMENT setenv = # https://github.com/tomchristie/django-rest-framework/issues/1957 @@ -24,34 +18,29 @@ setenv = env36: JEDI_TEST_ENVIRONMENT=36 env37: JEDI_TEST_ENVIRONMENT=37 commands = - py.test {posargs:jedi test} + pytest {posargs:jedi test} [testenv:py27] deps = # for testing the typing module typing # numpydoc for typing scipy stack numpydoc - {[testenv]deps} [testenv:py34] deps = typing numpydoc - {[testenv]deps} [testenv:py35] deps = numpydoc - {[testenv]deps} [testenv:py36] deps = numpydoc - {[testenv]deps} [testenv:cov] deps = coverage numpydoc - {[testenv]deps} commands = - coverage run --source jedi -m py.test + coverage run --source jedi -m pytest coverage report [testenv:sith] commands = From b9127147e46997b79bdb99562b5fccbd97bbb49a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Sep 2018 21:45:34 +0200 Subject: [PATCH 6/8] Recognize {**d} as a dict instead of set --- jedi/evaluate/syntax_tree.py | 3 ++- test/completion/types.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/jedi/evaluate/syntax_tree.py b/jedi/evaluate/syntax_tree.py index dc7ea0a7..720ea349 100644 --- a/jedi/evaluate/syntax_tree.py +++ b/jedi/evaluate/syntax_tree.py @@ -255,7 +255,8 @@ def eval_atom(context, atom): array_node_c = array_node.children except AttributeError: array_node_c = [] - if c[0] == '{' and (array_node == '}' or ':' in array_node_c): + if c[0] == '{' and (array_node == '}' or ':' in array_node_c or + '**' in array_node_c): context = iterable.DictLiteralContext(context.evaluator, context, atom) else: context = iterable.SequenceLiteralContext(context.evaluator, context, atom) diff --git a/test/completion/types.py b/test/completion/types.py index 19621b29..a6aca08b 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -131,3 +131,11 @@ set_t2 = set() #? ['clear', 'copy'] set_t2.c + +# ----------------- +# pep 448 unpacking generalizations +# ----------------- +# python >= 3.5 + +#? dict() +{**d} From 6bc79b493323e5e1eff03daa109fd4dc2d6f7682 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Sep 2018 22:18:17 +0200 Subject: [PATCH 7/8] Fixed crash (and now recognises correctly) {**d, "b": "b"}["b"] --- jedi/evaluate/context/iterable.py | 18 ++++++++++++------ test/completion/types.py | 10 ++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/jedi/evaluate/context/iterable.py b/jedi/evaluate/context/iterable.py index 31011e36..45b3f435 100644 --- a/jedi/evaluate/context/iterable.py +++ b/jedi/evaluate/context/iterable.py @@ -351,13 +351,19 @@ class SequenceLiteralContext(Sequence): kv = [] iterator = iter(array_node.children) for key in iterator: - op = next(iterator, None) - if op is None or op == ',': - kv.append(key) # A set. - else: - assert op == ':' # A dict. - kv.append((key, next(iterator))) + if key == "**": + # dict with pep 448 double-star unpacking + # for now ignoring the values imported by ** + next(iterator) next(iterator, None) # Possible comma. + else: + op = next(iterator, None) + if op is None or op == ',': + kv.append(key) # A set. + else: + assert op == ':' # A dict. + kv.append((key, next(iterator))) + next(iterator, None) # Possible comma. return kv else: return [array_node] diff --git a/test/completion/types.py b/test/completion/types.py index a6aca08b..a01d2425 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -137,5 +137,15 @@ set_t2.c # ----------------- # python >= 3.5 +d = {'a': 3} + #? dict() {**d} + +#? str() +{**d, "b": "b"}["b"] + +# Should resolve to int() but jedi is not smart enough yet +# Here to make sure it doesn't result in crash though +#? str() +{**d, "b": "b"}["a"] From a2b984ce24f6ac730d67d56135680429f77b96d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Sep 2018 23:29:13 +0200 Subject: [PATCH 8/8] also remove crashes with pep 448 unpacking of lists and sets --- jedi/evaluate/context/iterable.py | 18 +++++++++++++++--- test/completion/types.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/jedi/evaluate/context/iterable.py b/jedi/evaluate/context/iterable.py index 45b3f435..c69498e7 100644 --- a/jedi/evaluate/context/iterable.py +++ b/jedi/evaluate/context/iterable.py @@ -346,7 +346,9 @@ class SequenceLiteralContext(Sequence): return [] # Direct closing bracket, doesn't contain items. if array_node.type == 'testlist_comp': - return array_node.children[::2] + # filter out (for now) pep 448 single-star unpacking + return [value for value in array_node.children[::2] + if value.type != "star_expr"] elif array_node.type == 'dictorsetmaker': kv = [] iterator = iter(array_node.children) @@ -359,14 +361,24 @@ class SequenceLiteralContext(Sequence): else: op = next(iterator, None) if op is None or op == ',': - kv.append(key) # A set. + if key.type == "star_expr": + # pep 448 single-star unpacking + # for now ignoring values imported by * + pass + else: + kv.append(key) # A set. else: assert op == ':' # A dict. kv.append((key, next(iterator))) next(iterator, None) # Possible comma. return kv else: - return [array_node] + if array_node.type == "star_expr": + # pep 448 single-star unpacking + # for now ignoring values imported by * + return [] + else: + return [array_node] def exact_key_items(self): """ diff --git a/test/completion/types.py b/test/completion/types.py index a01d2425..f0c4c838 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -147,5 +147,30 @@ d = {'a': 3} # Should resolve to int() but jedi is not smart enough yet # Here to make sure it doesn't result in crash though -#? str() -{**d, "b": "b"}["a"] +#? +{**d}["a"] + +s = {1, 2, 3} + +#? set() +{*s} + +#? set() +{*s, 4, *s} + +s = {1, 2, 3} +# Should resolve to int() but jedi is not smart enough yet +# Here to make sure it doesn't result in crash though +#? +{*s}.pop() + +#? int() +{*s, 4}.pop() + +# Should resolve to int() but jedi is not smart enough yet +# Here to make sure it doesn't result in crash though +#? +[*s][0] + +#? int() +[*s, 4][0]