From 0334918d73da24da2a4aea19a17f6e968061e463 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:18:19 +0200 Subject: [PATCH 01/22] Ignore IDE metadata --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 369f71c6..ec2920f1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .tox .coveralls.yml .coverage +.idea /build/ /docs/_build/ /dist/ From 7c31ea9042c5f290c2195380fc3a38358ce0bd2c Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 5 Jan 2018 10:17:38 +0200 Subject: [PATCH 02/22] Drop support for EOL Python 2.6 --- .travis.yml | 1 - README.rst | 2 +- docs/docs/features.rst | 12 ++++++------ jedi/_compatibility.py | 19 ++----------------- jedi/evaluate/stdlib.py | 6 ------ setup.py | 1 - test/completion/arrays.py | 2 -- test/completion/basic.py | 2 -- test/completion/comprehensions.py | 1 - test/completion/dynamic_arrays.py | 2 -- test/completion/pep0484_comments.py | 4 ---- test/completion/pep0484_typing.py | 2 -- test/completion/types.py | 2 -- test/completion/usages.py | 2 -- test/test_evaluate/test_imports.py | 5 +---- test/test_evaluate/test_literals.py | 2 +- test/test_evaluate/test_pyc.py | 15 --------------- test/test_evaluate/test_stdlib.py | 11 ++--------- tox.ini | 4 ---- 19 files changed, 13 insertions(+), 82 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7916832e..e791c10a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python sudo: false python: - - 2.6 - 2.7 - 3.3 - 3.4 diff --git a/README.rst b/README.rst index d698bc7c..f9f16460 100644 --- a/README.rst +++ b/README.rst @@ -96,7 +96,7 @@ understands, see: `Features `_. A list of caveats can be found on the same page. -You can run Jedi on cPython 2.6, 2.7, 3.3, 3.4 or 3.5 but it should also +You can run Jedi on CPython 2.7 or 3.3+ but it should also understand/parse code older than those versions. Tips on how to use Jedi efficiently can be found `here diff --git a/docs/docs/features.rst b/docs/docs/features.rst index ad4e900c..c8f478ba 100644 --- a/docs/docs/features.rst +++ b/docs/docs/features.rst @@ -20,7 +20,7 @@ make it work. General Features ---------------- -- python 2.6+ and 3.3+ support +- Python 2.7 and 3.3+ support - ignores syntax errors and wrong indentation - can deal with complex module / function / class structures - virtualenv support @@ -64,7 +64,7 @@ Not yet implemented: - manipulations of instances outside the instance variables without using methods -- implicit namespace packages (Python 3.3+, `PEP 420 `_) +- implicit namespace packages (Python 3.4+, `PEP 420 `_) Will probably never be implemented: @@ -88,7 +88,7 @@ etc. **Security** Security is an important issue for |jedi|. Therefore no Python code is -executed. As long as you write pure python, everything is evaluated +executed. As long as you write pure Python, everything is evaluated statically. But: If you use builtin modules (``c_builtin``) there is no other option than to execute those modules. However: Execute isn't that critical (as e.g. in pythoncomplete, which used to execute *every* import!), because it @@ -117,7 +117,7 @@ one of the following docstring/annotation syntax styles: https://www.python.org/dev/peps/pep-0484/ -function annotations (python 3 only; python 2 function annotations with +function annotations (Python 3 only; Python 2 function annotations with comments in planned but not yet implemented) :: @@ -129,7 +129,7 @@ comments in planned but not yet implemented) node.| # complete here -assignment, for-loop and with-statement type hints (all python versions). +assignment, for-loop and with-statement type hints (all Python versions). Note that the type hints must be on the same line as the statement :: @@ -142,7 +142,7 @@ Note that the type hints must be on the same line as the statement print(f + 3) Most of the features in PEP-0484 are supported including the typing module -(for python < 3.5 you have to do ``pip install typing`` to use these), +(for Python < 3.5 you have to do ``pip install typing`` to use these), and forward references. Things that are missing (and this is not an exhaustive list; some of these diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index 52a20fe2..7ee82160 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -1,5 +1,5 @@ """ -To ensure compatibility from Python ``2.6`` - ``3.3``, a module has been +To ensure compatibility from Python ``2.7`` - ``3.x``, a module has been created. Clearly there is huge need to use conforming syntax. """ import sys @@ -13,13 +13,10 @@ try: except ImportError: pass -# Cannot use sys.version.major and minor names, because in Python 2.6 it's not -# a namedtuple. is_py3 = sys.version_info[0] >= 3 is_py33 = is_py3 and sys.version_info[1] >= 3 is_py34 = is_py3 and sys.version_info[1] >= 4 is_py35 = is_py3 and sys.version_info[1] >= 5 -is_py26 = not is_py3 and sys.version_info[1] < 7 py_version = int(str(sys.version_info[0]) + str(sys.version_info[1])) @@ -127,14 +124,7 @@ def find_module_pre_py33(string, path=None, fullname=None): if loader: is_package = loader.is_package(string) is_archive = hasattr(loader, 'archive') - try: - module_path = loader.get_filename(string) - except AttributeError: - # fallback for py26 - try: - module_path = loader._get_filename(string) - except AttributeError: - continue + module_path = loader.get_filename(string) if is_package: module_path = os.path.dirname(module_path) if is_archive: @@ -242,11 +232,6 @@ import ast def literal_eval(string): - # py3.0, py3.1 and py32 don't support unicode literals. Support those, I - # don't want to write two versions of the tokenizer. - if is_py3 and sys.version_info.minor < 3: - if re.match('[uU][\'"]', string): - string = string[1:] return ast.literal_eval(string) diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index 259d6927..bcd8b622 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -256,13 +256,7 @@ def collections_namedtuple(evaluator, obj, arguments): This has to be done by processing the namedtuple class template and evaluating the result. - .. note:: |jedi| only supports namedtuples on Python >2.6. - """ - # Namedtuples are not supported on Python 2.6 - if not hasattr(collections, '_class_template'): - return NO_CONTEXTS - # Process arguments # TODO here we only use one of the types, we should use all. name = list(_follow_param(evaluator, arguments, 0))[0].obj diff --git a/setup.py b/setup.py index 3f3b7e54..81d69ba2 100755 --- a/setup.py +++ b/setup.py @@ -44,7 +44,6 @@ setup(name='jedi', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', diff --git a/test/completion/arrays.py b/test/completion/arrays.py index 8be1cece..e44a0671 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -403,8 +403,6 @@ def test_func(): x -# python >= 2.7 -# Set literals are not valid in 2.6. #? int() tuple({1})[0] diff --git a/test/completion/basic.py b/test/completion/basic.py index 34e88100..d79a15ed 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -286,8 +286,6 @@ with open('') as f: #? str() line -# Nested with statements don't exist in Python 2.6. -# python >= 2.7 with open('') as f1, open('') as f2: #? ['closed'] f1.closed diff --git a/test/completion/comprehensions.py b/test/completion/comprehensions.py index 2894cf33..402ef753 100644 --- a/test/completion/comprehensions.py +++ b/test/completion/comprehensions.py @@ -210,6 +210,5 @@ d[2] next(iter({a for a in range(10)})) -# with a set literal (also doesn't work in 2.6). #? int() [a for a in {1, 2, 3}][0] diff --git a/test/completion/dynamic_arrays.py b/test/completion/dynamic_arrays.py index 9be530fa..5cb52fc6 100644 --- a/test/completion/dynamic_arrays.py +++ b/test/completion/dynamic_arrays.py @@ -288,8 +288,6 @@ third()[0] # ----------------- # set.add # ----------------- -# Set literals are not valid in 2.6. -# python >= 2.7 st = {1.0} for a in [1,2]: st.add(a) diff --git a/test/completion/pep0484_comments.py b/test/completion/pep0484_comments.py index 7d5f7c2e..7707fcc3 100644 --- a/test/completion/pep0484_comments.py +++ b/test/completion/pep0484_comments.py @@ -47,10 +47,6 @@ b class Employee: pass -# The typing library is not installable for Python 2.6, therefore ignore the -# following tests. -# python >= 2.7 - from typing import List x = [] # type: List[Employee] #? Employee() diff --git a/test/completion/pep0484_typing.py b/test/completion/pep0484_typing.py index 75c1c0b0..7bee1e64 100644 --- a/test/completion/pep0484_typing.py +++ b/test/completion/pep0484_typing.py @@ -3,8 +3,6 @@ Test the typing library, with docstrings. This is needed since annotations are not supported in python 2.7 else then annotating by comment (and this is still TODO at 2016-01-23) """ -# There's no Python 2.6 typing module. -# python >= 2.7 import typing class B: pass diff --git a/test/completion/types.py b/test/completion/types.py index 2ef01f9a..8fd2c594 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -116,8 +116,6 @@ tup4.index # ----------------- # set # ----------------- -# Set literals are not valid in 2.6. -# python >= 2.7 set_t = {1,2} #? ['clear', 'copy'] diff --git a/test/completion/usages.py b/test/completion/usages.py index d7231b15..be27ae51 100644 --- a/test/completion/usages.py +++ b/test/completion/usages.py @@ -296,8 +296,6 @@ x = 32 [x for x in something] x = 3 -# Not supported syntax in Python 2.6. -# python >= 2.7 #< 1 (0,1), (0,10) {x:1 for x in something} #< 10 (0,1), (0,10) diff --git a/test/test_evaluate/test_imports.py b/test/test_evaluate/test_imports.py index a41d4f0d..307b811c 100644 --- a/test/test_evaluate/test_imports.py +++ b/test/test_evaluate/test_imports.py @@ -13,7 +13,6 @@ from jedi._compatibility import find_module_py33, find_module from ..helpers import cwd_at from jedi import Script -from jedi._compatibility import is_py26 @pytest.mark.skipif('sys.version_info < (3,3)') @@ -47,7 +46,6 @@ def test_find_module_package_zipped(): assert len(jedi.Script('import pkg; pkg.mod', 1, 19).completions()) == 1 -@pytest.mark.skipif('sys.version_info < (2,7)') def test_find_module_not_package_zipped(): if 'zipped_imports/not_pkg.zip' not in sys.path: sys.path.append(os.path.join(os.path.dirname(__file__), @@ -160,8 +158,7 @@ def test_complete_on_empty_import(): wanted = set(['ImportError', 'import', 'ImportWarning']) assert set([c.name for c in Script("import").completions()]) == wanted - if not is_py26: # python 2.6 doesn't always come with a library `import*`. - assert len(Script("import import", path='').completions()) > 0 + assert len(Script("import import", path='').completions()) > 0 # 111 assert Script("from datetime import").completions()[0].name == 'import' diff --git a/test/test_evaluate/test_literals.py b/test/test_evaluate/test_literals.py index 403020ac..4f30d109 100644 --- a/test/test_evaluate/test_literals.py +++ b/test/test_evaluate/test_literals.py @@ -1,7 +1,7 @@ import pytest import jedi -from jedi._compatibility import py_version, unicode +from jedi._compatibility import py_version def _eval_literal(code): diff --git a/test/test_evaluate/test_pyc.py b/test/test_evaluate/test_pyc.py index c101da13..057e9417 100644 --- a/test/test_evaluate/test_pyc.py +++ b/test/test_evaluate/test_pyc.py @@ -45,20 +45,5 @@ def generate_pyc(): shutil.copy(os.path.join("dummy_package/__pycache__", f), dst) -# Python 2.6 does not necessarily come with `compileall.compile_file`. -@pytest.mark.skipif("sys.version_info > (2,6)") -@cwd_at('test/test_evaluate') -def test_pyc(): - """ - The list of completion must be greater than 2. - """ - try: - generate_pyc() - s = jedi.Script("from dummy_package import dummy; dummy.", path='blub.py') - assert len(s.completions()) >= 2 - finally: - shutil.rmtree("dummy_package") - - if __name__ == "__main__": test_pyc() diff --git a/test/test_evaluate/test_stdlib.py b/test/test_evaluate/test_stdlib.py index 7347d840..6b55224d 100644 --- a/test/test_evaluate/test_stdlib.py +++ b/test/test_evaluate/test_stdlib.py @@ -6,7 +6,6 @@ from textwrap import dedent import pytest from jedi import Script -from jedi._compatibility import is_py26 # The namedtuple is different for different Python2.7 versions. Some versions # are missing the attribute `_class_template`. @@ -25,10 +24,7 @@ def test_namedtuple_str(letter, expected): dave.%s""") % letter result = Script(source).completions() completions = set(r.name for r in result) - if is_py26: - assert completions == set() - else: - assert completions == set(expected) + assert completions == set(expected) def test_namedtuple_list(): @@ -39,10 +35,7 @@ def test_namedtuple_list(): garfield.l""") result = Script(source).completions() completions = set(r.name for r in result) - if is_py26: - assert completions == set() - else: - assert completions == set(['legs', 'length', 'large']) + assert completions == set(['legs', 'length', 'large']) def test_namedtuple_content(): diff --git a/tox.ini b/tox.ini index 7b0a537d..917ce3b9 100644 --- a/tox.ini +++ b/tox.ini @@ -15,10 +15,6 @@ setenv = PYTHONDONTWRITEBYTECODE=1 commands = py.test {posargs:jedi test} -[testenv:py26] -deps = - unittest2 - {[testenv]deps} [testenv:py27] deps = # for testing the typing module From 7821203d8ec95041ba2d9e2e04579fc03074de71 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:29:35 +0200 Subject: [PATCH 03/22] Use automatic formatters --- jedi/_compatibility.py | 4 ++-- jedi/evaluate/docstrings.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index 7ee82160..809f64f1 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -71,7 +71,7 @@ def find_module_py33(string, path=None, loader=None, fullname=None): raise ImportError("Originally " + repr(e)) if loader is None: - raise ImportError("Couldn't find a loader for {0}".format(string)) + raise ImportError("Couldn't find a loader for {}".format(string)) try: is_package = loader.is_package(string) @@ -135,7 +135,7 @@ def find_module_pre_py33(string, path=None, fullname=None): return (file, module_path, is_package) except ImportError: pass - raise ImportError("No module named {0}".format(string)) + raise ImportError("No module named {}".format(string)) find_module = find_module_py33 if is_py33 else find_module_pre_py33 diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index f9c11412..4bbb0a06 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -179,7 +179,7 @@ def _evaluate_for_statement_string(module_context, string): Need this docstring so that if the below part is not valid Python this is still a function. ''' - {0} + {} """)) if string is None: return [] From a7ac6474980bd349f01e1b3780dee1b651aab525 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:31:38 +0200 Subject: [PATCH 04/22] Remove redundant character escape --- jedi/evaluate/context/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/evaluate/context/module.py b/jedi/evaluate/context/module.py index 5ba92cdb..0e0a4552 100644 --- a/jedi/evaluate/context/module.py +++ b/jedi/evaluate/context/module.py @@ -131,7 +131,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, TreeContext)): def py__package__(self): if self._get_init_directory() is None: - return re.sub(r'\.?[^\.]+$', '', self.py__name__()) + return re.sub(r'\.?[^.]+$', '', self.py__name__()) else: return self.py__name__() From 8cf708d0d4584e9edee48461b9eba0983d7a3419 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:32:52 +0200 Subject: [PATCH 05/22] Remove redundant parentheses --- jedi/_compatibility.py | 2 +- jedi/api/classes.py | 2 +- jedi/evaluate/compiled/__init__.py | 2 +- jedi/evaluate/compiled/getattr_static.py | 4 +-- jedi/evaluate/compiled/mixed.py | 2 +- test/completion/arrays.py | 30 ++++++++--------- test/completion/async_.py | 2 +- test/completion/basic.py | 10 +++--- test/completion/classes.py | 32 +++++++++---------- test/completion/comprehensions.py | 2 +- test/completion/context.py | 4 +-- test/completion/decorators.py | 14 ++++---- test/completion/descriptors.py | 8 ++--- test/completion/docstring.py | 10 +++--- test/completion/dynamic_arrays.py | 8 ++--- test/completion/dynamic_params.py | 4 +-- test/completion/flow_analysis.py | 4 +-- test/completion/functions.py | 2 +- test/completion/generators.py | 2 +- test/completion/goto.py | 10 +++--- test/completion/import_tree/classes.py | 4 +-- test/completion/invalid.py | 2 +- test/completion/isinstance.py | 2 +- test/completion/lambdas.py | 2 +- test/completion/ordering.py | 2 +- test/completion/parser.py | 2 +- test/completion/pep0484_basic.py | 2 +- test/completion/recursion.py | 4 +-- test/completion/stdlib.py | 2 +- test/completion/usages.py | 8 ++--- test/conftest.py | 4 +-- test/static_analysis/attribute_error.py | 4 +-- test/static_analysis/attribute_warnings.py | 4 +-- test/static_analysis/class_simple.py | 2 +- test/static_analysis/descriptors.py | 2 +- test/static_analysis/normal_arguments.py | 2 +- test/static_analysis/star_arguments.py | 2 +- test/static_analysis/try_except.py | 2 +- test/test_api/test_interpreter.py | 14 ++++---- .../test_parser_utils.py | 2 +- test/test_speed.py | 2 +- 41 files changed, 112 insertions(+), 112 deletions(-) diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index 809f64f1..1c00d74b 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -132,7 +132,7 @@ def find_module_pre_py33(string, path=None, fullname=None): file = None if not is_package or is_archive: file = DummyFile(loader, string) - return (file, module_path, is_package) + return file, module_path, is_package except ImportError: pass raise ImportError("No module named {}".format(string)) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 1937cc60..ebb1ca05 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -555,7 +555,7 @@ class Definition(BaseDefinition): .. todo:: Add full path. This function is should return a `module.class.function` path. """ - position = '' if self.in_builtin_module else '@%s' % (self.line) + position = '' if self.in_builtin_module else '@%s' % self.line return "%s:%s%s" % (self.module_name, self.description, position) @memoize_method diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index f9f2e078..9c2b6424 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -432,7 +432,7 @@ def dotted_from_fs_path(fs_path, sys_path): # C:\path\to\Lib path = '' for s in sys_path: - if (fs_path.startswith(s) and len(path) < len(s)): + if fs_path.startswith(s) and len(path) < len(s): path = s # - Window diff --git a/jedi/evaluate/compiled/getattr_static.py b/jedi/evaluate/compiled/getattr_static.py index 9f8cd8a8..65eddad9 100644 --- a/jedi/evaluate/compiled/getattr_static.py +++ b/jedi/evaluate/compiled/getattr_static.py @@ -87,7 +87,7 @@ else: return getattr(klass, '__dict__', _sentinel) return _shadowed_dict_newstyle(klass) - class _OldStyleClass(): + class _OldStyleClass: pass _oldstyle_instance_type = type(_OldStyleClass()) @@ -122,7 +122,7 @@ def _safe_hasattr(obj, name): def _safe_is_data_descriptor(obj): - return (_safe_hasattr(obj, '__set__') or _safe_hasattr(obj, '__delete__')) + return _safe_hasattr(obj, '__set__') or _safe_hasattr(obj, '__delete__') def getattr_static(obj, attr, default=_sentinel): diff --git a/jedi/evaluate/compiled/mixed.py b/jedi/evaluate/compiled/mixed.py index ac0f6dd6..462ac7d5 100644 --- a/jedi/evaluate/compiled/mixed.py +++ b/jedi/evaluate/compiled/mixed.py @@ -64,7 +64,7 @@ class MixedName(compiled.CompiledName): contexts = list(self.infer()) if not contexts: # This means a start_pos that doesn't exist (compiled objects). - return (0, 0) + return 0, 0 return contexts[0].name.start_pos @start_pos.setter diff --git a/test/completion/arrays.py b/test/completion/arrays.py index e44a0671..19c6222f 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -43,7 +43,7 @@ b[int():] b[:] -class _StrangeSlice(): +class _StrangeSlice: def __getitem__(self, sliced): return sliced @@ -128,25 +128,25 @@ f # ----------------- # unnessecary braces # ----------------- -a = (1) +a = 1 #? int() a #? int() +1 +#? int() (1) #? int() -((1)) -#? int() -((1)+1) +(1 + 1) u, v = 1, "" #? int() u -((u1, v1)) = 1, "" +(u1, v1) = 1, "" #? int() u1 #? int() -(u1) +u1 (a), b = 1, '' #? int() @@ -154,15 +154,15 @@ a def a(): return '' #? str() -(a)() +a() #? str() -(a)().replace() +a().replace() #? int() -(tuple).index() +tuple.index() #? int() -(tuple)().index() +tuple().index() -class C(): +class C: def __init__(self): self.a = (str()).upper() @@ -283,14 +283,14 @@ dic2[index] # __getitem__ # ----------------- -class GetItem(): +class GetItem: def __getitem__(self, index): return 1.0 #? float() GetItem()[0] -class GetItem(): +class GetItem: def __init__(self, el): self.el = el @@ -300,7 +300,7 @@ class GetItem(): #? str() GetItem("")[1] -class GetItemWithList(): +class GetItemWithList: def __getitem__(self, index): return [1, 1.0, 's'][index] diff --git a/test/completion/async_.py b/test/completion/async_.py index b2202137..a63e93ab 100644 --- a/test/completion/async_.py +++ b/test/completion/async_.py @@ -24,7 +24,7 @@ async def x2(): #? ['readlines'] f.readlines -class A(): +class A: @staticmethod async def b(c=1, d=2): return 1 diff --git a/test/completion/basic.py b/test/completion/basic.py index d79a15ed..efe30c78 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -23,9 +23,9 @@ a(0):. # if/else/elif # ----------------- -if (random.choice([0, 1])): +if random.choice([0, 1]): 1 -elif(random.choice([0, 1])): +elif random.choice([0, 1]): a = 3 else: a = '' @@ -34,7 +34,7 @@ a def func(): if random.choice([0, 1]): 1 - elif(random.choice([0, 1])): + elif random.choice([0, 1]): a = 3 else: a = '' @@ -187,7 +187,7 @@ some_word # ----------------- class A(object): pass -class B(): pass +class B: pass #? ['__init__'] A.__init__ @@ -201,7 +201,7 @@ int().__init__ # comments # ----------------- -class A(): +class A: def __init__(self): self.hello = {} # comment shouldn't be a string #? dict() diff --git a/test/completion/classes.py b/test/completion/classes.py index 292cfc36..fa09a038 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -6,7 +6,7 @@ def find_class(): #? ['ret'] TestClass.ret -class FindClass(): +class FindClass: #? [] TestClass.ret if a: @@ -125,7 +125,7 @@ strs.second TestClass.var_class.var_class.var_class.var_class # operations (+, *, etc) shouldn't be InstanceElements - #246 -class A(): +class A: def __init__(self): self.addition = 1 + 2 #? int() @@ -219,7 +219,7 @@ class Dude(classgetter()): # __call__ # ----------------- -class CallClass(): +class CallClass: def __call__(self): return 1 @@ -256,7 +256,7 @@ V(1).d() # ----------------- # ordering # ----------------- -class A(): +class A: def b(self): #? int() a_func() @@ -278,8 +278,8 @@ A().a_func() # ----------------- # nested classes # ----------------- -class A(): - class B(): +class A: + class B: pass def b(self): return 1.0 @@ -287,9 +287,9 @@ class A(): #? float() A().b() -class A(): +class A: def b(self): - class B(): + class B: def b(self): return [] return B().b() @@ -304,7 +304,7 @@ A().b() def meth(self): return self.a, self.b -class WithoutMethod(): +class WithoutMethod: a = 1 def __init__(self): self.b = 1.0 @@ -312,7 +312,7 @@ class WithoutMethod(): return self.b m = meth -class B(): +class B: b = '' a = WithoutMethod().m() @@ -348,18 +348,18 @@ getattr(getattr, 1) getattr(str, []) -class Base(): +class Base: def ret(self, b): return b -class Wrapper(): +class Wrapper: def __init__(self, obj): self.obj = obj def __getattr__(self, name): return getattr(self.obj, name) -class Wrapper2(): +class Wrapper2: def __getattribute__(self, name): return getattr(Base(), name) @@ -369,7 +369,7 @@ Wrapper(Base()).ret(3) #? int() Wrapper2(Base()).ret(3) -class GetattrArray(): +class GetattrArray: def __getattr__(self, name): return [1] @@ -380,7 +380,7 @@ GetattrArray().something[0] # ----------------- # private vars # ----------------- -class PrivateVar(): +class PrivateVar: def __init__(self): self.__var = 1 #? int() @@ -517,7 +517,7 @@ Config.mode2 class Foo(object): a = 3 def create_class(self): - class X(): + class X: a = self.a self.b = 3.0 return X diff --git a/test/completion/comprehensions.py b/test/completion/comprehensions.py index 402ef753..db9e3178 100644 --- a/test/completion/comprehensions.py +++ b/test/completion/comprehensions.py @@ -154,7 +154,7 @@ foo[1] # In class # ----------------- -class X(): +class X: def __init__(self, bar): self.bar = bar diff --git a/test/completion/context.py b/test/completion/context.py index d3e79b81..f26ff0a6 100644 --- a/test/completion/context.py +++ b/test/completion/context.py @@ -1,4 +1,4 @@ -class Base(): +class Base: myfoobar = 3 @@ -35,7 +35,7 @@ myfoobar # Inheritance # ----------------- -class Super(): +class Super: enabled = True if enabled: yo_dude = 4 diff --git a/test/completion/decorators.py b/test/completion/decorators.py index 27e455ae..099c12c5 100644 --- a/test/completion/decorators.py +++ b/test/completion/decorators.py @@ -106,7 +106,7 @@ def nothing(a,b,c): #? int() nothing("")[0] -class MethodDecoratorAsClass(): +class MethodDecoratorAsClass: class_var = 3 @Decorator def func_without_self(arg, arg2): @@ -124,7 +124,7 @@ MethodDecoratorAsClass().func_without_self('')[1] MethodDecoratorAsClass().func_with_self(1) -class SelfVars(): +class SelfVars: """Init decorator problem as an instance, #247""" @Decorator def __init__(self): @@ -181,7 +181,7 @@ JustAClass.a() # illegal decorators # ----------------- -class DecoratorWithoutCall(): +class DecoratorWithoutCall: def __init__(self, func): self.func = func @@ -200,7 +200,7 @@ f() g() -class X(): +class X: @str def x(self): pass @@ -220,7 +220,7 @@ def dec(f): return f(s) return wrapper -class MethodDecorators(): +class MethodDecorators: _class_var = 1 def __init__(self): self._method_var = '' @@ -245,7 +245,7 @@ MethodDecorators().class_var() MethodDecorators().method_var() -class Base(): +class Base: @not_existing def __init__(self): pass @@ -298,7 +298,7 @@ follow_statement(1) # class decorators should just be ignored @should_ignore -class A(): +class A: def ret(self): return 1 diff --git a/test/completion/descriptors.py b/test/completion/descriptors.py index 3cc01faf..3f1674a4 100644 --- a/test/completion/descriptors.py +++ b/test/completion/descriptors.py @@ -50,7 +50,7 @@ C.just_a_method # ----------------- # properties # ----------------- -class B(): +class B: @property def r(self): return 1 @@ -71,7 +71,7 @@ B().p #? [] B().p(). -class PropClass(): +class PropClass: def __init__(self, a): self.a = a @property @@ -190,7 +190,7 @@ E.u(1) from functools import partial -class Memoize(): +class Memoize: def __init__(self, func): self.func = func @@ -205,7 +205,7 @@ class Memoize(): return self.func(*args, **kwargs) -class MemoizeTest(): +class MemoizeTest: def __init__(self, x): self.x = x diff --git a/test/completion/docstring.py b/test/completion/docstring.py index 88db52d1..1e2d68ed 100644 --- a/test/completion/docstring.py +++ b/test/completion/docstring.py @@ -61,7 +61,7 @@ def sphinxy_param_type_wrapped(a): # local classes -> github #370 -class ProgramNode(): +class ProgramNode: pass def local_classes(node, node2): @@ -75,7 +75,7 @@ def local_classes(node, node2): #? ProgramNode2() node2 -class ProgramNode2(): +class ProgramNode2: pass @@ -193,7 +193,7 @@ d.upper() # class docstrings # ----------------- -class InInit(): +class InInit: def __init__(self, foo): """ :type foo: str @@ -202,7 +202,7 @@ class InInit(): foo -class InClass(): +class InClass: """ :type foo: str """ @@ -211,7 +211,7 @@ class InClass(): foo -class InBoth(): +class InBoth: """ :type foo: str """ diff --git a/test/completion/dynamic_arrays.py b/test/completion/dynamic_arrays.py index 5cb52fc6..e20dde86 100644 --- a/test/completion/dynamic_arrays.py +++ b/test/completion/dynamic_arrays.py @@ -112,9 +112,9 @@ iter(lst)[0] # ----------------- # complex including += # ----------------- -class C(): pass -class D(): pass -class E(): pass +class C: pass +class D: pass +class E: pass lst = [1] lst.append(1.0) lst += [C] @@ -207,7 +207,7 @@ blub()[0] # ----------------- # returns, the same for classes # ----------------- -class C(): +class C: def blub(self, b): if 1: a = [] diff --git a/test/completion/dynamic_params.py b/test/completion/dynamic_params.py index 8af1730c..b274d235 100644 --- a/test/completion/dynamic_params.py +++ b/test/completion/dynamic_params.py @@ -90,14 +90,14 @@ func.sys # classes # ----------------- -class A(): +class A: def __init__(self, a): #? str() a A("s") -class A(): +class A: def __init__(self, a): #? int() a diff --git a/test/completion/flow_analysis.py b/test/completion/flow_analysis.py index af292b47..1b4e742a 100644 --- a/test/completion/flow_analysis.py +++ b/test/completion/flow_analysis.py @@ -191,7 +191,7 @@ a # isinstance # ----------------- -class A(): pass +class A: pass def isinst(x): if isinstance(x, A): @@ -251,7 +251,7 @@ if False: # True objects like modules # ----------------- -class X(): +class X: pass if X: a = 1 diff --git a/test/completion/functions.py b/test/completion/functions.py index 893e4a39..3a1c727e 100644 --- a/test/completion/functions.py +++ b/test/completion/functions.py @@ -285,7 +285,7 @@ def memoize(func): return wrapper -class Something(): +class Something: @memoize def x(self, a, b=1): return a diff --git a/test/completion/generators.py b/test/completion/generators.py index 2327b185..e9840128 100644 --- a/test/completion/generators.py +++ b/test/completion/generators.py @@ -52,7 +52,7 @@ for a in get(): a -class Get(): +class Get: def __iter__(self): if random.choice([0, 1]): yield 1 diff --git a/test/completion/goto.py b/test/completion/goto.py index adff012d..a50693d4 100644 --- a/test/completion/goto.py +++ b/test/completion/goto.py @@ -83,7 +83,7 @@ c c() -class ClassVar(): +class ClassVar: x = 3 #! ['x = 3'] @@ -103,7 +103,7 @@ def f(t=None): t = t or 1 -class X(): +class X: pass #! 3 [] @@ -158,7 +158,7 @@ from . import some_variable # anonymous classes # ----------------- def func(): - class A(): + class A: def b(self): return 1 return A() @@ -171,7 +171,7 @@ func().b() # ----------------- #! 7 ['class ClassDef'] -class ClassDef(): +class ClassDef: """ abc """ pass @@ -216,7 +216,7 @@ def dec(dec_param=3): def y(): pass -class ClassDec(): +class ClassDec: def class_func(func): return func diff --git a/test/completion/import_tree/classes.py b/test/completion/import_tree/classes.py index 23b088c3..ef9a0359 100644 --- a/test/completion/import_tree/classes.py +++ b/test/completion/import_tree/classes.py @@ -1,10 +1,10 @@ blub = 1 -class Config2(): +class Config2: pass -class BaseClass(): +class BaseClass: mode = Config2() if isinstance(whaat, int): mode2 = whaat diff --git a/test/completion/invalid.py b/test/completion/invalid.py index 7c047e66..f489e2bb 100644 --- a/test/completion/invalid.py +++ b/test/completion/invalid.py @@ -193,7 +193,7 @@ invalid # classes # ----------------- -class BrokenPartsOfClass(): +class BrokenPartsOfClass: def foo(self): # This construct contains two places where Jedi with Python 3 can fail. # It should just ignore those constructs and still execute `bar`. diff --git a/test/completion/isinstance.py b/test/completion/isinstance.py index 15fb9a76..45b18e5b 100644 --- a/test/completion/isinstance.py +++ b/test/completion/isinstance.py @@ -78,7 +78,7 @@ def isinstance_func(arr): # Names with multiple indices. # ----------------- -class Test(): +class Test: def __init__(self, testing): if isinstance(testing, str): self.testing = testing diff --git a/test/completion/lambdas.py b/test/completion/lambdas.py index 524df0ce..c5f10686 100644 --- a/test/completion/lambdas.py +++ b/test/completion/lambdas.py @@ -54,7 +54,7 @@ a = lambda: 3 #? ['__closure__'] a.__closure__ -class C(): +class C: def __init__(self, foo=1.0): self.a = lambda: 1 self.foo = foo diff --git a/test/completion/ordering.py b/test/completion/ordering.py index 61eb1928..f3edebcc 100644 --- a/test/completion/ordering.py +++ b/test/completion/ordering.py @@ -157,7 +157,7 @@ a.real a.a a = 3 -class a(): +class a: def __init__(self, a): self.a = a diff --git a/test/completion/parser.py b/test/completion/parser.py index 68793f4f..37f59446 100644 --- a/test/completion/parser.py +++ b/test/completion/parser.py @@ -2,7 +2,7 @@ Issues with the parser and not the type inference should be part of this file. """ -class IndentIssues(): +class IndentIssues: """ issue jedi-vim#288 Which is really a fast parser issue. It used to start a new block at the diff --git a/test/completion/pep0484_basic.py b/test/completion/pep0484_basic.py index 0230d375..33fed348 100644 --- a/test/completion/pep0484_basic.py +++ b/test/completion/pep0484_basic.py @@ -3,7 +3,7 @@ # python >= 3.2 -class A(): +class A: pass diff --git a/test/completion/recursion.py b/test/completion/recursion.py index a3e7670b..a9f013be 100644 --- a/test/completion/recursion.py +++ b/test/completion/recursion.py @@ -14,7 +14,7 @@ Recursion().a Recursion().b -class X(): +class X: def __init__(self): self.recursive = [1, 3] @@ -39,7 +39,7 @@ def recursion1(foo): recursion1([1,2])[0] -class FooListComp(): +class FooListComp: def __init__(self): self.recursive = [1] diff --git a/test/completion/stdlib.py b/test/completion/stdlib.py index b6b739af..623e879c 100644 --- a/test/completion/stdlib.py +++ b/test/completion/stdlib.py @@ -61,7 +61,7 @@ import math import os #? type(os) type(math) -class X(): pass +class X: pass #? type type(X) diff --git a/test/completion/usages.py b/test/completion/usages.py index be27ae51..d0509b32 100644 --- a/test/completion/usages.py +++ b/test/completion/usages.py @@ -29,7 +29,7 @@ abc = 5 Abc = 3 #< 6 (0,6), (2,4), (5,8), (17,0) -class Abc(): +class Abc: #< (-2,6), (0,4), (3,8), (15,0) Abc @@ -132,7 +132,7 @@ class TestClassVar(object): #< (0,8), (-7, 8) class_v -class TestInstanceVar(): +class TestInstanceVar: def a(self): #< 13 (4,13), (0,13) self._instance_var = 3 @@ -145,7 +145,7 @@ class TestInstanceVar(): self() -class NestedClass(): +class NestedClass: def __getattr__(self, name): return self @@ -249,7 +249,7 @@ if isinstance(j, int): # Dynamic Param Search # ----------------- -class DynamicParam(): +class DynamicParam: def foo(self): return diff --git a/test/conftest.py b/test/conftest.py index db2f8260..fcabd38c 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -41,9 +41,9 @@ def parse_test_files_option(opt): opt = str(opt) if ':' in opt: (f_name, rest) = opt.split(':', 1) - return (f_name, list(map(int, rest.split(',')))) + return f_name, list(map(int, rest.split(','))) else: - return (opt, []) + return opt, [] def pytest_generate_tests(metafunc): diff --git a/test/static_analysis/attribute_error.py b/test/static_analysis/attribute_error.py index 4b084c11..9747429d 100644 --- a/test/static_analysis/attribute_error.py +++ b/test/static_analysis/attribute_error.py @@ -1,4 +1,4 @@ -class Cls(): +class Cls: class_attr = '' def __init__(self, input): self.instance_attr = 3 @@ -77,7 +77,7 @@ return_one(''.undefined_attribute) [r for r in [1, 2]] # some random error that showed up -class NotCalled(): +class NotCalled: def match_something(self, param): seems_to_need_an_assignment = param return [value.match_something() for value in []] diff --git a/test/static_analysis/attribute_warnings.py b/test/static_analysis/attribute_warnings.py index 0e1e5e95..5630a5b6 100644 --- a/test/static_analysis/attribute_warnings.py +++ b/test/static_analysis/attribute_warnings.py @@ -8,7 +8,7 @@ Jedi issues warnings for possible errors if ``__getattr__``, # ----------------- -class Cls(): +class Cls: def __getattr__(self, name): return getattr(str, name) @@ -32,7 +32,7 @@ Inherited().undefined # ----------------- -class SetattrCls(): +class SetattrCls: def __init__(self, dct): # Jedi doesn't even try to understand such code for k, v in dct.items(): diff --git a/test/static_analysis/class_simple.py b/test/static_analysis/class_simple.py index 3f84fde0..63d6073a 100644 --- a/test/static_analysis/class_simple.py +++ b/test/static_analysis/class_simple.py @@ -1,5 +1,5 @@ class Base(object): - class Nested(): + class Nested: def foo(): pass diff --git a/test/static_analysis/descriptors.py b/test/static_analysis/descriptors.py index 0fc5d159..a17d1b46 100644 --- a/test/static_analysis/descriptors.py +++ b/test/static_analysis/descriptors.py @@ -1,5 +1,5 @@ # classmethod -class TarFile(): +class TarFile: @classmethod def open(cls, name, **kwargs): return cls.taropen(name, **kwargs) diff --git a/test/static_analysis/normal_arguments.py b/test/static_analysis/normal_arguments.py index 2fc8e81d..25729f51 100644 --- a/test/static_analysis/normal_arguments.py +++ b/test/static_analysis/normal_arguments.py @@ -60,7 +60,7 @@ default(x=1) # class arguments # ----------------- -class Instance(): +class Instance: def __init__(self, foo): self.foo = foo diff --git a/test/static_analysis/star_arguments.py b/test/static_analysis/star_arguments.py index 34be43b5..f1f8c78d 100644 --- a/test/static_analysis/star_arguments.py +++ b/test/static_analysis/star_arguments.py @@ -111,7 +111,7 @@ mixed2(3, b=5) simple(1, **[]) #! 12 type-error-star-star simple(1, **1) -class A(): pass +class A: pass #! 12 type-error-star-star simple(1, **A()) diff --git a/test/static_analysis/try_except.py b/test/static_analysis/try_except.py index e6543280..0481de63 100644 --- a/test/static_analysis/try_except.py +++ b/test/static_analysis/try_except.py @@ -44,7 +44,7 @@ except (TypeError, NotImplementedError): pass # ----------------- try: str.not_existing -except ((AttributeError)): pass +except (AttributeError): pass try: #! 4 attribute-error str.not_existing diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index a4c0311e..8e91e566 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -16,8 +16,8 @@ else: exec source in global_map """, 'blub', 'exec')) -class _GlobalNameSpace(): - class SideEffectContainer(): +class _GlobalNameSpace: + class SideEffectContainer: pass @@ -80,7 +80,7 @@ def test_numpy_like_non_zero(): def test_nested_resolve(): - class XX(): + class XX: def x(): pass @@ -168,7 +168,7 @@ def test_list(): def test_slice(): - class Foo1(): + class Foo1: bar = [] baz = 'xbarx' _assert_interpreter_complete('getattr(Foo1, baz[1:-1]).append', @@ -177,7 +177,7 @@ def test_slice(): def test_getitem_side_effects(): - class Foo2(): + class Foo2: def __getitem__(self, index): # Possible side effects here, should therefore not call this. if True: @@ -190,7 +190,7 @@ def test_getitem_side_effects(): def test_property_error_oldstyle(): lst = [] - class Foo3(): + class Foo3: @property def bar(self): lst.append(1) @@ -269,7 +269,7 @@ def test_more_complex_instances(): def foo(self, other): return self - class Base(): + class Base: def wow(self): return Something() diff --git a/test/test_parso_integration/test_parser_utils.py b/test/test_parso_integration/test_parser_utils.py index e49c3f56..c207fdd6 100644 --- a/test/test_parso_integration/test_parser_utils.py +++ b/test/test_parso_integration/test_parser_utils.py @@ -7,7 +7,7 @@ from parso.python import tree import pytest -class TestCallAndName(): +class TestCallAndName: def get_call(self, source): # Get the simple_stmt and then the first one. node = parse(source).children[0] diff --git a/test/test_speed.py b/test/test_speed.py index 8d5bc9a3..be81d739 100644 --- a/test/test_speed.py +++ b/test/test_speed.py @@ -59,7 +59,7 @@ class TestSpeed(TestCase): unwanted computation of repr(). Exemple : big pandas data. See issue #919. """ - class SlowRepr(): + class SlowRepr: "class to test what happens if __repr__ is very slow." def some_method(self): pass From 5755fcb900d2ea493f5811d127980dc5dc039260 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:34:10 +0200 Subject: [PATCH 06/22] Replace comparison with None with equality operator --- test/test_evaluate/test_context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_evaluate/test_context.py b/test/test_evaluate/test_context.py index 178b879d..4e29e90a 100644 --- a/test/test_evaluate/test_context.py +++ b/test/test_evaluate/test_context.py @@ -4,7 +4,7 @@ from jedi import Script def test_module_attributes(): def_, = Script('__name__').completions() assert def_.name == '__name__' - assert def_.line == None - assert def_.column == None + assert def_.line is None + assert def_.column is None str_, = def_._goto_definitions() assert str_.name == 'str' From cc623218e5927f2004bc66381521f26d6d9d047b Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:37:50 +0200 Subject: [PATCH 07/22] Replace function call with set literal --- jedi/evaluate/docstrings.py | 2 +- jedi/evaluate/filters.py | 2 +- jedi/evaluate/syntax_tree.py | 4 ++-- jedi/parser_utils.py | 9 ++++--- test/completion/dynamic_arrays.py | 2 +- test/test_api/test_api.py | 4 ++-- .../test_api_classes_follow_definition.py | 3 ++- test/test_api/test_classes.py | 24 +++++++++---------- test/test_api/test_interpreter.py | 2 +- test/test_evaluate/test_imports.py | 2 +- test/test_evaluate/test_stdlib.py | 2 +- test/test_evaluate/test_sys_path.py | 6 ++--- test/test_utils.py | 2 +- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index 4bbb0a06..ebb71b11 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -243,7 +243,7 @@ def _execute_array_values(evaluator, array): for typ in lazy_context.infer() ) values.append(LazyKnownContexts(objects)) - return set([FakeSequence(evaluator, array.array_type, values)]) + return {FakeSequence(evaluator, array.array_type, values)} else: return array.execute_evaluated() diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index 35dff9da..1b4754eb 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -27,7 +27,7 @@ class AbstractNameDefinition(object): def goto(self): # Typically names are already definitions and therefore a goto on that # name will always result on itself. - return set([self]) + return {self} def get_root_context(self): return self.parent_context.get_root_context() diff --git a/jedi/evaluate/syntax_tree.py b/jedi/evaluate/syntax_tree.py index 1d847a49..123617da 100644 --- a/jedi/evaluate/syntax_tree.py +++ b/jedi/evaluate/syntax_tree.py @@ -286,10 +286,10 @@ def eval_or_test(context, or_test): # handle lazy evaluation of and/or here. if operator in ('and', 'or'): left_bools = set(left.py__bool__() for left in types) - if left_bools == set([True]): + if left_bools == {True}: if operator == 'and': types = context.eval_node(right) - elif left_bools == set([False]): + elif left_bools == {False}: if operator != 'and': types = context.eval_node(right) # Otherwise continue, because of uncertainty. diff --git a/jedi/parser_utils.py b/jedi/parser_utils.py index 59c6408e..69decc9c 100644 --- a/jedi/parser_utils.py +++ b/jedi/parser_utils.py @@ -4,11 +4,10 @@ from inspect import cleandoc from jedi._compatibility import literal_eval, is_py3 from parso.python import tree -_EXECUTE_NODES = set([ - 'funcdef', 'classdef', 'import_from', 'import_name', 'test', 'or_test', - 'and_test', 'not_test', 'comparison', 'expr', 'xor_expr', 'and_expr', - 'shift_expr', 'arith_expr', 'atom_expr', 'term', 'factor', 'power', 'atom' -]) +_EXECUTE_NODES = {'funcdef', 'classdef', 'import_from', 'import_name', 'test', + 'or_test', 'and_test', 'not_test', 'comparison', 'expr', + 'xor_expr', 'and_expr', 'shift_expr', 'arith_expr', + 'atom_expr', 'term', 'factor', 'power', 'atom'} _FLOW_KEYWORDS = ( 'try', 'except', 'finally', 'else', 'if', 'elif', 'with', 'for', 'while' diff --git a/test/completion/dynamic_arrays.py b/test/completion/dynamic_arrays.py index e20dde86..5097c8b5 100644 --- a/test/completion/dynamic_arrays.py +++ b/test/completion/dynamic_arrays.py @@ -254,7 +254,7 @@ C().list_arr(1.0)[0] # array recursions # ----------------- -a = set([1.0]) +a = {1.0} a.update(a) a.update([1]) diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index a8064d7c..c456c7cb 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -104,7 +104,7 @@ def test_completion_on_complex_literals(): # No dot no completion - I thought, but 4j is actually a literall after # which a keyword like or is allowed. Good times, haha! assert (set([c.name for c in api.Script('4j').completions()]) == - set(['if', 'and', 'in', 'is', 'not', 'or'])) + {'if', 'and', 'in', 'is', 'not', 'or'}) def test_goto_assignments_on_non_name(): @@ -152,7 +152,7 @@ def test_goto_definition_not_multiple(): def test_usage_description(): descs = [u.description for u in api.Script("foo = ''; foo").usages()] - assert set(descs) == set(["foo = ''", 'foo']) + assert set(descs) == {"foo = ''", 'foo'} def test_get_line_code(): diff --git a/test/test_api/test_api_classes_follow_definition.py b/test/test_api/test_api_classes_follow_definition.py index ffc0cb64..9ecbe0d1 100644 --- a/test/test_api/test_api_classes_follow_definition.py +++ b/test/test_api/test_api_classes_follow_definition.py @@ -34,7 +34,8 @@ def test_follow_import_incomplete(): # incomplete `from * import` part datetime = check_follow_definition_types("from datetime import datetim") - assert set(datetime) == set(['class', 'instance']) # py33: builtin and pure py version + assert set(datetime) == {'class', + 'instance'} # py33: builtin and pure py version # os.path check ospath = check_follow_definition_types("from os.path import abspat") diff --git a/test/test_api/test_classes.py b/test/test_api/test_classes.py index cc01c2a3..1e0d952d 100644 --- a/test/test_api/test_classes.py +++ b/test/test_api/test_classes.py @@ -71,22 +71,22 @@ def test_basedefinition_type_import(): return set([t.type for t in Script(source, **kwargs).completions()]) # import one level - assert get_types('import t') == set(['module']) - assert get_types('import ') == set(['module']) - assert get_types('import datetime; datetime') == set(['module']) + assert get_types('import t') == {'module'} + assert get_types('import ') == {'module'} + assert get_types('import datetime; datetime') == {'module'} # from - assert get_types('from datetime import timedelta') == set(['class']) - assert get_types('from datetime import timedelta; timedelta') == set(['class']) - assert get_types('from json import tool') == set(['module']) - assert get_types('from json import tool; tool') == set(['module']) + assert get_types('from datetime import timedelta') == {'class'} + assert get_types('from datetime import timedelta; timedelta') == {'class'} + assert get_types('from json import tool') == {'module'} + assert get_types('from json import tool; tool') == {'module'} # import two levels - assert get_types('import json.tool; json') == set(['module']) - assert get_types('import json.tool; json.tool') == set(['module']) - assert get_types('import json.tool; json.tool.main') == set(['function']) - assert get_types('import json.tool') == set(['module']) - assert get_types('import json.tool', column=9) == set(['module']) + assert get_types('import json.tool; json') == {'module'} + assert get_types('import json.tool; json.tool') == {'module'} + assert get_types('import json.tool; json.tool.main') == {'function'} + assert get_types('import json.tool') == {'module'} + assert get_types('import json.tool', column=9) == {'module'} def test_function_call_signature_in_doc(): diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index 8e91e566..89a0bb75 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -261,7 +261,7 @@ def test_completion_param_annotations(): a, b, c = c.params assert a._goto_definitions() == [] assert [d.name for d in b._goto_definitions()] == ['str'] - assert set([d.name for d in c._goto_definitions()]) == set(['int', 'float']) + assert set([d.name for d in c._goto_definitions()]) == {'int', 'float'} def test_more_complex_instances(): diff --git a/test/test_evaluate/test_imports.py b/test/test_evaluate/test_imports.py index 307b811c..738c1cdc 100644 --- a/test/test_evaluate/test_imports.py +++ b/test/test_evaluate/test_imports.py @@ -156,7 +156,7 @@ def test_complete_on_empty_import(): # relative import assert 10 < len(Script("from . import classes", 1, 6, 'whatever.py').completions()) < 30 - wanted = set(['ImportError', 'import', 'ImportWarning']) + wanted = {'ImportError', 'import', 'ImportWarning'} assert set([c.name for c in Script("import").completions()]) == wanted assert len(Script("import import", path='').completions()) > 0 diff --git a/test/test_evaluate/test_stdlib.py b/test/test_evaluate/test_stdlib.py index 6b55224d..3ba3f79f 100644 --- a/test/test_evaluate/test_stdlib.py +++ b/test/test_evaluate/test_stdlib.py @@ -35,7 +35,7 @@ def test_namedtuple_list(): garfield.l""") result = Script(source).completions() completions = set(r.name for r in result) - assert completions == set(['legs', 'length', 'large']) + assert completions == {'legs', 'length', 'large'} def test_namedtuple_content(): diff --git a/test/test_evaluate/test_sys_path.py b/test/test_evaluate/test_sys_path.py index 7bedfa17..e825912d 100644 --- a/test/test_evaluate/test_sys_path.py +++ b/test/test_evaluate/test_sys_path.py @@ -14,9 +14,9 @@ def test_paths_from_assignment(): expr_stmt = script._get_module_node().children[0] return set(sys_path._paths_from_assignment(script._get_module(), expr_stmt)) - assert paths('sys.path[0:0] = ["a"]') == set(['/foo/a']) - assert paths('sys.path = ["b", 1, x + 3, y, "c"]') == set(['/foo/b', '/foo/c']) - assert paths('sys.path = a = ["a"]') == set(['/foo/a']) + assert paths('sys.path[0:0] = ["a"]') == {'/foo/a'} + assert paths('sys.path = ["b", 1, x + 3, y, "c"]') == {'/foo/b', '/foo/c'} + assert paths('sys.path = a = ["a"]') == {'/foo/a'} # Fail for complicated examples. assert paths('sys.path, other = ["a"], 2') == set() diff --git a/test/test_utils.py b/test/test_utils.py index 2eb6e8ca..367decf4 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -68,7 +68,7 @@ class TestSetupReadline(unittest.TestCase): def test_import(self): s = 'from os.path import a' - assert set(self.completions(s)) == set([s + 'ltsep', s + 'bspath']) + assert set(self.completions(s)) == {s + 'ltsep', s + 'bspath'} assert self.completions('import keyword') == ['import keyword'] import os From f56035182cac59afdf0e1d4515c2788dc5dea727 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 16:39:42 +0200 Subject: [PATCH 08/22] Remove trailing semicolons --- test/completion/dynamic_arrays.py | 4 ++-- test/completion/ordering.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/completion/dynamic_arrays.py b/test/completion/dynamic_arrays.py index 5097c8b5..046b91ea 100644 --- a/test/completion/dynamic_arrays.py +++ b/test/completion/dynamic_arrays.py @@ -6,7 +6,7 @@ Checking for ``list.append`` and all the other possible array modifications. # ----------------- arr = [] for a in [1,2]: - arr.append(a); + arr.append(a) arr.append # should not cause an exception arr.append() # should not cause an exception @@ -16,7 +16,7 @@ arr[10] arr = [tuple()] for a in [1,2]: - arr.append(a); + arr.append(a) #? int() tuple() arr[10] diff --git a/test/completion/ordering.py b/test/completion/ordering.py index f3edebcc..e2d02d06 100644 --- a/test/completion/ordering.py +++ b/test/completion/ordering.py @@ -20,7 +20,7 @@ b temp a = 1 -temp = b; +temp = b b = a a = temp #? int() From abe0f27e6a4d4afce93687fd7d14d8ce4292daf1 Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 5 Jan 2018 10:21:16 +0200 Subject: [PATCH 09/22] Add python_requires to help pip --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 81d69ba2..585a04dd 100755 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ setup(name='jedi', keywords='python completion refactoring vim', long_description=readme, packages=find_packages(exclude=['test']), + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*', install_requires=install_requires, extras_require={'dev': ['docopt']}, package_data={'jedi': ['evaluate/compiled/fake/*.pym']}, From 3644c72efec218149cbbc620cf81ad3b3fb76b4e Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 17:29:03 +0200 Subject: [PATCH 10/22] Add version badges, use SVG badges, fix typos --- README.rst | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index f9f16460..e8c8d7d5 100644 --- a/README.rst +++ b/README.rst @@ -2,16 +2,23 @@ Jedi - an awesome autocompletion/static analysis library for Python ################################################################### -.. image:: https://secure.travis-ci.org/davidhalter/jedi.png?branch=master - :target: http://travis-ci.org/davidhalter/jedi - :alt: Travis-CI build status +.. image:: https://img.shields.io/pypi/v/jedi.svg?style=flat + :target: https://pypi.python.org/pypi/jedi + :alt: PyPI version -.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.png?branch=master +.. image:: https://img.shields.io/pypi/pyversions/jedi.svg + :target: https://pypi.python.org/pypi/jedi + :alt: Supported Python versions + +.. image:: https://travis-ci.org/davidhalter/jedi.svg?branch=master + :target: https://travis-ci.org/davidhalter/jedi + :alt: Travis CI build status + +.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.svg?branch=master :target: https://coveralls.io/r/davidhalter/jedi - :alt: Coverage Status + :alt: Coverage status - -*If you have specific questions, please add an issue or ask on* `stackoverflow +*If you have specific questions, please add an issue or ask on* `Stack Overflow `_ *with the label* ``python-jedi``. @@ -25,7 +32,7 @@ related names and to list all names in a Python file and infer them. Jedi understands docstrings and you can use Jedi autocompletion in your REPL as well. -Jedi uses a very simple API to connect with IDE's. There's a reference +Jedi uses a very simple API to connect with IDEs. There's a reference implementation as a `VIM-Plugin `_, which uses Jedi's autocompletion. We encourage you to use Jedi in your IDEs. It's really easy. @@ -45,7 +52,7 @@ Jedi can currently be used with the following editors/projects: - Gedit (gedi_) - wdb_ - Web Debugger - `Eric IDE`_ (Available as a plugin) -- `Ipython 6.0.0+ `_ +- `IPython 6.0.0+ `_ and many more! @@ -123,7 +130,7 @@ The returned objects are very powerful and really all you might need. Autocompletion in your REPL (IPython, etc.) ------------------------------------------- -Starting with Ipython `6.0.0` Jedi is a dependency of IPython. Autocompletion +Starting with IPython `6.0.0` Jedi is a dependency of IPython. Autocompletion in IPython is therefore possible without additional configuration. It's possible to have Jedi autocompletion in REPL modes - `example video `_. @@ -178,7 +185,7 @@ Tests are also run automatically on `Travis CI `_. For more detailed information visit the `testing documentation -`_ +`_. Acknowledgements From 3e8cd9f128074042496b8cf61ac26328f88889b5 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 4 Jan 2018 18:17:35 +0200 Subject: [PATCH 11/22] Use set literals --- jedi/api/keywords.py | 2 +- test/run.py | 2 +- test/test_api/test_api.py | 2 +- test/test_api/test_classes.py | 2 +- test/test_api/test_interpreter.py | 2 +- test/test_evaluate/test_imports.py | 2 +- test/test_utils.py | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jedi/api/keywords.py b/jedi/api/keywords.py index a1bc4e7f..a4875c1c 100644 --- a/jedi/api/keywords.py +++ b/jedi/api/keywords.py @@ -52,7 +52,7 @@ def completion_names(evaluator, stmt, pos, module): def all_keywords(evaluator, pos=(0, 0)): - return set([Keyword(evaluator, k, pos) for k in keys]) + return {Keyword(evaluator, k, pos) for k in keys} def keyword(evaluator, string, pos=(0, 0)): diff --git a/test/run.py b/test/run.py index a3b0c0df..5eed56e7 100755 --- a/test/run.py +++ b/test/run.py @@ -177,7 +177,7 @@ class IntegrationTestCase(object): completions = self.script().completions() #import cProfile; cProfile.run('script.completions()') - comp_str = set([c.name for c in completions]) + comp_str = {c.name for c in completions} return compare_cb(self, comp_str, set(literal_eval(self.correct))) def run_goto_definitions(self, compare_cb): diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index c456c7cb..33f6f0c0 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -103,7 +103,7 @@ def test_completion_on_complex_literals(): _check_number('4.0j.', 'complex') # No dot no completion - I thought, but 4j is actually a literall after # which a keyword like or is allowed. Good times, haha! - assert (set([c.name for c in api.Script('4j').completions()]) == + assert ({c.name for c in api.Script('4j').completions()} == {'if', 'and', 'in', 'is', 'not', 'or'}) diff --git a/test/test_api/test_classes.py b/test/test_api/test_classes.py index 1e0d952d..3603a5f3 100644 --- a/test/test_api/test_classes.py +++ b/test/test_api/test_classes.py @@ -68,7 +68,7 @@ def test_basedefinition_type(definition): def test_basedefinition_type_import(): def get_types(source, **kwargs): - return set([t.type for t in Script(source, **kwargs).completions()]) + return {t.type for t in Script(source, **kwargs).completions()} # import one level assert get_types('import t') == {'module'} diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index 89a0bb75..419eae50 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -261,7 +261,7 @@ def test_completion_param_annotations(): a, b, c = c.params assert a._goto_definitions() == [] assert [d.name for d in b._goto_definitions()] == ['str'] - assert set([d.name for d in c._goto_definitions()]) == {'int', 'float'} + assert {d.name for d in c._goto_definitions()} == {'int', 'float'} def test_more_complex_instances(): diff --git a/test/test_evaluate/test_imports.py b/test/test_evaluate/test_imports.py index 738c1cdc..f66c66b7 100644 --- a/test/test_evaluate/test_imports.py +++ b/test/test_evaluate/test_imports.py @@ -157,7 +157,7 @@ def test_complete_on_empty_import(): assert 10 < len(Script("from . import classes", 1, 6, 'whatever.py').completions()) < 30 wanted = {'ImportError', 'import', 'ImportWarning'} - assert set([c.name for c in Script("import").completions()]) == wanted + assert {c.name for c in Script("import").completions()} == wanted assert len(Script("import import", path='').completions()) > 0 # 111 diff --git a/test/test_utils.py b/test/test_utils.py index 367decf4..2b4fd5a2 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -56,7 +56,7 @@ class TestSetupReadline(unittest.TestCase): string = 'os.path.join("a").upper' assert self.completions(string) == [string] - c = set(['os.' + d for d in dir(os) if d.startswith('ch')]) + c = {'os.' + d for d in dir(os) if d.startswith('ch')} assert set(self.completions('os.ch')) == set(c) finally: del self.namespace.sys @@ -73,7 +73,7 @@ class TestSetupReadline(unittest.TestCase): import os s = 'from os import ' - goal = set([s + el for el in dir(os)]) + goal = {s + el for el in dir(os)} # There are minor differences, e.g. the dir doesn't include deleted # items as well as items that are not only available on linux. assert len(set(self.completions(s)).symmetric_difference(goal)) < 20 @@ -85,7 +85,7 @@ class TestSetupReadline(unittest.TestCase): def test_preexisting_values(self): self.namespace.a = range(10) - assert set(self.completions('a.')) == set(['a.' + n for n in dir(range(1))]) + assert set(self.completions('a.')) == {'a.' + n for n in dir(range(1))} del self.namespace.a def test_colorama(self): From 7e449af4bd6c8863419c38e418100f0ae01f615a Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 7 Jan 2018 10:33:24 +0200 Subject: [PATCH 12/22] Revert changes to test/completion and test/static_analysis except for 2.6 comment removal --- test/completion/arrays.py | 30 ++++++++++---------- test/completion/async_.py | 2 +- test/completion/basic.py | 10 +++---- test/completion/classes.py | 32 +++++++++++----------- test/completion/comprehensions.py | 2 +- test/completion/context.py | 4 +-- test/completion/decorators.py | 14 +++++----- test/completion/descriptors.py | 8 +++--- test/completion/docstring.py | 10 +++---- test/completion/dynamic_arrays.py | 14 +++++----- test/completion/dynamic_params.py | 4 +-- test/completion/flow_analysis.py | 4 +-- test/completion/functions.py | 2 +- test/completion/generators.py | 2 +- test/completion/goto.py | 10 +++---- test/completion/import_tree/classes.py | 4 +-- test/completion/invalid.py | 2 +- test/completion/isinstance.py | 2 +- test/completion/lambdas.py | 2 +- test/completion/ordering.py | 4 +-- test/completion/parser.py | 2 +- test/completion/pep0484_basic.py | 2 +- test/completion/recursion.py | 4 +-- test/completion/stdlib.py | 2 +- test/completion/usages.py | 8 +++--- test/static_analysis/attribute_error.py | 4 +-- test/static_analysis/attribute_warnings.py | 4 +-- test/static_analysis/class_simple.py | 2 +- test/static_analysis/descriptors.py | 2 +- test/static_analysis/normal_arguments.py | 2 +- test/static_analysis/star_arguments.py | 2 +- test/static_analysis/try_except.py | 2 +- 32 files changed, 99 insertions(+), 99 deletions(-) diff --git a/test/completion/arrays.py b/test/completion/arrays.py index 19c6222f..e44a0671 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -43,7 +43,7 @@ b[int():] b[:] -class _StrangeSlice: +class _StrangeSlice(): def __getitem__(self, sliced): return sliced @@ -128,25 +128,25 @@ f # ----------------- # unnessecary braces # ----------------- -a = 1 +a = (1) #? int() a #? int() -1 -#? int() (1) #? int() -(1 + 1) +((1)) +#? int() +((1)+1) u, v = 1, "" #? int() u -(u1, v1) = 1, "" +((u1, v1)) = 1, "" #? int() u1 #? int() -u1 +(u1) (a), b = 1, '' #? int() @@ -154,15 +154,15 @@ a def a(): return '' #? str() -a() +(a)() #? str() -a().replace() +(a)().replace() #? int() -tuple.index() +(tuple).index() #? int() -tuple().index() +(tuple)().index() -class C: +class C(): def __init__(self): self.a = (str()).upper() @@ -283,14 +283,14 @@ dic2[index] # __getitem__ # ----------------- -class GetItem: +class GetItem(): def __getitem__(self, index): return 1.0 #? float() GetItem()[0] -class GetItem: +class GetItem(): def __init__(self, el): self.el = el @@ -300,7 +300,7 @@ class GetItem: #? str() GetItem("")[1] -class GetItemWithList: +class GetItemWithList(): def __getitem__(self, index): return [1, 1.0, 's'][index] diff --git a/test/completion/async_.py b/test/completion/async_.py index a63e93ab..b2202137 100644 --- a/test/completion/async_.py +++ b/test/completion/async_.py @@ -24,7 +24,7 @@ async def x2(): #? ['readlines'] f.readlines -class A: +class A(): @staticmethod async def b(c=1, d=2): return 1 diff --git a/test/completion/basic.py b/test/completion/basic.py index efe30c78..d79a15ed 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -23,9 +23,9 @@ a(0):. # if/else/elif # ----------------- -if random.choice([0, 1]): +if (random.choice([0, 1])): 1 -elif random.choice([0, 1]): +elif(random.choice([0, 1])): a = 3 else: a = '' @@ -34,7 +34,7 @@ a def func(): if random.choice([0, 1]): 1 - elif random.choice([0, 1]): + elif(random.choice([0, 1])): a = 3 else: a = '' @@ -187,7 +187,7 @@ some_word # ----------------- class A(object): pass -class B: pass +class B(): pass #? ['__init__'] A.__init__ @@ -201,7 +201,7 @@ int().__init__ # comments # ----------------- -class A: +class A(): def __init__(self): self.hello = {} # comment shouldn't be a string #? dict() diff --git a/test/completion/classes.py b/test/completion/classes.py index fa09a038..292cfc36 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -6,7 +6,7 @@ def find_class(): #? ['ret'] TestClass.ret -class FindClass: +class FindClass(): #? [] TestClass.ret if a: @@ -125,7 +125,7 @@ strs.second TestClass.var_class.var_class.var_class.var_class # operations (+, *, etc) shouldn't be InstanceElements - #246 -class A: +class A(): def __init__(self): self.addition = 1 + 2 #? int() @@ -219,7 +219,7 @@ class Dude(classgetter()): # __call__ # ----------------- -class CallClass: +class CallClass(): def __call__(self): return 1 @@ -256,7 +256,7 @@ V(1).d() # ----------------- # ordering # ----------------- -class A: +class A(): def b(self): #? int() a_func() @@ -278,8 +278,8 @@ A().a_func() # ----------------- # nested classes # ----------------- -class A: - class B: +class A(): + class B(): pass def b(self): return 1.0 @@ -287,9 +287,9 @@ class A: #? float() A().b() -class A: +class A(): def b(self): - class B: + class B(): def b(self): return [] return B().b() @@ -304,7 +304,7 @@ A().b() def meth(self): return self.a, self.b -class WithoutMethod: +class WithoutMethod(): a = 1 def __init__(self): self.b = 1.0 @@ -312,7 +312,7 @@ class WithoutMethod: return self.b m = meth -class B: +class B(): b = '' a = WithoutMethod().m() @@ -348,18 +348,18 @@ getattr(getattr, 1) getattr(str, []) -class Base: +class Base(): def ret(self, b): return b -class Wrapper: +class Wrapper(): def __init__(self, obj): self.obj = obj def __getattr__(self, name): return getattr(self.obj, name) -class Wrapper2: +class Wrapper2(): def __getattribute__(self, name): return getattr(Base(), name) @@ -369,7 +369,7 @@ Wrapper(Base()).ret(3) #? int() Wrapper2(Base()).ret(3) -class GetattrArray: +class GetattrArray(): def __getattr__(self, name): return [1] @@ -380,7 +380,7 @@ GetattrArray().something[0] # ----------------- # private vars # ----------------- -class PrivateVar: +class PrivateVar(): def __init__(self): self.__var = 1 #? int() @@ -517,7 +517,7 @@ Config.mode2 class Foo(object): a = 3 def create_class(self): - class X: + class X(): a = self.a self.b = 3.0 return X diff --git a/test/completion/comprehensions.py b/test/completion/comprehensions.py index db9e3178..402ef753 100644 --- a/test/completion/comprehensions.py +++ b/test/completion/comprehensions.py @@ -154,7 +154,7 @@ foo[1] # In class # ----------------- -class X: +class X(): def __init__(self, bar): self.bar = bar diff --git a/test/completion/context.py b/test/completion/context.py index f26ff0a6..d3e79b81 100644 --- a/test/completion/context.py +++ b/test/completion/context.py @@ -1,4 +1,4 @@ -class Base: +class Base(): myfoobar = 3 @@ -35,7 +35,7 @@ myfoobar # Inheritance # ----------------- -class Super: +class Super(): enabled = True if enabled: yo_dude = 4 diff --git a/test/completion/decorators.py b/test/completion/decorators.py index 099c12c5..27e455ae 100644 --- a/test/completion/decorators.py +++ b/test/completion/decorators.py @@ -106,7 +106,7 @@ def nothing(a,b,c): #? int() nothing("")[0] -class MethodDecoratorAsClass: +class MethodDecoratorAsClass(): class_var = 3 @Decorator def func_without_self(arg, arg2): @@ -124,7 +124,7 @@ MethodDecoratorAsClass().func_without_self('')[1] MethodDecoratorAsClass().func_with_self(1) -class SelfVars: +class SelfVars(): """Init decorator problem as an instance, #247""" @Decorator def __init__(self): @@ -181,7 +181,7 @@ JustAClass.a() # illegal decorators # ----------------- -class DecoratorWithoutCall: +class DecoratorWithoutCall(): def __init__(self, func): self.func = func @@ -200,7 +200,7 @@ f() g() -class X: +class X(): @str def x(self): pass @@ -220,7 +220,7 @@ def dec(f): return f(s) return wrapper -class MethodDecorators: +class MethodDecorators(): _class_var = 1 def __init__(self): self._method_var = '' @@ -245,7 +245,7 @@ MethodDecorators().class_var() MethodDecorators().method_var() -class Base: +class Base(): @not_existing def __init__(self): pass @@ -298,7 +298,7 @@ follow_statement(1) # class decorators should just be ignored @should_ignore -class A: +class A(): def ret(self): return 1 diff --git a/test/completion/descriptors.py b/test/completion/descriptors.py index 3f1674a4..3cc01faf 100644 --- a/test/completion/descriptors.py +++ b/test/completion/descriptors.py @@ -50,7 +50,7 @@ C.just_a_method # ----------------- # properties # ----------------- -class B: +class B(): @property def r(self): return 1 @@ -71,7 +71,7 @@ B().p #? [] B().p(). -class PropClass: +class PropClass(): def __init__(self, a): self.a = a @property @@ -190,7 +190,7 @@ E.u(1) from functools import partial -class Memoize: +class Memoize(): def __init__(self, func): self.func = func @@ -205,7 +205,7 @@ class Memoize: return self.func(*args, **kwargs) -class MemoizeTest: +class MemoizeTest(): def __init__(self, x): self.x = x diff --git a/test/completion/docstring.py b/test/completion/docstring.py index 1e2d68ed..88db52d1 100644 --- a/test/completion/docstring.py +++ b/test/completion/docstring.py @@ -61,7 +61,7 @@ def sphinxy_param_type_wrapped(a): # local classes -> github #370 -class ProgramNode: +class ProgramNode(): pass def local_classes(node, node2): @@ -75,7 +75,7 @@ def local_classes(node, node2): #? ProgramNode2() node2 -class ProgramNode2: +class ProgramNode2(): pass @@ -193,7 +193,7 @@ d.upper() # class docstrings # ----------------- -class InInit: +class InInit(): def __init__(self, foo): """ :type foo: str @@ -202,7 +202,7 @@ class InInit: foo -class InClass: +class InClass(): """ :type foo: str """ @@ -211,7 +211,7 @@ class InClass: foo -class InBoth: +class InBoth(): """ :type foo: str """ diff --git a/test/completion/dynamic_arrays.py b/test/completion/dynamic_arrays.py index 046b91ea..5cb52fc6 100644 --- a/test/completion/dynamic_arrays.py +++ b/test/completion/dynamic_arrays.py @@ -6,7 +6,7 @@ Checking for ``list.append`` and all the other possible array modifications. # ----------------- arr = [] for a in [1,2]: - arr.append(a) + arr.append(a); arr.append # should not cause an exception arr.append() # should not cause an exception @@ -16,7 +16,7 @@ arr[10] arr = [tuple()] for a in [1,2]: - arr.append(a) + arr.append(a); #? int() tuple() arr[10] @@ -112,9 +112,9 @@ iter(lst)[0] # ----------------- # complex including += # ----------------- -class C: pass -class D: pass -class E: pass +class C(): pass +class D(): pass +class E(): pass lst = [1] lst.append(1.0) lst += [C] @@ -207,7 +207,7 @@ blub()[0] # ----------------- # returns, the same for classes # ----------------- -class C: +class C(): def blub(self, b): if 1: a = [] @@ -254,7 +254,7 @@ C().list_arr(1.0)[0] # array recursions # ----------------- -a = {1.0} +a = set([1.0]) a.update(a) a.update([1]) diff --git a/test/completion/dynamic_params.py b/test/completion/dynamic_params.py index b274d235..8af1730c 100644 --- a/test/completion/dynamic_params.py +++ b/test/completion/dynamic_params.py @@ -90,14 +90,14 @@ func.sys # classes # ----------------- -class A: +class A(): def __init__(self, a): #? str() a A("s") -class A: +class A(): def __init__(self, a): #? int() a diff --git a/test/completion/flow_analysis.py b/test/completion/flow_analysis.py index 1b4e742a..af292b47 100644 --- a/test/completion/flow_analysis.py +++ b/test/completion/flow_analysis.py @@ -191,7 +191,7 @@ a # isinstance # ----------------- -class A: pass +class A(): pass def isinst(x): if isinstance(x, A): @@ -251,7 +251,7 @@ if False: # True objects like modules # ----------------- -class X: +class X(): pass if X: a = 1 diff --git a/test/completion/functions.py b/test/completion/functions.py index 3a1c727e..893e4a39 100644 --- a/test/completion/functions.py +++ b/test/completion/functions.py @@ -285,7 +285,7 @@ def memoize(func): return wrapper -class Something: +class Something(): @memoize def x(self, a, b=1): return a diff --git a/test/completion/generators.py b/test/completion/generators.py index e9840128..2327b185 100644 --- a/test/completion/generators.py +++ b/test/completion/generators.py @@ -52,7 +52,7 @@ for a in get(): a -class Get: +class Get(): def __iter__(self): if random.choice([0, 1]): yield 1 diff --git a/test/completion/goto.py b/test/completion/goto.py index a50693d4..adff012d 100644 --- a/test/completion/goto.py +++ b/test/completion/goto.py @@ -83,7 +83,7 @@ c c() -class ClassVar: +class ClassVar(): x = 3 #! ['x = 3'] @@ -103,7 +103,7 @@ def f(t=None): t = t or 1 -class X: +class X(): pass #! 3 [] @@ -158,7 +158,7 @@ from . import some_variable # anonymous classes # ----------------- def func(): - class A: + class A(): def b(self): return 1 return A() @@ -171,7 +171,7 @@ func().b() # ----------------- #! 7 ['class ClassDef'] -class ClassDef: +class ClassDef(): """ abc """ pass @@ -216,7 +216,7 @@ def dec(dec_param=3): def y(): pass -class ClassDec: +class ClassDec(): def class_func(func): return func diff --git a/test/completion/import_tree/classes.py b/test/completion/import_tree/classes.py index ef9a0359..23b088c3 100644 --- a/test/completion/import_tree/classes.py +++ b/test/completion/import_tree/classes.py @@ -1,10 +1,10 @@ blub = 1 -class Config2: +class Config2(): pass -class BaseClass: +class BaseClass(): mode = Config2() if isinstance(whaat, int): mode2 = whaat diff --git a/test/completion/invalid.py b/test/completion/invalid.py index f489e2bb..7c047e66 100644 --- a/test/completion/invalid.py +++ b/test/completion/invalid.py @@ -193,7 +193,7 @@ invalid # classes # ----------------- -class BrokenPartsOfClass: +class BrokenPartsOfClass(): def foo(self): # This construct contains two places where Jedi with Python 3 can fail. # It should just ignore those constructs and still execute `bar`. diff --git a/test/completion/isinstance.py b/test/completion/isinstance.py index 45b18e5b..15fb9a76 100644 --- a/test/completion/isinstance.py +++ b/test/completion/isinstance.py @@ -78,7 +78,7 @@ def isinstance_func(arr): # Names with multiple indices. # ----------------- -class Test: +class Test(): def __init__(self, testing): if isinstance(testing, str): self.testing = testing diff --git a/test/completion/lambdas.py b/test/completion/lambdas.py index c5f10686..524df0ce 100644 --- a/test/completion/lambdas.py +++ b/test/completion/lambdas.py @@ -54,7 +54,7 @@ a = lambda: 3 #? ['__closure__'] a.__closure__ -class C: +class C(): def __init__(self, foo=1.0): self.a = lambda: 1 self.foo = foo diff --git a/test/completion/ordering.py b/test/completion/ordering.py index e2d02d06..61eb1928 100644 --- a/test/completion/ordering.py +++ b/test/completion/ordering.py @@ -20,7 +20,7 @@ b temp a = 1 -temp = b +temp = b; b = a a = temp #? int() @@ -157,7 +157,7 @@ a.real a.a a = 3 -class a: +class a(): def __init__(self, a): self.a = a diff --git a/test/completion/parser.py b/test/completion/parser.py index 37f59446..68793f4f 100644 --- a/test/completion/parser.py +++ b/test/completion/parser.py @@ -2,7 +2,7 @@ Issues with the parser and not the type inference should be part of this file. """ -class IndentIssues: +class IndentIssues(): """ issue jedi-vim#288 Which is really a fast parser issue. It used to start a new block at the diff --git a/test/completion/pep0484_basic.py b/test/completion/pep0484_basic.py index 33fed348..0230d375 100644 --- a/test/completion/pep0484_basic.py +++ b/test/completion/pep0484_basic.py @@ -3,7 +3,7 @@ # python >= 3.2 -class A: +class A(): pass diff --git a/test/completion/recursion.py b/test/completion/recursion.py index a9f013be..a3e7670b 100644 --- a/test/completion/recursion.py +++ b/test/completion/recursion.py @@ -14,7 +14,7 @@ Recursion().a Recursion().b -class X: +class X(): def __init__(self): self.recursive = [1, 3] @@ -39,7 +39,7 @@ def recursion1(foo): recursion1([1,2])[0] -class FooListComp: +class FooListComp(): def __init__(self): self.recursive = [1] diff --git a/test/completion/stdlib.py b/test/completion/stdlib.py index 623e879c..b6b739af 100644 --- a/test/completion/stdlib.py +++ b/test/completion/stdlib.py @@ -61,7 +61,7 @@ import math import os #? type(os) type(math) -class X: pass +class X(): pass #? type type(X) diff --git a/test/completion/usages.py b/test/completion/usages.py index d0509b32..be27ae51 100644 --- a/test/completion/usages.py +++ b/test/completion/usages.py @@ -29,7 +29,7 @@ abc = 5 Abc = 3 #< 6 (0,6), (2,4), (5,8), (17,0) -class Abc: +class Abc(): #< (-2,6), (0,4), (3,8), (15,0) Abc @@ -132,7 +132,7 @@ class TestClassVar(object): #< (0,8), (-7, 8) class_v -class TestInstanceVar: +class TestInstanceVar(): def a(self): #< 13 (4,13), (0,13) self._instance_var = 3 @@ -145,7 +145,7 @@ class TestInstanceVar: self() -class NestedClass: +class NestedClass(): def __getattr__(self, name): return self @@ -249,7 +249,7 @@ if isinstance(j, int): # Dynamic Param Search # ----------------- -class DynamicParam: +class DynamicParam(): def foo(self): return diff --git a/test/static_analysis/attribute_error.py b/test/static_analysis/attribute_error.py index 9747429d..4b084c11 100644 --- a/test/static_analysis/attribute_error.py +++ b/test/static_analysis/attribute_error.py @@ -1,4 +1,4 @@ -class Cls: +class Cls(): class_attr = '' def __init__(self, input): self.instance_attr = 3 @@ -77,7 +77,7 @@ return_one(''.undefined_attribute) [r for r in [1, 2]] # some random error that showed up -class NotCalled: +class NotCalled(): def match_something(self, param): seems_to_need_an_assignment = param return [value.match_something() for value in []] diff --git a/test/static_analysis/attribute_warnings.py b/test/static_analysis/attribute_warnings.py index 5630a5b6..0e1e5e95 100644 --- a/test/static_analysis/attribute_warnings.py +++ b/test/static_analysis/attribute_warnings.py @@ -8,7 +8,7 @@ Jedi issues warnings for possible errors if ``__getattr__``, # ----------------- -class Cls: +class Cls(): def __getattr__(self, name): return getattr(str, name) @@ -32,7 +32,7 @@ Inherited().undefined # ----------------- -class SetattrCls: +class SetattrCls(): def __init__(self, dct): # Jedi doesn't even try to understand such code for k, v in dct.items(): diff --git a/test/static_analysis/class_simple.py b/test/static_analysis/class_simple.py index 63d6073a..3f84fde0 100644 --- a/test/static_analysis/class_simple.py +++ b/test/static_analysis/class_simple.py @@ -1,5 +1,5 @@ class Base(object): - class Nested: + class Nested(): def foo(): pass diff --git a/test/static_analysis/descriptors.py b/test/static_analysis/descriptors.py index a17d1b46..0fc5d159 100644 --- a/test/static_analysis/descriptors.py +++ b/test/static_analysis/descriptors.py @@ -1,5 +1,5 @@ # classmethod -class TarFile: +class TarFile(): @classmethod def open(cls, name, **kwargs): return cls.taropen(name, **kwargs) diff --git a/test/static_analysis/normal_arguments.py b/test/static_analysis/normal_arguments.py index 25729f51..2fc8e81d 100644 --- a/test/static_analysis/normal_arguments.py +++ b/test/static_analysis/normal_arguments.py @@ -60,7 +60,7 @@ default(x=1) # class arguments # ----------------- -class Instance: +class Instance(): def __init__(self, foo): self.foo = foo diff --git a/test/static_analysis/star_arguments.py b/test/static_analysis/star_arguments.py index f1f8c78d..34be43b5 100644 --- a/test/static_analysis/star_arguments.py +++ b/test/static_analysis/star_arguments.py @@ -111,7 +111,7 @@ mixed2(3, b=5) simple(1, **[]) #! 12 type-error-star-star simple(1, **1) -class A: pass +class A(): pass #! 12 type-error-star-star simple(1, **A()) diff --git a/test/static_analysis/try_except.py b/test/static_analysis/try_except.py index 0481de63..e6543280 100644 --- a/test/static_analysis/try_except.py +++ b/test/static_analysis/try_except.py @@ -44,7 +44,7 @@ except (TypeError, NotImplementedError): pass # ----------------- try: str.not_existing -except (AttributeError): pass +except ((AttributeError)): pass try: #! 4 attribute-error str.not_existing From 73c71d6475ee6b0e500836a2abb07cb8e8858492 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 7 Jan 2018 10:39:38 +0200 Subject: [PATCH 13/22] This test will be removed in the virtualenv branch --- test/test_evaluate/test_pyc.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_evaluate/test_pyc.py b/test/test_evaluate/test_pyc.py index 057e9417..c101da13 100644 --- a/test/test_evaluate/test_pyc.py +++ b/test/test_evaluate/test_pyc.py @@ -45,5 +45,20 @@ def generate_pyc(): shutil.copy(os.path.join("dummy_package/__pycache__", f), dst) +# Python 2.6 does not necessarily come with `compileall.compile_file`. +@pytest.mark.skipif("sys.version_info > (2,6)") +@cwd_at('test/test_evaluate') +def test_pyc(): + """ + The list of completion must be greater than 2. + """ + try: + generate_pyc() + s = jedi.Script("from dummy_package import dummy; dummy.", path='blub.py') + assert len(s.completions()) >= 2 + finally: + shutil.rmtree("dummy_package") + + if __name__ == "__main__": test_pyc() From 4e52acbf26b6d52e26e757cb04817d17c5464331 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 7 Jan 2018 14:13:21 +0100 Subject: [PATCH 14/22] Using setup.py build should not include part of tests It looks like that we have to not only exclude the test package but also 'test.*'. Thanks to @david-geiger for noticing this. Fixes #1024. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3f3b7e54..c7081858 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ setup(name='jedi', license='MIT', keywords='python completion refactoring vim', long_description=readme, - packages=find_packages(exclude=['test']), + packages=find_packages(exclude=['test', 'test.*']), install_requires=install_requires, extras_require={'dev': ['docopt']}, package_data={'jedi': ['evaluate/compiled/fake/*.pym']}, From 598ea1b89b976c0e4517e7495ce68077b205d0ec Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 7 Jan 2018 14:39:08 +0100 Subject: [PATCH 15/22] Add Python 2.6 removal to changelog. Refs #1018 --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9873229..05f454f5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,12 @@ Changelog --------- +0.12.0 (2018-01-01) ++++++++++++++++++++ + +- Remove Python 2.6 +- VirtualEnvs + 0.11.1 (2017-12-14) +++++++++++++++++++ From d815470e54bcc487e63ca5b97963a1c4515b75dd Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 9 Jan 2018 23:29:33 +0100 Subject: [PATCH 16/22] Remove the copyright notice from docs --- docs/_themes/flask/layout.html | 1 - docs/conf.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/_themes/flask/layout.html b/docs/_themes/flask/layout.html index e781a119..48cb4d5f 100644 --- a/docs/_themes/flask/layout.html +++ b/docs/_themes/flask/layout.html @@ -19,7 +19,6 @@ {% endblock %} {%- block footer %} {% if pagename == 'index' %} diff --git a/docs/conf.py b/docs/conf.py index 37ae0642..4199bca8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,7 +45,7 @@ master_doc = 'index' # General information about the project. project = u'Jedi' -copyright = u'2012 - {today.year}, Jedi contributors'.format(today=datetime.date.today()) +copyright = u'jedi contributors' import jedi from jedi.utils import version_info From 3a0ac37ee8b5cc4ba33265f3ca2de6598714c555 Mon Sep 17 00:00:00 2001 From: micbou Date: Fri, 12 Jan 2018 17:33:10 +0100 Subject: [PATCH 17/22] Fix error when using generators with variable-length arguments --- jedi/evaluate/arguments.py | 8 +++++++- test/completion/decorators.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/jedi/evaluate/arguments.py b/jedi/evaluate/arguments.py index 32b9238c..a0b7d416 100644 --- a/jedi/evaluate/arguments.py +++ b/jedi/evaluate/arguments.py @@ -29,6 +29,8 @@ def try_iter_content(types, depth=0): class AbstractArguments(object): context = None + argument_node = None + trailer = None def eval_argument_clinic(self, parameters): """Uses a list with argument clinic information (see PEP 436).""" @@ -197,7 +199,11 @@ class TreeArguments(AbstractArguments): arguments = param.var_args break - return [arguments.argument_node or arguments.trailer] + if arguments.argument_node: + return [arguments.argument_node] + if arguments.trailer: + return [arguments.trailer] + return [] class ValuesArguments(AbstractArguments): diff --git a/test/completion/decorators.py b/test/completion/decorators.py index 27e455ae..043ed0bf 100644 --- a/test/completion/decorators.py +++ b/test/completion/decorators.py @@ -211,6 +211,17 @@ class X(): #? self.x() + +def decorator_var_args(function, *args): + return function(*args) + +@decorator_var_args +def function_var_args(param): + return param + +#? int() +function_var_args(1) + # ----------------- # method decorators # ----------------- From b92c7d3351a34052237df4a292ec81ef97647e7f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 13 Jan 2018 18:59:03 +0100 Subject: [PATCH 18/22] Some cleaning up of code --- jedi/evaluate/arguments.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jedi/evaluate/arguments.py b/jedi/evaluate/arguments.py index a0b7d416..55f1f837 100644 --- a/jedi/evaluate/arguments.py +++ b/jedi/evaluate/arguments.py @@ -10,6 +10,7 @@ from jedi.evaluate.base_context import NO_CONTEXTS from jedi.evaluate.context import iterable from jedi.evaluate.param import get_params, ExecutedParam + def try_iter_content(types, depth=0): """Helper method for static analysis.""" if depth > 10: @@ -199,9 +200,9 @@ class TreeArguments(AbstractArguments): arguments = param.var_args break - if arguments.argument_node: + if arguments.argument_node is not None: return [arguments.argument_node] - if arguments.trailer: + if arguments.trailer is not None: return [arguments.trailer] return [] From 609f59ce4152a1cfec4361f72a316d1a177728c4 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Thu, 18 Jan 2018 09:54:19 +0100 Subject: [PATCH 19/22] Fix issues with random tuples in TreeArgument. Thanks @micbou for noticing it. https://github.com/davidhalter/jedi/commit/b92c7d3351a34052237df4a292ec81ef97647e7f --- jedi/evaluate/arguments.py | 43 ++++++++++++++++++------------------ jedi/evaluate/dynamic.py | 2 +- jedi/evaluate/syntax_tree.py | 2 +- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/jedi/evaluate/arguments.py b/jedi/evaluate/arguments.py index 55f1f837..48c0d5e6 100644 --- a/jedi/evaluate/arguments.py +++ b/jedi/evaluate/arguments.py @@ -98,29 +98,28 @@ class TreeArguments(AbstractArguments): self.trailer = trailer # Can be None, e.g. in a class definition. def _split(self): - if isinstance(self.argument_node, (tuple, list)): - for el in self.argument_node: - yield 0, el - else: - if not (self.argument_node.type == 'arglist' or ( - # in python 3.5 **arg is an argument, not arglist - (self.argument_node.type == 'argument') and - self.argument_node.children[0] in ('*', '**'))): - yield 0, self.argument_node - return + if self.argument_node is None: + return - iterator = iter(self.argument_node.children) - for child in iterator: - if child == ',': - continue - elif child in ('*', '**'): - yield len(child.value), next(iterator) - elif child.type == 'argument' and \ - child.children[0] in ('*', '**'): - assert len(child.children) == 2 - yield len(child.children[0].value), child.children[1] - else: - yield 0, child + if not (self.argument_node.type == 'arglist' or ( + # in python 3.5 **arg is an argument, not arglist + (self.argument_node.type == 'argument') and + self.argument_node.children[0] in ('*', '**'))): + yield 0, self.argument_node + return + + iterator = iter(self.argument_node.children) + for child in iterator: + if child == ',': + continue + elif child in ('*', '**'): + yield len(child.value), next(iterator) + elif child.type == 'argument' and \ + child.children[0] in ('*', '**'): + assert len(child.children) == 2 + yield len(child.children[0].value), child.children[1] + else: + yield 0, child def unpack(self, funcdef=None): named_args = [] diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 7d05000d..ff38fc80 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -156,7 +156,7 @@ def _check_name_for_execution(evaluator, context, compare_node, name, trailer): def create_func_excs(): arglist = trailer.children[1] if arglist == ')': - arglist = () + arglist = None args = TreeArguments(evaluator, context, arglist, trailer) if value_node.type == 'funcdef': yield value.get_function_execution(args) diff --git a/jedi/evaluate/syntax_tree.py b/jedi/evaluate/syntax_tree.py index 123617da..984434fc 100644 --- a/jedi/evaluate/syntax_tree.py +++ b/jedi/evaluate/syntax_tree.py @@ -119,7 +119,7 @@ def eval_node(context, element): def eval_trailer(context, base_contexts, trailer): trailer_op, node = trailer.children[:2] if node == ')': # `arglist` is optional. - node = () + node = None if trailer_op == '[': trailer_op, node, _ = trailer.children From c1394a82b5fd767866a459a739369c94c49471a5 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Thu, 18 Jan 2018 19:12:32 +0100 Subject: [PATCH 20/22] Better error reporting, see #944 --- jedi/evaluate/syntax_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jedi/evaluate/syntax_tree.py b/jedi/evaluate/syntax_tree.py index 984434fc..aa0a225c 100644 --- a/jedi/evaluate/syntax_tree.py +++ b/jedi/evaluate/syntax_tree.py @@ -100,7 +100,7 @@ def eval_node(context, element): # Must be an ellipsis, other operators are not evaluated. # In Python 2 ellipsis is coded as three single dot tokens, not # as one token 3 dot token. - assert element.value in ('.', '...') + assert element.value in ('.', '...'), 'value is actually ' + element.value return ContextSet(compiled.create(evaluator, Ellipsis)) elif typ == 'dotted_name': context_set = eval_atom(context, element.children[0]) @@ -148,7 +148,7 @@ def eval_trailer(context, base_contexts, trailer): name_or_str=node ) else: - assert trailer_op == '(' + assert trailer_op == '(', 'trailer_op is actually %s' % trailer_op args = arguments.TreeArguments(context.evaluator, context, node, trailer) return base_contexts.execute(args) From 16b463a64664989ba2aa276486f0e5e08e775685 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 19 Jan 2018 19:23:11 +0100 Subject: [PATCH 21/22] Refactor to avoid having unicode decode errors by default --- jedi/api/__init__.py | 50 +++++++++++++-------------------- jedi/evaluate/__init__.py | 14 +++++++++ jedi/evaluate/compiled/mixed.py | 2 +- jedi/evaluate/imports.py | 2 +- jedi/evaluate/sys_path.py | 2 +- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 871dc84b..ec81e952 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -16,7 +16,7 @@ import parso from parso.python import tree from parso import python_bytes_to_unicode, split_lines -from jedi.parser_utils import get_executable_nodes, get_statement_of_position +from jedi.parser_utils import get_executable_nodes from jedi import debug from jedi import settings from jedi import cache @@ -92,9 +92,14 @@ class Script(object): with open(path, 'rb') as f: source = f.read() - # TODO do we really want that? - self._source = python_bytes_to_unicode(source, encoding, errors='replace') - self._code_lines = split_lines(self._source) + self._module_node, code = self.evaluator.parse_and_get_code( + code=self._source, + path=self.path, + cache=False, # No disk cache, because the current script often changes. + diff_cache=True, + cache_path=settings.cache_directory + ) + self._code_lines = split_lines(code) line = max(len(self._code_lines), 1) if line is None else line if not (0 < line <= len(self._code_lines)): raise ValueError('`line` parameter is not in a valid range.') @@ -116,23 +121,9 @@ class Script(object): project.add_script_path(self.path) debug.speed('init') - @cache.memoize_method - def _get_module_node(self): - return self._grammar.parse( - code=self._source, - path=self.path, - cache=False, # No disk cache, because the current script often changes. - diff_cache=True, - cache_path=settings.cache_directory - ) - @cache.memoize_method def _get_module(self): - module = ModuleContext( - self._evaluator, - self._get_module_node(), - self.path - ) + module = ModuleContext(self._evaluator, self._module_node, self.path) if self.path is not None: name = dotted_path_in_sys_path(self._evaluator.project.sys_path, self.path) if name is not None: @@ -171,10 +162,9 @@ class Script(object): :rtype: list of :class:`classes.Definition` """ - module_node = self._get_module_node() - leaf = module_node.get_name_of_position(self._pos) + leaf = self._module_node.get_name_of_position(self._pos) if leaf is None: - leaf = module_node.get_leaf_for_position(self._pos) + leaf = self._module_node.get_leaf_for_position(self._pos) if leaf is None: return [] @@ -205,7 +195,7 @@ class Script(object): else: yield name - tree_name = self._get_module_node().get_name_of_position(self._pos) + tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: return [] context = self._evaluator.create_context(self._get_module(), tree_name) @@ -236,7 +226,7 @@ class Script(object): :rtype: list of :class:`classes.Definition` """ - tree_name = self._get_module_node().get_name_of_position(self._pos) + tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Must be syntax return [] @@ -263,7 +253,7 @@ class Script(object): :rtype: list of :class:`classes.CallSignature` """ call_signature_details = \ - helpers.get_call_signature_details(self._get_module_node(), self._pos) + helpers.get_call_signature_details(self._module_node, self._pos) if call_signature_details is None: return [] @@ -288,10 +278,9 @@ class Script(object): def _analysis(self): self._evaluator.is_analysis = True - module_node = self._get_module_node() - self._evaluator.analysis_modules = [module_node] + self._evaluator.analysis_modules = [self._module_node] try: - for node in get_executable_nodes(module_node): + for node in get_executable_nodes(self._module_node): context = self._get_module().create_context(node) if node.type in ('funcdef', 'classdef'): # Resolve the decorators. @@ -360,10 +349,9 @@ class Interpreter(Script): self.namespaces = namespaces def _get_module(self): - parser_module = super(Interpreter, self)._get_module_node() return interpreter.MixedModuleContext( self._evaluator, - parser_module, + self._module_node, self.namespaces, path=self.path ) @@ -399,7 +387,7 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False, module_context.create_context(name if name.parent.type == 'file_input' else name.parent), name ) - ) for name in get_module_names(script._get_module_node(), all_scopes) + ) for name in get_module_names(script._module_node, all_scopes) ] return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column)) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 20461071..f8e5f39e 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -66,6 +66,7 @@ import sys from parso.python import tree import parso +from parso import python_bytes_to_unicode from jedi import debug from jedi import parser_utils @@ -103,6 +104,7 @@ class Evaluator(object): project.add_evaluator(self) self.reset_recursion_limitations() + self.allow_different_encoding = False # Constants self.BUILTINS = compiled.get_special_object(self, 'BUILTINS') @@ -357,3 +359,15 @@ class Evaluator(object): node = node.parent scope_node = parent_scope(node) return from_scope_node(scope_node, is_nested=True, node_is_object=node_is_object) + + def parse_and_get_code(self, code, path, **kwargs): + if self.allow_different_encoding: + if code is None: + with open('rb') as f: + code = f.read() + code = python_bytes_to_unicode(code, errors='replace') + + return self.grammar.parse(code=code, path=path, **kwargs), code + + def parse(self, *args, **kwargs): + return self.parse_and_get_code(*args, **kwargs)[0] diff --git a/jedi/evaluate/compiled/mixed.py b/jedi/evaluate/compiled/mixed.py index 462ac7d5..6cc0d847 100644 --- a/jedi/evaluate/compiled/mixed.py +++ b/jedi/evaluate/compiled/mixed.py @@ -106,7 +106,7 @@ class MixedObjectFilter(compiled.CompiledObjectFilter): @evaluator_function_cache() def _load_module(evaluator, path, python_object): - module = evaluator.grammar.parse( + module = evaluator.parse( path=path, cache=True, diff_cache=True, diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 89dd833f..8cc9b5b6 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -484,7 +484,7 @@ def _load_module(evaluator, path=None, code=None, sys_path=None, parent_module=N if path is not None and path.endswith(('.py', '.zip', '.egg')) \ and dotted_path not in settings.auto_import_modules: - module_node = evaluator.grammar.parse( + module_node = evaluator.parse( code=code, path=path, cache=True, diff_cache=True, cache_path=settings.cache_directory) diff --git a/jedi/evaluate/sys_path.py b/jedi/evaluate/sys_path.py index 82e5e9df..0a8485f2 100644 --- a/jedi/evaluate/sys_path.py +++ b/jedi/evaluate/sys_path.py @@ -204,7 +204,7 @@ def detect_additional_paths(evaluator, script_path): def _get_paths_from_buildout_script(evaluator, buildout_script_path): try: - module_node = evaluator.grammar.parse( + module_node = evaluator.parse( path=buildout_script_path, cache=True, cache_path=settings.cache_directory From 877383b110a66fa688486791c45b0dd774a1cd68 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 20 Jan 2018 18:28:29 +0100 Subject: [PATCH 22/22] Add a test to avoid encoding issues. Fixes #1003 --- jedi/api/__init__.py | 14 +++++++------- jedi/evaluate/__init__.py | 2 +- jedi/evaluate/imports.py | 3 ++- test/conftest.py | 2 +- test/test_api/test_unicode.py | 9 +++++++++ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index ec81e952..1c37abfb 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -92,14 +92,18 @@ class Script(object): with open(path, 'rb') as f: source = f.read() - self._module_node, code = self.evaluator.parse_and_get_code( - code=self._source, + # Load the Python grammar of the current interpreter. + self._grammar = parso.load_grammar() + project = Project(sys_path=sys_path) + self._evaluator = Evaluator(self._grammar, project) + self._module_node, source = self._evaluator.parse_and_get_code( + code=source, path=self.path, cache=False, # No disk cache, because the current script often changes. diff_cache=True, cache_path=settings.cache_directory ) - self._code_lines = split_lines(code) + self._code_lines = split_lines(source) line = max(len(self._code_lines), 1) if line is None else line if not (0 < line <= len(self._code_lines)): raise ValueError('`line` parameter is not in a valid range.') @@ -114,10 +118,6 @@ class Script(object): cache.clear_time_caches() debug.reset_time() - # Load the Python grammar of the current interpreter. - self._grammar = parso.load_grammar() - project = Project(sys_path=sys_path) - self._evaluator = Evaluator(self._grammar, project) project.add_script_path(self.path) debug.speed('init') diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index f8e5f39e..683c33a0 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -104,7 +104,7 @@ class Evaluator(object): project.add_evaluator(self) self.reset_recursion_limitations() - self.allow_different_encoding = False + self.allow_different_encoding = True # Constants self.BUILTINS = compiled.get_special_object(self, 'BUILTINS') diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 8cc9b5b6..97529172 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -369,8 +369,9 @@ class Importer(object): else: module_path = get_init_path(module_path) elif module_file: - code = module_file.read() module_file.close() + with open(module_path, 'rb') as f: + code = f.read() if isinstance(module_path, ImplicitNSInfo): from jedi.evaluate.context.namespace import ImplicitNamespaceContext diff --git a/test/conftest.py b/test/conftest.py index fcabd38c..266f854e 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -123,5 +123,5 @@ class StaticAnalysisCase(object): @pytest.fixture() def cwd_tmpdir(monkeypatch, tmpdir): - with helpers.set_cwd(tmpdir.dirpath): + with helpers.set_cwd(tmpdir.strpath): yield tmpdir diff --git a/test/test_api/test_unicode.py b/test/test_api/test_unicode.py index bcd8ad42..0ea1a8e6 100644 --- a/test/test_api/test_unicode.py +++ b/test/test_api/test_unicode.py @@ -64,3 +64,12 @@ def test_complete_at_zero(): s = Script("", 1, 0).completions() assert len(s) > 0 + + +def test_wrong_encoding(cwd_tmpdir): + x = cwd_tmpdir.join('x.py') + # Use both latin-1 and utf-8 (a really broken file). + x.write_binary(u'foobar = 1\nä'.encode('latin-1') + 'ä'.encode()) + + c, = Script('import x; x.foo', sys_path=['.']).completions() + assert c.name == 'foobar'