From 171873761b8c6b86c62bb88095f950047ff8aef2 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 13 Aug 2016 09:04:57 +0200 Subject: [PATCH 01/12] doc: fix goto_assignments, which can follow imports now --- jedi/api/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 5e0d6d4e..491c5e2e 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -198,8 +198,8 @@ class Script(object): def goto_assignments(self, follow_imports=False): """ - Return the first definition found. Imports and statements aren't - followed. Multiple objects may be returned, because Python itself is a + Return the first definition found, while optionally following imports. + Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. From b82687642da2d6f33a6b82d39a0f2d961cceed3d Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 24 Aug 2016 20:27:40 +1000 Subject: [PATCH 02/12] update usage.rst Updated to make reference to VS Code using this library. --- docs/docs/usage.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docs/usage.rst b/docs/docs/usage.rst index 015c3e2a..5b222f85 100644 --- a/docs/docs/usage.rst +++ b/docs/docs/usage.rst @@ -48,6 +48,10 @@ Kate: `__, you have to enable it, though. +Visual Studio Code: + +- Python_ + Atom: - autocomplete-python_ @@ -112,3 +116,4 @@ Using a custom ``$HOME/.pythonrc.py`` .. _GNOME Builder: https://wiki.gnome.org/Apps/Builder/ .. _gedi: https://github.com/isamert/gedi .. _Eric IDE: http://eric-ide.python-projects.org +.. _Python: https://marketplace.visualstudio.com/items?itemName=donjayamanne.python From 85970d25f942640d58467dbfd0e16ee6fabca272 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 25 Aug 2016 20:57:35 +1000 Subject: [PATCH 03/12] updated as per code review comments --- docs/docs/usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/usage.rst b/docs/docs/usage.rst index 5b222f85..82e1040c 100644 --- a/docs/docs/usage.rst +++ b/docs/docs/usage.rst @@ -50,7 +50,7 @@ Kate: Visual Studio Code: -- Python_ +- `Python Extension`_ Atom: @@ -116,4 +116,4 @@ Using a custom ``$HOME/.pythonrc.py`` .. _GNOME Builder: https://wiki.gnome.org/Apps/Builder/ .. _gedi: https://github.com/isamert/gedi .. _Eric IDE: http://eric-ide.python-projects.org -.. _Python: https://marketplace.visualstudio.com/items?itemName=donjayamanne.python +.. _Python Extension: https://marketplace.visualstudio.com/items?itemName=donjayamanne.python From e08209f35e1b8ed9c9a677e03b4d26bbd6b6b9fe Mon Sep 17 00:00:00 2001 From: Uvview Date: Sat, 17 Sep 2016 03:47:56 +0400 Subject: [PATCH 04/12] For Py3.5 embeddable, which misses pydoc_data module --- jedi/api/keywords.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/jedi/api/keywords.py b/jedi/api/keywords.py index 365cb20c..d6a72b1d 100644 --- a/jedi/api/keywords.py +++ b/jedi/api/keywords.py @@ -8,8 +8,13 @@ from jedi.parser.tree import Leaf try: from pydoc_data import topics as pydoc_topics except ImportError: - # Python 2.6 - import pydoc_topics + # Python 2 + try: + import pydoc_topics + except ImportError: + # This is for Python 3 embeddable version, which dont have + # pydoc_data module in its file python3x.zip. + pydoc_topics = None if is_py3: if is_py35: @@ -99,6 +104,9 @@ def imitate_pydoc(string): It's not possible to get the pydoc's without starting the annoying pager stuff. """ + if pydoc_topics is None: + return '' + # str needed because of possible unicode stuff in py2k (pydoc doesn't work # with unicode strings) string = str(string) From f7f966805f7d522b54b63c266da790a8a9bfdd19 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 14 Oct 2016 13:56:33 +0200 Subject: [PATCH 05/12] sys_path: prepend/prefer egg-link files With `pip install -e` the generated .egg-link file gets preferred over any normally installed distribution, and `pip uninstall` will first remove the egg-link before the normal package. --- jedi/evaluate/sys_path.py | 4 ++-- test/test_evaluate/test_sys_path.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jedi/evaluate/sys_path.py b/jedi/evaluate/sys_path.py index 658f66a8..4fbc6aca 100644 --- a/jedi/evaluate/sys_path.py +++ b/jedi/evaluate/sys_path.py @@ -27,14 +27,13 @@ def get_venv_path(venv): def _get_sys_path_with_egglinks(sys_path): """Find all paths including those referenced by egg-links. - Egg-link-referenced directories are inserted into path immediately after + Egg-link-referenced directories are inserted into path immediately before the directory on which their links were found. Such directories are not taken into consideration by normal import mechanism, but they are traversed when doing pkg_resources.require. """ result = [] for p in sys_path: - result.append(p) # pkg_resources does not define a specific order for egg-link files # using os.listdir to enumerate them, we're sorting them to have # reproducible tests. @@ -47,6 +46,7 @@ def _get_sys_path_with_egglinks(sys_path): # pkg_resources package only interprets the first # non-empty line in egg-link files. break + result.append(p) return result diff --git a/test/test_evaluate/test_sys_path.py b/test/test_evaluate/test_sys_path.py index f7ce0fab..9635eecf 100644 --- a/test/test_evaluate/test_sys_path.py +++ b/test/test_evaluate/test_sys_path.py @@ -42,9 +42,9 @@ def test_get_venv_path(venv): site_pkgs = (glob(pjoin(venv, 'lib', 'python*', 'site-packages')) + glob(pjoin(venv, 'lib', 'site-packages')))[0] ETALON = [ - site_pkgs, pjoin('/path', 'from', 'egg-link'), pjoin(site_pkgs, '.', 'relative', 'egg-link', 'path'), + site_pkgs, pjoin(site_pkgs, 'dir-from-foo-pth'), ] From a5480c054d2727602515264723a33a672f71cec3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 14 Oct 2016 14:20:39 +0200 Subject: [PATCH 06/12] parser.utils.clear_cache: clear self.__index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a potential FileNotFoundError when clearing the cache manually, using the method from https://github.com/davidhalter/jedi-vim/pull/625. Traceback: ``` File "…/jedi/evaluate/imports.py", line 342, in _do_import module = _load_module(self._evaluator, module_path, source, sys_path, parent_module) File "…/jedi/evaluate/imports.py", line 457, in _load_module cached = load_parser(path) File "…/jedi/parser/utils.py", line 72, in load_parser return ParserPickling.load_parser(path, p_time) File "…/jedi/parser/utils.py", line 126, in load_parser with open(self._get_hashed_path(path), 'rb') as f: FileNotFoundError: [Errno 2] No such file or directory: '…/.cache/jedi/cpython-35/759d60e96c76f41ffd882d9b8d844899.pkl' ``` --- jedi/parser/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/parser/utils.py b/jedi/parser/utils.py index d64e03f5..9098b095 100644 --- a/jedi/parser/utils.py +++ b/jedi/parser/utils.py @@ -160,7 +160,6 @@ class ParserPickling(object): # 0 means version is not defined (= always delete cache): if data.get('version', 0) != self.version: self.clear_cache() - self.__index = {} else: self.__index = data['index'] return self.__index @@ -180,6 +179,7 @@ class ParserPickling(object): def clear_cache(self): shutil.rmtree(self._cache_directory()) + self.__index = {} def _get_hashed_path(self, path): return self._get_path('%s.pkl' % hashlib.md5(path.encode("utf-8")).hexdigest()) From 78573b8fa25d527d45a501019c128fc4451c4a72 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 14 Oct 2016 14:44:30 +0200 Subject: [PATCH 07/12] Fix goto_definitions being invoked on a parent class When invoking `goto_definitions` on `RequestFactory` in line 5, it would jump to `Client` after 27f05de: ```python class RequestFactory(object): pass class Client(RequestFactory): pass ``` Fixes https://github.com/davidhalter/jedi/issues/761. --- jedi/evaluate/__init__.py | 4 +++- test/completion/classes.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 37e0cd1c..9a6ad64a 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -446,7 +446,9 @@ class Evaluator(object): def_ = name.get_definition() is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: - if name.parent.type in ('file_input', 'classdef', 'funcdef'): + if name.parent.type == 'classdef' and name.parent.name == name: + return [self.wrap(name.parent)] + if name.parent.type in ('file_input', 'funcdef'): return [self.wrap(name.parent)] if def_.type == 'expr_stmt' and name in def_.get_defined_names(): return self.eval_statement(def_, name) diff --git a/test/completion/classes.py b/test/completion/classes.py index b4f67a1f..6aa226b4 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -160,6 +160,7 @@ class Mixin(SuperClass): def method_mixin(self): return int +#? 20 SuperClass class SubClass(SuperClass): class_sub = 3 def __init__(self): From a4aabc2b65186c50cfb9e04dd87fc3d25d259c8e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 4 Nov 2016 14:28:27 +0100 Subject: [PATCH 08/12] Improve documentation in test/run.py --- test/run.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/run.py b/test/run.py index 3eef7343..8337f7ce 100755 --- a/test/run.py +++ b/test/run.py @@ -25,10 +25,10 @@ multiple Python versions. .. _tox: http://testrun.org/tox Integration test cases are located in ``test/completion`` directory -and each test cases are indicated by the comment ``#?`` (completions / -definitions), ``#!`` (assignments) and ``#<`` (usages). There is also -support for third party libraries. In a normal test run they are not -being executed, you have to provide a ``--thirdparty`` option. +and each test case is indicated by either the comment ``#?`` (completions / +definitions), ``#!`` (assignments), or ``#<`` (usages). +There is also support for third party libraries. In a normal test run they are +not being executed, you have to provide a ``--thirdparty`` option. In addition to standard `-k` and `-m` options in py.test, you can use `-T` (`--test-files`) option to specify integration test cases to run. @@ -64,7 +64,7 @@ happening. Auto-Completion +++++++++++++++ -Uses comments to specify a test in the next line. The comment says, which +Uses comments to specify a test in the next line. The comment says which results are expected. The comment always begins with `#?`. The last row symbolizes the cursor. @@ -94,8 +94,8 @@ Tests look like this:: #! ['abc=1'] abc -Additionally it is possible to add a number which describes to position of -the test (otherwise it's just end of line):: +Additionally it is possible to specify the column by adding a number, which +describes the position of the test (otherwise it's just the end of line):: #! 2 ['abc=1'] abc From 94dc563d8adf09241028fe0d30271d1439dcfdfd Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 14 Oct 2016 14:18:53 +0200 Subject: [PATCH 09/12] tox: use posargs ("jedi test") for py.test command Without this it would collect tests from other dirs also by default. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index dadbb2fe..97b77a14 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ setenv = # tox corrupts __pycache__, solution from here: PYTHONDONTWRITEBYTECODE=1 commands = - py.test [] + py.test {posargs:jedi test} [testenv:py26] deps = unittest2 From a51475d265fab0361c35608a3204dbbd0c5a1df8 Mon Sep 17 00:00:00 2001 From: cologler Date: Wed, 9 Nov 2016 07:48:45 +0800 Subject: [PATCH 10/12] Update __init__.py fix the source file read mode issue. if use 'r' mode, this may raise a `UnicodeDecodeError`. --- jedi/api/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 491c5e2e..d4439100 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -105,7 +105,7 @@ class Script(object): if source is None: # TODO add a better warning than the traceback! - with open(path) as f: + with open(path, 'rb') as f: source = f.read() self._source = common.source_to_unicode(source, encoding) From 14e722ff13d6c2dbda0fe4a2de4e4f8151686c57 Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Wed, 28 Dec 2016 14:58:44 -0500 Subject: [PATCH 11/12] parser: add grammar3.6 I manually replicated the changes that were applied to grammar3.5. --- jedi/parser/grammar3.6.txt | 161 +++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 jedi/parser/grammar3.6.txt diff --git a/jedi/parser/grammar3.6.txt b/jedi/parser/grammar3.6.txt new file mode 100644 index 00000000..b44a5698 --- /dev/null +++ b/jedi/parser/grammar3.6.txt @@ -0,0 +1,161 @@ +# Grammar for Python + +# Note: Changing the grammar specified in this file will most likely +# require corresponding changes in the parser module +# (../Modules/parsermodule.c). If you can't make the changes to +# that module yourself, please co-ordinate the required changes +# with someone who can; ask around on python-dev for help. Fred +# Drake will probably be listening there. + +# NOTE WELL: You should also follow all the steps listed at +# https://docs.python.org/devguide/grammar.html + +# Start symbols for the grammar: +# file_input is a module or sequence of commands read from an input file; +# single_input is a single interactive statement; +# eval_input is the input for the eval() functions. +# NB: compound_stmt in single_input is followed by extra NEWLINE! +file_input: (NEWLINE | stmt)* ENDMARKER +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +eval_input: testlist NEWLINE* ENDMARKER + +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE +decorators: decorator+ +decorated: decorators (classdef | funcdef | async_funcdef) + +# NOTE: Francisco Souza/Reinoud Elhorst, using ASYNC/'await' keywords instead of +# skipping python3.5+ compatibility, in favour of 3.7 solution +async_funcdef: 'async' funcdef +funcdef: 'def' NAME parameters ['->' test] ':' suite + +parameters: '(' [typedargslist] ')' +typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [ + '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']]] + | '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']) +tfpdef: NAME [':' test] +varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [ + '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [',']]] + | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [','] +) +vfpdef: NAME + +stmt: simple_stmt | compound_stmt +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE +small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | nonlocal_stmt | assert_stmt) +expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | + ('=' (yield_expr|testlist_star_expr))*) +annassign: ':' test ['=' test] +testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] +augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | + '<<=' | '>>=' | '**=' | '//=') +# For normal and annotated assignments, additional restrictions enforced by the interpreter +del_stmt: 'del' exprlist +pass_stmt: 'pass' +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +break_stmt: 'break' +continue_stmt: 'continue' +return_stmt: 'return' [testlist] +yield_stmt: yield_expr +raise_stmt: 'raise' [test ['from' test]] +import_stmt: import_name | import_from +import_name: 'import' dotted_as_names +# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS +import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)) +import_as_name: NAME ['as' NAME] +dotted_as_name: dotted_name ['as' NAME] +import_as_names: import_as_name (',' import_as_name)* [','] +dotted_as_names: dotted_as_name (',' dotted_as_name)* +dotted_name: NAME ('.' NAME)* +global_stmt: 'global' NAME (',' NAME)* +nonlocal_stmt: 'nonlocal' NAME (',' NAME)* +assert_stmt: 'assert' test [',' test] + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt +async_stmt: 'async' (funcdef | with_stmt | for_stmt) +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +while_stmt: 'while' test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] +try_stmt: ('try' ':' suite + ((except_clause ':' suite)+ + ['else' ':' suite] + ['finally' ':' suite] | + 'finally' ':' suite)) +with_stmt: 'with' with_item (',' with_item)* ':' suite +with_item: test ['as' expr] +# NB compile.c makes sure that the default except clause is last +except_clause: 'except' [test ['as' NAME]] +# Edit by Francisco Souza/David Halter: The stmt is now optional. This reflects +# how Jedi allows classes and functions to be empty, which is beneficial for +# autocompletion. +suite: simple_stmt | NEWLINE INDENT stmt* DEDENT + +test: or_test ['if' or_test 'else' test] | lambdef +test_nocond: or_test | lambdef_nocond +lambdef: 'lambda' [varargslist] ':' test +lambdef_nocond: 'lambda' [varargslist] ':' test_nocond +or_test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +# <> isn't actually a valid comparison operator in Python. It's here for the +# sake of a __future__ import described in PEP 401 (which really works :-) +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' +star_expr: '*' expr +expr: xor_expr ('|' xor_expr)* +xor_expr: and_expr ('^' and_expr)* +and_expr: shift_expr ('&' shift_expr)* +shift_expr: arith_expr (('<<'|'>>') arith_expr)* +arith_expr: term (('+'|'-') term)* +term: factor (('*'|'@'|'/'|'%'|'//') factor)* +factor: ('+'|'-'|'~') factor | power +power: atom_expr ['**' factor] +atom_expr: ['await'] atom trailer* +atom: ('(' [yield_expr|testlist_comp] ')' | + '[' [testlist_comp] ']' | + '{' [dictorsetmaker] '}' | + NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') +testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME +subscriptlist: subscript (',' subscript)* [','] +subscript: test | [test] ':' [test] [sliceop] +sliceop: ':' [test] +exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] +testlist: test (',' test)* [','] +dictorsetmaker: ( ((test ':' test | '**' expr) + (comp_for | (',' (test ':' test | '**' expr))* [','])) | + ((test | star_expr) + (comp_for | (',' (test | star_expr))* [','])) ) + +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite + +arglist: argument (',' argument)* [','] + +# The reason that keywords are test nodes instead of NAME is that using NAME +# results in an ambiguity. ast.c makes sure it's a NAME. +# "test '=' test" is really "keyword '=' test", but we have no such token. +# These need to be in a single rule to avoid grammar that is ambiguous +# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, +# we explicitly match '*' here, too, to give it proper precedence. +# Illegal combinations and orderings are blocked in ast.c: +# multiple (test comp_for) arguments are blocked; keyword unpackings +# that precede iterable unpackings are blocked; etc. +argument: ( test [comp_for] | + test '=' test | + '**' test | + '*' test ) + +comp_iter: comp_for | comp_if +comp_for: ['async'] 'for' exprlist 'in' or_test [comp_iter] +comp_if: 'if' test_nocond [comp_iter] + +# not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME + +yield_expr: 'yield' [yield_arg] +yield_arg: 'from' test | testlist From 65371ca59a8df4aa930d44e91107a722dfd8f937 Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Fri, 30 Dec 2016 22:18:23 -0500 Subject: [PATCH 12/12] travis: add support for Python 3.6 and use tox-travis --- .travis.yml | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25c3a21e..e51e2c9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,25 @@ language: python -python: 3.5 sudo: false -env: - - TOXENV=py26 - - TOXENV=py27 - - TOXENV=py33 - - TOXENV=py34 - - TOXENV=py35 - - TOXENV=pypy - - TOXENV=cov - - TOXENV=sith +python: + - 2.6 + - 2.7 + - 3.3 + - 3.4 + - 3.5 + - 3.6 + - pypy matrix: - allow_failures: - - env: TOXENV=cov - - env: TOXENV=sith - - env: TOXENV=pypy -python: 3.5 + allow_failures: + - python: pypy + - env: TOXENV=cov + - env: TOXENV=sith + include: + - python: 3.5 + env: TOXENV=cov + - python: 3.5 + env: TOXENV=sith install: - - pip install --quiet tox + - pip install --quiet tox-travis script: - tox after_script: