mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 23:34:45 +08:00
Merge master into linter.
This commit is contained in:
@@ -34,5 +34,6 @@ Phillip Berndt (@phillipberndt) <phillip.berndt@gmail.com>
|
||||
Ian Lee (@IanLee1521) <IanLee1521@gmail.com>
|
||||
Farkhad Khatamov (@hatamov) <comsgn@gmail.com>
|
||||
Kevin Kelley (@kelleyk) <kelleyk@kelleyk.net>
|
||||
Sid Shanker (@squidarth) <sid.p.shanker@gmail.com>
|
||||
|
||||
Note: (@user) means a github user name.
|
||||
|
||||
10
README.rst
10
README.rst
@@ -33,12 +33,14 @@ It's really easy.
|
||||
Jedi can currently be used with the following editors:
|
||||
|
||||
- Vim (jedi-vim_, YouCompleteMe_)
|
||||
- Emacs (Jedi.el_, elpy_, anaconda-mode_, ycmd_)
|
||||
- Emacs (Jedi.el_, company-mode_, elpy_, anaconda-mode_, ycmd_)
|
||||
- Sublime Text (SublimeJEDI_ [ST2 + ST3], anaconda_ [only ST3])
|
||||
- SynWrite_
|
||||
- TextMate_ (Not sure if it's actually working)
|
||||
- Kate_ version 4.13+ supports it natively, you have to enable it, though. [`proof
|
||||
<https://projects.kde.org/projects/kde/applications/kate/repository/show?rev=KDE%2F4.13>`_]
|
||||
- Atom_ (autocomplete-python_)
|
||||
- SourceLair_
|
||||
|
||||
And it powers the following projects:
|
||||
|
||||
@@ -95,7 +97,7 @@ You can run Jedi on cPython 2.6, 2.7, 3.2, 3.3 or 3.4, but it should also
|
||||
understand/parse code older than those versions.
|
||||
|
||||
Tips on how to use Jedi efficiently can be found `here
|
||||
<https://jedi.readthedocs.org/en/latest/docs/recipes.html>`_.
|
||||
<https://jedi.readthedocs.org/en/latest/docs/features.html#recipes>`_.
|
||||
|
||||
API
|
||||
---
|
||||
@@ -176,6 +178,7 @@ For more detailed information visit the `testing documentation
|
||||
.. _jedi-vim: https://github.com/davidhalter/jedi-vim
|
||||
.. _youcompleteme: http://valloric.github.io/YouCompleteMe/
|
||||
.. _Jedi.el: https://github.com/tkf/emacs-jedi
|
||||
.. _company-mode: https://github.com/syohex/emacs-company-jedi
|
||||
.. _elpy: https://github.com/jorgenschaefer/elpy
|
||||
.. _anaconda-mode: https://github.com/proofit404/anaconda-mode
|
||||
.. _ycmd: https://github.com/abingham/emacs-ycmd
|
||||
@@ -185,3 +188,6 @@ For more detailed information visit the `testing documentation
|
||||
.. _wdb: https://github.com/Kozea/wdb
|
||||
.. _TextMate: https://github.com/lawrenceakka/python-jedi.tmbundle
|
||||
.. _Kate: http://kate-editor.org
|
||||
.. _Atom: https://atom.io/
|
||||
.. _autocomplete-python: https://atom.io/packages/autocomplete-python
|
||||
.. _SourceLair: https://www.sourcelair.com
|
||||
|
||||
@@ -47,6 +47,14 @@ Kate:
|
||||
<https://projects.kde.org/projects/kde/applications/kate/repository/entry/addons/kate/pate/src/plugins/python_autocomplete_jedi.py?rev=KDE%2F4.13>`__,
|
||||
you have to enable it, though.
|
||||
|
||||
Atom:
|
||||
|
||||
- autocomplete-python_
|
||||
|
||||
SourceLair:
|
||||
|
||||
- SourceLair_
|
||||
|
||||
|
||||
.. _other-software:
|
||||
|
||||
@@ -86,3 +94,5 @@ Using a custom ``$HOME/.pythonrc.py``
|
||||
.. _wdb: https://github.com/Kozea/wdb
|
||||
.. _TextMate: https://github.com/lawrenceakka/python-jedi.tmbundle
|
||||
.. _kate: http://kate-editor.org/
|
||||
.. _autocomplete-python: https://atom.io/packages/autocomplete-python
|
||||
.. _SourceLair: https://www.sourcelair.com
|
||||
|
||||
@@ -76,8 +76,8 @@ class Script(object):
|
||||
:type source: str
|
||||
:param line: The line to perform actions on (starting with 1).
|
||||
:type line: int
|
||||
:param col: The column of the cursor (starting with 0).
|
||||
:type col: int
|
||||
:param column: The column of the cursor (starting with 0).
|
||||
:type column: int
|
||||
:param path: The path of the file in the file system, or ``''`` if
|
||||
it hasn't been saved yet.
|
||||
:type path: str or None
|
||||
@@ -179,7 +179,7 @@ class Script(object):
|
||||
if unfinished_dotted:
|
||||
return completion_names
|
||||
else:
|
||||
return keywords.keyword_names(self._evaluator, 'import')
|
||||
return set([keywords.keyword(self._evaluator, 'import').name])
|
||||
|
||||
if isinstance(user_stmt, tree.Import):
|
||||
module = self._parser.module()
|
||||
@@ -190,7 +190,11 @@ class Script(object):
|
||||
if names is None and not isinstance(user_stmt, tree.Import):
|
||||
if not path and not dot:
|
||||
# add keywords
|
||||
completion_names += keywords.keyword_names(self._evaluator, all=True)
|
||||
completion_names += keywords.completion_names(
|
||||
self._evaluator,
|
||||
user_stmt,
|
||||
self._pos,
|
||||
module)
|
||||
# TODO delete? We should search for valid parser
|
||||
# transformations.
|
||||
completion_names += self._simple_complete(path, dot, like)
|
||||
|
||||
@@ -4,7 +4,7 @@ import keyword
|
||||
from jedi._compatibility import is_py3
|
||||
from jedi import common
|
||||
from jedi.evaluate.helpers import FakeName
|
||||
|
||||
from jedi.parser.tree import Leaf
|
||||
try:
|
||||
from pydoc_data import topics as pydoc_topics
|
||||
except ImportError:
|
||||
@@ -17,22 +17,50 @@ else:
|
||||
keys = keyword.kwlist + ['None', 'False', 'True']
|
||||
|
||||
|
||||
def keywords(evaluator, string='', pos=(0, 0), all=False):
|
||||
if all:
|
||||
def has_inappropriate_leaf_keyword(pos, module):
|
||||
relevant_errors = filter(
|
||||
lambda error: error.first_pos[0] == pos[0],
|
||||
module.error_statement_stacks)
|
||||
|
||||
for error in relevant_errors:
|
||||
if error.next_token in keys:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def completion_names(evaluator, stmt, pos, module):
|
||||
keyword_list = all_keywords(evaluator)
|
||||
|
||||
if not isinstance(stmt, Leaf) or has_inappropriate_leaf_keyword(pos, module):
|
||||
keyword_list = filter(
|
||||
lambda keyword: not keyword.only_valid_as_leaf,
|
||||
keyword_list
|
||||
)
|
||||
return [keyword.name for keyword in keyword_list]
|
||||
|
||||
|
||||
def all_keywords(evaluator, pos=(0, 0)):
|
||||
return set([Keyword(evaluator, k, pos) for k in keys])
|
||||
|
||||
|
||||
def keyword(evaluator, string, pos=(0, 0)):
|
||||
if string in keys:
|
||||
return set([Keyword(evaluator, string, pos)])
|
||||
return set()
|
||||
|
||||
|
||||
def keyword_names(evaluator, *args, **kwargs):
|
||||
return [k.name for k in keywords(evaluator, *args, **kwargs)]
|
||||
return Keyword(evaluator, string, pos)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_operator(evaluator, string, pos):
|
||||
return Keyword(evaluator, string, pos)
|
||||
|
||||
|
||||
keywords_only_valid_as_leaf = (
|
||||
'continue',
|
||||
'break',
|
||||
)
|
||||
|
||||
|
||||
class Keyword(object):
|
||||
def __init__(self, evaluator, name, pos):
|
||||
self.name = FakeName(name, self, pos)
|
||||
@@ -42,6 +70,10 @@ class Keyword(object):
|
||||
def get_parent_until(self):
|
||||
return self.parent
|
||||
|
||||
@property
|
||||
def only_valid_as_leaf(self):
|
||||
return self.name.value in keywords_only_valid_as_leaf
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
""" For a `parsing.Name` like comparision """
|
||||
|
||||
@@ -207,6 +207,21 @@ class dict():
|
||||
return d
|
||||
|
||||
|
||||
class enumerate():
|
||||
def __init__(self, sequence, start=0):
|
||||
self.__sequence = sequence
|
||||
|
||||
def __iter__(self):
|
||||
for i in self.__sequence:
|
||||
yield 1, i
|
||||
|
||||
def __next__(self):
|
||||
return next(self.__iter__())
|
||||
|
||||
def next(self):
|
||||
return next(self.__iter__())
|
||||
|
||||
|
||||
class reversed():
|
||||
def __init__(self, sequence):
|
||||
self.__sequence = sequence
|
||||
|
||||
@@ -305,6 +305,10 @@ class LeafWithNewLines(Leaf):
|
||||
return end_pos_line, end_pos_col
|
||||
|
||||
|
||||
@utf8_repr
|
||||
def __repr__(self):
|
||||
return "<%s: %r>" % (type(self).__name__, self.value)
|
||||
|
||||
class Whitespace(LeafWithNewLines):
|
||||
"""Contains NEWLINE and ENDMARKER tokens."""
|
||||
__slots__ = ()
|
||||
|
||||
@@ -51,6 +51,26 @@ left
|
||||
#? int()
|
||||
[a for a in {1:'x'}][0]
|
||||
|
||||
##? str()
|
||||
{a-1:b for a,b in {1:'a', 3:1.0}.items()}[0]
|
||||
|
||||
# with a set literal
|
||||
#? int()
|
||||
[a for a in {1, 2, 3}][0]
|
||||
|
||||
##? set()
|
||||
{a for a in range(10)}
|
||||
|
||||
##? int()
|
||||
[x for x in {a for a in range(10)}][0]
|
||||
|
||||
##? int()
|
||||
{a for a in range(10)}.pop()
|
||||
|
||||
##? int()
|
||||
iter({a for a in range(10)}).next()
|
||||
|
||||
|
||||
# list comprehensions should also work in combination with functions
|
||||
def listen(arg):
|
||||
for x in arg:
|
||||
|
||||
@@ -4,3 +4,24 @@ raise
|
||||
|
||||
#? ['except', 'Exception']
|
||||
except
|
||||
|
||||
#? []
|
||||
b + continu
|
||||
|
||||
#? []
|
||||
b + continue
|
||||
|
||||
#? ['continue']
|
||||
b; continue
|
||||
|
||||
#? ['continue']
|
||||
b; continu
|
||||
|
||||
#? []
|
||||
c + brea
|
||||
|
||||
#? []
|
||||
a + break
|
||||
|
||||
#? ['break']
|
||||
b; break
|
||||
|
||||
@@ -65,6 +65,15 @@ class X(): pass
|
||||
#? type
|
||||
type(X)
|
||||
|
||||
# -----------------
|
||||
# enumerate
|
||||
# -----------------
|
||||
for i, j in enumerate(["as", "ad"]):
|
||||
#? int()
|
||||
i
|
||||
#? str()
|
||||
j
|
||||
|
||||
# -----------------
|
||||
# re
|
||||
# -----------------
|
||||
|
||||
@@ -295,9 +295,12 @@ def collect_dir_tests(base_dir, test_files, check_thirdparty=False):
|
||||
skip = 'Thirdparty-Library %s not found.' % lib
|
||||
|
||||
path = os.path.join(base_dir, f_name)
|
||||
source = open(path).read()
|
||||
if not is_py3:
|
||||
source = unicode(source, 'UTF-8')
|
||||
|
||||
if is_py3:
|
||||
source = open(path, encoding='utf-8').read()
|
||||
else:
|
||||
source = unicode(open(path).read(), 'UTF-8')
|
||||
|
||||
for case in collect_file_tests(StringIO(source),
|
||||
lines_to_execute):
|
||||
case.path = path
|
||||
|
||||
Reference in New Issue
Block a user