Revision 4de03d63 ncclient/operations/rpc.py

b/ncclient/operations/rpc.py
23 23
import logging
24 24
logger = logging.getLogger('ncclient.rpc')
25 25

  
26
class RPC(object):
27
    
28
    DEPENDS = []
29
    REPLY_CLS = RPCReply
30
    
31
    def __init__(self, session, async=False, timeout=None):
32
        if not session.can_pipeline:
33
            raise UserWarning('Asynchronous mode not supported for this device/session')
34
        self._session = session
35
        try:
36
            for cap in self.DEPENDS:
37
                self._assert(cap)
38
        except AttributeError:
39
            pass        
40
        self._async = async
41
        self._timeout = timeout
42
        # keeps things simple instead of having a class attr that has to be locked
43
        self._id = uuid1().urn
44
        self._listener = RPCReplyListener(session)
45
        self._listener.register(self._id, self)
46
        self._reply = None
47
        self._reply_event = Event()
48
    
49
    def _build(self, opspec, encoding='utf-8'):
50
        "TODO: docstring"
51
        spec = {
52
            'tag': content.qualify('rpc'),
53
            'attributes': {'message-id': self._id},
54
            'subtree': opspec
55
            }
56
        return content.dtree2xml(encoding)
57
    
58
    def _request(self, op):
59
        req = self._build(op)
60
        self._session.send(req)
61
        if self._async:
62
            return self._reply_event
63
        else:
64
            self._reply_event.wait(self._timeout)
65
            if self._reply_event.isSet():
66
                self._reply.parse()
67
                return self._reply
68
            else:
69
                raise ReplyTimeoutError
70
    
71
    def request(self):
72
        return self._request(self.SPEC)
73
    
74
    def _delivery_hook(self):
75
        'For subclasses'
76
        pass
77
    
78
    def _assert(self, capability):
79
        if capability not in self._session.server_capabilities:
80
            raise MissingCapabilityError('Server does not support [%s]' % cap)
81
    
82
    def deliver(self, raw):
83
        self._reply = self.REPLY_CLS(raw)
84
        self._delivery_hook()
85
        self._reply_event.set()
86
    
87
    @property
88
    def has_reply(self):
89
        return self._reply_event.isSet()
90
    
91
    @property
92
    def reply(self):
93
        return self._reply
94
    
95
    @property
96
    def id(self):
97
        return self._id
98
    
99
    @property
100
    def session(self):
101
        return self._session
102
    
103
    @property
104
    def reply_event(self):
105
        return self._reply_event
106
    
107
    def set_async(self, bool): self._async = bool
108
    async = property(fget=lambda self: self._async, fset=set_async)
109
    
110
    def set_timeout(self, timeout): self._timeout = timeout
111
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)
112

  
113 26

  
114 27
class RPCReply:
115 28
    
......
235 148
    __repr__ = lambda self: repr(self._dict)
236 149

  
237 150

  
238
class RPCReplyListener:
151
class RPCReplyListener(object):
239 152
    
240 153
    # one instance per session
241 154
    def __new__(cls, session):
......
286 199
    def errback(self, err):
287 200
        if self._errback is not None:
288 201
            self._errback(err)
202

  
203

  
204
class RPC(object):
205
    
206
    DEPENDS = []
207
    REPLY_CLS = RPCReply
208
    
209
    def __init__(self, session, async=False, timeout=None):
210
        if not session.can_pipeline:
211
            raise UserWarning('Asynchronous mode not supported for this device/session')
212
        self._session = session
213
        try:
214
            for cap in self.DEPENDS:
215
                self._assert(cap)
216
        except AttributeError:
217
            pass        
218
        self._async = async
219
        self._timeout = timeout
220
        # keeps things simple instead of having a class attr that has to be locked
221
        self._id = uuid1().urn
222
        # RPCReplyListener itself makes sure there isn't more than one instance -- i.e. multiton
223
        self._listener = RPCReplyListener(session)
224
        self._listener.register(self._id, self)
225
        self._reply = None
226
        self._reply_event = Event()
227
    
228
    def _build(self, opspec, encoding='utf-8'):
229
        "TODO: docstring"
230
        spec = {
231
            'tag': content.qualify('rpc'),
232
            'attributes': {'message-id': self._id},
233
            'subtree': opspec
234
            }
235
        return content.dtree2xml(encoding)
236
    
237
    def _request(self, op):
238
        req = self._build(op)
239
        self._session.send(req)
240
        if self._async:
241
            return self._reply_event
242
        else:
243
            self._reply_event.wait(self._timeout)
244
            if self._reply_event.isSet():
245
                self._reply.parse()
246
                return self._reply
247
            else:
248
                raise ReplyTimeoutError
249
    
250
    def request(self):
251
        return self._request(self.SPEC)
252
    
253
    def _delivery_hook(self):
254
        'For subclasses'
255
        pass
256
    
257
    def _assert(self, capability):
258
        if capability not in self._session.server_capabilities:
259
            raise MissingCapabilityError('Server does not support [%s]' % cap)
260
    
261
    def deliver(self, raw):
262
        self._reply = self.REPLY_CLS(raw)
263
        self._delivery_hook()
264
        self._reply_event.set()
265
    
266
    @property
267
    def has_reply(self):
268
        return self._reply_event.isSet()
269
    
270
    @property
271
    def reply(self):
272
        return self._reply
273
    
274
    @property
275
    def id(self):
276
        return self._id
277
    
278
    @property
279
    def session(self):
280
        return self._session
281
    
282
    @property
283
    def reply_event(self):
284
        return self._reply_event
285
    
286
    def set_async(self, bool): self._async = bool
287
    async = property(fget=lambda self: self._async, fset=set_async)
288
    
289
    def set_timeout(self, timeout): self._timeout = timeout
290
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)

Also available in: Unified diff