Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 0 additions & 27 deletions pyls/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,33 +89,6 @@ def _merge_dicts_(a, b):
return dict(_merge_dicts_(dict_a, dict_b))


def race_hooks(hook_caller, pool, **kwargs):
"""Given a pluggy hook spec, execute impls in parallel returning the first non-None result.

Note this does not support a lot of pluggy functionality, e.g. hook wrappers.
"""
impls = hook_caller._nonwrappers + hook_caller._wrappers
log.debug("Racing hook impls for hook %s: %s", hook_caller, impls)

if not impls:
return None

def _apply(impl):
try:
return impl, impl.function(**kwargs)
except Exception:
log.exception("Failed to run hook %s", impl.plugin_name)
raise

# imap unordered gives us an iterator over the items in the order they finish.
# We have to be careful to set chunksize to 1 to ensure hooks each get their own thread.
# Unfortunately, there's no way to interrupt these threads, so we just have to leave them be.
for impl, result in pool.imap_unordered(_apply, impls, chunksize=1):
if result is not None:
log.debug("Hook from plugin %s returned: %s", impl.plugin_name, result)
return result


def format_docstring(contents):
"""Python doc strings come in a number of formats, but LSP wants markdown.

Expand Down
70 changes: 33 additions & 37 deletions pyls/plugins/jedi_completion.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
from pyls.lsp import CompletionItemKind
from pyls import hookimpl, _utils
from pyls import hookimpl, lsp, _utils

log = logging.getLogger(__name__)


@hookimpl
def pyls_completions(document, position):
log.debug('Launching Jedi')
definitions = document.jedi_script(position).completions()
definitions = [{
return [{
'label': _label(d),
'kind': _kind(d),
'detail': _detail(d),
'documentation': _utils.format_docstring(d.docstring()),
'sortText': _sort_text(d),
'insertText': d.name
} for d in definitions]
log.debug('Jedi finished')
return definitions
} for d in definitions] or None


def _label(definition):
Expand Down Expand Up @@ -53,36 +49,36 @@ def _sort_text(definition):
def _kind(d):
""" Return the VSCode type """
MAP = {
'none': CompletionItemKind.Value,
'type': CompletionItemKind.Class,
'tuple': CompletionItemKind.Class,
'dict': CompletionItemKind.Class,
'dictionary': CompletionItemKind.Class,
'function': CompletionItemKind.Function,
'lambda': CompletionItemKind.Function,
'generator': CompletionItemKind.Function,
'class': CompletionItemKind.Class,
'instance': CompletionItemKind.Reference,
'method': CompletionItemKind.Method,
'builtin': CompletionItemKind.Class,
'builtinfunction': CompletionItemKind.Function,
'module': CompletionItemKind.Module,
'file': CompletionItemKind.File,
'xrange': CompletionItemKind.Class,
'slice': CompletionItemKind.Class,
'traceback': CompletionItemKind.Class,
'frame': CompletionItemKind.Class,
'buffer': CompletionItemKind.Class,
'dictproxy': CompletionItemKind.Class,
'funcdef': CompletionItemKind.Function,
'property': CompletionItemKind.Property,
'import': CompletionItemKind.Module,
'keyword': CompletionItemKind.Keyword,
'constant': CompletionItemKind.Variable,
'variable': CompletionItemKind.Variable,
'value': CompletionItemKind.Value,
'param': CompletionItemKind.Variable,
'statement': CompletionItemKind.Keyword,
'none': lsp.CompletionItemKind.Value,
'type': lsp.CompletionItemKind.Class,
'tuple': lsp.CompletionItemKind.Class,
'dict': lsp.CompletionItemKind.Class,
'dictionary': lsp.CompletionItemKind.Class,
'function': lsp.CompletionItemKind.Function,
'lambda': lsp.CompletionItemKind.Function,
'generator': lsp.CompletionItemKind.Function,
'class': lsp.CompletionItemKind.Class,
'instance': lsp.CompletionItemKind.Reference,
'method': lsp.CompletionItemKind.Method,
'builtin': lsp.CompletionItemKind.Class,
'builtinfunction': lsp.CompletionItemKind.Function,
'module': lsp.CompletionItemKind.Module,
'file': lsp.CompletionItemKind.File,
'xrange': lsp.CompletionItemKind.Class,
'slice': lsp.CompletionItemKind.Class,
'traceback': lsp.CompletionItemKind.Class,
'frame': lsp.CompletionItemKind.Class,
'buffer': lsp.CompletionItemKind.Class,
'dictproxy': lsp.CompletionItemKind.Class,
'funcdef': lsp.CompletionItemKind.Function,
'property': lsp.CompletionItemKind.Property,
'import': lsp.CompletionItemKind.Module,
'keyword': lsp.CompletionItemKind.Keyword,
'constant': lsp.CompletionItemKind.Variable,
'variable': lsp.CompletionItemKind.Variable,
'value': lsp.CompletionItemKind.Value,
'param': lsp.CompletionItemKind.Variable,
'statement': lsp.CompletionItemKind.Keyword,
}

return MAP.get(d.type)
10 changes: 7 additions & 3 deletions pyls/plugins/rope_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@


@hookimpl
def pyls_completions(document, position):
log.debug('Launching Rope')
def pyls_settings():
# Default rope_completion to disabled
return {'plugins': {'rope_completion': {'enabled': False}}}


@hookimpl
def pyls_completions(document, position):
# Rope is a bit rubbish at completing module imports, so we'll return None
word = document.word_at_position({
# The -1 should really be trying to look at the previous word, but that might be quite expensive
Expand Down Expand Up @@ -40,7 +44,7 @@ def pyls_completions(document, position):
'documentation': doc or "",
'sortText': _sort_text(d)})
definitions = new_definitions
log.debug('Rope finished')

return definitions or None


Expand Down
15 changes: 4 additions & 11 deletions pyls/python_ls.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
from multiprocessing import dummy as multiprocessing
from . import lsp, _utils
from .config import config
from .language_server import LanguageServer
from .workspace import Workspace

log = logging.getLogger(__name__)

PLUGGY_RACE_POOL_SIZE = 5
LINT_DEBOUNCE_S = 0.5 # 500 ms


Expand All @@ -21,8 +19,6 @@ class PythonLanguageServer(LanguageServer):
# Set of method dispatchers to query
_dispatchers = []

_pool = multiprocessing.Pool(PLUGGY_RACE_POOL_SIZE)

def __getitem__(self, item):
"""Override the method dispatcher to farm out any unknown messages to our plugins."""
try:
Expand All @@ -41,7 +37,8 @@ def _hook_caller(self, hook_name):

def _hook(self, hook_name, doc_uri=None, **kwargs):
doc = self.workspace.get_document(doc_uri) if doc_uri else None
return self._hook_caller(hook_name)(config=self.config, workspace=self.workspace, document=doc, **kwargs)
hook = self.config.plugin_manager.subset_hook_caller(hook_name, self.config.disabled_plugins)
return hook(config=self.config, workspace=self.workspace, document=doc, **kwargs)

def capabilities(self):
server_capabilities = {
Expand Down Expand Up @@ -85,14 +82,10 @@ def code_lens(self, doc_uri):
return flatten(self._hook('pyls_code_lens', doc_uri))

def completions(self, doc_uri, position):
completions = _utils.race_hooks(
self._hook_caller('pyls_completions'), self._pool,
document=self.workspace.get_document(doc_uri) if doc_uri else None,
position=position
)
completions = self._hook('pyls_completions', doc_uri, position=position)
return {
'isIncomplete': False,
'items': completions or []
'items': flatten(completions)
}

def definitions(self, doc_uri, position):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
'pyls = pyls.__main__:main',
],
'pyls': [
'rope_completion = pyls.plugins.rope_completion',
'jedi_completion = pyls.plugins.jedi_completion',
'jedi_definition = pyls.plugins.definition',
'jedi_hover = pyls.plugins.hover',
Expand All @@ -72,6 +71,7 @@
'pycodestyle = pyls.plugins.pycodestyle_lint',
'pydocstyle = pyls.plugins.pydocstyle_lint',
'pyflakes = pyls.plugins.pyflakes_lint',
'rope_completion = pyls.plugins.rope_completion',
'rope_rename = pyls.plugins.rope_rename',
'yapf = pyls.plugins.format',
]
Expand Down