Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ b2d60e49

History | View | Annotate | Download (13 kB)

1 a14c36f9 Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 a14c36f9 Shikhar Bhushan
#
3 a14c36f9 Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 a14c36f9 Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 a14c36f9 Shikhar Bhushan
# You may obtain a copy of the License at
6 a14c36f9 Shikhar Bhushan
#
7 a14c36f9 Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 a14c36f9 Shikhar Bhushan
#
9 a14c36f9 Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 a14c36f9 Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 a14c36f9 Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 a14c36f9 Shikhar Bhushan
# See the License for the specific language governing permissions and
13 a14c36f9 Shikhar Bhushan
# limitations under the License.
14 a14c36f9 Shikhar Bhushan
15 a14c36f9 Shikhar Bhushan
from threading import Event, Lock
16 a14c36f9 Shikhar Bhushan
from uuid import uuid1
17 a14c36f9 Shikhar Bhushan
18 9667bcb2 Shikhar Bhushan
from ncclient.xml_ import *
19 0cdb8b3c Shikhar Bhushan
from ncclient.transport import SessionListener
20 a14c36f9 Shikhar Bhushan
21 216bb34c Shikhar Bhushan
from errors import OperationError, TimeoutExpiredError, MissingCapabilityError
22 a14c36f9 Shikhar Bhushan
23 a14c36f9 Shikhar Bhushan
import logging
24 9667bcb2 Shikhar Bhushan
logger = logging.getLogger("ncclient.operations.rpc")
25 a14c36f9 Shikhar Bhushan
26 a14c36f9 Shikhar Bhushan
27 9667bcb2 Shikhar Bhushan
class RPCError(OperationError):
28 4f650d54 Shikhar Bhushan
29 4bc8021f Shikhar Bhushan
    """Represents an *rpc-error*. It is a type of :exc:`OperationError` and can be raised like any
30 4bc8021f Shikhar Bhushan
    other exception."""
31 11bab021 Shikhar Bhushan
    
32 11bab021 Shikhar Bhushan
    tag_to_attr = {
33 11bab021 Shikhar Bhushan
        qualify("error-type"): "_type",
34 11bab021 Shikhar Bhushan
        qualify("error-tag"): "_tag",
35 11bab021 Shikhar Bhushan
        qualify("error-severity"): "_severity",
36 11bab021 Shikhar Bhushan
        qualify("error-info"): "_info",
37 11bab021 Shikhar Bhushan
        qualify("error-path"): "_path",
38 11bab021 Shikhar Bhushan
        qualify("error-message"): "_message"
39 11bab021 Shikhar Bhushan
    }
40 11bab021 Shikhar Bhushan
    
41 4bc8021f Shikhar Bhushan
    def __init__(self, raw):
42 4bc8021f Shikhar Bhushan
        self._raw = raw
43 7c4ff459 Shikhar Bhushan
        for attr in RPCError.tag_to_attr.values():
44 11bab021 Shikhar Bhushan
            setattr(self, attr, None)
45 4bc8021f Shikhar Bhushan
        for subele in raw:
46 7c4ff459 Shikhar Bhushan
            attr = RPCError.tag_to_attr.get(subele.tag, None)
47 11bab021 Shikhar Bhushan
            if attr is not None:
48 0c55eea9 Shikhar Bhushan
                setattr(self, attr, subele.text if attr != "_info" else to_xml(subele) )
49 a14c36f9 Shikhar Bhushan
        if self.message is not None:
50 d771dffc Shikhar Bhushan
            OperationError.__init__(self, self.message)
51 a14c36f9 Shikhar Bhushan
        else:
52 c1bdbd86 Shikhar Bhushan
            OperationError.__init__(self, self.to_dict())
53 22566666 Shikhar Bhushan
    
54 22566666 Shikhar Bhushan
    def to_dict(self):
55 0c55eea9 Shikhar Bhushan
        return dict([ (attr[1:], getattr(self, attr)) for attr in RPCError.tag_to_attr.values() ])
56 22566666 Shikhar Bhushan
    
57 4bc8021f Shikhar Bhushan
    @property
58 4bc8021f Shikhar Bhushan
    def xml(self):
59 b2d60e49 Shikhar Bhushan
        "*rpc-error* element as returned."
60 4bc8021f Shikhar Bhushan
        return self._raw
61 4bc8021f Shikhar Bhushan
    
62 a14c36f9 Shikhar Bhushan
    @property
63 a14c36f9 Shikhar Bhushan
    def type(self):
64 4bc8021f Shikhar Bhushan
        "`string` representing text of *error-type* element."
65 9667bcb2 Shikhar Bhushan
        return self._type
66 bd7957fb Shikhar Bhushan
    
67 a14c36f9 Shikhar Bhushan
    @property
68 a14c36f9 Shikhar Bhushan
    def tag(self):
69 4bc8021f Shikhar Bhushan
        "`string` representing text of *error-tag* element."
70 9667bcb2 Shikhar Bhushan
        return self._tag
71 bd7957fb Shikhar Bhushan
    
72 bd7957fb Shikhar Bhushan
    @property
73 bd7957fb Shikhar Bhushan
    def severity(self):
74 4bc8021f Shikhar Bhushan
        "`string` representing text of *error-severity* element."
75 bd7957fb Shikhar Bhushan
        return self._severity
76 bd7957fb Shikhar Bhushan
    
77 a14c36f9 Shikhar Bhushan
    @property
78 a14c36f9 Shikhar Bhushan
    def path(self):
79 4bc8021f Shikhar Bhushan
        "`string` or :const:`None`; representing text of *error-path* element."
80 9667bcb2 Shikhar Bhushan
        return self._path
81 11bab021 Shikhar Bhushan
    
82 a14c36f9 Shikhar Bhushan
    @property
83 a14c36f9 Shikhar Bhushan
    def message(self):
84 4bc8021f Shikhar Bhushan
        "`string` or :const:`None`; representing text of *error-message* element."
85 9667bcb2 Shikhar Bhushan
        return self._message
86 11bab021 Shikhar Bhushan
    
87 a14c36f9 Shikhar Bhushan
    @property
88 a14c36f9 Shikhar Bhushan
    def info(self):
89 4bc8021f Shikhar Bhushan
        "`string` (XML) or :const:`None`; representing *error-info* element."
90 9667bcb2 Shikhar Bhushan
        return self._info
91 a14c36f9 Shikhar Bhushan
92 a14c36f9 Shikhar Bhushan
93 4bc8021f Shikhar Bhushan
class RPCReply:
94 4bc8021f Shikhar Bhushan
95 4bc8021f Shikhar Bhushan
    """Represents an *rpc-reply*. Only concerns itself with whether the operation was successful.
96 4bc8021f Shikhar Bhushan

97 4bc8021f Shikhar Bhushan
    .. note::
98 4bc8021f Shikhar Bhushan
        If the reply has not yet been parsed there is an implicit, one-time parsing overhead to
99 4bc8021f Shikhar Bhushan
        accessing the attributes defined by this class and any subclasses.
100 4bc8021f Shikhar Bhushan
    """
101 4bc8021f Shikhar Bhushan
    
102 4bc8021f Shikhar Bhushan
    ERROR_CLS = RPCError
103 4bc8021f Shikhar Bhushan
    "Subclasses can specify a different error class, but it should be a subclass of `RPCError`."
104 4bc8021f Shikhar Bhushan
    
105 4bc8021f Shikhar Bhushan
    def __init__(self, raw):
106 4bc8021f Shikhar Bhushan
        self._raw = raw
107 4bc8021f Shikhar Bhushan
        self._parsed = False
108 4bc8021f Shikhar Bhushan
        self._root = None
109 4bc8021f Shikhar Bhushan
        self._errors = []
110 4bc8021f Shikhar Bhushan
111 4bc8021f Shikhar Bhushan
    def __repr__(self):
112 4bc8021f Shikhar Bhushan
        return self._raw
113 4bc8021f Shikhar Bhushan
    
114 4bc8021f Shikhar Bhushan
    def parse(self):
115 4bc8021f Shikhar Bhushan
        "Parses the *rpc-reply*."
116 4bc8021f Shikhar Bhushan
        if self._parsed: return
117 4bc8021f Shikhar Bhushan
        root = self._root = to_ele(self._raw) # The <rpc-reply> element
118 4bc8021f Shikhar Bhushan
        # Per RFC 4741 an <ok/> tag is sent when there are no errors or warnings
119 4bc8021f Shikhar Bhushan
        ok = root.find(qualify("ok"))
120 4bc8021f Shikhar Bhushan
        if ok is None:
121 4bc8021f Shikhar Bhushan
            # Create RPCError objects from <rpc-error> elements
122 4bc8021f Shikhar Bhushan
            error = root.find(qualify("rpc-error"))
123 4bc8021f Shikhar Bhushan
            if error is not None:
124 4bc8021f Shikhar Bhushan
                for err in root.getiterator(error.tag):
125 4bc8021f Shikhar Bhushan
                    # Process a particular <rpc-error>
126 b2d60e49 Shikhar Bhushan
                    self._errors.append(self.ERROR_CLS(err))
127 b2d60e49 Shikhar Bhushan
        self._parsing_hook(root)
128 4bc8021f Shikhar Bhushan
        self._parsed = True
129 b2d60e49 Shikhar Bhushan
130 b2d60e49 Shikhar Bhushan
    def _parsing_hook(self, root):
131 b2d60e49 Shikhar Bhushan
        pass
132 4bc8021f Shikhar Bhushan
    
133 4bc8021f Shikhar Bhushan
    @property
134 4bc8021f Shikhar Bhushan
    def xml(self):
135 4bc8021f Shikhar Bhushan
        "*rpc-reply* element as returned."
136 4bc8021f Shikhar Bhushan
        return self._raw
137 4bc8021f Shikhar Bhushan
    
138 4bc8021f Shikhar Bhushan
    @property
139 4bc8021f Shikhar Bhushan
    def ok(self):
140 4bc8021f Shikhar Bhushan
        "Boolean value indicating if there were no errors."
141 4bc8021f Shikhar Bhushan
        return not self.errors # empty list => false
142 4bc8021f Shikhar Bhushan
    
143 4bc8021f Shikhar Bhushan
    @property
144 4bc8021f Shikhar Bhushan
    def error(self):
145 4bc8021f Shikhar Bhushan
        "Returns the first `RPCError` and :const:`None` if there were no errors."
146 4bc8021f Shikhar Bhushan
        self.parse()
147 4bc8021f Shikhar Bhushan
        if self._errors:
148 4bc8021f Shikhar Bhushan
            return self._errors[0]
149 4bc8021f Shikhar Bhushan
        else:
150 4bc8021f Shikhar Bhushan
            return None
151 4bc8021f Shikhar Bhushan
    
152 4bc8021f Shikhar Bhushan
    @property
153 4bc8021f Shikhar Bhushan
    def errors(self):
154 4bc8021f Shikhar Bhushan
        """`list` of `RPCError` objects. Will be empty if there were no *rpc-error* elements in
155 4bc8021f Shikhar Bhushan
        reply."""
156 4bc8021f Shikhar Bhushan
        self.parse()
157 4bc8021f Shikhar Bhushan
        return self._errors
158 4bc8021f Shikhar Bhushan
159 4bc8021f Shikhar Bhushan
160 11bab021 Shikhar Bhushan
class RPCReplyListener(SessionListener): # internal use
161 11bab021 Shikhar Bhushan
    
162 11bab021 Shikhar Bhushan
    creation_lock = Lock()
163 11bab021 Shikhar Bhushan
    
164 7b02d55b Shikhar Bhushan
    # one instance per session -- maybe there is a better way??
165 a14c36f9 Shikhar Bhushan
    def __new__(cls, session):
166 7c4ff459 Shikhar Bhushan
        with RPCReplyListener.creation_lock:
167 11bab021 Shikhar Bhushan
            instance = session.get_listener_instance(cls)
168 11bab021 Shikhar Bhushan
            if instance is None:
169 11bab021 Shikhar Bhushan
                instance = object.__new__(cls)
170 11bab021 Shikhar Bhushan
                instance._lock = Lock()
171 11bab021 Shikhar Bhushan
                instance._id2rpc = {}
172 11bab021 Shikhar Bhushan
                #instance._pipelined = session.can_pipeline
173 11bab021 Shikhar Bhushan
                session.add_listener(instance)
174 11bab021 Shikhar Bhushan
            return instance
175 4f650d54 Shikhar Bhushan
176 a14c36f9 Shikhar Bhushan
    def register(self, id, rpc):
177 a14c36f9 Shikhar Bhushan
        with self._lock:
178 a14c36f9 Shikhar Bhushan
            self._id2rpc[id] = rpc
179 4f650d54 Shikhar Bhushan
180 a14c36f9 Shikhar Bhushan
    def callback(self, root, raw):
181 a14c36f9 Shikhar Bhushan
        tag, attrs = root
182 9667bcb2 Shikhar Bhushan
        if tag != qualify("rpc-reply"):
183 a14c36f9 Shikhar Bhushan
            return
184 0304f041 Shikhar Bhushan
        for key in attrs: # in the <rpc-reply> attributes
185 9667bcb2 Shikhar Bhushan
            if key == "message-id": # if we found msgid attr
186 0304f041 Shikhar Bhushan
                id = attrs[key] # get the msgid
187 9667bcb2 Shikhar Bhushan
                with self._lock:
188 11bab021 Shikhar Bhushan
                    try:
189 9667bcb2 Shikhar Bhushan
                        rpc = self._id2rpc[id] # the corresponding rpc
190 9667bcb2 Shikhar Bhushan
                        logger.debug("Delivering to %r" % rpc)
191 0304f041 Shikhar Bhushan
                        rpc.deliver_reply(raw)
192 9667bcb2 Shikhar Bhushan
                    except KeyError:
193 11bab021 Shikhar Bhushan
                        raise OperationError("Unknown 'message-id': %s", id)
194 9667bcb2 Shikhar Bhushan
                    # no catching other exceptions, fail loudly if must
195 9667bcb2 Shikhar Bhushan
                    else:
196 9667bcb2 Shikhar Bhushan
                        # if no error delivering, can del the reference to the RPC
197 9667bcb2 Shikhar Bhushan
                        del self._id2rpc[id]
198 9667bcb2 Shikhar Bhushan
                        break
199 a14c36f9 Shikhar Bhushan
        else:
200 9667bcb2 Shikhar Bhushan
            raise OperationError("Could not find 'message-id' attribute in <rpc-reply>")
201 0304f041 Shikhar Bhushan
    
202 a14c36f9 Shikhar Bhushan
    def errback(self, err):
203 6a2dfeb4 Shikhar Bhushan
        try:
204 6a2dfeb4 Shikhar Bhushan
            for rpc in self._id2rpc.values():
205 6a2dfeb4 Shikhar Bhushan
                rpc.deliver_error(err)
206 6a2dfeb4 Shikhar Bhushan
        finally:
207 6a2dfeb4 Shikhar Bhushan
            self._id2rpc.clear()
208 4de03d63 Shikhar Bhushan
209 4de03d63 Shikhar Bhushan
210 4de03d63 Shikhar Bhushan
class RPC(object):
211 4bc8021f Shikhar Bhushan
    
212 4bc8021f Shikhar Bhushan
    """Base class for all operations, directly corresponding to *rpc* requests. Handles making the
213 4bc8021f Shikhar Bhushan
    request, and taking delivery of the reply."""
214 4bc8021f Shikhar Bhushan
    
215 4de03d63 Shikhar Bhushan
    DEPENDS = []
216 4bc8021f Shikhar Bhushan
    """Subclasses can specify their dependencies on capabilities. List of URI's or abbreviated
217 4bc8021f Shikhar Bhushan
    names, e.g. ':writable-running'. These are verified at the time of instantiation. If the
218 4bc8021f Shikhar Bhushan
    capability is not available, a :exc:`MissingCapabilityError` is raised.
219 4bc8021f Shikhar Bhushan
    """
220 4bc8021f Shikhar Bhushan
    
221 4de03d63 Shikhar Bhushan
    REPLY_CLS = RPCReply
222 4bc8021f Shikhar Bhushan
    "Subclasses can specify a different reply class, but it should be a subclass of `RPCReply`."
223 4bc8021f Shikhar Bhushan
    
224 9667bcb2 Shikhar Bhushan
    def __init__(self, session, async=False, timeout=None, raise_mode="none"):
225 4de03d63 Shikhar Bhushan
        self._session = session
226 4de03d63 Shikhar Bhushan
        try:
227 4de03d63 Shikhar Bhushan
            for cap in self.DEPENDS:
228 4de03d63 Shikhar Bhushan
                self._assert(cap)
229 4de03d63 Shikhar Bhushan
        except AttributeError:
230 4f650d54 Shikhar Bhushan
            pass
231 4de03d63 Shikhar Bhushan
        self._async = async
232 4de03d63 Shikhar Bhushan
        self._timeout = timeout
233 6c70b245 Shikhar Bhushan
        self._raise_mode = raise_mode
234 4bc8021f Shikhar Bhushan
        self._id = uuid1().urn # Keeps things simple instead of having a class attr with running ID that has to be locked
235 4de03d63 Shikhar Bhushan
        self._listener = RPCReplyListener(session)
236 4de03d63 Shikhar Bhushan
        self._listener.register(self._id, self)
237 4de03d63 Shikhar Bhushan
        self._reply = None
238 4f650d54 Shikhar Bhushan
        self._error = None
239 a7cb58ce Shikhar Bhushan
        self._event = Event()
240 4bc8021f Shikhar Bhushan
    
241 4bc8021f Shikhar Bhushan
    def _wrap(self, subele):
242 4bc8021f Shikhar Bhushan
        # internal use
243 9667bcb2 Shikhar Bhushan
        ele = new_ele("rpc", {"message-id": self._id}, xmlns=BASE_NS_1_0)
244 9667bcb2 Shikhar Bhushan
        ele.append(subele)
245 9667bcb2 Shikhar Bhushan
        return to_xml(ele)
246 4f650d54 Shikhar Bhushan
247 4de03d63 Shikhar Bhushan
    def _request(self, op):
248 4bc8021f Shikhar Bhushan
        """Implementations of :meth:`request` call this method to send the request and process the
249 4bc8021f Shikhar Bhushan
        reply.
250 0304f041 Shikhar Bhushan
        
251 4bc8021f Shikhar Bhushan
        In synchronous mode, blocks until the reply is received and returns `RPCReply`. Depending on
252 4bc8021f Shikhar Bhushan
        the :attr:`raise_mode` a *rpc-error* element in the reply may lead to an :exc:`RPCError`
253 4bc8021f Shikhar Bhushan
        exception.
254 0304f041 Shikhar Bhushan
        
255 4bc8021f Shikhar Bhushan
        In asynchronous mode, returns immediately, returning *self*. The :attr:`event` attribute
256 4bc8021f Shikhar Bhushan
        will be set when the reply has been received (see :attr:`reply`) or an error occured (see
257 4bc8021f Shikhar Bhushan
        :attr:`error`).
258 0304f041 Shikhar Bhushan
        
259 4bc8021f Shikhar Bhushan
        :param op: operation to be requested
260 4bc8021f Shikhar Bhushan
        :type ops: `~xml.etree.ElementTree.Element`
261 4bc8021f Shikhar Bhushan
        
262 4bc8021f Shikhar Bhushan
        :rtype: `RPCReply` (sync) or `RPC` (async)
263 a7cb58ce Shikhar Bhushan
        """
264 9667bcb2 Shikhar Bhushan
        logger.info('Requesting %r' % self.__class__.__name__)
265 4bc8021f Shikhar Bhushan
        req = self._wrap(op)
266 66cd54c8 Shikhar Bhushan
        self._session.send(req)
267 66cd54c8 Shikhar Bhushan
        if self._async:
268 9667bcb2 Shikhar Bhushan
            logger.debug('Async request, returning %r', self)
269 0304f041 Shikhar Bhushan
            return self
270 4de03d63 Shikhar Bhushan
        else:
271 b2d60e49 Shikhar Bhushan
            logger.debug('Sync request, will wait for timeout=%r' % self._timeout)
272 66cd54c8 Shikhar Bhushan
            self._event.wait(self._timeout)
273 66cd54c8 Shikhar Bhushan
            if self._event.isSet():
274 66cd54c8 Shikhar Bhushan
                if self._error:
275 6c70b245 Shikhar Bhushan
                    # Error that prevented reply delivery
276 0cdb8b3c Shikhar Bhushan
                    raise self._error
277 66cd54c8 Shikhar Bhushan
                self._reply.parse()
278 6c70b245 Shikhar Bhushan
                if self._reply.error is not None:
279 6c70b245 Shikhar Bhushan
                    # <rpc-error>'s [ RPCError ]
280 6c70b245 Shikhar Bhushan
                    if self._raise_mode == "all":
281 7b02d55b Shikhar Bhushan
                        raise self._reply.error
282 6c70b245 Shikhar Bhushan
                    elif (self._raise_mode == "errors" and
283 6c70b245 Shikhar Bhushan
                          self._reply.error.type == "error"):
284 6c70b245 Shikhar Bhushan
                        raise self._reply.error
285 66cd54c8 Shikhar Bhushan
                return self._reply
286 4de03d63 Shikhar Bhushan
            else:
287 216bb34c Shikhar Bhushan
                raise TimeoutExpiredError
288 4f650d54 Shikhar Bhushan
289 b2d60e49 Shikhar Bhushan
    def request(self):
290 4bc8021f Shikhar Bhushan
        """Subclasses must implement this method. Typically only the request needs to be built as an
291 4bc8021f Shikhar Bhushan
        `~xml.etree.ElementTree.Element` and everything else can be handed off to
292 4bc8021f Shikhar Bhushan
        :meth:`_request`."""
293 4bc8021f Shikhar Bhushan
        pass
294 6c70b245 Shikhar Bhushan
    
295 4de03d63 Shikhar Bhushan
    def _assert(self, capability):
296 4bc8021f Shikhar Bhushan
        """Subclasses can use this method to verify that a capability is available with the NETCONF
297 4bc8021f Shikhar Bhushan
        server, before making a request that requires it. A :exc:`MissingCapabilityError` will be
298 4bc8021f Shikhar Bhushan
        raised if the capability is not available."""
299 4de03d63 Shikhar Bhushan
        if capability not in self._session.server_capabilities:
300 b2d60e49 Shikhar Bhushan
            raise MissingCapabilityError('Server does not support [%s]' % capability)
301 0304f041 Shikhar Bhushan
    
302 a7cb58ce Shikhar Bhushan
    def deliver_reply(self, raw):
303 a7cb58ce Shikhar Bhushan
        # internal use
304 4de03d63 Shikhar Bhushan
        self._reply = self.REPLY_CLS(raw)
305 a7cb58ce Shikhar Bhushan
        self._event.set()
306 4f650d54 Shikhar Bhushan
307 a7cb58ce Shikhar Bhushan
    def deliver_error(self, err):
308 a7cb58ce Shikhar Bhushan
        # internal use
309 0cdb8b3c Shikhar Bhushan
        self._error = err
310 a7cb58ce Shikhar Bhushan
        self._event.set()
311 4bc8021f Shikhar Bhushan
    
312 4de03d63 Shikhar Bhushan
    @property
313 4de03d63 Shikhar Bhushan
    def reply(self):
314 4bc8021f Shikhar Bhushan
        "`RPCReply` element if reply has been received or :const:`None`"
315 4de03d63 Shikhar Bhushan
        return self._reply
316 4bc8021f Shikhar Bhushan
    
317 4de03d63 Shikhar Bhushan
    @property
318 a7cb58ce Shikhar Bhushan
    def error(self):
319 a7cb58ce Shikhar Bhushan
        """:exc:`Exception` type if an error occured or :const:`None`.
320 0304f041 Shikhar Bhushan
        
321 a7cb58ce Shikhar Bhushan
        .. note::
322 4bc8021f Shikhar Bhushan
            This represents an error which prevented a reply from being received. An *rpc-error*
323 4bc8021f Shikhar Bhushan
            does not fall in that category -- see `RPCReply` for that.
324 a7cb58ce Shikhar Bhushan
        """
325 a7cb58ce Shikhar Bhushan
        return self._error
326 4bc8021f Shikhar Bhushan
    
327 a7cb58ce Shikhar Bhushan
    @property
328 4de03d63 Shikhar Bhushan
    def id(self):
329 4bc8021f Shikhar Bhushan
        "The *message-id* for this RPC."
330 4de03d63 Shikhar Bhushan
        return self._id
331 4bc8021f Shikhar Bhushan
    
332 4de03d63 Shikhar Bhushan
    @property
333 4de03d63 Shikhar Bhushan
    def session(self):
334 4bc8021f Shikhar Bhushan
        "The `~ncclient.transport.Session` object associated with this RPC."
335 4de03d63 Shikhar Bhushan
        return self._session
336 4f650d54 Shikhar Bhushan
337 4de03d63 Shikhar Bhushan
    @property
338 a7cb58ce Shikhar Bhushan
    def event(self):
339 4bc8021f Shikhar Bhushan
        """`~threading.Event` that is set when reply has been received or when an error preventing
340 4bc8021f Shikhar Bhushan
        delivery of the reply occurs.
341 4bc8021f Shikhar Bhushan
        """
342 a7cb58ce Shikhar Bhushan
        return self._event
343 a7cb58ce Shikhar Bhushan
344 a7cb58ce Shikhar Bhushan
    def set_async(self, async=True):
345 a7cb58ce Shikhar Bhushan
        self._async = async
346 a7cb58ce Shikhar Bhushan
        if async and not session.can_pipeline:
347 a7cb58ce Shikhar Bhushan
            raise UserWarning('Asynchronous mode not supported for this device/session')
348 a7cb58ce Shikhar Bhushan
349 6c70b245 Shikhar Bhushan
    def set_raise_mode(self, mode):
350 9667bcb2 Shikhar Bhushan
        assert(choice in ("all", "errors", "none"))
351 6c70b245 Shikhar Bhushan
        self._raise_mode = mode
352 e0e01d37 Shikhar Bhushan
353 a7cb58ce Shikhar Bhushan
    def set_timeout(self, timeout):
354 a7cb58ce Shikhar Bhushan
        self._timeout = timeout
355 4f650d54 Shikhar Bhushan
356 4bc8021f Shikhar Bhushan
    raise_mode = property(fget=lambda self: self._raise_mode, fset=set_raise_mode)
357 4bc8021f Shikhar Bhushan
    """Depending on this exception raising mode, an *rpc-error* in the reply may be raised as
358 4bc8021f Shikhar Bhushan
    :exc:`RPCError` exceptions. Valid values:
359 4bc8021f Shikhar Bhushan
    
360 4bc8021f Shikhar Bhushan
    * ``"all"`` -- any kind of *rpc-error* (error or warning)
361 4bc8021f Shikhar Bhushan
    * ``"errors"`` -- when the *error-type* element says it is an error
362 4bc8021f Shikhar Bhushan
    * ``"none"`` -- neither
363 4bc8021f Shikhar Bhushan
    """
364 4bc8021f Shikhar Bhushan
    
365 9667bcb2 Shikhar Bhushan
    is_async = property(fget=lambda self: self._async, fset=set_async)
366 4bc8021f Shikhar Bhushan
    """Specifies whether this RPC will be / was requested asynchronously. By default RPC's are
367 4bc8021f Shikhar Bhushan
    synchronous.
368 4bc8021f Shikhar Bhushan
    """
369 4bc8021f Shikhar Bhushan
    
370 4de03d63 Shikhar Bhushan
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)
371 4bc8021f Shikhar Bhushan
    """Timeout in seconds for synchronous waiting defining how long the RPC request will block on a
372 4bc8021f Shikhar Bhushan
    reply before raising :exc:`TimeoutExpiredError`. By default there is no timeout, represented by
373 4bc8021f Shikhar Bhushan
    :const:`None`.
374 4bc8021f Shikhar Bhushan
    
375 4bc8021f Shikhar Bhushan
    Irrelevant for asynchronous usage.
376 4bc8021f Shikhar Bhushan
    """