[Python-modules-commits] [python-neovim] 01/04: Import python-neovim_0.1.7.orig.tar.gz

Víctor Cuadrado Juan viccuad-guest at moszumanska.debian.org
Wed Apr 20 14:14:32 UTC 2016


This is an automated email from the git hooks/post-receive script.

viccuad-guest pushed a commit to branch master
in repository python-neovim.

commit f729dd943f0eee2e1133614c74683250704426a9
Author: Víctor Cuadrado Juan <me at viccuad.me>
Date:   Wed Apr 20 12:57:17 2016 +0200

    Import python-neovim_0.1.7.orig.tar.gz
---
 PKG-INFO                      |   4 +-
 README.md                     |  59 ++++++++++--
 neovim.egg-info/PKG-INFO      |   4 +-
 neovim/__init__.py            |  22 +++--
 neovim/api/__init__.py        |   6 +-
 neovim/api/buffer.py          |  54 +++++------
 neovim/api/common.py          | 187 ++++++++++---------------------------
 neovim/api/nvim.py            | 211 ++++++++++++++++++++++++++++--------------
 neovim/api/tabpage.py         |  20 ++--
 neovim/api/window.py          |  37 +++-----
 neovim/msgpack_rpc/session.py |   6 +-
 neovim/plugin/__init__.py     |   6 +-
 neovim/plugin/decorators.py   |  17 +++-
 neovim/plugin/host.py         |  82 ++++++++--------
 neovim/plugin/script_host.py  |  38 +++-----
 setup.py                      |   4 +-
 test/test_buffer.py           |  10 ++
 test/test_client_rpc.py       |  16 ++--
 test/test_common.py           |  16 ++--
 test/test_concurrency.py      |  18 ++--
 test/test_events.py           |  12 +--
 test/test_vim.py              |   6 ++
 22 files changed, 425 insertions(+), 410 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 46a580d..defd180 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,11 @@
 Metadata-Version: 1.1
 Name: neovim
-Version: 0.1.5
+Version: 0.1.7
 Summary: Python client to neovim
 Home-page: http://github.com/neovim/python-client
 Author: Thiago de Arruda
 Author-email: tpadilha84 at gmail.com
 License: Apache
-Download-URL: https://github.com/neovim/python-client/archive/0.1.5.tar.gz
+Download-URL: https://github.com/neovim/python-client/archive/0.1.7.tar.gz
 Description: UNKNOWN
 Platform: UNKNOWN
diff --git a/README.md b/README.md
index 14f00a4..ce07b07 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,27 @@ connecting to and scripting Nvim processes through its msgpack-rpc API.
 #### Installation
 
 ```sh
-pip install neovim
+pip2 install neovim
+pip3 install neovim
 ```
 
-You can install the package without being root by adding the `--user` flag. You
-can use `pip2` and `pip3` to explicitly install for python2 and python3,
-respectively.
+If you only use one of python2 or python3, it is enough to install that
+version. You can install the package without being root by adding the `--user`
+flag.
+
+If you follow Neovim master, make sure to upgrade the python-client when you
+upgrade neovim:
+```sh
+pip2 install --upgrade neovim
+pip3 install --upgrade neovim
+```
+
+Alternatively, the master version could be installed by executing the following
+in the root of this repository:
+```sh
+pip2 install .
+pip3 install .
+```
 
 #### Python Plugin API
 
@@ -84,12 +99,18 @@ to have effect. For details see `:help remote-plugin` in nvim.
 
 #### Development
 
-Install the master version by cloning this repository and in the root directory
-execute
-
+If you change the code, you need to run
 ```sh
-pip install .
+pip2 install .
+pip3 install .
+```
+for the changes to have effect. Alternatively you could execute neovim
+with the `$PYTHONPATH` environment variable
+```
+PYTHONPATH=/path/to/python-client nvim
 ```
+But note this is not completely reliable as installed packages can appear before
+`$PYTHONPATH` in the python search path.
 
 You need to rerun this command if you have changed the code, in order for nvim
 to use it for the plugin host.
@@ -97,10 +118,16 @@ to use it for the plugin host.
 To run the tests execute
 
 ```sh
-NVIM_CHILD_ARGV='["nvim", "-u", "NONE", "--embed"]' nosetests
+nosetests
 ```
 
-Alternatively, if you want to see the state of nvim, you could
+This will run the tests in an embedded instance of nvim.
+If you want to test a different version than `nvim` in `$PATH` use
+```sh
+NVIM_CHILD_ARGV='["/path/to/nvim", "-u", "NONE", "--embed"]' nosetests
+```
+
+Alternatively, if you want to see the state of nvim, you could use
 
 ```sh
 export NVIM_LISTEN_ADDRESS=/tmp/nvimtest
@@ -111,6 +138,18 @@ nosetests
 But note you need to restart nvim every time you run the tests! Substitute your
 favorite terminal emulator for `xterm`.
 
+#### Troubleshooting
+
+You can run the plugin host in nvim with logging enabled to debug errors:
+```
+NVIM_PYTHON_LOG_FILE=logfile NVIM_PYTHON_LOG_LEVEL=DEBUG nvim
+```
+As more than one python host process might be started, the log filenames take
+the pattern `logfile_PID` where `PID` is the process id.
+
+If the host cannot start at all, the error could be found in `~/.nvimlog` if
+`nvim` was compiled with logging.
+
 #### Usage through the python REPL
 
 A number of different transports are supported, but the simplest way to get
diff --git a/neovim.egg-info/PKG-INFO b/neovim.egg-info/PKG-INFO
index 46a580d..defd180 100644
--- a/neovim.egg-info/PKG-INFO
+++ b/neovim.egg-info/PKG-INFO
@@ -1,11 +1,11 @@
 Metadata-Version: 1.1
 Name: neovim
-Version: 0.1.5
+Version: 0.1.7
 Summary: Python client to neovim
 Home-page: http://github.com/neovim/python-client
 Author: Thiago de Arruda
 Author-email: tpadilha84 at gmail.com
 License: Apache
-Download-URL: https://github.com/neovim/python-client/archive/0.1.5.tar.gz
+Download-URL: https://github.com/neovim/python-client/archive/0.1.7.tar.gz
 Description: UNKNOWN
 Platform: UNKNOWN
diff --git a/neovim/__init__.py b/neovim/__init__.py
index 6fea713..15c7b16 100644
--- a/neovim/__init__.py
+++ b/neovim/__init__.py
@@ -6,18 +6,18 @@ import logging
 import os
 import sys
 
-from .api import DecodeHook, Nvim, SessionHook
+from .api import Nvim
+from .compat import IS_PYTHON3
 from .msgpack_rpc import (ErrorResponse, child_session, socket_session,
                           stdio_session, tcp_session)
-from .plugin import (Host, autocmd, command, encoding, function, plugin,
-                     rpc_export, shutdown_hook)
+from .plugin import (Host, autocmd, command, decode, encoding, function,
+                     plugin, rpc_export, shutdown_hook)
 
 
 __all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
-           'start_host', 'autocmd', 'command', 'encoding', 'function',
-           'plugin', 'rpc_export', 'Host', 'DecodeHook', 'Nvim',
-           'SessionHook', 'shutdown_hook', 'attach', 'setup_logging',
-           'ErrorResponse')
+           'start_host', 'autocmd', 'command', 'encoding', 'decode',
+           'function', 'plugin', 'rpc_export', 'Host', 'Nvim',
+           'shutdown_hook', 'attach', 'setup_logging', 'ErrorResponse')
 
 
 def start_host(session=None):
@@ -64,7 +64,8 @@ def start_host(session=None):
     host.start(plugins)
 
 
-def attach(session_type, address=None, port=None, path=None, argv=None):
+def attach(session_type, address=None, port=None,
+           path=None, argv=None, decode=None):
     """Provide a nicer interface to create python api sessions.
 
     Previous machinery to create python api sessions is still there. This only
@@ -90,7 +91,10 @@ def attach(session_type, address=None, port=None, path=None, argv=None):
     if not session:
         raise Exception('Unknown session type "%s"' % session_type)
 
-    return Nvim.from_session(session)
+    if decode is None:
+        decode = IS_PYTHON3
+
+    return Nvim.from_session(session).with_decode(decode)
 
 
 def setup_logging():
diff --git a/neovim/api/__init__.py b/neovim/api/__init__.py
index 10f2147..7feb889 100644
--- a/neovim/api/__init__.py
+++ b/neovim/api/__init__.py
@@ -5,11 +5,11 @@ instances.
 """
 
 from .buffer import Buffer
-from .common import DecodeHook, SessionHook
+from .common import decode_if_bytes, walk
 from .nvim import Nvim, NvimError
 from .tabpage import Tabpage
 from .window import Window
 
 
-__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError', 'SessionHook',
-           'DecodeHook')
+__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError',
+           'decode_if_bytes', 'walk')
diff --git a/neovim/api/buffer.py b/neovim/api/buffer.py
index d90280e..ab90b74 100644
--- a/neovim/api/buffer.py
+++ b/neovim/api/buffer.py
@@ -1,5 +1,5 @@
 """API for working with Nvim buffers."""
-from .common import Remote, RemoteMap
+from .common import Remote
 from ..compat import IS_PYTHON3
 
 
@@ -14,22 +14,11 @@ class Buffer(Remote):
 
     """A remote Nvim buffer."""
 
-    def __init__(self, session, code_data):
-        """Initialize from session and code_data immutable object.
-
-        The `code_data` contains serialization information required for
-        msgpack-rpc calls. It must be immutable for Buffer equality to work.
-        """
-        self._session = session
-        self.code_data = code_data
-        self.vars = RemoteMap(session, 'buffer_get_var', 'buffer_set_var',
-                              self)
-        self.options = RemoteMap(session, 'buffer_get_option',
-                                 'buffer_set_option', self)
+    _api_prefix = "buffer_"
 
     def __len__(self):
         """Return the number of lines contained in a Buffer."""
-        return self._session.request('buffer_line_count', self)
+        return self.request('buffer_line_count')
 
     def __getitem__(self, idx):
         """Get a buffer line or slice by integer index.
@@ -121,7 +110,7 @@ class Buffer(Remote):
 
     def mark(self, name):
         """Return (row, col) tuple for a named mark."""
-        return self._session.request('buffer_get_mark', self, name)
+        return self.request('buffer_get_mark', name)
 
     def range(self, start, end):
         """Return a `Range` object, which represents part of the Buffer."""
@@ -132,44 +121,43 @@ class Buffer(Remote):
         """Add a highlight to the buffer."""
         if async is None:
             async = (src_id != 0)
-        return self._session.request('buffer_add_highlight', self, src_id,
-                                     hl_group, line, col_start,
-                                     col_end, async=async)
+        return self.request('buffer_add_highlight', src_id, hl_group,
+                            line, col_start, col_end, async=async)
 
     def clear_highlight(self, src_id, line_start=0, line_end=-1, async=True):
         """clear highlights from the buffer."""
-        self._session.request('buffer_clear_highlight', self, src_id,
-                              line_start, line_end, async=async)
+        self.request('buffer_clear_highlight', src_id,
+                     line_start, line_end, async=async)
 
     @property
     def name(self):
         """Get the buffer name."""
-        return self._session.request('buffer_get_name', self)
+        return self.request('buffer_get_name')
 
     @name.setter
     def name(self, value):
         """Set the buffer name. BufFilePre/BufFilePost are triggered."""
-        return self._session.request('buffer_set_name', self, value)
+        return self.request('buffer_set_name', value)
 
     @property
     def valid(self):
         """Return True if the buffer still exists."""
-        return self._session.request('buffer_is_valid', self)
+        return self.request('buffer_is_valid')
 
     @property
     def number(self):
         """Get the buffer number."""
-        return self._session.request('buffer_get_number', self)
+        return self.request('buffer_get_number')
 
 
 class Range(object):
     def __init__(self, buffer, start, end):
         self._buffer = buffer
         self.start = start - 1
-        self.end = end
+        self.end = end - 1
 
     def __len__(self):
-        return self.end - self.start
+        return self.end - self.start + 1
 
     def __getitem__(self, idx):
         if not isinstance(idx, slice):
@@ -179,7 +167,7 @@ class Range(object):
         if start is None:
             start = self.start
         if end is None:
-            end = self.end
+            end = self.end + 1
         return self._buffer[start:end]
 
     def __setitem__(self, idx, lines):
@@ -191,26 +179,26 @@ class Range(object):
         if start is None:
             start = self.start
         if end is None:
-            end = self.end
+            end = self.end + 1
         self._buffer[start:end] = lines
 
     def __iter__(self):
-        for i in range(self.start, self.end):
+        for i in range(self.start, self.end + 1):
             yield self._buffer[i]
 
     def append(self, lines, i=None):
         i = self._normalize_index(i)
         if i is None:
-            i = self.end
+            i = self.end + 1
         self._buffer.append(lines, i)
 
     def _normalize_index(self, index):
         if index is None:
             return None
         if index < 0:
-            index = self.end - 1
+            index = self.end
         else:
             index += self.start
-            if index >= self.end:
-                index = self.end - 1
+            if index > self.end:
+                index = self.end
         return index
diff --git a/neovim/api/common.py b/neovim/api/common.py
index 3a456e3..eb7da90 100644
--- a/neovim/api/common.py
+++ b/neovim/api/common.py
@@ -1,4 +1,5 @@
 """Code shared between the API classes."""
+import functools
 
 
 class Remote(object):
@@ -10,6 +11,20 @@ class Remote(object):
     object handle into consideration.
     """
 
+    def __init__(self, session, code_data):
+        """Initialize from session and code_data immutable object.
+
+        The `code_data` contains serialization information required for
+        msgpack-rpc calls. It must be immutable for Buffer equality to work.
+        """
+        self._session = session
+        self.code_data = code_data
+        self.api = RemoteApi(self, self._api_prefix)
+        self.vars = RemoteMap(self, self._api_prefix + 'get_var',
+                              self._api_prefix + 'set_var')
+        self.options = RemoteMap(self, self._api_prefix + 'get_option',
+                                 self._api_prefix + 'set_option')
+
     def __eq__(self, other):
         """Return True if `self` and `other` are the same object."""
         return (hasattr(other, 'code_data') and
@@ -19,6 +34,24 @@ class Remote(object):
         """Return hash based on remote object id."""
         return self.code_data.__hash__()
 
+    def request(self, name, *args, **kwargs):
+        """Wrapper for nvim.request."""
+        return self._session.request(name, self, *args, **kwargs)
+
+
+class RemoteApi(object):
+
+    """Wrapper to allow api methods to be called like python methods."""
+
+    def __init__(self, obj, api_prefix):
+        """Initialize a RemoteApi with object and api prefix."""
+        self._obj = obj
+        self._api_prefix = api_prefix
+
+    def __getattr__(self, name):
+        """Return wrapper to named api method."""
+        return functools.partial(self._obj.request, self._api_prefix + name)
+
 
 class RemoteMap(object):
 
@@ -31,12 +64,12 @@ class RemoteMap(object):
     It is used to provide a dict-like API to vim variables and options.
     """
 
-    def __init__(self, session, get_method, set_method, self_obj=None):
+    def __init__(self, obj, get_method, set_method=None, self_obj=None):
         """Initialize a RemoteMap with session, getter/setter and self_obj."""
-        self._get = _wrap(session, get_method, self_obj)
+        self._get = functools.partial(obj.request, get_method)
         self._set = None
         if set_method:
-            self._set = _wrap(session, set_method, self_obj)
+            self._set = functools.partial(obj.request, set_method)
 
     def __getitem__(self, key):
         """Return a map value by key."""
@@ -91,9 +124,9 @@ class RemoteSequence(object):
     locally(iteration, indexing, counting, etc).
     """
 
-    def __init__(self, session, method, self_obj=None):
+    def __init__(self, session, method):
         """Initialize a RemoteSequence with session, method and self_obj."""
-        self._fetch = _wrap(session, method, self_obj)
+        self._fetch = functools.partial(session.request, method)
 
     def __len__(self):
         """Return the length of the remote sequence."""
@@ -120,146 +153,20 @@ def _identity(obj, session, method, kind):
     return obj
 
 
-class SessionHook(object):
-
-    """Pair of functions to filter objects coming/going from/to Nvim.
-
-    Filter functions receive the following arguments:
-
-    - obj: The object to process
-    - session: The current session object
-    - method: The method name
-    - kind: Kind of filter, can be one of:
-        - 'request' for requests coming from Nvim
-        - 'notification' for notifications coming from Nvim
-        - 'out-request' for requests going to Nvim
-
-    Whatever is returned from the function is used as a replacement for `obj`.
-
-    This class also provides a `compose` method for composing hooks.
-    """
-
-    def __init__(self, from_nvim=_identity, to_nvim=_identity):
-        """Initialize a SessionHook with from/to filters."""
-        self.from_nvim = from_nvim
-        self.to_nvim = to_nvim
-
-    def compose(self, other):
-        """Compose two SessionHook instances.
-
-        This works by composing the individual from/to filters and creating
-        a new SessionHook instance with the composed filters.
-        """
-        def comp(f1, f2):
-            if f1 is _identity:
-                return f2
-            if f2 is _identity:
-                return f1
-            return lambda o, s, m, k: f1(f2(o, s, m, k), s, m, k)
-
-        return SessionHook(comp(other.from_nvim, self.from_nvim),
-                           comp(other.to_nvim, self.to_nvim))
-
-
-class DecodeHook(SessionHook):
-
-    """SessionHook subclass that decodes utf-8 strings coming from Nvim.
-
-    This class is useful for python3, where strings are now unicode by
-    default(byte strings need to be prefixed with "b").
-    """
-
-    def __init__(self, encoding='utf-8', encoding_errors='strict'):
-        """Initialize with encoding and encoding errors policy."""
-        self.encoding = encoding
-        self.encoding_errors = encoding_errors
-        super(DecodeHook, self).__init__(from_nvim=self._decode_if_bytes)
-
-    def _decode_if_bytes(self, obj, session, method, kind):
-        if isinstance(obj, bytes):
-            return obj.decode(self.encoding, errors=self.encoding_errors)
-        return obj
-
-    def walk(self, obj):
-        """Decode bytes found in obj (any msgpack object).
-
-        Uses encoding and policy specified in constructor.
-        """
-        return walk(self._decode_if_bytes, obj, None, None, None)
-
-
-class SessionFilter(object):
-
-    """Wraps a session-like object with a SessionHook instance.
-
-    This class can be used as a drop-in replacement for a sessions, the
-    difference is that a hook is applied to all data passing through a
-    SessionFilter instance.
-    """
-
-    def __init__(self, session, hook):
-        """Initialize with a Session(or SessionFilter) and a hook.
-
-        If `session` is already a SessionFilter, it's hook will be extracted
-        and composed with `hook`.
-        """
-        if isinstance(session, SessionFilter):
-            self._hook = session._hook.compose(hook)
-            self._session = session._session
-        else:
-            self._hook = hook
-            self._session = session
-        # Both filters are applied to `walk` so objects are transformed
-        # recursively
-        self._in = self._hook.from_nvim
-        self._out = self._hook.to_nvim
-
-    def threadsafe_call(self, fn, *args, **kwargs):
-        """Wrapper for Session.threadsafe_call."""
-        self._session.threadsafe_call(fn, *args, **kwargs)
-
-    def next_message(self):
-        """Wrapper for Session.next_message."""
-        msg = self._session.next_message()
-        if msg:
-            return walk(self._in, msg, self, msg[1], msg[0])
-
-    def request(self, name, *args, **kwargs):
-        """Wrapper for Session.request."""
-        args = walk(self._out, args, self, name, 'out-request')
-        return walk(self._in, self._session.request(name, *args, **kwargs),
-                    self, name, 'out-request')
-
-    def run(self, request_cb, notification_cb, setup_cb=None):
-        """Wrapper for Session.run."""
-        def filter_request_cb(name, args):
-            result = request_cb(self._in(name, self, name, 'request'),
-                                walk(self._in, args, self, name, 'request'))
-            return walk(self._out, result, self, name, 'request')
-
-        def filter_notification_cb(name, args):
-            notification_cb(self._in(name, self, name, 'notification'),
-                            walk(self._in, args, self, name, 'notification'))
-
-        self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
-
-    def stop(self):
-        """Wrapper for Session.stop."""
-        self._session.stop()
+def decode_if_bytes(obj, mode=True):
+    """Decode obj if it is bytes."""
+    if mode is True:
+        mode = "strict"
+    if isinstance(obj, bytes):
+        return obj.decode("utf-8", errors=mode)
+    return obj
 
 
-def walk(fn, obj, *args):
+def walk(fn, obj, *args, **kwargs):
     """Recursively walk an object graph applying `fn`/`args` to objects."""
     if type(obj) in [list, tuple]:
         return list(walk(fn, o, *args) for o in obj)
     if type(obj) is dict:
         return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
                     obj.items())
-    return fn(obj, *args)
-
-
-def _wrap(session, method, self_obj):
-    if self_obj is not None:
-        return lambda *args: session.request(method, self_obj, *args)
-    else:
-        return lambda *args: session.request(method, *args)
+    return fn(obj, *args, **kwargs)
diff --git a/neovim/api/nvim.py b/neovim/api/nvim.py
index 9650f31..2b68407 100644
--- a/neovim/api/nvim.py
+++ b/neovim/api/nvim.py
@@ -1,14 +1,15 @@
 """Main Nvim interface."""
 import functools
 import os
+import sys
 
 from traceback import format_exc, format_stack
 
 from msgpack import ExtType
 
 from .buffer import Buffer
-from .common import (DecodeHook, Remote, RemoteMap, RemoteSequence,
-                     SessionFilter, SessionHook, walk)
+from .common import (Remote, RemoteApi, RemoteMap, RemoteSequence,
+                     decode_if_bytes, walk)
 from .tabpage import Tabpage
 from .window import Window
 from ..compat import IS_PYTHON3
@@ -24,7 +25,7 @@ class Nvim(object):
 
     """Class that represents a remote Nvim instance.
 
-    This class is main entry point to Nvim remote API, it is a thin wrapper
+    This class is main entry point to Nvim remote API, it is a wrapper
     around Session instances.
 
     The constructor of this class must not be called directly. Instead, the
@@ -32,9 +33,10 @@ class Nvim(object):
     from a raw `Session` instance.
 
     Subsequent instances for the same session can be created by calling the
-    `with_hook` instance method and passing a SessionHook instance. This can
-    be useful to have multiple `Nvim` objects that behave differently without
-    one affecting the other.
+    `with_decode` instance method to change the decoding behavior or
+    `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.
     """
 
     @classmethod
@@ -49,9 +51,8 @@ class Nvim(object):
         channel_id, metadata = session.request(b'vim_get_api_info')
 
         if IS_PYTHON3:
-            hook = DecodeHook()
             # decode all metadata strings for python3
-            metadata = walk(hook.from_nvim, metadata, None, None, None)
+            metadata = walk(decode_if_bytes, metadata)
 
         types = {
             metadata['types']['Buffer']['id']: Buffer,
@@ -59,32 +60,114 @@ class Nvim(object):
             metadata['types']['Tabpage']['id']: Tabpage,
         }
 
-        return cls(session, channel_id, metadata).with_hook(ExtHook(types))
+        return cls(session, channel_id, metadata, types)
 
-    def __init__(self, session, channel_id, metadata):
+    @classmethod
+    def from_nvim(cls, nvim):
+        """Create a new Nvim instance from an existing instance."""
+        return cls(nvim._session, nvim.channel_id, nvim.metadata,
+                   nvim.types, nvim._decode, nvim._err_cb)
+
+    def __init__(self, session, channel_id, metadata, types,
+                 decode=False, err_cb=None):
         """Initialize a new Nvim instance. This method is module-private."""
         self._session = session
         self.channel_id = channel_id
         self.metadata = metadata
-        self.vars = RemoteMap(session, 'vim_get_var', 'vim_set_var')
-        self.vvars = RemoteMap(session, 'vim_get_vvar', None)
-        self.options = RemoteMap(session, 'vim_get_option', 'vim_set_option')
-        self.buffers = RemoteSequence(session, 'vim_get_buffers')
-        self.windows = RemoteSequence(session, 'vim_get_windows')
-        self.tabpages = RemoteSequence(session, 'vim_get_tabpages')
-        self.current = Current(session)
+        self.types = types
+        self.api = RemoteApi(self, 'vim_')
+        self.vars = RemoteMap(self, 'vim_get_var', 'vim_set_var')
+        self.vvars = RemoteMap(self, 'vim_get_vvar', None)
+        self.options = RemoteMap(self, 'vim_get_option', 'vim_set_option')
+        self.buffers = RemoteSequence(self, 'vim_get_buffers')
+        self.windows = RemoteSequence(self, 'vim_get_windows')
+        self.tabpages = RemoteSequence(self, 'vim_get_tabpages')
+        self.current = Current(self)
+        self.session = CompatibilitySession(self)
         self.funcs = Funcs(self)
         self.error = NvimError
+        self._decode = decode
+        self._err_cb = err_cb
 
-    def with_hook(self, hook):
-        """Initialize a new Nvim instance."""
-        return Nvim(SessionFilter(self.session, hook), self.channel_id,
-                    self.metadata)
+    def _from_nvim(self, obj, decode=None):
+        if decode is None:
+            decode = self._decode
+        if type(obj) is ExtType:
+            cls = self.types[obj.code]
+            return cls(self, (obj.code, obj.data))
+        if decode:
+            obj = decode_if_bytes(obj, decode)
+        return obj
 
-    @property
-    def session(self):
-        """Return the Session or SessionFilter for a Nvim instance."""
-        return self._session
+    def _to_nvim(self, obj):
+        if isinstance(obj, Remote):
+            return ExtType(*obj.code_data)
+        return obj
+
+    def request(self, name, *args, **kwargs):
+        r"""Send an API request or notification to nvim.
+
+        It is rarely needed to call this function directly, as most API
+        functions have python wrapper functions. The `api` object can
+        be also be used to call API functions as methods:
+
+            vim.api.err_write('ERROR\n', async=True)
+            vim.current.buffer.api.get_mark('.')
+
+        is equivalent to
+
+            vim.request('vim_err_write', 'ERROR\n', async=True)
+            vim.request('buffer_get_mark', vim.current.buffer, '.')
+
+
+        Normally a blocking request will be sent.  If the `async` flag is
+        present and True, a asynchronous notification is sent instead. This
+        will never block, and the return value or error is ignored.
+        """
+        decode = kwargs.pop('decode', self._decode)
+        args = walk(self._to_nvim, args)
+        res = self._session.request(name, *args, **kwargs)
+        return walk(self._from_nvim, res, decode=decode)
+
+    def next_message(self):
+        """Block until a message(request or notification) is available.
+
+        If any messages were previously enqueued, return the first in queue.
+        If not, run the event loop until one is received.
+        """
+        msg = self._session.next_message()
+        if msg:
+            return walk(self._from_nvim, msg)
+
+    def run_loop(self, request_cb, notification_cb,
+                 setup_cb=None, err_cb=None):
+        """Run the event loop to receive requests and notifications from Nvim.
+
+        This should not be called from a plugin running in the host, which
+        already runs the loop and dispatches events to plugins.
+        """
+        def filter_request_cb(name, args):
+            args = walk(self._from_nvim, args)
+            result = request_cb(self._from_nvim(name), args)
+            return walk(self._to_nvim, result)
+
+        def filter_notification_cb(name, args):
+            notification_cb(self._from_nvim(name), walk(self._from_nvim, args))
+
+        if err_cb is None:
+            err_cb = sys.stderr.write
+        self._err_cb = err_cb
+
+        self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
+
+    def stop_loop(self):
+        """Stop the event loop being started with `run_loop`."""
+        self._session.stop()
+
+    def with_decode(self, decode=True):
+        """Initialize a new Nvim instance."""
+        return Nvim(self._session, self.channel_id,
+                    self.metadata, self.types, decode, self._err_cb)
 
     def ui_attach(self, width, height, rgb):
         """Register as a remote UI.
@@ -92,57 +175,53 @@ class Nvim(object):
         After this method is called, the client will receive redraw
         notifications.
         """
-        return self._session.request('ui_attach', width, height, rgb)
+        return self.request('ui_attach', width, height, rgb)
 
     def ui_detach(self):
         """Unregister as a remote UI."""
-        return self._session.request('ui_detach')
+        return self.request('ui_detach')
 
     def ui_try_resize(self, width, height):
         """Notify nvim that the client window has resized.
 
         If possible, nvim will send a redraw request to resize.
         """
-        return self._session.request('ui_try_resize', width, height)
+        return self.request('ui_try_resize', width, height)
 
     def subscribe(self, event):
         """Subscribe to a Nvim event."""
-        return self._session.request('vim_subscribe', event)
+        return self.request('vim_subscribe', event)
 
     def unsubscribe(self, event):
         """Unsubscribe to a Nvim event."""
-        return self._session.request('vim_unsubscribe', event)
+        return self.request('vim_unsubscribe', event)
 
-    def command(self, string, async=False):
+    def command(self, string, **kwargs):
         """Execute a single ex command."""
-        return self._session.request('vim_command', string, async=async)
+        return self.request('vim_command', string, **kwargs)
 
     def command_output(self, string):
         """Execute a single ex command and return the output."""
-        return self._session.request('vim_command_output', string)
+        return self.request('vim_command_output', string)
 
-    def eval(self, string, async=False):
+    def eval(self, string, **kwargs):
         """Evaluate a vimscript expression."""
-        return self._session.request('vim_eval', string, async=async)
+        return self.request('vim_eval', string, **kwargs)
 
     def call(self, name, *args, **kwargs):
         """Call a vimscript function."""
-        for k in kwargs:
-            if k != "async":
-                raise TypeError(
-                    "call() got an unexpected keyword argument '{}'".format(k))
-        return self._session.request('vim_call_function', name, args, **kwargs)
+        return self.request('vim_call_function', name, args, **kwargs)
 
     def strwidth(self, string):
         """Return the number of display cells `string` occupies.
 
         Tab is counted as one cell.
         """
-        return self._session.request('vim_strwidth', string)
+        return self.request('vim_strwidth', string)
 
     def list_runtime_paths(self):
         """Return a list of paths contained in the 'runtimepath' option."""
-        return self._session.request('vim_list_runtime_paths')
+        return self.request('vim_list_runtime_paths')
 
     def foreach_rtp(self, cb):
         """Invoke `cb` for each path in 'runtimepath'.
@@ -152,7 +231,7 @@ class Nvim(object):
         are no longer paths. If stopped in case callable returned non-None,
         vim.foreach_rtp function returns the value returned by callable.
         """
-        for path in self._session.request('vim_list_runtime_paths'):
+        for path in self.request('vim_list_runtime_paths'):
             try:
                 if cb(path) is not None:
                     break
@@ -162,7 +241,7 @@ class Nvim(object):
     def chdir(self, dir_path):
         """Run os.chdir, then all appropriate vim stuff."""
         os_chdir(dir_path)
-        return self._session.request('vim_change_directory', dir_path)
+        return self.request('vim_change_directory', dir_path)
 
     def feedkeys(self, keys, options='', escape_csi=True):
         """Push `keys` to Nvim user input buffer.
@@ -173,7 +252,7 @@ class Nvim(object):
         - 't': Handle keys as if typed; otherwise they are handled as if coming
                from a mapping. This matters for undo, opening folds, etc.
         """
-        return self._session.request('vim_feedkeys', keys, options, escape_csi)
+        return self.request('vim_feedkeys', keys, options, escape_csi)
 
     def input(self, bytes):
         """Push `bytes` to Nvim low level input buffer.
@@ -183,7 +262,7 @@ class Nvim(object):
         written(which can be less than what was requested if the buffer is
         full).
         """
-        return self._session.request('vim_input', bytes)
+        return self.request('vim_input', bytes)
 
     def replace_termcodes(self, string, from_part=False, do_lt=True,
                           special=True):
@@ -199,16 +278,16 @@ class Nvim(object):
 
         The returned sequences can be used as input to `feedkeys`.
         """
-        return self._session.request('vim_replace_termcodes', string,
-                                     from_part, do_lt, special)
+        return self.request('vim_replace_termcodes', string,
+                            from_part, do_lt, special)
 
     def out_write(self, msg):
         """Print `msg` as a normal message."""
-        return self._session.request('vim_out_write', msg)
+        return self.request('vim_out_write', msg)
 
-    def err_write(self, msg, async=False):
+    def err_write(self, msg, **kwargs):
         """Print `msg` as an error message."""
-        return self._session.request('vim_err_write', msg, async=async)
+        return self.request('vim_err_write', msg, **kwargs)
 
     def quit(self, quit_command='qa!'):
         """Send a quit command to Nvim.
@@ -245,13 +324,21 @@ class Nvim(object):
                 fn(*args, **kwargs)
             except Exception as err:
                 msg = ("error caught while executing async callback:\n"
-                       "{!r}\n{}\n \nthe call was requested at\n{}"
+                       "{0!r}\n{1}\n \nthe call was requested at\n{2}"
                        .format(err, format_exc(5), call_point))
-                self.err_write(msg, async=True)
+                self._err_cb(msg)
                 raise
         self._session.threadsafe_call(handler)
 
 
+class CompatibilitySession(object):
+
+    """Helper class for API compatibility."""
+
+    def __init__(self, nvim):
+        self.threadsafe_call = nvim.async_call
+
+
 class Current(object):
 
     """Helper class for emulating vim.current from python-vim."""
@@ -304,23 +391,5 @@ class Funcs(object):
         return functools.partial(self._nvim.call, name)
 
 
-class ExtHook(SessionHook):
-    def __init__(self, types):
-        self.types = types
-        super(ExtHook, self).__init__(from_nvim=self.from_ext,
-                                      to_nvim=self.to_ext)
-
-    def from_ext(self, obj, session, method, kind):
-        if type(obj) is ExtType:
-            cls = self.types[obj.code]
-            return cls(session, (obj.code, obj.data))
-        return obj
-
-    def to_ext(self, obj, session, method, kind):
-        if isinstance(obj, Remote):
-            return ExtType(*obj.code_data)
-        return obj
-
-
 class NvimError(Exception):
     pass
diff --git a/neovim/api/tabpage.py b/neovim/api/tabpage.py
index 355ba5c..7742ba3 100644
--- a/neovim/api/tabpage.py
+++ b/neovim/api/tabpage.py
@@ -1,32 +1,30 @@
 """API for working with Nvim tabpages."""
-from .common import Remote, RemoteMap, RemoteSequence
+from .common import Remote, RemoteSequence
 
 
 __all__ = ('Tabpage')
 
 
 class Tabpage(Remote):
-
     """A remote Nvim tabpage."""
 
-    def __init__(self, session, code_data):
+    _api_prefix = "tabpage_"
... 693 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-neovim.git



More information about the Python-modules-commits mailing list