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