Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jedi 0.18 update #354

Merged
merged 8 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
os: linux
dist: xenial
sudo: false
language: python
git:
depth: 3
python:
# First python version in this list is the default for matrix.include
# - "3.7"
- "3.7"
- "3.9"
- "3.8"
- "3.6"
- "3.5"
- "3.4"
- "2.7"
env:
matrix:
- EVM_EMACS=emacs-26.3-travis-linux-xenial
- EVM_EMACS=emacs-27.1-travis-linux-xenial
global:
# Turn on --use-mirrors option everywhere (even in tox):
- PIP_USE_MIRRORS=t
# Turn on --use-mirrors option everywhere (even in tox):
- PIP_USE_MIRRORS=t
matrix:
include:
- env: EVM_EMACS=emacs-24.4-travis
- env: EVM_EMACS=emacs-24.5-travis
- env: EVM_EMACS=emacs-25.1-travis
- env: EVM_EMACS=emacs-25.2-travis
- env: EVM_EMACS=emacs-25.3-travis
- env: EVM_EMACS=emacs-26.1-travis-linux-xenial
- env: EVM_EMACS=emacs-26.2-travis-linux-xenial
- env: EVM_EMACS=emacs-26.3-travis-linux-xenial
- env: EVM_EMACS=emacs-27.1-travis-linux-xenial
- env: EVM_EMACS=emacs-git-snapshot-travis-linux-xenial

before_install:
- pip install -q virtualenv tox tox-travis
- curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh
- curl -fsSL https://raw.githubusercontent.com/cask/cask/v0.8.5/go | python
- export PATH="/home/travis/.cask/bin:$PATH"
- git clone https://github.com/rejeep/evm.git /home/travis/.evm
- export PATH="/home/travis/.evm/bin:$PATH"
- evm config path /tmp
- evm install $EVM_EMACS --use --skip
- evm list
- emacs --version
- cask
- make before-test

script:
make travis-ci
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ ELPA_DIR = $(shell EMACS=$(EMACS) $(CASK) package-directory)
# See: cask-elpa-dir

VIRTUAL_EMACS = ${CASK} exec ${EMACS} -Q \
--eval "(setq python-environment--verbose t)" \
--eval "(setq jedi:environment-root \"$(ENV)\")"

.PHONY : test test-1 tryout clean-elpa requirements env clean-env clean \
Expand Down
14 changes: 7 additions & 7 deletions jedi-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
;; Package-Requires: ((emacs "24") (epc "0.1.0") (python-environment "0.0.2") (cl-lib "0.5"))
;; Version: 0.2.8
;; Version: 0.3.0

;; This file is NOT part of GNU Emacs.

Expand Down Expand Up @@ -41,7 +41,7 @@
:group 'completion
:prefix "jedi:")

(defconst jedi:version "0.2.8")
(defconst jedi:version "0.3.0")

(defvar jedi:source-dir (if load-file-name
(file-name-directory load-file-name)
Expand Down Expand Up @@ -714,12 +714,12 @@ See: https://github.com/tkf/emacs-jedi/issues/54"
(substring-no-properties (or (buffer-file-name) "")))

(defun jedi:call-deferred (method-name)
"Call ``Script(...).METHOD-NAME`` and return a deferred object."
"Call ``Script(...).METHOD-NAME()`` and return a deferred object."
(let ((source (buffer-substring-no-properties (point-min) (point-max)))
(source-path (jedi:-buffer-file-name))
;; line=0 is an error for jedi, but is possible for empty buffers.
(line (max 1 (count-lines (point-min) (min (1+ (point)) (point-max)))))
(column (- (point) (line-beginning-position)))
(source-path (jedi:-buffer-file-name)))
(column (- (point) (line-beginning-position))))
(epc:call-deferred (jedi:get-epc)
method-name
(list source line column source-path))))
Expand Down Expand Up @@ -1028,13 +1028,13 @@ It must take these arguments: (file-to-read other-window-flag line_number column
initially (erase-buffer)
for def in reply
do (cl-destructuring-bind
(&key doc desc_with_module &allow-other-keys)
(&key doc full_name &allow-other-keys)
def
(unless (or (null doc) (equal doc ""))
(if first
(setq first nil)
(insert "\n\n---\n\n"))
(insert "Docstring for " desc_with_module "\n\n" doc)
(insert "Docstring for " full_name "\n\n" doc)
(setq has-doc t)))
finally do
(if (not has-doc)
Expand Down
136 changes: 81 additions & 55 deletions jediepcserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import re
import site
import sys
import pkg_resources
from collections import namedtuple

import jedi
Expand Down Expand Up @@ -125,6 +126,50 @@ def jedi_create_environment(venv, safe=False):
_cached_jedi_environments[venv] = jedienv
return jedienv

jedi_script_wrapper = jedi.Script
JEDI_VERSION = pkg_resources.parse_version(jedi.__version__)
if JEDI_VERSION < pkg_resources.parse_version('0.16.0'):
class JediScriptCompatWrapper:
def __init__(self, code, path, **kwargs):
self.source = code
self.source_path = path
self.kwargs = kwargs

def complete(self, line, column):
return jedi.Script(self.source,
line, column,
self.source_path,
**self.kwargs).completions()

def get_signatures(self, line, column):
return jedi.Script(self.source,
line, column,
self.source_path,
**self.kwargs).call_signatures()

def goto(self, line, column):
return jedi.Script(self.source,
line, column,
self.source_path,
**self.kwargs).goto_assignments()

def get_references(self, line, column):
return jedi.Script(self.source,
line, column,
self.source_path,
**self.kwargs).usages()

def infer(self, line, column):
return jedi.Script(self.source,
line, column,
self.source_path,
**self.kwargs).goto_definitions()

def get_names(self):
return jedi.api.names(self.source, self.source_path, **self.kwargs)

jedi_script_wrapper = JediScriptCompatWrapper


def get_venv_sys_path(venv):
if jedi_create_environment is not None:
Expand All @@ -134,11 +179,9 @@ def get_venv_sys_path(venv):


class JediEPCHandler(object):
def __init__(self, sys_path=(), virtual_envs=(), sys_path_append=()):
self.script_kwargs = self._get_script_path_kwargs(
sys_path=sys_path,
virtual_envs=virtual_envs,
sys_path_append=sys_path_append,
def __init__(self, sys_path=None, virtual_envs=None, sys_path_append=None):
self.script_kwargs = JediEPCHandler._get_script_path_kwargs(
sys_path, virtual_envs, sys_path_append
)

def get_sys_path(self):
Expand All @@ -150,8 +193,8 @@ def get_sys_path(self):
return sys_path
return sys.path

@classmethod
def _get_script_path_kwargs(cls, sys_path, virtual_envs, sys_path_append):
@staticmethod
def _get_script_path_kwargs(sys_path, virtual_envs, sys_path_append):
result = {}
if jedi_create_environment:
# Need to specify some environment explicitly to workaround
Expand All @@ -178,9 +221,11 @@ def _get_script_path_kwargs(cls, sys_path, virtual_envs, sys_path_append):
# Either multiple environments or custom sys_path extensions are
# specified, or jedi version doesn't support environments.
final_sys_path = []
sys_path = () if sys_path is None else sys_path
final_sys_path.extend(path_expand_vars_and_user(p) for p in sys_path)
for p in virtual_envs:
final_sys_path.extend(get_venv_sys_path(path_expand_vars_and_user(p)))
sys_path_append = () if sys_path_append is None else sys_path_append
final_sys_path.extend(
path_expand_vars_and_user(p) for p in sys_path_append
)
Expand All @@ -194,15 +239,13 @@ def not_seen_yet(val):
result['sys_path'] = [p for p in final_sys_path if not_seen_yet(p)]
return result

def jedi_script(self, source, line, column, source_path):
def jedi_script(self, source, source_path):
if NEED_ENCODE:
source = source.encode('utf-8')
source_path = source_path and source_path.encode('utf-8')
return jedi.Script(
source, line, column, source_path or '', **self.script_kwargs
)
return jedi_script_wrapper(code=source, path=source_path, **self.script_kwargs)

def complete(self, *args):
def complete(self, source, line, column, source_path):
def _wrap_completion_result(comp):
try:
docstr = comp.docstring()
Expand All @@ -217,14 +260,13 @@ def _wrap_completion_result(comp):
description=candidates_description(comp),
symbol=candidate_symbol(comp),
)

return [
_wrap_completion_result(comp)
for comp in self.jedi_script(*args).completions()
for comp in self.jedi_script(source, source_path).complete(line, column)
]

def get_in_function_call(self, *args):
sig = self.jedi_script(*args).call_signatures()
def get_in_function_call(self, source, line, column, source_path):
sig = self.jedi_script(source, source_path).get_signatures(line, column)
call_def = sig[0] if sig else None

if not call_def:
Expand All @@ -239,45 +281,22 @@ def get_in_function_call(self, *args):
call_name=call_def.name,
)

def _goto(self, method, *args):
"""
Helper function for `goto_assignments` and `usages`.

:arg method: `jedi.Script.goto_assignments` or `jedi.Script.usages`
:arg args: Arguments to `jedi_script`

"""
# `definitions` is a list. Each element is an instances of
# `jedi.api_classes.BaseOutput` subclass, i.e.,
# `jedi.api_classes.RelatedName` or `jedi.api_classes.Definition`.
definitions = method(self.jedi_script(*args))
return [dict(
column=d.column,
line_nr=d.line,
module_path=d.module_path if d.module_path != '__builtin__' else [],
module_name=d.module_name,
description=d.description,
) for d in definitions]

def goto(self, *args):
return self._goto(jedi.Script.goto_assignments, *args)
def goto(self, source, line, column, source_path):
definitions = self.jedi_script(source, source_path).goto(line, column)
return [definition_to_short_dict(d) for d in definitions]

def related_names(self, *args):
return self._goto(jedi.Script.usages, *args)
def related_names(self, source, line, column, source_path):
definitions = self.jedi_script(source, source_path).get_references(line, column)
return [definition_to_short_dict(d) for d in definitions]

def get_definition(self, *args):
definitions = self.jedi_script(*args).goto_definitions()
def get_definition(self, source, line, column, source_path):
definitions = self.jedi_script(source, source_path).infer(line, column)
return [definition_to_dict(d) for d in definitions]

def defined_names(self, *args):
# XXX: there's a bug in Jedi that returns returns definitions from inside
# classes or functions even though all_scopes=False is set by
# default. Hence some additional filtering is in order.
#
# See https://github.com/davidhalter/jedi/issues/1202
def defined_names(self, source, source_path):
top_level_names = [
defn
for defn in jedi.api.names(*args)
for defn in self.jedi_script(source, source_path).get_names()
if defn.parent().type == 'module'
]
return list(map(get_names_recursively, top_level_names))
Expand All @@ -295,7 +314,7 @@ def candidate_symbol(comp):
Return a character representing completion type.

:type comp: jedi.api.Completion
:arg comp: A completion object returned by `jedi.Script.completions`.
:arg comp: A completion object returned by `jedi.Script.complete`.

"""
try:
Expand Down Expand Up @@ -326,15 +345,22 @@ def definition_to_dict(d):
return dict(
doc=d.docstring(),
description=d.description,
desc_with_module=d.desc_with_module,
line_nr=d.line,
column=d.column,
module_path=d.module_path,
name=getattr(d, 'name', []),
full_name=getattr(d, 'full_name', []),
type=getattr(d, 'type', []),
module_path=str(d.module_path),
name=getattr(d, 'name', '?'),
full_name=getattr(d, 'full_name', '?'),
type=getattr(d, 'type', '?'),
)

def definition_to_short_dict(d):
return dict(
column=d.column,
line_nr=d.line,
module_path=str(d.module_path) if d.module_path != '__builtin__' else '',
module_name=d.module_name,
description=d.description,
)

def get_names_recursively(definition, parent=None):
"""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setup(
name='jediepcserver',
version='0.2.8',
version='0.3.0',
py_modules=['jediepcserver'],
install_requires=[
"jedi>=0.11.0",
Expand Down
22 changes: 14 additions & 8 deletions test-jedi.el
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,14 @@ json.load
"
(goto-char (1- (point-max)))
(let ((reply (jedi-testing:sync (jedi:call-deferred 'goto))))
(destructuring-bind (&key line_nr module_path
column module_name description)
(destructuring-bind (&key column line_nr module_path
module_name description)
(car reply)
(should (integerp column))
(should (integerp line_nr))
(should (stringp module_path))))))
(should (stringp module_path))
(should (stringp module_name))
(should (stringp description))))))

(ert-deftest jedi:get-definition-request ()
(with-python-temp-buffer
Expand All @@ -101,14 +104,17 @@ json.load
"
(goto-char (1- (point-max)))
(let ((reply (jedi-testing:sync (jedi:call-deferred 'get_definition))))
(destructuring-bind (&key doc desc_with_module line_nr column module_path
full_name name type description)
(destructuring-bind (&key doc description line_nr column module_path
name full_name type)
(car reply)
(should (stringp doc))
(should (stringp desc_with_module))
(should (stringp description))
(should (integerp line_nr))
(should (integerp column))
(should (stringp module_path))))))
(should (stringp module_path))
(should (stringp name))
(should (stringp full_name))
(should (stringp type))))))

(ert-deftest jedi:show-version-info ()
(kill-buffer (get-buffer-create "*jedi:version*"))
Expand Down Expand Up @@ -296,7 +302,7 @@ if True:
(search-forward "func(x)")
(goto-char (match-beginning 0))
(let ((reply (jedi-testing:sync (jedi:call-deferred 'get_definition))))
(destructuring-bind (&key doc desc_with_module line_nr column module_path
(destructuring-bind (&key doc line_nr column module_path
full_name name type description)
(car reply)
(should (= line_nr def-line)))))))
Expand Down
Loading