Revision 0304f041 ncclient/operations/rpc.py
b/ncclient/operations/rpc.py | ||
---|---|---|
188 | 188 |
instance = object.__new__(cls) |
189 | 189 |
instance._lock = Lock() |
190 | 190 |
instance._id2rpc = {} |
191 |
instance._pipelined = session.can_pipeline |
|
191 |
#instance._pipelined = session.can_pipeline
|
|
192 | 192 |
session.add_listener(instance) |
193 | 193 |
return instance |
194 | 194 |
|
... | ... | |
200 | 200 |
tag, attrs = root |
201 | 201 |
if xml_.unqualify(tag) != 'rpc-reply': |
202 | 202 |
return |
203 |
rpc = None |
|
204 |
for key in attrs: |
|
205 |
if xml_.unqualify(key) == 'message-id': |
|
206 |
id = attrs[key] |
|
203 |
for key in attrs: # in the <rpc-reply> attributes |
|
204 |
if xml_.unqualify(key) == 'message-id': # if we found msgid attr |
|
205 |
id = attrs[key] # get the msgid |
|
207 | 206 |
try: |
208 | 207 |
with self._lock: |
209 |
rpc = self._id2rpc.pop(id) |
|
208 |
rpc = self._id2rpc.get(id) # the corresponding rpc |
|
209 |
logger.debug('delivering to %r' % rpc) |
|
210 |
rpc.deliver_reply(raw) |
|
210 | 211 |
except KeyError: |
211 |
logger.warning('no object registered for message-id: [%s]' % id) |
|
212 |
except Exception as e: |
|
213 |
logger.debug('error - %r' % e) |
|
214 |
break |
|
212 |
raise OperationError('Unknown message-id: %s', id) |
|
213 |
# no catching other exceptions, fail loudly if must |
|
214 |
else: |
|
215 |
# if no error delivering, can del the reference to the RPC |
|
216 |
del self._id2rpc[id] |
|
217 |
break |
|
215 | 218 |
else: |
216 |
if not self._pipelined: |
|
217 |
with self._lock: |
|
218 |
assert(len(self._id2rpc) == 1) |
|
219 |
rpc = self._id2rpc.values()[0] |
|
220 |
self._id2rpc.clear() |
|
221 |
else: |
|
222 |
logger.warning('<rpc-reply> without message-id received: %s' % raw) |
|
223 |
logger.debug('delivering to %r' % rpc) |
|
224 |
rpc.deliver_reply(raw) |
|
225 |
|
|
219 |
raise OperationError('Could not find "message-id" attribute in <rpc-reply>') |
|
220 |
|
|
226 | 221 |
def errback(self, err): |
227 | 222 |
try: |
228 | 223 |
for rpc in self._id2rpc.values(): |
... | ... | |
281 | 276 |
|
282 | 277 |
def _request(self, op): |
283 | 278 |
"""Subclasses call this method to make the RPC request. |
284 |
|
|
285 |
In asynchronous mode, returns an :class:`~threading.Event` which is set |
|
286 |
when the reply has been received or an error occured. It is prudent, |
|
287 |
therefore, to check the :attr:`error` attribute before accesing |
|
288 |
:attr:`reply`. |
|
289 |
|
|
290 |
Otherwise, waits until the reply is received and returns |
|
279 |
|
|
280 |
In synchronous mode, waits until the reply is received and returns |
|
291 | 281 |
:class:`RPCReply`. |
292 |
|
|
282 |
|
|
283 |
In asynchronous mode, returns immediately, returning a reference to this |
|
284 |
object. The :attr:`event` attribute will be set when the reply has been |
|
285 |
received (see :attr:`reply`) or an error occured (see :attr:`error`). |
|
286 |
|
|
293 | 287 |
:arg opspec: :ref:`dtree` for the operation |
294 | 288 |
:type opspec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element` |
295 |
:rtype: :class:`~threading.Event` or :class:`RPCReply`
|
|
289 |
:rtype: :class:`RPCReply` (sync) or :class:`RPC` (async)
|
|
296 | 290 |
""" |
297 | 291 |
logger.debug('request %r with opsepc=%r' % (self, op)) |
298 | 292 |
req = self._build(op) |
299 | 293 |
self._session.send(req) |
300 | 294 |
if self._async: |
301 |
logger.debug('async, returning event')
|
|
302 |
return self._event
|
|
295 |
logger.debug('async, returning') |
|
296 |
return self |
|
303 | 297 |
else: |
304 | 298 |
logger.debug('sync, will wait for timeout=%r' % self._timeout) |
305 | 299 |
self._event.wait(self._timeout) |
... | ... | |
332 | 326 |
if capability not in self._session.server_capabilities: |
333 | 327 |
raise MissingCapabilityError('Server does not support [%s]' % |
334 | 328 |
capability) |
335 |
|
|
329 |
|
|
336 | 330 |
def deliver_reply(self, raw): |
337 | 331 |
# internal use |
338 | 332 |
self._reply = self.REPLY_CLS(raw) |
339 |
self._delivery_hook()
|
|
333 |
#self._delivery_hook() -- usecase?!
|
|
340 | 334 |
self._event.set() |
341 | 335 |
|
342 | 336 |
def deliver_error(self, err): |
343 | 337 |
# internal use |
344 | 338 |
self._error = err |
345 |
self._delivery_hook()
|
|
339 |
#self._delivery_hook() -- usecase?!
|
|
346 | 340 |
self._event.set() |
347 | 341 |
|
348 | 342 |
@property |
... | ... | |
353 | 347 |
@property |
354 | 348 |
def error(self): |
355 | 349 |
""":exc:`Exception` type if an error occured or :const:`None`. |
356 |
|
|
357 |
This attribute should be checked if the request was made asynchronously, |
|
358 |
so that it can be determined if :attr:`event` being set is because of a |
|
359 |
reply or error. |
|
360 |
|
|
350 |
|
|
361 | 351 |
.. note:: |
362 | 352 |
This represents an error which prevented a reply from being |
363 | 353 |
received. An *<rpc-error>* does not fall in that category -- see |
Also available in: Unified diff