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

Several refactoring on asyncio eventloop implementations #545

Merged
merged 6 commits into from
Dec 5, 2023
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
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