Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.
Open
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
Binary file added .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- checkout
- run: pip install -e .[all] .[test]
- run: py.test test/
- run: pylint pyls test
- run: pylint pyls test --ignore-patterns="pyls_race_py3.py"
- run: pycodestyle pyls test
- run: pyflakes pyls test

Expand Down
4 changes: 0 additions & 4 deletions MANIFEST.in

This file was deleted.

19 changes: 9 additions & 10 deletions pyls/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
import logging
import os
import threading
import sys

log = logging.getLogger(__name__)
PY3 = sys.version[0] == '3'
if PY3:
# noqa pylint: disable=import-error
from .pyls_race_py3 import async_race
else:
from .pyls_race_py2 import async_race


def debounce(interval_s, keyed_by=None):
Expand Down Expand Up @@ -163,7 +170,7 @@ def is_process_alive(pid):
return True


def race_hooks(hook_caller, pool, **kwargs):
def race_hooks(hook_caller, **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.
Expand All @@ -174,15 +181,7 @@ def race_hooks(hook_caller, pool, **kwargs):
if not impls:
return None

def _apply(impl):
return impl, impl.function(**kwargs)

# 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.
result = None
while result is None:
first_impl, result = next(pool.imap_unordered(_apply, impls, chunksize=1))
first_impl, result = async_race(impls, **kwargs)
log.debug("Hook from plugin %s returned: %s", first_impl.plugin_name,
result)
return result
4 changes: 4 additions & 0 deletions pyls/pyls_race_py2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pylint: disable=unused-argument
def async_race(impls, **kwargs):
"""Dummy function when running the server on python 2."""
return None
28 changes: 28 additions & 0 deletions pyls/pyls_race_py3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import trio


def async_race(impls, **kwargs):
"""Create the race between rope and jedi using async functions."""
# pylint: disable=syntax-error
async def race(impls):
send_channel, receive_channel = trio.open_memory_channel(0)

# pylint: disable=syntax-error
async def _apply(impl):
return impl, impl.function(**kwargs)

# pylint: disable=syntax-error
async def jockey(impl):
if impl.plugin_name == 'rope_completion':
await trio.sleep(0.1)
await send_channel.send(await _apply(impl))

async with trio.open_nursery() as nursery:
for impl in impls:
nursery.start_soon(jockey, impl)

winner = await receive_channel.receive()
if winner is not None or winner is []:
nursery.cancel_scope.cancel()
return winner
return trio.run(race, impls)
11 changes: 4 additions & 7 deletions pyls/python_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import socketserver
import threading
from multiprocessing import dummy as multiprocessing
import sys

from pyls_jsonrpc.dispatchers import MethodDispatcher
from pyls_jsonrpc.endpoint import Endpoint
Expand All @@ -17,9 +17,9 @@
LINT_DEBOUNCE_S = 0.5 # 500 ms
PARENT_PROCESS_WATCH_INTERVAL = 10 # 10 s
MAX_WORKERS = 64
PLUGGY_RACE_POOL_SIZE = 5
PYTHON_FILE_EXTENSIONS = ('.py', '.pyi')
CONFIG_FILEs = ('pycodestyle.cfg', 'setup.cfg', 'tox.ini', '.flake8')
PY3 = sys.version[0] == '3'


class _StreamHandlerWrapper(socketserver.StreamRequestHandler, object):
Expand Down Expand Up @@ -76,7 +76,6 @@ class PythonLanguageServer(MethodDispatcher):
def __init__(self, rx, tx, check_parent_process=False):
self.workspace = None
self.config = None
self._pool = None

self._jsonrpc_stream_reader = JsonRpcStreamReader(rx)
self._jsonrpc_stream_writer = JsonRpcStreamWriter(tx)
Expand Down Expand Up @@ -148,7 +147,7 @@ def capabilities(self):
'referencesProvider': True,
'renameProvider': True,
'signatureHelpProvider': {
'triggerCharacters': ['(', ',']
'triggerCharacters': ['(', ',', '=']
},
'textDocumentSync': lsp.TextDocumentSyncKind.INCREMENTAL,
'experimental': merge(self._hook('pyls_experimental_capabilities'))
Expand All @@ -165,7 +164,6 @@ def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializati
self.config = config.Config(rootUri, initializationOptions or {},
processId, _kwargs.get('capabilities', {}))
self._dispatchers = self._hook('pyls_dispatchers')
self._pool = multiprocessing.Pool(PLUGGY_RACE_POOL_SIZE)
self._hook('pyls_initialize')

if self._check_parent_process and processId is not None:
Expand Down Expand Up @@ -195,10 +193,9 @@ def code_lens(self, doc_uri):

def completions(self, doc_uri, position):
rope_enabled = self.config.settings()['plugins']['rope_completion']['enabled']
if rope_enabled:
if rope_enabled and PY3:
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,
config=self.config,
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ def get_readme():
'pycodestyle',
'pydocstyle>=2.0.0',
'pyflakes>=1.6.0',
'rope>=0.10.5'
'rope>=0.10.5',
'trio; python_version>="3.5"'
],

# List additional groups of dependencies here (e.g. development
Expand Down