Skip to content
Closed
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
18 changes: 18 additions & 0 deletions pyls/plugins/completion/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pyls import hookimpl
from .jedi_completion import pyls_jedi_completions
from .rope_completion import pyls_rope_completions


@hookimpl
def pyls_settings():
return {'plugins': {'completion': {'provider': 'jedi'}}}


@hookimpl
def pyls_completions(config, document, position):
provider = config.plugin_settings('completion').get('provider', 'jedi')
if provider == 'jedi':
return pyls_jedi_completions(document, position)
elif provider == 'rope':
return pyls_rope_completions(document, position)
return []
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
from pyls.lsp import CompletionItemKind
from pyls import hookimpl, _utils
from pyls import _utils

log = logging.getLogger(__name__)


@hookimpl
def pyls_completions(document, position):
def pyls_jedi_completions(document, position):
log.debug('Launching Jedi')
definitions = document.jedi_script(position).completions()
definitions = [{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
import logging
from rope.contrib.codeassist import code_assist, sorted_proposals

from pyls import hookimpl, lsp
from pyls import lsp


log = logging.getLogger(__name__)


@hookimpl
def pyls_completions(document, position):
def pyls_rope_completions(document, position):
log.debug('Launching Rope')

# Rope is a bit rubbish at completing module imports, so we'll return None
Expand Down
18 changes: 4 additions & 14 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 @@ -18,14 +16,10 @@ class PythonLanguageServer(LanguageServer):
workspace = None
config = None

_pool = multiprocessing.Pool(PLUGGY_RACE_POOL_SIZE)

def _hook_caller(self, hook_name):
return self.config.plugin_manager.subset_hook_caller(hook_name, self.config.disabled_plugins)

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):
return {
Expand Down Expand Up @@ -65,14 +59,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
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@
'pyls = pyls.__main__:main',
],
'pyls': [
'rope_completion = pyls.plugins.rope_completion',
'jedi_completion = pyls.plugins.jedi_completion',
'completion = pyls.plugins.completion',
'jedi_definition = pyls.plugins.definition',
'jedi_hover = pyls.plugins.hover',
'jedi_references = pyls.plugins.references',
Expand Down
4 changes: 2 additions & 2 deletions test/plugins/test_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

from pyls import uris
from pyls.workspace import Document, get_preferred_submodules
from pyls.plugins.jedi_completion import pyls_completions as pyls_jedi_completions
from pyls.plugins.rope_completion import pyls_completions as pyls_rope_completions
from pyls.plugins.completion.jedi_completion import pyls_jedi_completions
from pyls.plugins.completion.rope_completion import pyls_rope_completions

LOCATION = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__))
Expand Down
15 changes: 8 additions & 7 deletions vscode-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@
},
"uniqueItems": true
},
"pyls.plugins.jedi_completion.enabled": {
"pyls.plugins.completion.enabled": {
"type": "boolean",
"default": true,
"description": "Enable or disable the plugin."
"description": "Enable or disable completions."
},
"pyls.plugins.completion.provider": {
"type": "string",
"default": "jedi",
"enum": ["jedi", "rope"],
"description": "Select a completion provider."
},
"pyls.plugins.jedi_definition.enabled": {
"type": "boolean",
Expand Down Expand Up @@ -136,11 +142,6 @@
"default": true,
"description": "Enable or disable the plugin."
},
"pyls.plugins.rope_completion.enabled": {
"type": "boolean",
"default": true,
"description": "Enable or disable the plugin."
},
"pyls.plugins.yapf.enabled": {
"type": "boolean",
"default": true,
Expand Down