Commit e9855939 authored by Víctor Cuadrado Juan's avatar Víctor Cuadrado Juan

New upstream version 0.3.0

parent 8d2249b8
Metadata-Version: 2.1
Name: neovim
Version: 0.2.6
Version: 0.3.0
Summary: Python client to neovim
Home-page: http://github.com/neovim/python-client
Author: Thiago de Arruda
Author-email: tpadilha84@gmail.com
License: Apache
Download-URL: https://github.com/neovim/python-client/archive/0.2.6.tar.gz
Download-URL: https://github.com/neovim/python-client/archive/0.3.0.tar.gz
Description: UNKNOWN
Platform: UNKNOWN
Provides-Extra: pyuv
Provides-Extra: test
Metadata-Version: 2.1
Name: neovim
Version: 0.2.6
Version: 0.3.0
Summary: Python client to neovim
Home-page: http://github.com/neovim/python-client
Author: Thiago de Arruda
Author-email: tpadilha84@gmail.com
License: Apache
Download-URL: https://github.com/neovim/python-client/archive/0.2.6.tar.gz
Download-URL: https://github.com/neovim/python-client/archive/0.3.0.tar.gz
Description: UNKNOWN
Platform: UNKNOWN
Provides-Extra: pyuv
Provides-Extra: test
......@@ -35,6 +35,7 @@ test/test_client_rpc.py
test/test_concurrency.py
test/test_decorators.py
test/test_events.py
test/test_host.py
test/test_tabpage.py
test/test_vim.py
test/test_window.py
\ No newline at end of file
......@@ -3,3 +3,6 @@ greenlet
[pyuv]
pyuv>=1.0.0
[test]
pytest>=3.4.0
......@@ -12,16 +12,14 @@ from .msgpack_rpc import (ErrorResponse, child_session, socket_session,
stdio_session, tcp_session)
from .plugin import (Host, autocmd, command, decode, encoding, function,
plugin, rpc_export, shutdown_hook)
from .util import Version
from .util import VERSION, Version
__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
'start_host', 'autocmd', 'command', 'encoding', 'decode',
'function', 'plugin', 'rpc_export', 'Host', 'Nvim', 'VERSION',
'shutdown_hook', 'attach', 'setup_logging', 'ErrorResponse')
VERSION = Version(major=0, minor=2, patch=6, prerelease='')
'function', 'plugin', 'rpc_export', 'Host', 'Nvim', 'Version',
'VERSION', 'shutdown_hook', 'attach', 'setup_logging',
'ErrorResponse')
def start_host(session=None):
......
......@@ -30,6 +30,13 @@ class Remote(object):
self.options = RemoteMap(self, self._api_prefix + 'get_option',
self._api_prefix + 'set_option')
def __repr__(self):
"""Get text representation of the object."""
return '<%s(handle=%r)>' % (
self.__class__.__name__,
self.handle,
)
def __eq__(self, other):
"""Return True if `self` and `other` are the same object."""
return (hasattr(other, 'code_data') and
......
"""Main Nvim interface."""
import os
import sys
import threading
from functools import partial
from traceback import format_stack
......@@ -121,7 +122,7 @@ class Nvim(object):
self._err_cb = err_cb
# only on python3.4+ we expose asyncio
if IS_PYTHON3 and os.name != 'nt':
if IS_PYTHON3:
self.loop = self._session.loop._loop
def _from_nvim(self, obj, decode=None):
......@@ -165,6 +166,15 @@ class Nvim(object):
present and True, a asynchronous notification is sent instead. This
will never block, and the return value or error is ignored.
"""
if (self._session._loop_thread is not None and
threading.current_thread() != self._session._loop_thread):
msg = ("request from non-main thread:\n{}\n"
.format('\n'.join(format_stack(None, 5)[:-1])))
self.async_call(self._err_cb, msg)
raise NvimError("request from non-main thread")
decode = kwargs.pop('decode', self._decode)
args = walk(self._to_nvim, args)
res = self._session.request(name, *args, **kwargs)
......@@ -240,17 +250,20 @@ class Nvim(object):
return Nvim(self._session, self.channel_id,
self.metadata, self.types, decode, self._err_cb)
def ui_attach(self, width, height, rgb):
def ui_attach(self, width, height, rgb=None, **kwargs):
"""Register as a remote UI.
After this method is called, the client will receive redraw
notifications.
"""
return self.request('ui_attach', width, height, rgb)
options = kwargs
if rgb is not None:
options['rgb'] = rgb
return self.request('nvim_ui_attach', width, height, options)
def ui_detach(self):
"""Unregister as a remote UI."""
return self.request('ui_detach')
return self.request('nvim_ui_detach')
def ui_try_resize(self, width, height):
"""Notify nvim that the client window has resized.
......@@ -379,8 +392,18 @@ class Nvim(object):
def err_write(self, msg, **kwargs):
"""Print `msg` as an error message."""
if self._thread_invalid():
# special case: if a non-main thread writes to stderr
# i.e. due to an uncaught exception, pass it through
# without raising an additional exception.
self.async_call(self.err_write, msg, **kwargs)
return
return self.request('nvim_err_write', msg, **kwargs)
def _thread_invalid(self):
return (self._session._loop_thread is not None and
threading.current_thread() != self._session._loop_thread)
def quit(self, quit_command='qa!'):
"""Send a quit command to Nvim.
......
......@@ -3,12 +3,10 @@
Tries to use pyuv as a backend, falling back to the asyncio implementation.
"""
import os
from ...compat import IS_PYTHON3
# on python3 we only support asyncio, as we expose it to plugins
if IS_PYTHON3 and os.name != 'nt':
if IS_PYTHON3:
from .asyncio import AsyncioEventLoop
EventLoop = AsyncioEventLoop
else:
......
......@@ -10,6 +10,7 @@ is a backport of `asyncio` that works on Python 2.6+.
"""
from __future__ import absolute_import
import logging
import os
import sys
from collections import deque
......@@ -23,11 +24,17 @@ except (ImportError, SyntaxError):
from .base import BaseEventLoop
logger = logging.getLogger(__name__)
debug, info, warn = (logger.debug, logger.info, logger.warning,)
loop_cls = asyncio.SelectorEventLoop
if os.name == 'nt':
from asyncio.windows_utils import PipeHandle
import msvcrt
# On windows use ProactorEventLoop which support pipes and is backed by the
# more powerful IOCP facility
# NOTE: we override in the stdio case, because it doesn't work.
loop_cls = asyncio.ProactorEventLoop
......@@ -89,14 +96,26 @@ class AsyncioEventLoop(BaseEventLoop, asyncio.Protocol,
self._loop.run_until_complete(coroutine)
def _connect_stdio(self):
coroutine = self._loop.connect_read_pipe(self._fact, sys.stdin)
if os.name == 'nt':
pipe = PipeHandle(msvcrt.get_osfhandle(sys.stdin.fileno()))
else:
pipe = sys.stdin
coroutine = self._loop.connect_read_pipe(self._fact, pipe)
self._loop.run_until_complete(coroutine)
coroutine = self._loop.connect_write_pipe(self._fact, sys.stdout)
debug("native stdin connection successful")
if os.name == 'nt':
pipe = PipeHandle(msvcrt.get_osfhandle(sys.stdout.fileno()))
else:
pipe = sys.stdout
coroutine = self._loop.connect_write_pipe(self._fact, pipe)
self._loop.run_until_complete(coroutine)
debug("native stdout connection successful")
def _connect_child(self, argv):
self._child_watcher = asyncio.get_child_watcher()
self._child_watcher.attach_loop(self._loop)
if os.name != 'nt':
self._child_watcher = asyncio.get_child_watcher()
self._child_watcher.attach_loop(self._loop)
coroutine = self._loop.subprocess_exec(self._fact, *argv)
self._loop.run_until_complete(coroutine)
......
"""Synchronous msgpack-rpc session layer."""
import logging
import threading
from collections import deque
from traceback import format_exc
......@@ -29,6 +30,7 @@ class Session(object):
self._is_running = False
self._setup_exception = None
self.loop = async_session.loop
self._loop_thread = None
def threadsafe_call(self, fn, *args, **kwargs):
"""Wrapper around `AsyncSession.threadsafe_call`."""
......@@ -110,6 +112,7 @@ class Session(object):
self._notification_cb = notification_cb
self._is_running = True
self._setup_exception = None
self._loop_thread = threading.current_thread()
def on_setup():
try:
......@@ -135,6 +138,7 @@ class Session(object):
self._is_running = False
self._request_cb = None
self._notification_cb = None
self._loop_thread = None
if self._setup_exception:
raise self._setup_exception
......
......@@ -5,6 +5,7 @@ import logging
import os
import os.path
import re
import sys
from functools import partial
from traceback import format_exc
......@@ -12,7 +13,7 @@ from . import script_host
from ..api import decode_if_bytes, walk
from ..compat import IS_PYTHON3, find_module
from ..msgpack_rpc import ErrorResponse
from ..util import format_exc_skip
from ..util import VERSION, format_exc_skip
__all__ = ('Host')
......@@ -20,6 +21,8 @@ logger = logging.getLogger(__name__)
error, debug, info, warn = (logger.error, logger.debug, logger.info,
logger.warning,)
host_method_spec = {"poll": {}, "specs": {"nargs": 1}, "shutdown": {}}
class Host(object):
......@@ -116,6 +119,7 @@ class Host(object):
return msg
def _load(self, plugins):
has_script = False
for path in plugins:
err = None
if path in self._loaded:
......@@ -124,6 +128,7 @@ class Host(object):
try:
if path == "script_host.py":
module = script_host
has_script = True
else:
directory, name = os.path.split(os.path.splitext(path)[0])
file, pathname, descr = find_module(name, [directory])
......@@ -141,6 +146,17 @@ class Host(object):
error(err)
self._load_errors[path] = err
if len(plugins) == 1 and has_script:
kind = "script"
else:
kind = "rplugin"
name = "python{}-{}-host".format(sys.version_info[0], kind)
attributes = {"license": "Apache v2",
"website": "github.com/neovim/python-client"}
self.nvim.api.set_client_info(
name, VERSION.__dict__, "host", host_method_spec,
attributes, async_=True)
def _unload(self):
for path, plugin in self._loaded.items():
handlers = plugin['handlers']
......
......@@ -208,6 +208,8 @@ class LegacyVim(Nvim):
# This was copied/adapted from nvim-python help
def path_hook(nvim):
def _get_paths():
if nvim._thread_invalid():
return []
return discover_runtime_directories(nvim)
def _find_module(fullname, oldtail, path):
......@@ -227,8 +229,10 @@ def path_hook(nvim):
def load_module(self, fullname, path=None):
# Check sys.modules, required for reload (see PEP302).
if fullname in sys.modules:
try:
return sys.modules[fullname]
except KeyError:
pass
return imp.load_module(fullname, *self.module)
class VimPathFinder(object):
......@@ -242,9 +246,9 @@ def path_hook(nvim):
return None
@staticmethod
def find_spec(fullname, path=None, target=None):
def find_spec(fullname, target=None):
"""Method for Python 3.4+."""
return PathFinder.find_spec(fullname, path or _get_paths(), target)
return PathFinder.find_spec(fullname, _get_paths(), target)
def hook(path):
if path == nvim.VIM_SPECIAL_PATH:
......
......@@ -30,3 +30,6 @@ class Version:
def __eq__(self, other):
"""Check if version is same as other."""
return self.__dict__ == other.__dict__
VERSION = Version(major=0, minor=3, patch=0, prerelease='')
[flake8]
ignore = D211,E731,D401
[tool:pytest]
testpaths = test
timeout = 10
[egg_info]
tag_build =
tag_date = 0
......
......@@ -14,23 +14,25 @@ tests_require = [
extras_require = {
'pyuv': ['pyuv>=1.0.0'],
'test': tests_require,
}
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
install_requires.append('greenlet')
setup(name='neovim',
version='0.2.6',
version='0.3.0',
description='Python client to neovim',
url='http://github.com/neovim/python-client',
download_url='https://github.com/neovim/python-client/archive/0.2.6.tar.gz',
download_url='https://github.com/neovim/python-client/archive/0.3.0.tar.gz',
author='Thiago de Arruda',
author_email='tpadilha84@gmail.com',
license='Apache',
......
......@@ -3,6 +3,10 @@ import os
from neovim.compat import IS_PYTHON3
def test_repr(vim):
assert repr(vim.current.buffer) == "<Buffer(handle=2)>"
def test_get_length(vim):
assert len(vim.current.buffer) == 1
vim.current.buffer.append('line')
......
# -*- coding: utf-8 -*-
import time
def test_call_and_reply(vim):
......@@ -41,6 +42,11 @@ def test_async_call(vim):
# this would have dead-locked if not async
vim.funcs.rpcrequest(vim.channel_id, "test-event", async_=True)
vim.run_loop(request_cb, None, None)
# TODO(blueyed): This sleep is required on Travis, where it hangs with
# "Entering event loop" otherwise (asyncio's EpollSelector._epoll.poll).
time.sleep(0.1)
assert vim.vars['result'] == 17
......
# -*- coding: utf-8 -*-
from neovim.plugin.host import Host, host_method_spec
def test_host_method_spec(vim):
h = Host(vim)
assert h._request_handlers.keys() == host_method_spec.keys()
......@@ -28,3 +28,7 @@ def test_number(vim):
assert vim.current.tabpage.number == curnum + 1
vim.command('tabnew')
assert vim.current.tabpage.number == curnum + 2
def test_repr(vim):
assert repr(vim.current.tabpage) == "<Tabpage(handle=2)>"
......@@ -100,3 +100,7 @@ def test_handle(vim):
assert hnd1 != hnd2 != hnd3
vim.command('wincmd w')
assert vim.current.window.handle == hnd1
def test_repr(vim):
assert repr(vim.current.window) == "<Window(handle=1001)>"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment