Skip to content

Commit 3f7b1ef

Browse files
committed
Improve error handling
- Don't emit a fatal error when receiving signals - Handle SIGINT(useful for console testing) - Throw received error on next_message()
1 parent d1b3de6 commit 3f7b1ef

File tree

3 files changed

+29
-21
lines changed

3 files changed

+29
-21
lines changed

neovim/client.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ def next_message(self):
122122
if msg:
123123
return msg
124124

125+
error = {}
126+
125127
def request_cb(name, args, reply_fn):
126128
self.pending.append(('request', name, args, reply_fn,))
127129
self.stream.loop_stop()
@@ -131,12 +133,17 @@ def notification_cb(name, args):
131133
self.stream.loop_stop()
132134

133135
def error_cb(err):
134-
self.pending.append(('eof', err,))
136+
error['err'] = err
137+
if isinstance(err, VimExit):
138+
self.pending.append(('eof', err,))
135139
self.stream.loop_stop()
136140

137141
debug('will block until a message is available')
138142
self.stream.loop_start(request_cb, notification_cb, error_cb)
139143

144+
if error:
145+
raise error['err']
146+
140147
msg = self.next_pending_message()
141148
if msg:
142149
return msg

neovim/plugin_host.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ def install_plugins(self):
105105
try:
106106
plugin = plugin_class(self.vim)
107107
except:
108-
warn('constructor for %s failed. it must accept one argument',
109-
cls_name)
108+
err_str = format_exc(5)
109+
warn('constructor for %s failed: %s', cls_name, err_str)
110110
continue
111111
methods = inspect.getmembers(plugin, inspect.ismethod)
112112
debug('registering event handlers for %s', plugin_class.__name__)

neovim/uv_stream.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from collections import deque
22
from .util import VimExit
3-
from signal import SIGTERM
4-
import sys, pyuv, logging
3+
import sys, pyuv, logging, signal
54

65
logger = logging.getLogger(__name__)
76
debug, warn = (logger.debug, logger.warn,)
@@ -13,15 +12,19 @@ class UvStream(object):
1312
def __init__(self, address=None, port=None, spawn_argv=None):
1413
debug('initializing UvStream instance')
1514
self._loop = pyuv.Loop()
16-
self._error = None
15+
self._fatal = None
1716
self._connected = False
1817
self._data_cb = None
1918
self._error_cb = None
2019
self._connection_error = None
2120
self._pending_writes = 0
2221
self._async = pyuv.Async(self._loop, self._on_async)
2322
self._term = pyuv.Signal(self._loop)
24-
self._term.start(self._on_term, SIGTERM)
23+
self._term.start(self._on_signal, signal.SIGTERM)
24+
self._int = pyuv.Signal(self._loop)
25+
self._int.start(self._on_signal, signal.SIGINT)
26+
self._signames = dict((k, v) for v, k in signal.__dict__.items() \
27+
if v.startswith('SIG'))
2528
self._error_stream = None
2629
# Select the type of handle
2730
if spawn_argv:
@@ -84,20 +87,18 @@ def _on_connect(self, stream, error):
8487
self.loop_stop()
8588
if error:
8689
msg = pyuv.errno.strerror(error)
87-
self._error = msg
90+
self._fatal = msg
8891
warn('error connecting to neovim: %s', msg)
8992
self._connection_error = IOError(msg)
9093
return
9194
self._connected = True
9295
self._read_stream = self._write_stream = stream
9396

9497

95-
def _on_term(self, handle, signum):
98+
def _on_signal(self, handle, signum):
9699
self.loop_stop()
97-
self._error = 'Received SIGTERM'
98-
err = IOError(self._error)
100+
err = Exception('Received %s' % self._signames[signum])
99101
if not self._error_cb:
100-
self._loop.stop()
101102
raise err
102103
self._error_cb(err)
103104

@@ -116,7 +117,7 @@ def _connect(self):
116117

117118
def _on_exit(self, handle, exit_status, term_signal):
118119
self._loop.stop()
119-
self._error = (
120+
self._fatal = (
120121
'The child nvim instance exited with status %s' % exit_status)
121122

122123

@@ -127,7 +128,7 @@ def _on_stderr_read(self, handle, data, error):
127128
err = IOError(msg)
128129
if not self._error_cb:
129130
self._loop.stop()
130-
self._error = err
131+
self._fatal = err
131132
raise err
132133
self._error_cb(err)
133134
else:
@@ -143,12 +144,12 @@ def _on_read(self, handle, data, error):
143144
warn('error reading data: %s', msg)
144145
self._error_cb(IOError(msg))
145146
self._loop.stop()
146-
self._error = msg
147+
self._fatal = msg
147148
elif not data:
148149
warn('connection was closed by neovim')
149150
self._loop.stop()
150-
self._error = 'EOF'
151-
self._error_cb(IOError(self._error))
151+
self._fatal = 'EOF'
152+
self._error_cb(IOError(self._fatal))
152153
else:
153154
debug('successfully read %d bytes of data', len(data))
154155
self._data_cb(data)
@@ -176,7 +177,7 @@ def write_cb(handle, error):
176177
if error:
177178
self._loop.stop()
178179
msg = pyuv.errno.strerror(error)
179-
self._error = msg
180+
self._fatal = msg
180181
warn('error writing data: %s', msg)
181182
self._error_cb(IOError(msg))
182183
debug('successfully wrote %d bytes of data', data_len)
@@ -187,9 +188,9 @@ def write_cb(handle, error):
187188

188189

189190
def loop_start(self, data_cb, error_cb):
190-
if self._error:
191-
raise IOError('An error was raised and the connection ' +
192-
'was permanently closed: %s', self._error)
191+
if self._fatal:
192+
raise IOError('A fatal error was raised and the connection ' +
193+
'was permanently closed: %s', self._fatal)
193194
if not self._connected:
194195
self._connect()
195196
if self._connection_error:

0 commit comments

Comments
 (0)