diff --git a/.travis.yml b/.travis.yml index 59454b69..ff74f494 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ python: # If the build matrix gets bigger, also update the number of runs # at the bottom of .scrutinizer.yml. - 2.7 - - 3.3 - 3.4 - 3.5 - 3.6 diff --git a/README.md b/README.md index 9a72c449..f037bf6c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ connecting to and scripting Nvim processes through its msgpack-rpc API. #### Installation -Supports python 2.7, and 3.3 or later. +Supports python 2.7, and 3.4 or later. ```sh pip2 install neovim diff --git a/neovim/api/nvim.py b/neovim/api/nvim.py index 2394e01a..b49644e4 100644 --- a/neovim/api/nvim.py +++ b/neovim/api/nvim.py @@ -36,6 +36,12 @@ class Nvim(object): `SubClass.from_nvim(nvim)` where `SubClass` is a subclass of `Nvim`, which is useful for having multiple `Nvim` objects that behave differently without one affecting the other. + + When this library is used on python3.4+, asyncio event loop is guaranteed + to be used. It is available as the "loop" attribute of this class. Note + that asyncio callbacks cannot make blocking requests, which includes + accessing state-dependent attributes. They should instead schedule another + callback using nvim.async_call, which will not have this restriction. """ @classmethod @@ -90,6 +96,10 @@ def __init__(self, session, channel_id, metadata, types, self._decode = decode self._err_cb = err_cb + # only on python3.4+ we expose asyncio + if IS_PYTHON3: + self.loop = self._session.loop._loop + def _from_nvim(self, obj, decode=None): if decode is None: decode = self._decode diff --git a/neovim/msgpack_rpc/async_session.py b/neovim/msgpack_rpc/async_session.py index dd8b2372..78122090 100644 --- a/neovim/msgpack_rpc/async_session.py +++ b/neovim/msgpack_rpc/async_session.py @@ -27,6 +27,7 @@ def __init__(self, msgpack_stream): 1: self._on_response, 2: self._on_notification } + self.loop = msgpack_stream.loop def threadsafe_call(self, fn): """Wrapper around `MsgpackStream.threadsafe_call`.""" diff --git a/neovim/msgpack_rpc/event_loop/__init__.py b/neovim/msgpack_rpc/event_loop/__init__.py index 2e83807a..92aa695e 100644 --- a/neovim/msgpack_rpc/event_loop/__init__.py +++ b/neovim/msgpack_rpc/event_loop/__init__.py @@ -2,15 +2,23 @@ Tries to use pyuv as a backend, falling back to the asyncio implementation. """ -try: - # libuv is fully implemented in C, use it when available - from .uv import UvEventLoop - EventLoop = UvEventLoop -except ImportError: - # asyncio(trollius on python 2) is pure python and should be more portable - # across python implementations + +from ...compat import IS_PYTHON3 + +# on python3 we only support asyncio, as we expose it to plugins +if IS_PYTHON3: from .asyncio import AsyncioEventLoop EventLoop = AsyncioEventLoop +else: + try: + # libuv is fully implemented in C, use it when available + from .uv import UvEventLoop + EventLoop = UvEventLoop + except ImportError: + # asyncio(trollius on python 2) is pure python and should be more + # portable across python implementations + from .asyncio import AsyncioEventLoop + EventLoop = AsyncioEventLoop __all__ = ('EventLoop') diff --git a/neovim/msgpack_rpc/msgpack_stream.py b/neovim/msgpack_rpc/msgpack_stream.py index ce3eff55..48c9a23b 100644 --- a/neovim/msgpack_rpc/msgpack_stream.py +++ b/neovim/msgpack_rpc/msgpack_stream.py @@ -19,7 +19,7 @@ class MsgpackStream(object): def __init__(self, event_loop): """Wrap `event_loop` on a msgpack-aware interface.""" - self._event_loop = event_loop + self.loop = event_loop self._packer = Packer(encoding='utf-8', unicode_errors=unicode_errors_default) self._unpacker = Unpacker() @@ -27,12 +27,12 @@ def __init__(self, event_loop): def threadsafe_call(self, fn): """Wrapper around `BaseEventLoop.threadsafe_call`.""" - self._event_loop.threadsafe_call(fn) + self.loop .threadsafe_call(fn) def send(self, msg): """Queue `msg` for sending to Nvim.""" debug('sent %s', msg) - self._event_loop.send(self._packer.pack(msg)) + self.loop .send(self._packer.pack(msg)) def run(self, message_cb): """Run the event loop to receive messages from Nvim. @@ -41,12 +41,12 @@ def run(self, message_cb): a message has been successfully parsed from the input stream. """ self._message_cb = message_cb - self._event_loop.run(self._on_data) + self.loop .run(self._on_data) self._message_cb = None def stop(self): """Stop the event loop.""" - self._event_loop.stop() + self.loop .stop() def close(self): """Close the event loop.""" diff --git a/neovim/msgpack_rpc/session.py b/neovim/msgpack_rpc/session.py index ee7efab5..1a4aff2b 100644 --- a/neovim/msgpack_rpc/session.py +++ b/neovim/msgpack_rpc/session.py @@ -26,6 +26,7 @@ def __init__(self, async_session): self._pending_messages = deque() self._is_running = False self._setup_exception = None + self.loop = async_session.loop def threadsafe_call(self, fn, *args, **kwargs): """Wrapper around `AsyncSession.threadsafe_call`.""" diff --git a/setup.py b/setup.py index 147c5b82..63762803 100644 --- a/setup.py +++ b/setup.py @@ -7,15 +7,13 @@ install_requires = [ 'msgpack>=0.5.0', ] -extras_require = { - 'pyuv': ['pyuv>=1.0.0'], -} -if os.name == 'nt': - install_requires.append('pyuv>=1.0.0') -elif sys.version_info < (3, 4): - # trollius is just a backport of 3.4 asyncio module - install_requires.append('trollius') +if sys.version_info < (3, 4): + if os.name == 'nt': + install_requires.append('pyuv>=1.0.0') + else: + # trollius is just a backport of 3.4 asyncio module + install_requires.append('trollius') if platform.python_implementation() != 'PyPy': # pypy already includes an implementation of the greenlet module @@ -32,5 +30,4 @@ packages=['neovim', 'neovim.api', 'neovim.msgpack_rpc', 'neovim.msgpack_rpc.event_loop', 'neovim.plugin'], install_requires=install_requires, - extras_require=extras_require, zip_safe=False)