Skip to content

Commit

Permalink
Merge #545 refactor: asyncio eventloop
Browse files Browse the repository at this point in the history
  • Loading branch information
justinmk authored Dec 5, 2023
2 parents 5184647 + 17fbcbc commit a699fe7
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 263 deletions.
13 changes: 12 additions & 1 deletion pynvim/api/nvim.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Main Nvim interface."""

import asyncio
import os
import sys
import threading
Expand Down Expand Up @@ -140,7 +142,16 @@ def __init__(
self._err_cb: Callable[[str], Any] = lambda _: None
else:
self._err_cb = err_cb
self.loop = self._session.loop._loop

@property
def loop(self) -> asyncio.AbstractEventLoop:
"""Get the event loop (exposed to rplugins).""" # noqa

# see #294: for python 3.4+, the only available and guaranteed
# implementation of msgpack_rpc BaseEventLoop is the AsyncioEventLoop.
# The underlying asyncio event loop is exposed to rplugins.
# pylint: disable=protected-access
return self._session.loop._loop # type: ignore

def _from_nvim(self, obj: Any, decode: Optional[TDecodeMode] = None) -> Any:
if decode is None:
Expand Down
26 changes: 17 additions & 9 deletions pynvim/msgpack_rpc/async_session.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
"""Asynchronous msgpack-rpc handling in the event loop pipeline."""
import logging
from traceback import format_exc
from typing import Any, AnyStr, Callable, Dict

from pynvim.msgpack_rpc.msgpack_stream import MsgpackStream

logger = logging.getLogger(__name__)
debug, info, warn = (logger.debug, logger.info, logger.warning,)


class AsyncSession(object):
# response call back takes two arguments: (err, return_value)
ResponseCallback = Callable[..., None]


class AsyncSession:

"""Asynchronous msgpack-rpc layer that wraps a msgpack stream.
Expand All @@ -16,11 +22,11 @@ class AsyncSession(object):
requests and notifications.
"""

def __init__(self, msgpack_stream):
def __init__(self, msgpack_stream: MsgpackStream):
"""Wrap `msgpack_stream` on a msgpack-rpc interface."""
self._msgpack_stream = msgpack_stream
self._next_request_id = 1
self._pending_requests = {}
self._pending_requests: Dict[int, ResponseCallback] = {}
self._request_cb = self._notification_cb = None
self._handlers = {
0: self._on_request,
Expand All @@ -33,7 +39,8 @@ def threadsafe_call(self, fn):
"""Wrapper around `MsgpackStream.threadsafe_call`."""
self._msgpack_stream.threadsafe_call(fn)

def request(self, method, args, response_cb):
def request(self, method: AnyStr, args: Any,
response_cb: ResponseCallback) -> None:
"""Send a msgpack-rpc request to Nvim.
A msgpack-rpc with method `method` and argument `args` is sent to
Expand Down Expand Up @@ -89,8 +96,9 @@ def _on_request(self, msg):
# - msg[2]: method name
# - msg[3]: arguments
debug('received request: %s, %s', msg[2], msg[3])
self._request_cb(msg[2], msg[3], Response(self._msgpack_stream,
msg[1]))
assert self._request_cb is not None
self._request_cb(msg[2], msg[3],
Response(self._msgpack_stream, msg[1]))

def _on_response(self, msg):
# response to a previous request:
Expand All @@ -105,6 +113,7 @@ def _on_notification(self, msg):
# - msg[1]: event name
# - msg[2]: arguments
debug('received notification: %s, %s', msg[1], msg[2])
assert self._notification_cb is not None
self._notification_cb(msg[1], msg[2])

def _on_invalid_message(self, msg):
Expand All @@ -113,15 +122,14 @@ def _on_invalid_message(self, msg):
self._msgpack_stream.send([1, 0, error, None])


class Response(object):

class Response:
"""Response to a msgpack-rpc request that came from Nvim.
When Nvim sends a msgpack-rpc request, an instance of this class is
created for remembering state required to send a response.
"""

def __init__(self, msgpack_stream, request_id):
def __init__(self, msgpack_stream: MsgpackStream, request_id: int):
"""Initialize the Response instance."""
self._msgpack_stream = msgpack_stream
self._request_id = request_id
Expand Down
2 changes: 1 addition & 1 deletion pynvim/msgpack_rpc/event_loop/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Event loop abstraction subpackage.
Tries to use pyuv as a backend, falling back to the asyncio implementation.
We use python's built-in asyncio as the backend.
"""

from pynvim.msgpack_rpc.event_loop.asyncio import AsyncioEventLoop as EventLoop
Expand Down
Loading

0 comments on commit a699fe7

Please sign in to comment.